How to loop through all params in Less mixin - less

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;});

Related

Why no "each" method on Perl6 sequences?

Sometimes I'll start writing a chain of method calls at the Perl 6 REPL, like:
".".IO.dir.grep(...).map(...).
...and then I realize that what I want to do with the final list is print every element on its own line. I would expect sequences to have something like an each method so I could end the chain with .each(*.say), but there's no method like that that I can find. Instead I have to return to the beginning of the line and prepend .say for. It feels like it breaks up the flow of my thoughts.
It's a minor annoyance, but it strikes me as such a glaring omission that I wonder if I'm missing some easy alternative. The only ones I can think of are ยป.say and .join("\n").say, but the former can operate on the elements out of order (if I understand correctly) and the latter constructs a single string which could be problematically large, depending on the input list.
You can roll your own.
use MONKEY;
augment class Any
{
method each( &block )
{
for self -> $value {
&block( $value );
}
}
};
List.^compose;
Seq.^compose;
(1, 2).each({ .say });
(2, 3).map(* + 1).each({ .say });
# 1
# 2
# 3
# 4
If you like this, there's your First CPAN module opportunity right there.
As you wrote in the comment, just an other .map(*.say) does also create a line with True values when using REPL. You can try to call .sink method after the last map statement.
".".IO.dir.grep({$_.contains('e')}).map(*.uc).map(*.say).sink

What's the meaning of 'i' in for loop?

In almost every programming language, they use variable i when they explain for loop. Like,
for i in 'string':
print(i)
or
for(var i ; i<100 ; i++) {
console.log(i);
}
etc...
Does it mean anything? Or just a variable with no meaning?
I couldn't find any information about this in google search.
You have given two different example.
For the first one
for i in 'string':
print(i)
For this one, the variable 'i' is the variable where the value will be put from your parameter (here 'string'). If i gave an array as parameter for instance, each value of array will be put in 'i', step by step (element [0], then element[1], etc...).
Note that this is a simplified view of this question and it doesn't work exactly like that for the program. But you can understand it as it.
For the second one
for(var i ; i<100 ; i++) {
console.log(i);
}
You declare explicitly a variable to be used. This declared will be used by the loop, incrementig by the step you had defined until it reaches limit you also defined.
It is slightly the same thing for both example. Hope i explain well
it is just a common practice. Many people when learning see i being used as a variable name. But that's all it is. It is just a name that could be anything, you could us any other sequence of characters!
i is just a variable. Generally, it is referred to as "iteration for the loop".

sass sum or rest depending the argument in a function

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);
}

LESS: variable that refers to another one's value with concatenate name

The following (vey simplified) LESS code runs correctly, printing value of width property, previosly assigned to #screen-md variable.
#screen-md:700px;
#size:md;
#temp:"screen-#{size}";
#width:##temp;
.foo
{
width:#width;
}
Imagine that #size value could be a parameter passed to a mixin. In general, to obtain desired result, I need to pass through #temp variable, first assigning her a variable name based upon #size value, and then using Variable name to finally assign it to #width variable.
My question is: is it possible to avoid need of #temp variable, collapsing
#temp:"screen-#{size}";
#width:##temp;
into something like #width:##"screen-#{size}" ?
Yes, it is possible to collapse it into one single line like shown below:
#screen-md:700px;
#size:md;
.mixin(#size){
width: ~"#{screen-#{size}}"; /* can either be assigned to another variable or property */
}
.output{
.mixin(md);
}
Explanation:
screen-#{size} - would evaluate to screen-md as the input parameter to the mixin is md.
#{screen-#{size} - would therefore mean #{screen-md}. This would be evaluated as 700px.
~"" - escaping is used to avoid the quotes being in printed in the output.

Google Polymer Repeat value in range 1...n

I've started messing with Polymer and I've done the basic tutorial with the social media cards. In it several cards care looped over as repeat="{{post in posts}}". What I would like to do is something like repeat="{{post in range 1...10}}". Ultimately I'd like to use a published property cols to provide a max value instead of 10. I've been able to get something like this working by setting the cols property to something like [1,2,...,9] but that is unreasonable to any large set of values. I've also expanded on this by using the ready function and executing this.colsAr = new Array(cols), then in the repeat `{{col in colsAr}}.
What is the best/correct method of looping over a variable number of elements where the number is determined by a property?
To add to this lets also say the cols property is dynamically changed via a select input. This should cause a re-draw when a new value is selected.
Generally the best way to do this is to use a computed property to express your filtered Array.
Something like this:
<template repeat="{{post in slice}}">
...
computed: {
slice: 'sliced(posts)'
},
sliced: function(posts) {
return posts.slice(1, 3);
}
However, right now, the computed property engine doesn't automatically ArrayObserve posts, so we have to manually force a re-compute when the Array structure changes.
kick: 0,
computed: {
slice: 'sliced(posts, kick)'
},
sliced: function(posts) {
return posts.slice(1, 3);
},
postsChanged: function() {
this.kick++;
}
Incrementing kick forces the data engine to recompute slice (gives it a kick). Fwiw, we are trying to improve this particular situation, but the above technique should work in the short term.
Working example:
http://jsbin.com/dadeto/3/edit