In Ruby, you can easily pass a variable from inside a method into the attached code block:
def mymethod
(1..10).each { |e| yield(e * 10) } # Passes a number to associated block
end
mymethod { |i| puts "Here comes #{i}" } # Outputs the number received from the method
I would like to do the same thing in SASS mixin:
=my-mixin
@for $i from 1 to 8
.grid-#{$i}
@content
+my-mixin
color: nth("red green blue orange yellow brown black purple", $i)
This code won't work because $i is declared inside the mixin declaration and cannot be seen outside, where the mixin is used. :(
So... How do i leverage variables declared inside the mixin declaration?
When i work with a grid framework and media queries, i need this functionality badly. Currently i have to duplicate what's inside the mixin declaration every time i need it, violating the DRY rule.
UPD 2013-01-24
Here's a real-life example.
I have a mixin that cycles through breakpoints and applies the provided code once for every breakpoint:
=apply-to-each-bp
@each $bp in $bp-list
+at-breakpoint($bp) // This is from Susy gem
@content
When i use this mixin i have to use this $bp value inside @content. It could be like this:
// Applies to all direct children of container
.container > *
display: inline-block
// Applies to all direct children of container,
// if container does not have the .with-gutters class
.container:not(.with-gutters) > *
+apply-to-each-bp
width: 100% / $bp
// Applies to all direct children of container,
// if container has the .with-gutters class
.container.with-gutters > *
+apply-to-each-bp
$block-to-margin-ratio: 0.2
$width: 100% / ($bp * (1 + $block-to-margin-ratio) - $block-to-margin-ratio)
width: $width
margin-right: $width * $block-to-margin-ratio
&:nth-child(#{$bp})
margin-right: 0
But this won't work, because the value of $bp is not available inside @content.
Declaring the variable before calling the mixin won't help, because @content is parsed once and before the mixin is parsed.
Instead, EACH time i need that, i have to do two ugly thighs:
- declare an ad-hoc mixin,
- write the cycle, violating the DRY principle:
// Each of the following mixins is mentioned in the code only once.
=without-gutters($bp)
width: 100% / $bp
=with-gutters($bp)
$block-to-margin-ratio: 0.2
$width: 100% / ($bp * (1 + $block-to-margin-ratio) - $block-to-margin-ratio)
width: $width
margin-right: $width * $block-to-margin-ratio
&:nth-child(#{$bp})
margin-right: 0
// Applies to all direct children of container
.container > *
display: inline-block
// Applies to all direct children of container,
// if container does not have the .with-gutters class
.container:not(.with-gutters) > *
@each $bp in $bp-list
+at-breakpoint($bp) // This is from Susy gem
+without-gutters($bp)
// Applies to all direct children of container,
// if container has the .with-gutters class
.container.with-gutters > *
@each $bp in $bp-list // Duplicate code! :(
+at-breakpoint($bp) // Violates the DRY principle.
+with-gutters($bp)
So, the question is: is there a way to do this Ruby-style?