Ruby2sass 🎨

Ruby2sass is a powerful and flexible Ruby DSL for generating SASS and CSS. It allows you to write your stylesheets using Ruby syntax, providing a more programmatic and dynamic approach to stylesheet generation. 🚀

Installation 💻

Add this line to your application's Gemfile:

gem 'ruby2sass'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install ruby2sass

Usage 🔨

Here's a comprehensive example showcasing various features of Ruby2sass, along with the generated SASS output for each block:

require 'ruby2sass'

renderer = Ruby2sass::Renderer.new do
  # Variables
  primary_color = v('primary-color', '#007bff')
  secondary_color = v('secondary-color', '#6c757d')
  grid_columns = v('grid-columns', 12)

  s('body') do
    background_color primary_color
  end
end

puts renderer.to_sass

Output:

$primary-color: #007bff;
$secondary-color: #6c757d;
$grid-columns: 12;

body {
  background-color: #007bff;
}
renderer = Ruby2sass::Renderer.new do
  # Mixins
  mixin 'button-styles', '$bg-color' do
    background_color '$bg-color'
    padding '10px 15px'
    border_radius '5px'
    transition 'background-color 0.3s ease'
  end

  # Functions
  function 'darken', '$color, $amount' do
    raw '@return darken($color, $amount);'
  end
end

puts renderer.to_sass

Output:

@mixin button-styles($bg-color) {
  background-color: $bg-color;
  padding: 10px 15px;
  border-radius: 5px;
  transition: background-color 0.3s ease;
}

@function darken($color, $amount) {
  @return darken($color, $amount);
}
renderer = Ruby2sass::Renderer.new do
  # Base styles
  s('body') do
    font_family "'Arial', sans-serif"
    line_height '1.6'
    color '#333'
  end

  # Container
  s('.container') do
    max_width '1200px'
    margin '0 auto'
    padding '0 15px'
  end
end

puts renderer.to_sass

Output:

body {
  font-family: 'Arial', sans-serif;
  line-height: 1.6;
  color: #333;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 15px;
}
renderer = Ruby2sass::Renderer.new do
  primary_color = v('primary-color', '#007bff')
  secondary_color = v('secondary-color', '#6c757d')

  # Buttons
  s('.button') do |btn|
    include 'button-styles', primary_color

    btn.hover do
      background_color "darken(#{primary_color}, 10%)"
    end
  end

  s('.button-secondary') do |btn|
    include 'button-styles', secondary_color

    btn.hover do
      background_color "darken(#{secondary_color}, 10%)"
    end
  end
end

puts renderer.to_sass

Output:

$primary-color: #007bff;
$secondary-color: #6c757d;

.button {
  @include button-styles(#007bff);
  &:hover {
    background-color: darken(#007bff, 10%);
  }
}

.button-secondary {
  @include button-styles(#6c757d);
  &:hover {
    background-color: darken(#6c757d, 10%);
  }
}
renderer = Ruby2sass::Renderer.new do
  grid_columns = v('grid-columns', 12)

  # Grid system using for loop
  for_loop 'i', from: 1, to: grid_columns do
    s(".col-\#{$i}") do
      width "calc(100% / #{grid_columns} * \#{$i})"
      float 'left'
      padding '0 15px'
    end
  end
end

puts renderer.to_sass

Output:

$grid-columns: 12;

@for $i from 1 through 12 {
  .col-#{$i} {
    width: calc(100% / 12 * #{$i});
    float: left;
    padding: 0 15px;
  }
}
renderer = Ruby2sass::Renderer.new do
  # Color palette using each loop
  colors = v('colors', '("primary": #007bff, "secondary": #6c757d, "success": #28a745, "danger": #dc3545)')
  each_loop 'name, color', colors do
    s(".\#{$name}-bg") do
      background_color '$color'
    end
    s(".\#{$name}-text") do
      color '$color'
    end
  end
end

puts renderer.to_sass

Output:

$colors: ("primary": #007bff, "secondary": #6c757d, "success": #28a745, "danger": #dc3545);

@each $name, $color in $colors {
  .#{$name}-bg {
    background-color: $color;
  }
  .#{$name}-text {
    color: $color;
  }
}
renderer = Ruby2sass::Renderer.new do
  # Responsive font sizes using while loop
  base_font = v('base-font-size', 16)
  i = v('i', 6)
  while_loop "#{i} > 0" do
    s("h\#{$i}") do
      font_size "#{base_font} + \#{$i}px"
    end
    raw "#{i} = #{i} - 1;"
  end
end

puts renderer.to_sass

Output:

$base-font-size: 16;
$i: 6;

@while $i > 0 {
  h#{$i} {
    font-size: 16 + #{$i}px;
  }
$i: $i - 1;
}
renderer = Ruby2sass::Renderer.new do
  # Media queries
  breakpoints = v('breakpoints', '("sm": 576px, "md": 768px, "lg": 992px, "xl": 1200px)')
  each_loop 'name, width', breakpoints do
    media "screen and (min-width: \#{$width})" do
      s('.container') do
        max_width '$width'
      end
    end
  end
end

puts renderer.to_sass

Output:

$breakpoints: ("sm": 576px, "md": 768px, "lg": 992px, "xl": 1200px);

@each $name, $width in $breakpoints {
  @media screen and (min-width: #{$width}) {
    .container {
      max-width: $width;
    }
  }
}
renderer = Ruby2sass::Renderer.new do
  # Theme switching with if-else
  theme = v('theme', 'light')
  if_statement "#{theme} == 'light'" do
    s('body') do
      background_color '#fff'
      color '#333'
    end
  end
  else_statement do
    s('body') do
      background_color '#333'
      color '#fff'
    end
  end
end

puts renderer.to_sass

Output:

$theme: light;

@if $theme == 'light' {
  body {
    background-color: #fff;
    color: #333;
  }
}
@else {
  body {
    background-color: #333;
    color: #fff;
  }
}
renderer = Ruby2sass::Renderer.new do
  # Using raw SASS for complex selectors
  raw <<~SCSS
    nav {
      ul {
        margin: 0;
        padding: 0;
        list-style: none;

        li { display: inline-block; }

        a {
          display: block;
          padding: 6px 12px;
          text-decoration: none;
        }
      }
    }
  SCSS
end

puts renderer.to_sass

Output:

nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;

    li { display: inline-block; }

    a {
      display: block;
      padding: 6px 12px;
      text-decoration: none;
    }
  }
}

This example demonstrates:

  • Variable declaration using v() and usage
  • Mixins and includes
  • Custom functions
  • Nested selectors with yield
  • Various types of loops (for, each, while) for generating classes and styles
  • Media queries with dynamic breakpoints
  • Conditional statements for theming
  • Raw SASS input for complex nesting

to_sass Method 📝

The to_sass method generates SASS output from your Ruby2sass DSL:

sass_output = renderer.to_sass

to_css Method 🎭

The to_css method compiles your Ruby2sass DSL directly to CSS:

css_output = renderer.to_css(include: nil, compress: false)

Parameters:

  • include: An array of file paths, strings, or IO objects to be included before the main SASS content.
  • compress: A boolean indicating whether the output CSS should be compressed (default is false).

Example with options:

css_output = renderer.to_css(
  include: ['path/to/variables.sass', '$primary-color: #007bff;'],
  compress: true
)

Features 🌟

Ruby2sass supports:

  • Variables with v() method
  • Mixins and includes
  • Custom functions
  • Nested selectors with yield for pseudo-classes and pseudo-elements
  • Loops (for, each, while) with various use cases
  • Conditionals (if-else)
  • Media queries with dynamic breakpoints
  • Keyframe animations
  • Raw SASS input for complex scenarios
  • CSS property method missing for easy property setting

Performance 🏎️

Ruby2sass is designed to handle various sizes of SASS structures efficiently. Here are some benchmark results:

Structure Details:
Small (Depth: 3, Breadth: 3):
  Total Selectors: 39
  Total Properties: 117
  SASS Size: 3.74 KB
  CSS Size: 3.96 KB
Medium (Depth: 4, Breadth: 4):
  Total Selectors: 340
  Total Properties: 1020
  SASS Size: 36.13 KB
  CSS Size: 39.14 KB
Large (Depth: 5, Breadth: 5):
  Total Selectors: 3905
  Total Properties: 11715
  SASS Size: 455.77 KB
  CSS Size: 502.50 KB

Benchmark Results:
     Ruby2sass small:    145.5 i/s
    Ruby2sass medium:     20.0 i/s - 7.29x  slower
     Ruby2sass large:      1.7 i/s - 84.77x  slower

These results show that Ruby2sass can handle small to medium-sized stylesheets very efficiently, while still being capable of processing larger stylesheets. 📊

Development 🛠️

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install.

Contributing 🤝

Bug reports and pull requests are welcome on GitHub at https://github.com/sebyx07/ruby2sass.

License 📄

The gem is available as open source under the terms of the MIT License.