I am refactoring functions in my sass code so their use is broader while trying to follow as much as possible functional programming rules. How can I assign the type of operation depending on parameter so I don't have to repeat code inside if else statements?
In fact what I want to achieve is to select next or previous index on a list
#function mathOperation($number, $type) {
#return $number #{if($type == sum, '+', '-')} 1;
}
#debug mathOperation(5, sum);
#debug type-of(mathOperation(5, sum));
Gives as result
DEBUG 5 + 1
DEBUG list
Instead of the actual sum and type number.
Even tried to directly pass the actual operator such as + or - as argument and simply use it as variable, with no luck.
You create a sass list in your function rather than you do a mathematical calculation. Using inspect(), you could create a string from ist so what you basically are searching for is a method to eval a string.
Sass does not offer this, you will have to write a numerical equation that returns a number like
#function mathOperation($number, $type) {
#return $number + if($type == sum, 1, -1);
}
Related
Consider
subset MySubset of Str where * ~~ /^ \d $<interesting> = ( \d+ ) $/;
Now I want to use the subset as a Type in my signature, but put the captured part(s) into a variable via unpacking, kinda like
sub f( MySubset $( :$interesting ) )
{
say $interesting;
}
f( "12345678" ); # should say 2345678
That's not working of course. Is it even possible to do this?
Subsignature unpacking is about turning a value into a Capture and matching against that.
class Point {
has ( $.x, $.y );
}
my ( :$x, :$y ) := Point.new( x => 3, y => 4 ).Capture;
say "[$x,$y]"; # [3,4]
Since a Str doesn't have a public attribute named $.interesting, it won't match.
A subset is just extra code to check a value more completely than you could otherwise do. It does not turn the value into a new type.
It would be more likely to work if you used $<interesting>.
sub f( MySubset )
{
say $<interesting>;
}
Of course since blocks get their own $/, this also does not work.
While it might be nice to pass information from a subset to a signature, I am not aware of anyway to do it.
As a side note, where already does smart matching so it is an incredibly bad idea to use ~~ inside of it.
This is basically how your subset works:
"12345678" ~~ ( * ~~ /…/ )
In this particular case you could just use .substr
sub f( MySubset $_ ) {
.substr(1)
}
I can't figure out a way with a subset type, however there is a way - with a little...creativity - to do a match and unpack it in the signature.
Match inherits from Capture, so having one be unpacked in a signature is straightforward - if only we can arrange for there to be a parameter that contains the Match we wish to unpack. One way to do that is to introduce a further parameter with a default. We can't really stop anyone passing to it - though we can make it a pain to do so by using the anonymous named parameter. Thus, if we write this:
sub foo($value, :$ (:$col, :$row) = $value.match(/^$<col>=[<:L>+]$<row>=[\d+]$/)) {
say $col;
say $row;
}
And call it as foo("AB23"), the output is:
「AB」
「23」
Finally, we may factor the rule out to a named token, achieving:
my token colrow { ^$<col>=[<:L>+]$<row>=[\d+]$ }
sub foo($value, :$ (:$col, :$row) = $value.match(&colrow)) {
say $col;
say $row;
}
I'm pretty sure wheres (and subsets) just answer True/False. Brad concurs.
There are essentially always metaprogramming answers to questions but I presume you don't mean that (and almost never dig that deep anyway).
So here are a couple ways to get something approaching what you seem to be after.
A (dubious due to MONKEYing) solution based on Brad's insights:
use MONKEY;
augment class Str {
method MyMatch { self ~~ / ^ \d $<interesting> = ( \d+ ) $ / }
}
class MyMatch is Match {}
sub f( MyMatch() $foo (:$interesting) ) { say ~$interesting }
f( "12345678" ); # 2345678
The bad news is that the sub dispatch works even if the string doesn't match. The doc makes it clear that the coercer method (method MyMatch in the above) cannot currently signal failure:
The method is assumed to return the correct type — no additional checks on the result are currently performed.
One can hope that one day augmenting a class will be an officially respectable thing to do (rather than requiring a use MONKEY...) and that coercing can signal failure. At that point I think this might be a decent solution.
A variant on the above that binds to $/ so you can use $<interesting>:
use MONKEY;
augment class Str {
method MyMatch { self ~~ / ^ \d $<interesting> = ( \d+ ) $ / }
}
class MyMatch is Match {}
sub f( MyMatch() $/ ) { say ~$<interesting> }
f( "12345678" ); # 2345678
Another way that avoids MONKEYing around is to use a subset as you suggest but separate the regex and subset:
my regex Regex { ^ \d $<interesting> = ( \d+ ) $ }
subset Subset of Str where &Regex;
sub f( Subset $foo ; $interesting = ~($foo ~~ &Regex)<interesting> )
{
say $interesting;
}
f( "12345678" ); # 2345678
Notes:
The regex parses the input value at least twice. First in the Subset to decide whether the call dispatches to the sub. But the result of the match is thrown away -- the value arrives as a string. Then the regex matches again so the match can be deconstructed. With current Rakudo, if the sub were a multi, it would be even worse -- the regex would be used three times because Rakudo currently does both a trial bind as part of deciding which multi to match, and then does another bind for the actual call.
Parameters can be set to values based on previous parameters. I've done that with $interesting. A signature can have parameters that are part of dispatch decisions, and others that are not. These are separated by a semi-colon. I've combined these two features to create another variable, thinking you might think that a positive thing. Your comment suggest you don't, which is more than reasonable. :)
The list repetition operator (xx) evaluates the list every time it is repeated. For example,
my #input = get() xx 5;
will evaluate to the first 5 lines of STDIN. Is there any way I can repeat just the value of the element 5 times, rather than evaluating it each time? Currently, I've been assigning it to a variable, then repeating it, but it seems a bit cumbersome that way.
my $firstLine = get();
my #firstlineRepeated = $firstLine xx 5;
Is there a prefix or something that lets me do it in one statement?
Using given to contextualize it into $_ is one fairly neat way:
my #input = ($_ xx 5 given get());
say #input;
That, when I type hello, gives:
[hello hello hello hello hello]
Since given simply contextualizes, rather than doing any kind of definedness or truth test, it's a bit safer as a general pattern than andthen.
You could try use the andthen operator:
my #input = (get() andthen $_ xx 5);
From the documentation:
The andthen operator returns Empty upon encountering the first
undefined argument, otherwise the last argument. Last argument is
returned as-is, without being checked for definedness at all.
Short-circuits. The result of the left side is bound to $_ for the
right side, or passed as arguments if the right side is a Callable,
whose count must be 0 or 1.
Using phrase ENTER works too
my #input = ENTER { get() } xx 5;
I have a custom keyword in the robot framework which counts the items of a list. This works already in my underlying python file and prints the number 5 when five elements exists in a list.
Then I want to bring this value to the robot framework. But instead of a number I get:
${N_groups} is <built-in method count of list object at 0x03B01D78>
The code of the robot file:
*** Test Cases ***
Count Groups
${N_groups} Setup Groups Count Groups
log to console ${N_groups}
How to get item-count of the list as an integer value?
Here is a part of my python file:
#keyword(name="Count Groups")
def count_groups(self):
N = self.cur_page.count_groups()
return N
And a more low level python file:
def count_groups(self):
ele_tc = self._wait_for_treecontainer_loaded(self._ef.get_setup_groups_treecontainer())
children_text = self._get_sublist_filter(ele_tc, lambda ele: ele.find_element_by_tag_name('a').text,
True)
return children_text.count
Your function count_groups is returning children_text.count. children_text is a list, and you're returning the count method of that object, which explains the error that you're seeing. It's no different than if you did something like return [1,2,3].count.
Perhaps you intend to actually call the count function and return the results? Or, perhaps you are intending to return the length of the list? It's hard to see what the intent of the code is.
In either case, robot is reporting exactly what you're doing: you're returning a reference to a function, not an integer. My guess is that what you really want to do is return the number of items in the list, in which case you should change the return statement to:
return len(children_text)
I'm writing a Less mixin.
I want to be able to pass the mixin several parameters. The first will be a string. The rest, an infinite number of parameters, will be value pairs.
In my mixin how can I loop through the infinite number of parameters?
For example one time I will call...
.my-mixin(#name, #foo: bar, #hello: world);
and another time...
.my-mixin(#name, #iam: cool, #youare: lame, #someoneis: awesome);
Here's what it would look like if Less supported JS/PHP...
.my-mixin() {
#name: #arguments[0]; //First param
for (#arguments as #label => #value) {
#label: #value;
}
}
Is this possible?
In fact you ask two questions. First how to create a mixin that can accept an endless number of parameters, and secondly who to iterate over the list / array of parameters.
Less has the special ... syntax to create mixins with an endless number of parameters. The official documentation can be found here: Advanced arguments and the #rest variable. An example / use case can be found at Can I define a LESS mixin to generate a transition-property with a variable number of parameters?.
The special ... syntax can be used to assign the parameter list to a variable by adding the variable name before the ...:
.mixin(#parameter1, #endlesslistofparameters...) {}
The #endlesslistofparameters variable now contains a list of parameters, you can use the Less list functions to extract a value from this list (or find its length):
length() returns the length of a list and extract(#list,position) return the value of a certain position in the list. Notice that the first value is on position 1 and not 0.
Finally you can use a loop to iterate over this list of arguments.
In Less a mixin can call itself. Such recursive mixins, when combined
with Guard Expressions and Pattern Matching, can be used to create
various iterative/loop structures.
See also: Loop over an array of name value pairs in LESS
All together i think you can write something like that shown below:
.my-mixin(#name,#properties...) {
.setproperties(#iterator:1) when (#iterator <= length(#properties)) {
#propertyname: extract(extract(#properties,#iterator),1);
#{propertyname}: extract(extract(#properties,#iterator),2);
.setproperties((#iterator + 1));
}
.#{name} {
.setproperties();
}
}
.my-mixin(jared; iam cool, youare lame, someoneis awesome);
The preceding Less code will compile into the following CSS code:
.jared {
iam: cool;
youare: lame;
someoneis: awesome;
}
And than also notice that Less allows you to Passing Rulesets to Mixins since version 1.7, which enables you to write:
.my-mixin2(#name,#properties) {
.#{name} {
#properties();
}
}
.my-mixin2(jared; {iam: cool; youare: lame; someoneis: awesome;});
I have a string in field 'product' in the following form:
";TT_RAV;44;22;"
and am wanting to first split on the ';' and then split on the '_' so that what is returned is
"RAV"
I know that I can do something like this:
parse_1 = foreach {
splitup = STRSPLIT(product,';',3);
generate splitup.$1 as depiction;
};
This will return the string 'TT_RAV' and then I can do another split and project out the 'RAV' however this seems like it will be passing the data through multiple Map jobs -- Is it possible to parse out the desired field in one pass?
This example does NOT work, as the inner splitstring retuns tuples, but shows logic:
c parse_1 = foreach {
splitup = STRSPLIT(STRSPLIT(product,';',3),'_',1);
generate splitup.$1 as depiction;
};
Is it possible to do this in pure piglatin without multiple map phases?
Don't use STRSPLIT. You are looking for REGEX_EXTRACT:
REGEX_EXTRACT(product, '_([^;]*);', 1) AS depiction
If it's important to be able to precisely pick out the second semicolon-delimited field and then the second underscore-delimited subfield, you can make your regex more complicated:
REGEX_EXTRACT(product, '^[^;]*;[^_;]*_([^_;]*)', 1) AS depiction
Here's a breakdown of how that regex works:
^ // Start at the beginning
[^;]* // Match as many non-semicolons as possible, if any (first field)
; // Match the semicolon; now we'll start the second field
[^_;]* // Match any characters in the first subfield
_ // Match the underscore; now we'll start the second subfield (what we want)
( // Start capturing!
[^_;]* // Match any characters in the second subfield
) // End capturing
The only time there will be multiple maps is if you have an operator that triggers a reduce (JOIN, GROUP, etc...). If you run an explain on the script you can see if there is more than one reduce phase.