22 / 22 lines covered (100.0%)
1unit module BDD::Behave::LetRuntime;23class LetDefinition is export {4 has Str $.name is required;5 has Callable $.block is required;6 has IO::Path $.file;7 has Int $.line;89 submethod BUILD(:$!name, :$!block, :$file, :$line) {10 $!file = $file ~~ IO::Path ?? $file !! $file.IO if $file.defined;11 $!line = $line if $line.defined;12 }1314 method evaluate(*%context) {15 %context.elems ?? $!block(|%context) !! $!block();16 }17}1819# `let(:name, ...)` and `let('name', ...)` name the same definition, so a name20# is indexed under its bare form whichever spelling declared it.21sub bare-name(Str $name --> Str) {22 $name.starts-with(':') ?? $name.substr(1) !! $name;23}2425class LetRuntime is export {26 has LetDefinition @.definitions is rw;27 has %.memo;28 has %!by-name;2930 submethod TWEAK { self!remember($_) for @!definitions }3132 # A later definition of a name shadows an earlier one, which is what the33 # reversed scan this replaces gave.34 method !remember(LetDefinition $definition) {35 %!by-name{bare-name($definition.name)} = $definition;36 }3738 method add-definition(LetDefinition $definition) {39 @!definitions.push($definition);40 self!remember($definition);41 $definition;42 }4344 method value(Str $name, *%context) {45 my $key = bare-name($name);46 return %.memo{$key} if %.memo{$key}:exists;4748 my $definition = %!by-name{$key} or die "Unknown let($name)";4950 %.memo{$key} = %context.elems ?? $definition.evaluate(|%context) !! $definition.evaluate;51 }5253 method names {54 @!definitions.map(*.name).unique.List;55 }5657 method has-name(Str $name --> Bool) {58 %!by-name{bare-name($name)}:exists;59 }60}