From ad41dcea5a20ba122e8bed46310b01c4b2b1fbd5 Mon Sep 17 00:00:00 2001 From: Jonathan Worthington Date: Fri, 30 Oct 2020 12:56:16 +0100 Subject: [PATCH 1/5] Refactor handling of enums in inputs Parse the value language string up front, when we create the input, so that we don't have to do it every time we call `as-hash`, and also so we don't have `.enums` handing back an unparsed string in its value. --- lib/Agrammon/Model/Input.pm6 | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lib/Agrammon/Model/Input.pm6 b/lib/Agrammon/Model/Input.pm6 index da49a2063..359836d8d 100644 --- a/lib/Agrammon/Model/Input.pm6 +++ b/lib/Agrammon/Model/Input.pm6 @@ -15,10 +15,6 @@ class Agrammon::Model::Input { has %.units; has %.help; has Str @.models; - # has Str @.options; # XXX set correct type: array of arrays - # has Str @.optionsLang; # XXX set correct type: array of hashes - has @.options; # XXX set correct type: array of arrays - has @.options-lang; # XXX set correct type: array of hashes has @!enum-order; has %!enum-lookup; has Int $.order; @@ -38,8 +34,8 @@ class Agrammon::Model::Input { } } if @enum { - @!enum-order = @enum; - %!enum-lookup = @enum; + @!enum-order = @enum.map({ .key => self!parse-enum-lang-values(.value) }); + %!enum-lookup = @!enum-order; } with $filter { if .lc eq 'true' { @@ -73,19 +69,9 @@ class Agrammon::Model::Input { for @!enum-order { my $name = .key; - my $optLang = .value; - my $label = $name; - $label ~~ s:g/_/ /; - my @opt = [ $label, '', $name]; - my @opt-lang = split("\n", $optLang); - my %opt-lang; - for @opt-lang -> $ol { - my ($l, $o) = split(/ \s* '=' \s* /, $ol); - $o ~~ s:g/_/ /; - %opt-lang{$l} = $o; - } - push @options, @opt; - push @options-lang, %opt-lang; + my $label = $name.subst('_', ' ', :g); + push @options, [$label, '', $name]; + push @options-lang, .value; } return %( @@ -107,4 +93,13 @@ class Agrammon::Model::Input { ) } + method !parse-enum-lang-values(Str $value --> Hash) { + my %opt-lang; + for (split("\n", $value)) -> $ol { + my ($l, $o) = split(/ \s* '=' \s* /, $ol); + $o ~~ s:g/_/ /; + %opt-lang{$l} = $o; + } + %opt-lang + } } From 38977f2ad85336386079d02cb6eefbc6467d8942 Mon Sep 17 00:00:00 2001 From: Jonathan Worthington Date: Fri, 30 Oct 2020 16:04:50 +0100 Subject: [PATCH 2/5] Provide a way to get all possible filter outputs Keep track of the filter sets that contribute to a filter group in the outputs. With the possible options in the enum attached to the filter sets, this means we can produce all of the filter keys that could ever occur. Use this to offer a means to get all of the filter group's values including zero entries for those that have no instances using those enum options. The options are sorted according to the enum within a given module, however the order of modules is undetermined. --- lib/Agrammon/Model.pm6 | 2 +- lib/Agrammon/Model/FilterSet.pm6 | 18 +++++- lib/Agrammon/Model/Input.pm6 | 2 + lib/Agrammon/Outputs.pm6 | 19 ++++++- .../Outputs/FilterGroupCollection.pm6 | 55 +++++++++++++++---- t/model-with-filters.t | 12 +++- 6 files changed, 91 insertions(+), 17 deletions(-) diff --git a/lib/Agrammon/Model.pm6 b/lib/Agrammon/Model.pm6 index 03398e9a3..9fb5a8033 100644 --- a/lib/Agrammon/Model.pm6 +++ b/lib/Agrammon/Model.pm6 @@ -95,7 +95,7 @@ class Agrammon::Model { $outputs.declare-multi-instance($tax); for $input.inputs-list-for($tax) -> $multi-input { my %filters := $!filter-set.filters-for($multi-input); - my $multi-output = $outputs.new-instance($tax, $multi-input.instance-id, :%filters); + my $multi-output = $outputs.new-instance($tax, $multi-input.instance-id, :%filters, :$!filter-set); self!run-as-single($multi-input, %technical, $multi-output, %run-already.clone); } self!mark-multi-run(%run-already); diff --git a/lib/Agrammon/Model/FilterSet.pm6 b/lib/Agrammon/Model/FilterSet.pm6 index 2f4ed45e3..2358b272e 100644 --- a/lib/Agrammon/Model/FilterSet.pm6 +++ b/lib/Agrammon/Model/FilterSet.pm6 @@ -9,6 +9,7 @@ class Agrammon::Model::FilterSet { has Str $.taxonomy is required; has Str $.input-name is required; has Str $.filter-key = $!taxonomy ~ '::' ~ $!input-name; + has @.options is required; } has Filter @!filters; @@ -21,7 +22,14 @@ class Agrammon::Model::FilterSet { method !add-from-module(Agrammon::Model::Module $module --> Nil) { for $module.input -> Agrammon::Model::Input $input { if $input.is-filter { - @!filters.push: Filter.new: taxonomy => $module.taxonomy, input-name => $input.name; + my @enums := $input.enum-ordered; + unless @enums { + die "Filter input '$input.name()' in module '$module.taxonomy()' is not an enum type"; + } + @!filters.push: Filter.new: + taxonomy => $module.taxonomy, + input-name => $input.name, + options => @enums; } } } @@ -38,4 +46,12 @@ class Agrammon::Model::FilterSet { } } } + + #| Get all possible filter key sets. + method all-possible-filter-keys(--> Sequence) { + my @combos = @!filters.map: -> Filter $filter { + [ $filter.filter-key <<=>>> $filter.options.map(*.key) ] + } + (@!filters == 1 ?? @combos[0] !! cross(@combos)).map(*.hash) + } } diff --git a/lib/Agrammon/Model/Input.pm6 b/lib/Agrammon/Model/Input.pm6 index 359836d8d..3a3913a2c 100644 --- a/lib/Agrammon/Model/Input.pm6 +++ b/lib/Agrammon/Model/Input.pm6 @@ -46,6 +46,8 @@ class Agrammon::Model::Input { method enum(--> Hash) { %!enum-lookup } + method enum-ordered(--> Array) { @!enum-order } + method is-branch(--> Bool) { $!branch } method is-filter(--> Bool) { $!filter } diff --git a/lib/Agrammon/Outputs.pm6 b/lib/Agrammon/Outputs.pm6 index 883bcb68d..d7e229dcc 100644 --- a/lib/Agrammon/Outputs.pm6 +++ b/lib/Agrammon/Outputs.pm6 @@ -16,6 +16,13 @@ class X::Agrammon::Outputs::DuplicateInstance is Exception { } } +class X::Agrammon::Ouputs::FiltersWithoutFilterSet is Exception { + has Str $.taxonomy-prefix is required; + method message() { + "Cannot create instance with filters without also providing filter set" + } +} + class X::Agrammon::Outputs::IsMultiInstance is Exception { has $.module is required; has $.name is required; @@ -53,6 +60,7 @@ class Agrammon::Outputs::Instance does Agrammon::Outputs::SingleOutputStorage { has Str $.taxonomy-prefix is required; has Str $.instance-name is required; has %.filters; + has $.filter-set; has Agrammon::Outputs $.parent is required; method get-output(Str $module, Str $name) { @@ -85,14 +93,18 @@ class Agrammon::Outputs does Agrammon::Outputs::SingleOutputStorage { %!instances{$taxonomy-prefix} //= {}; } - method new-instance(Str $taxonomy-prefix, Str $instance-name, :%filters --> Agrammon::Outputs::Instance) { + method new-instance(Str $taxonomy-prefix, Str $instance-name, :%filters, + :$filter-set --> Agrammon::Outputs::Instance) { without %!instances{$taxonomy-prefix} { die X::Agrammon::Outputs::NotDeclaredMultiInstance.new(module => $taxonomy-prefix); } with %!instances{$taxonomy-prefix}{$instance-name} { die X::Agrammon::Outputs::DuplicateInstance.new(:$taxonomy-prefix, :$instance-name); } - given Agrammon::Outputs::Instance.new(:$taxonomy-prefix, :$instance-name, :parent(self), :%filters) -> $instance { + if %filters && !$filter-set { + die X::Agrammon::Ouputs::FiltersWithoutFilterSet.new(:$taxonomy-prefix); + } + given Agrammon::Outputs::Instance.new(:$taxonomy-prefix, :$instance-name, :parent(self), :%filters, :$filter-set) -> $instance { %!instances{$taxonomy-prefix}{$instance-name} = $instance; return $instance; } @@ -117,7 +129,8 @@ class Agrammon::Outputs does Agrammon::Outputs::SingleOutputStorage { method get-sum(Str $module, Str $name) { with self.find-instances($module) { Agrammon::Outputs::FilterGroupCollection.from-filter-to-value-pairs: - .values.map({ .filters => .get-output($module, $name) }) + .values.map({ .filters => .get-output($module, $name) }), + :provenance(set(.values.map(*.filter-set))) } else { # Make sure it's not a bogus use of single-instance symbol, diff --git a/lib/Agrammon/Outputs/FilterGroupCollection.pm6 b/lib/Agrammon/Outputs/FilterGroupCollection.pm6 index 8a78587b8..dff7f0647 100644 --- a/lib/Agrammon/Outputs/FilterGroupCollection.pm6 +++ b/lib/Agrammon/Outputs/FilterGroupCollection.pm6 @@ -21,8 +21,9 @@ class Agrammon::Outputs::FilterGroupCollection { } has Numeric %!values-by-filter{FilterKey}; + has Set $.provenance; - submethod BUILD(:@instances!) { + submethod BUILD(:$!provenance = ∅, :@instances!) { for @instances { %!values-by-filter{.key} += .value; } @@ -35,8 +36,10 @@ class Agrammon::Outputs::FilterGroupCollection { #| Create from a list of pairs where the key is a hash of filter values for an instance #| and the value is the instance's value. - method from-filter-to-value-pairs(@instances) { - self.bless: instances => @instances.map({ FilterKey.new(filters => .key) => +.value }) + method from-filter-to-value-pairs(@instances, Set :$provenance = ∅) { + self.bless: + :instances(@instances.map({ FilterKey.new(filters => .key) => +.value })), + :$provenance } #| Check if the collection has any filters. @@ -54,9 +57,30 @@ class Agrammon::Outputs::FilterGroupCollection { self.Numeric.Real } - #| Get a list of pairs mapping filter groups into the total value for that group. - method results-by-filter-group() { - [%!values-by-filter.map({ .key.filters => .value })] + #| Get a list of pairs mapping filter groups into the total value for that + #| group. If :all is passed, then all filters that could possibly have been + #| selected will be included, even if no instance used them, and they will + #| have a zero value. + method results-by-filter-group(Bool :$all = False) { + if $all { + if %!values-by-filter && !$!provenance { + die "Can only got all values when provenance of the filter group was provided"; + } + my @results; + for $!provenance.keys -> $filter-set { + for $filter-set.all-possible-filter-keys -> %filters { + my $key = FilterKey.new(:%filters); + @results.push(%filters => %!values-by-filter{$key} // 0); + } + } + with %!values-by-filter{FilterKey.empty} { + @results.push({} => $_); + } + @results + } + else { + [%!values-by-filter.map({ .key.filters => .value })] + } } #| Produce a new filter group collection which has the values of this one scaled by @@ -64,7 +88,9 @@ class Agrammon::Outputs::FilterGroupCollection { #| (these two just commute), and `group / scalar` (by passing in `1 / scalar` as the #| factor). method scale(Numeric $factor --> Agrammon::Outputs::FilterGroupCollection) { - self.bless: instances => %!values-by-filter.map({ .key => $factor * .value }) + self.bless: + :instances(%!values-by-filter.map({ .key => $factor * .value })), + :$!provenance } #| Produce a new filter group collection which has the values of this one added to @@ -72,12 +98,16 @@ class Agrammon::Outputs::FilterGroupCollection { #| (these two just commute), and `group - scalar` (by passing in `- scalar` as the #| additor). method add(Numeric $factor --> Agrammon::Outputs::FilterGroupCollection) { - self.bless: instances => %!values-by-filter.map({ .key => $factor + .value }) + self.bless: + :instances(%!values-by-filter.map({ .key => $factor + .value })), + :$!provenance } #| Produce a new filter group collection which has the sign of this one. method sign() { - self.bless: instances => %!values-by-filter.map({ .key => sign( .value ) }) + self.bless: + :instances(%!values-by-filter.map({ .key => sign( .value ) })), + :$!provenance } #| Apply an operation pairwise between this group collection and another one, returning a @@ -109,7 +139,9 @@ class Agrammon::Outputs::FilterGroupCollection { } } - Agrammon::Outputs::FilterGroupCollection.new(instances => @result-instances) + Agrammon::Outputs::FilterGroupCollection.new: + instances => @result-instances, + provenance => $!provenance ∪ $other.provenance } #| Check in the other filter group collection for values that are greater than a threshold @@ -140,7 +172,8 @@ class Agrammon::Outputs::FilterGroupCollection { } } - Agrammon::Outputs::FilterGroupCollection.new(instances => @result-instances) + Agrammon::Outputs::FilterGroupCollection.new: + :instances(@result-instances), :$!provenance } #| Private accessor to get internal representation of another collection. diff --git a/t/model-with-filters.t b/t/model-with-filters.t index 6262e3caf..06e4053d2 100644 --- a/t/model-with-filters.t +++ b/t/model-with-filters.t @@ -90,6 +90,17 @@ subtest 'Running the model produces output instances with filters' => { is .elems, 1, 'Found filter group value for boars'; is .[0].value, <238158/10625>, 'Correct value calculated for boars'; } + my @all-results-by-group = $livestock-tan.results-by-filter-group(:all); + given @all-results-by-group[0] { + ok .key eqv {"Livestock::Pig::Excretion::animalcategory" => 'nursing_sows'}, + 'First key is first enum element'; + is-deeply .value, <347116/5625>, 'Correct value'; + } + given @all-results-by-group[2] { + ok .key eqv {"Livestock::Pig::Excretion::animalcategory" => 'gilts'}, + 'Have a key included without a value'; + is-deeply .value, 0, 'Zero value'; + } } subtest 'filterGroup builtin' => { @@ -97,7 +108,6 @@ subtest 'Running the model produces output instances with filters' => { isa-ok $factor, Agrammon::Outputs::FilterGroupCollection, 'filterGroup builtin will produce a filter group collection'; my @results-by-group = $factor.results-by-filter-group; - dd @results-by-group; given @results-by-group.grep(*.key eqv { "Livestock::Pig::Excretion::animalcategory" => "boars" }) { is .elems, 1, 'Found filter group value for boars'; is .[0].value, 0.75, 'Correct value for boars'; From 5753f56e32ef1b85f6de986127571d5147cb821d Mon Sep 17 00:00:00 2001 From: Fritz Zaucker Date: Fri, 30 Oct 2020 20:48:59 +0100 Subject: [PATCH 3/5] Sort by keys --- lib/Agrammon/Outputs/FilterGroupCollection.pm6 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Agrammon/Outputs/FilterGroupCollection.pm6 b/lib/Agrammon/Outputs/FilterGroupCollection.pm6 index dff7f0647..4427453f6 100644 --- a/lib/Agrammon/Outputs/FilterGroupCollection.pm6 +++ b/lib/Agrammon/Outputs/FilterGroupCollection.pm6 @@ -64,10 +64,10 @@ class Agrammon::Outputs::FilterGroupCollection { method results-by-filter-group(Bool :$all = False) { if $all { if %!values-by-filter && !$!provenance { - die "Can only got all values when provenance of the filter group was provided"; + die "Can only get all values when provenance of the filter group was provided"; } my @results; - for $!provenance.keys -> $filter-set { + for $!provenance.keys.sort.reverse -> $filter-set { for $filter-set.all-possible-filter-keys -> %filters { my $key = FilterKey.new(:%filters); @results.push(%filters => %!values-by-filter{$key} // 0); @@ -162,13 +162,13 @@ class Agrammon::Outputs::FilterGroupCollection { else { # Push 0 if their value > threshold, but key is not existing # 0 because of missing flow (zero flow) - @result-instances.push: $their-key => 0; - } - } + @result-instances.push: $their-key => 0; + } + } elsif $push-all { # Push threshold if their value <= threshold. Could also be 0, # but it might become handy for limiting ratio to 1, i.e. threshold = 1? - @result-instances.push: $their-key => $thresh; + @result-instances.push: $their-key => $thresh; } } From c0be941d584d8a2213f05bc51673b28f80efc4e7 Mon Sep 17 00:00:00 2001 From: Fritz Zaucker Date: Fri, 30 Oct 2020 20:50:55 +0100 Subject: [PATCH 4/5] Add --include-all-filters for text output --- lib/Agrammon/OutputFormatter/Text.pm6 | 17 ++++++++-------- lib/Agrammon/UI/CommandLine.pm6 | 28 +++++++++++++++++---------- t/test-data/agrammon.cfg.yaml | 2 ++ 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/Agrammon/OutputFormatter/Text.pm6 b/lib/Agrammon/OutputFormatter/Text.pm6 index d44279502..20d558bc1 100644 --- a/lib/Agrammon/OutputFormatter/Text.pm6 +++ b/lib/Agrammon/OutputFormatter/Text.pm6 @@ -2,24 +2,25 @@ use Agrammon::Model; use Agrammon::Outputs; sub output-as-text(Agrammon::Model $model, Agrammon::Outputs $outputs, Str $language, - Str $prints, Bool $include-filters --> Str) is export { + Str $prints, Bool $include-filters, Bool :$all-filters = False --> Str) is export { my @lines; - my @print-set = $prints.split(','); + my @print-set = $prints.split(',') if $prints; for sorted-kv($outputs.get-outputs-hash) -> $module, $_ { my $n = 0; my @module-lines; + my $indent = ' '; push @module-lines, $module; when Hash { for sorted-kv($_) -> $output, $value { my $val = flat-value($value // 'UNDEFINED'); my $var-print = $model.output-print($module, $output) ~ ',All'; - if $var-print.split(',') ∩ @print-set { + if not $prints or $var-print.split(',') ∩ @print-set { $n++; my $unit = $model.output-unit($module, $output, $language); push @module-lines, " $output = $val $unit"; if $include-filters { if $value ~~ Agrammon::Outputs::FilterGroupCollection && $value.has-filters { - render-filters(@module-lines, $value, $unit, " "); + render-filters(@module-lines, $value, $unit, $indent, :$all-filters); } } } @@ -33,13 +34,13 @@ sub output-as-text(Agrammon::Model $model, Agrammon::Outputs $outputs, Str $lang for sorted-kv(%values) -> $output, $value { my $val = flat-value($value // 'UNDEFINED'); my $var-print = $model.output-print($module, $output) ~ ',All'; - if $var-print.split(',') ∩ @print-set { + if not $prints or $var-print.split(',') ∩ @print-set { $n++; my $unit = $model.output-unit($module, $output, $language); push @module-lines, " $output = $val $unit"; if $include-filters { if $value ~~ Agrammon::Outputs::FilterGroupCollection && $value.has-filters { - render-filters(@module-lines, $value, $unit, " "); + render-filters(@module-lines, $value, $unit, $indent, :$all-filters); } } } @@ -62,8 +63,8 @@ multi sub flat-value(Agrammon::Outputs::FilterGroupCollection $collection) { } sub render-filters(@module-lines, Agrammon::Outputs::FilterGroupCollection $collection, - $unit, $prefix) { - my @results = $collection.results-by-filter-group; + $unit, Str $prefix, Bool :$all-filters) { + my @results = $collection.results-by-filter-group(:all($all-filters)); my $longest-filter = @results.map({ .key.map({ .key.chars + .value.chars }) }).flat.max + 1; for @results { my %filters := .key; diff --git a/lib/Agrammon/UI/CommandLine.pm6 b/lib/Agrammon/UI/CommandLine.pm6 index f44e5f8d2..e8391a6d8 100644 --- a/lib/Agrammon/UI/CommandLine.pm6 +++ b/lib/Agrammon/UI/CommandLine.pm6 @@ -44,11 +44,12 @@ multi sub MAIN('web', ExistingFile $cfg-filename, ExistingFile $model-filename, #| Run the model multi sub MAIN('run', ExistingFile $filename, ExistingFile $input, Str $technical-file?, SupportedLanguage :$language = 'de', Str :$prints, Str :$variants = 'SHL', - Bool :$include-filters, Int :$batch=1, Int :$degree=4, Int :$max-runs, + Bool :$include-filters, Bool :$include-all-filters=False, Int :$batch=1, Int :$degree=4, Int :$max-runs, OutputFormat :$format = 'text' ) is export { - my %results = run $filename.IO, $input.IO, $technical-file, $variants, $format, $language, $prints, $include-filters, - $batch, $degree, $max-runs; + my %results = run $filename.IO, $input.IO, $technical-file, $variants, $format, $language, $prints, + ($include-filters or $include-all-filters), + $batch, $degree, $max-runs, :all-filters($include-all-filters); my $output; if $format eq 'json' { $output = to-json %results; @@ -57,9 +58,9 @@ multi sub MAIN('run', ExistingFile $filename, ExistingFile $input, Str $technica my @output; @output.push("## Model: $filename"); @output.push("## Variants: $variants"); - for %results.keys -> $simulation, %sim-results { + for %results.kv -> $simulation, %sim-results { @output.push("### Simulation $simulation"); - @output.push("## Print filter: $prints"); + @output.push("## Print filter: $prints") if $prints; for %sim-results.keys.sort -> $dataset { @output.push("# Dataset $dataset"); @output.push(%sim-results{$dataset}); @@ -131,8 +132,8 @@ sub dump-model (IO::Path $path, $variants, $sort) is export { return $model.dump($sort); } -sub run (IO::Path $path, IO::Path $input-path, $technical-file, $variants, $format, $language, $prints, Bool $include-filters, - $batch, $degree, $max-runs) is export { +sub run (IO::Path $path, IO::Path $input-path, $technical-file, $variants, $format, $language, $prints, + Bool $include-filters, $batch, $degree, $max-runs, :$all-filters) is export { die "ERROR: run expects a .nhd file" unless $path.extension eq 'nhd'; my $module-path = $path.parent; @@ -176,13 +177,20 @@ sub run (IO::Path $path, IO::Path $input-path, $technical-file, $variants, $form given $format { when 'csv' { die "CSV output including filters is not yet supported" if $include-filters; - $result = output-as-csv($dataset.simulation-name, $dataset.dataset-id, $model, $outputs, $language); + $result = output-as-csv( + $dataset.simulation-name, $dataset.dataset-id, $model, + $outputs, $language, :$all-filters + ); } when 'json' { - $result = output-as-json($model, $outputs, $language, $prints, $include-filters); + $result = output-as-json( + $model, $outputs, $language, $prints, $include-filters, :$all-filters + ); } when 'text' { - $result = output-as-text($model, $outputs, $language, $prints, $include-filters); + $result = output-as-text( + $model, $outputs, $language, $prints, $include-filters, :$all-filters + ); } } $rc.add-result($dataset.simulation-name, $dataset.dataset-id, $result); diff --git a/t/test-data/agrammon.cfg.yaml b/t/test-data/agrammon.cfg.yaml index 351ff3d7a..586426c6a 100644 --- a/t/test-data/agrammon.cfg.yaml +++ b/t/test-data/agrammon.cfg.yaml @@ -7,6 +7,8 @@ General: Database: name: agrammon_test host: localhost +# host: 192.168.0.143 +# host: 10.46.102.25 user: agrammon password: agrammonATwork From 437fbcc183116b075dabb9eb6ed324ed49c97e9b Mon Sep 17 00:00:00 2001 From: Jonathan Worthington Date: Fri, 30 Oct 2020 23:00:20 +0100 Subject: [PATCH 5/5] Sort modules on something more useful --- lib/Agrammon/Model/FilterSet.pm6 | 5 +++-- lib/Agrammon/Outputs/FilterGroupCollection.pm6 | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Agrammon/Model/FilterSet.pm6 b/lib/Agrammon/Model/FilterSet.pm6 index 2358b272e..b8ffd82f1 100644 --- a/lib/Agrammon/Model/FilterSet.pm6 +++ b/lib/Agrammon/Model/FilterSet.pm6 @@ -13,9 +13,10 @@ class Agrammon::Model::FilterSet { } has Filter @!filters; + has Agrammon::Model::Module $.module; - submethod BUILD(Agrammon::Model::Module :$module!, :@dependencies! --> Nil) { - self!add-from-module($module); + submethod BUILD(Agrammon::Model::Module :$!module!, :@dependencies! --> Nil) { + self!add-from-module($!module); self!add-from-module($_) for @dependencies; } diff --git a/lib/Agrammon/Outputs/FilterGroupCollection.pm6 b/lib/Agrammon/Outputs/FilterGroupCollection.pm6 index 4427453f6..a91959f47 100644 --- a/lib/Agrammon/Outputs/FilterGroupCollection.pm6 +++ b/lib/Agrammon/Outputs/FilterGroupCollection.pm6 @@ -67,7 +67,7 @@ class Agrammon::Outputs::FilterGroupCollection { die "Can only get all values when provenance of the filter group was provided"; } my @results; - for $!provenance.keys.sort.reverse -> $filter-set { + for $!provenance.keys.sort(*.module.taxonomy).reverse -> $filter-set { for $filter-set.all-possible-filter-keys -> %filters { my $key = FilterKey.new(:%filters); @results.push(%filters => %!values-by-filter{$key} // 0);