ruby2sass 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4f6519722922ec9885f511090e1a96d53d16366bd8d4661700a2bb3981dafdb5
4
+ data.tar.gz: 6b556ef775589059171cc2f1d7f3e8702aabfdf4ad4ae07332d97100b91a21f6
5
+ SHA512:
6
+ metadata.gz: 813f8522d3fd9f93af4577a6eeada174c947b2dccfb63b12a193f6bbc310fea6a877d093cbdbd069efb8473a2d2f5d2a4215358d04f0a17e6caabbbae4e8b83e
7
+ data.tar.gz: e69ad4657aeb5de80ee28855289802494cd4fceb2478a68c46db9bb577a60c8c527b2a2a01dc76a6ffcf011c82f8b8e409fb2dcb6d22ad7c36782862ad7f4e7c
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format progress
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ inherit_gem:
2
+ rubocop-rails_config:
3
+ - config/rails.yml
4
+
5
+ Style/ClassAndModuleChildren:
6
+ EnforcedStyle: nested
7
+
8
+ Lint/Debugger:
9
+ Enabled: true
10
+
11
+ Style/StringLiterals:
12
+ Enabled: true
13
+ EnforcedStyle: single_quotes
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 sebi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,478 @@
1
+ # Ruby2sass 🎨
2
+
3
+ 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. 🚀
4
+
5
+ ## Installation 💻
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'ruby2sass'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```
16
+ $ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```
22
+ $ gem install ruby2sass
23
+ ```
24
+
25
+ ## Usage 🔨
26
+
27
+ Here's a comprehensive example showcasing various features of Ruby2sass, along with the generated SASS output for each block:
28
+
29
+ ```ruby
30
+ require 'ruby2sass'
31
+
32
+ renderer = Ruby2sass::Renderer.new do
33
+ # Variables
34
+ primary_color = v('primary-color', '#007bff')
35
+ secondary_color = v('secondary-color', '#6c757d')
36
+ grid_columns = v('grid-columns', 12)
37
+
38
+ s('body') do
39
+ background_color primary_color
40
+ end
41
+ end
42
+
43
+ puts renderer.to_sass
44
+ ```
45
+
46
+ Output:
47
+
48
+ ```sass
49
+ $primary-color: #007bff;
50
+ $secondary-color: #6c757d;
51
+ $grid-columns: 12;
52
+
53
+ body {
54
+ background-color: #007bff;
55
+ }
56
+ ```
57
+
58
+ ```ruby
59
+ renderer = Ruby2sass::Renderer.new do
60
+ # Mixins
61
+ mixin 'button-styles', '$bg-color' do
62
+ background_color '$bg-color'
63
+ padding '10px 15px'
64
+ border_radius '5px'
65
+ transition 'background-color 0.3s ease'
66
+ end
67
+
68
+ # Functions
69
+ function 'darken', '$color, $amount' do
70
+ raw '@return darken($color, $amount);'
71
+ end
72
+ end
73
+
74
+ puts renderer.to_sass
75
+ ```
76
+
77
+ Output:
78
+
79
+ ```sass
80
+ @mixin button-styles($bg-color) {
81
+ background-color: $bg-color;
82
+ padding: 10px 15px;
83
+ border-radius: 5px;
84
+ transition: background-color 0.3s ease;
85
+ }
86
+
87
+ @function darken($color, $amount) {
88
+ @return darken($color, $amount);
89
+ }
90
+ ```
91
+
92
+ ```ruby
93
+ renderer = Ruby2sass::Renderer.new do
94
+ # Base styles
95
+ s('body') do
96
+ font_family "'Arial', sans-serif"
97
+ line_height '1.6'
98
+ color '#333'
99
+ end
100
+
101
+ # Container
102
+ s('.container') do
103
+ max_width '1200px'
104
+ margin '0 auto'
105
+ padding '0 15px'
106
+ end
107
+ end
108
+
109
+ puts renderer.to_sass
110
+ ```
111
+
112
+ Output:
113
+
114
+ ```sass
115
+ body {
116
+ font-family: 'Arial', sans-serif;
117
+ line-height: 1.6;
118
+ color: #333;
119
+ }
120
+
121
+ .container {
122
+ max-width: 1200px;
123
+ margin: 0 auto;
124
+ padding: 0 15px;
125
+ }
126
+ ```
127
+
128
+ ```ruby
129
+ renderer = Ruby2sass::Renderer.new do
130
+ primary_color = v('primary-color', '#007bff')
131
+ secondary_color = v('secondary-color', '#6c757d')
132
+
133
+ # Buttons
134
+ s('.button') do |btn|
135
+ include 'button-styles', primary_color
136
+
137
+ btn.hover do
138
+ background_color "darken(#{primary_color}, 10%)"
139
+ end
140
+ end
141
+
142
+ s('.button-secondary') do |btn|
143
+ include 'button-styles', secondary_color
144
+
145
+ btn.hover do
146
+ background_color "darken(#{secondary_color}, 10%)"
147
+ end
148
+ end
149
+ end
150
+
151
+ puts renderer.to_sass
152
+ ```
153
+
154
+ Output:
155
+
156
+ ```sass
157
+ $primary-color: #007bff;
158
+ $secondary-color: #6c757d;
159
+
160
+ .button {
161
+ @include button-styles(#007bff);
162
+ &:hover {
163
+ background-color: darken(#007bff, 10%);
164
+ }
165
+ }
166
+
167
+ .button-secondary {
168
+ @include button-styles(#6c757d);
169
+ &:hover {
170
+ background-color: darken(#6c757d, 10%);
171
+ }
172
+ }
173
+ ```
174
+
175
+ ```ruby
176
+ renderer = Ruby2sass::Renderer.new do
177
+ grid_columns = v('grid-columns', 12)
178
+
179
+ # Grid system using for loop
180
+ for_loop 'i', from: 1, to: grid_columns do
181
+ s(".col-\#{$i}") do
182
+ width "calc(100% / #{grid_columns} * \#{$i})"
183
+ float 'left'
184
+ padding '0 15px'
185
+ end
186
+ end
187
+ end
188
+
189
+ puts renderer.to_sass
190
+ ```
191
+
192
+ Output:
193
+
194
+ ```sass
195
+ $grid-columns: 12;
196
+
197
+ @for $i from 1 through 12 {
198
+ .col-#{$i} {
199
+ width: calc(100% / 12 * #{$i});
200
+ float: left;
201
+ padding: 0 15px;
202
+ }
203
+ }
204
+ ```
205
+
206
+ ```ruby
207
+ renderer = Ruby2sass::Renderer.new do
208
+ # Color palette using each loop
209
+ colors = v('colors', '("primary": #007bff, "secondary": #6c757d, "success": #28a745, "danger": #dc3545)')
210
+ each_loop 'name, color', colors do
211
+ s(".\#{$name}-bg") do
212
+ background_color '$color'
213
+ end
214
+ s(".\#{$name}-text") do
215
+ color '$color'
216
+ end
217
+ end
218
+ end
219
+
220
+ puts renderer.to_sass
221
+ ```
222
+
223
+ Output:
224
+
225
+ ```sass
226
+ $colors: ("primary": #007bff, "secondary": #6c757d, "success": #28a745, "danger": #dc3545);
227
+
228
+ @each $name, $color in $colors {
229
+ .#{$name}-bg {
230
+ background-color: $color;
231
+ }
232
+ .#{$name}-text {
233
+ color: $color;
234
+ }
235
+ }
236
+ ```
237
+
238
+ ```ruby
239
+ renderer = Ruby2sass::Renderer.new do
240
+ # Responsive font sizes using while loop
241
+ base_font = v('base-font-size', 16)
242
+ i = v('i', 6)
243
+ while_loop "#{i} > 0" do
244
+ s("h\#{$i}") do
245
+ font_size "#{base_font} + \#{$i}px"
246
+ end
247
+ raw "#{i} = #{i} - 1;"
248
+ end
249
+ end
250
+
251
+ puts renderer.to_sass
252
+ ```
253
+
254
+ Output:
255
+
256
+ ```sass
257
+ $base-font-size: 16;
258
+ $i: 6;
259
+
260
+ @while $i > 0 {
261
+ h#{$i} {
262
+ font-size: 16 + #{$i}px;
263
+ }
264
+ $i: $i - 1;
265
+ }
266
+ ```
267
+
268
+ ```ruby
269
+ renderer = Ruby2sass::Renderer.new do
270
+ # Media queries
271
+ breakpoints = v('breakpoints', '("sm": 576px, "md": 768px, "lg": 992px, "xl": 1200px)')
272
+ each_loop 'name, width', breakpoints do
273
+ media "screen and (min-width: \#{$width})" do
274
+ s('.container') do
275
+ max_width '$width'
276
+ end
277
+ end
278
+ end
279
+ end
280
+
281
+ puts renderer.to_sass
282
+ ```
283
+
284
+ Output:
285
+
286
+ ```sass
287
+ $breakpoints: ("sm": 576px, "md": 768px, "lg": 992px, "xl": 1200px);
288
+
289
+ @each $name, $width in $breakpoints {
290
+ @media screen and (min-width: #{$width}) {
291
+ .container {
292
+ max-width: $width;
293
+ }
294
+ }
295
+ }
296
+ ```
297
+
298
+ ```ruby
299
+ renderer = Ruby2sass::Renderer.new do
300
+ # Theme switching with if-else
301
+ theme = v('theme', 'light')
302
+ if_statement "#{theme} == 'light'" do
303
+ s('body') do
304
+ background_color '#fff'
305
+ color '#333'
306
+ end
307
+ end
308
+ else_statement do
309
+ s('body') do
310
+ background_color '#333'
311
+ color '#fff'
312
+ end
313
+ end
314
+ end
315
+
316
+ puts renderer.to_sass
317
+ ```
318
+
319
+ Output:
320
+
321
+ ```sass
322
+ $theme: light;
323
+
324
+ @if $theme == 'light' {
325
+ body {
326
+ background-color: #fff;
327
+ color: #333;
328
+ }
329
+ }
330
+ @else {
331
+ body {
332
+ background-color: #333;
333
+ color: #fff;
334
+ }
335
+ }
336
+ ```
337
+
338
+ ```ruby
339
+ renderer = Ruby2sass::Renderer.new do
340
+ # Using raw SASS for complex selectors
341
+ raw <<~SCSS
342
+ nav {
343
+ ul {
344
+ margin: 0;
345
+ padding: 0;
346
+ list-style: none;
347
+
348
+ li { display: inline-block; }
349
+
350
+ a {
351
+ display: block;
352
+ padding: 6px 12px;
353
+ text-decoration: none;
354
+ }
355
+ }
356
+ }
357
+ SCSS
358
+ end
359
+
360
+ puts renderer.to_sass
361
+ ```
362
+
363
+ Output:
364
+
365
+ ```sass
366
+ nav {
367
+ ul {
368
+ margin: 0;
369
+ padding: 0;
370
+ list-style: none;
371
+
372
+ li { display: inline-block; }
373
+
374
+ a {
375
+ display: block;
376
+ padding: 6px 12px;
377
+ text-decoration: none;
378
+ }
379
+ }
380
+ }
381
+ ```
382
+
383
+ This example demonstrates:
384
+ - Variable declaration using `v()` and usage
385
+ - Mixins and includes
386
+ - Custom functions
387
+ - Nested selectors with yield
388
+ - Various types of loops (for, each, while) for generating classes and styles
389
+ - Media queries with dynamic breakpoints
390
+ - Conditional statements for theming
391
+ - Raw SASS input for complex nesting
392
+
393
+ ### `to_sass` Method 📝
394
+
395
+ The `to_sass` method generates SASS output from your Ruby2sass DSL:
396
+
397
+ ```ruby
398
+ sass_output = renderer.to_sass
399
+ ```
400
+
401
+ ### `to_css` Method 🎭
402
+
403
+ The `to_css` method compiles your Ruby2sass DSL directly to CSS:
404
+
405
+ ```ruby
406
+ css_output = renderer.to_css(include: nil, compress: false)
407
+ ```
408
+
409
+ Parameters:
410
+ - `include`: An array of file paths, strings, or IO objects to be included before the main SASS content.
411
+ - `compress`: A boolean indicating whether the output CSS should be compressed (default is false).
412
+
413
+ Example with options:
414
+
415
+ ```ruby
416
+ css_output = renderer.to_css(
417
+ include: ['path/to/variables.sass', '$primary-color: #007bff;'],
418
+ compress: true
419
+ )
420
+ ```
421
+
422
+ ## Features 🌟
423
+
424
+ Ruby2sass supports:
425
+ - Variables with `v()` method
426
+ - Mixins and includes
427
+ - Custom functions
428
+ - Nested selectors with yield for pseudo-classes and pseudo-elements
429
+ - Loops (for, each, while) with various use cases
430
+ - Conditionals (if-else)
431
+ - Media queries with dynamic breakpoints
432
+ - Keyframe animations
433
+ - Raw SASS input for complex scenarios
434
+ - CSS property method missing for easy property setting
435
+
436
+ ## Performance 🏎️
437
+
438
+ Ruby2sass is designed to handle various sizes of SASS structures efficiently. Here are some benchmark results:
439
+
440
+ ```
441
+ Structure Details:
442
+ Small (Depth: 3, Breadth: 3):
443
+ Total Selectors: 39
444
+ Total Properties: 117
445
+ SASS Size: 3.74 KB
446
+ CSS Size: 3.96 KB
447
+ Medium (Depth: 4, Breadth: 4):
448
+ Total Selectors: 340
449
+ Total Properties: 1020
450
+ SASS Size: 36.13 KB
451
+ CSS Size: 39.14 KB
452
+ Large (Depth: 5, Breadth: 5):
453
+ Total Selectors: 3905
454
+ Total Properties: 11715
455
+ SASS Size: 455.77 KB
456
+ CSS Size: 502.50 KB
457
+
458
+ Benchmark Results:
459
+ Ruby2sass small: 145.5 i/s
460
+ Ruby2sass medium: 20.0 i/s - 7.29x slower
461
+ Ruby2sass large: 1.7 i/s - 84.77x slower
462
+ ```
463
+
464
+ These results show that Ruby2sass can handle small to medium-sized stylesheets very efficiently, while still being capable of processing larger stylesheets. 📊
465
+
466
+ ## Development 🛠️
467
+
468
+ 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.
469
+
470
+ To install this gem onto your local machine, run `bundle exec rake install`.
471
+
472
+ ## Contributing 🤝
473
+
474
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sebyx07/ruby2sass.
475
+
476
+ ## License 📄
477
+
478
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/lefthook.yml ADDED
@@ -0,0 +1,7 @@
1
+ pre-commit:
2
+ commands:
3
+ rubocop:
4
+ run: bundle exec rubocop -A
5
+ skip:
6
+ - merge
7
+ - rebase
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruby2sass
4
+ CSS_PROPERTIES = ['accent-color', 'align-content', 'align-items', 'align-self', 'all', 'animation', 'animation-delay',
5
+ 'animation-direction', 'animation-duration', 'animation-fill-mode', 'animation-iteration-count',
6
+ 'animation-name', 'animation-play-state', 'animation-timing-function', 'aspect-ratio',
7
+ 'backdrop-filter', 'backface-visibility', 'background', 'background-attachment', 'background-blend-mode',
8
+ 'background-clip', 'background-color', 'background-image', 'background-origin', 'background-position',
9
+ 'background-position-x', 'background-position-y', 'background-repeat', 'background-size',
10
+ 'block-size', 'border', 'border-block', 'border-block-color', 'border-block-end', 'border-block-end-color',
11
+ 'border-block-end-style', 'border-block-end-width', 'border-block-start', 'border-block-start-color',
12
+ 'border-block-start-style', 'border-block-start-width', 'border-block-style', 'border-block-width',
13
+ 'border-bottom', 'border-bottom-color', 'border-bottom-left-radius', 'border-bottom-right-radius',
14
+ 'border-bottom-style', 'border-bottom-width', 'border-collapse', 'border-color', 'border-end-end-radius',
15
+ 'border-end-start-radius', 'border-image', 'border-image-outset', 'border-image-repeat', 'border-image-slice',
16
+ 'border-image-source', 'border-image-width', 'border-inline', 'border-inline-color', 'border-inline-end',
17
+ 'border-inline-end-color', 'border-inline-end-style', 'border-inline-end-width', 'border-inline-start',
18
+ 'border-inline-start-color', 'border-inline-start-style', 'border-inline-start-width', 'border-inline-style',
19
+ 'border-inline-width', 'border-left', 'border-left-color', 'border-left-style', 'border-left-width',
20
+ 'border-radius', 'border-right', 'border-right-color', 'border-right-style', 'border-right-width',
21
+ 'border-spacing', 'border-start-end-radius', 'border-start-start-radius', 'border-style', 'border-top',
22
+ 'border-top-color', 'border-top-left-radius', 'border-top-right-radius', 'border-top-style', 'border-top-width',
23
+ 'border-width', 'bottom', 'box-decoration-break', 'box-reflect', 'box-shadow', 'box-sizing', 'break-after',
24
+ 'break-before', 'break-inside', 'caption-side', 'caret-color', '@charset', 'clear', 'clip', 'clip-path',
25
+ 'color', 'color-scheme', 'column-count', 'column-fill', 'column-gap', 'column-rule', 'column-rule-color',
26
+ 'column-rule-style', 'column-rule-width', 'column-span', 'column-width', 'columns', 'content', 'counter-increment',
27
+ 'counter-reset', 'counter-set', 'cursor', 'direction', 'display', 'empty-cells', 'filter', 'flex', 'flex-basis',
28
+ 'flex-direction', 'flex-flow', 'flex-grow', 'flex-shrink', 'flex-wrap', 'float', 'font', '@font-face', 'font-family',
29
+ 'font-feature-settings', 'font-kerning', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style',
30
+ 'font-variant', 'font-variant-caps', 'font-weight', 'gap', 'grid', 'grid-area', 'grid-auto-columns',
31
+ 'grid-auto-flow', 'grid-auto-rows', 'grid-column', 'grid-column-end', 'grid-column-gap', 'grid-column-start',
32
+ 'grid-gap', 'grid-row', 'grid-row-end', 'grid-row-gap', 'grid-row-start', 'grid-template', 'grid-template-areas',
33
+ 'grid-template-columns', 'grid-template-rows', 'hanging-punctuation', 'height', 'hyphens', 'hypenate-character',
34
+ 'image-rendering', '@import', 'inline-size', 'inset', 'inset-block', 'inset-block-end', 'inset-block-start',
35
+ 'inset-inline', 'inset-inline-end', 'inset-inline-start', 'isolation', 'justify-content', 'justify-items',
36
+ 'justify-self', '@keyframes', 'left', 'letter-spacing', 'line-height', 'list-style', 'list-style-image',
37
+ 'list-style-position', 'list-style-type', 'margin', 'margin-block', 'margin-block-end', 'margin-block-start',
38
+ 'margin-bottom', 'margin-inline', 'margin-inline-end', 'margin-inline-start', 'margin-left', 'margin-right',
39
+ 'margin-top', 'mask-image', 'mask-mode', 'mask-origin', 'mask-position', 'mask-repeat', 'mask-size', 'max-height',
40
+ 'max-width', '@media', 'max-block-size', 'max-inline-size', 'min-block-size', 'min-inline-size', 'min-height',
41
+ 'min-width', 'mix-blend-mode', 'object-fit', 'object-position', 'offset', 'offset-anchor', 'offset-distance',
42
+ 'offset-path', 'offset-rotate', 'opacity', 'order', 'orphans', 'outline', 'outline-color', 'outline-offset',
43
+ 'outline-style', 'outline-width', 'overflow', 'overflow-anchor', 'overflow-wrap', 'overflow-x', 'overflow-y',
44
+ 'overscroll-behavior', 'overscroll-behavior-block', 'overscroll-behavior-inline', 'overscroll-behavior-x',
45
+ 'overscroll-behavior-y', 'padding', 'padding-block', 'padding-block-end', 'padding-block-start', 'padding-bottom',
46
+ 'padding-inline', 'padding-inline-end', 'padding-inline-start', 'padding-left', 'padding-right', 'padding-top',
47
+ 'page-break-after', 'page-break-before', 'page-break-inside', 'paint-order', 'perspective', 'perspective-origin',
48
+ 'place-content', 'place-items', 'place-self', 'pointer-events', 'position', 'quotes', 'resize', 'right', 'rotate',
49
+ 'row-gap', 'scale', 'scroll-behavior', 'scroll-margin', 'scroll-margin-block', 'scroll-margin-block-end',
50
+ 'scroll-margin-block-start', 'scroll-margin-bottom', 'scroll-margin-inline', 'scroll-margin-inline-end',
51
+ 'scroll-margin-inline-start', 'scroll-margin-left', 'scroll-margin-right', 'scroll-margin-top', 'scroll-padding',
52
+ 'scroll-padding-block', 'scroll-padding-block-end', 'scroll-padding-block-start', 'scroll-padding-bottom',
53
+ 'scroll-padding-inline', 'scroll-padding-inline-end', 'scroll-padding-inline-start', 'scroll-padding-left',
54
+ 'scroll-padding-right', 'scroll-padding-top', 'scroll-snap-align', 'scroll-snap-stop', 'scroll-snap-type',
55
+ 'scrollbar-color', 'tab-size', 'table-layout', 'text-align', 'text-align-last', 'text-decoration',
56
+ 'text-decoration-color', 'text-decoration-line', 'text-decoration-style', 'text-decoration-thickness',
57
+ 'text-emphasis', 'text-emphasis-color', 'text-emphasis-position', 'text-emphasis-style', 'text-indent',
58
+ 'text-justify', 'text-orientation', 'text-overflow', 'text-shadow', 'text-transform', 'text-underline-offset',
59
+ 'text-underline-position', 'top', 'transform', 'transform-origin', 'transform-style', 'transition',
60
+ 'transition-delay', 'transition-duration', 'transition-property', 'transition-timing-function', 'translate',
61
+ 'unicode-bidi', 'direction', 'user-select', 'vertical-align', 'visibility', 'white-space', 'widows',
62
+ 'width', 'word-break', 'word-spacing', 'word-wrap', 'writing-mode', 'z-index'
63
+ ]
64
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruby2sass
4
+ class CssRender
5
+ def initialize(sass, include, compress)
6
+ @sass = sass
7
+ @included_files = include
8
+ @compress = compress
9
+ end
10
+
11
+ def render
12
+ combined_sass = process_includes + @sass
13
+ options = {
14
+ style: @compress ? :compressed : :expanded
15
+ }
16
+
17
+ SassC::Engine.new(combined_sass, **options).render
18
+ end
19
+
20
+ private
21
+ def process_includes
22
+ return '' unless @included_files
23
+
24
+ Array(@included_files).map do |include_item|
25
+ content = case include_item
26
+ when String
27
+ if File.exist?(include_item)
28
+ File.read(include_item)
29
+ else
30
+ include_item
31
+ end
32
+ when IO, StringIO
33
+ include_item.read
34
+ else
35
+ raise ArgumentError, "Unsupported include type: #{include_item.class}"
36
+ end
37
+ content + "\n"
38
+ end.join
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruby2sass
4
+ class Renderer
5
+ def initialize(&block)
6
+ @output = StringIO.new
7
+ @indentation = 0
8
+ @input_block = block
9
+ @variables = {}
10
+ end
11
+
12
+ CSS_PROPERTIES.each do |property|
13
+ method_name = property.tr('-', '_').delete('@')
14
+
15
+ if property.start_with?('@')
16
+ define_method(method_name) do |*args, &block|
17
+ write_line("#{property} #{args.join(' ')} {")
18
+ indent
19
+ instance_eval(&block) if block_given?
20
+ dedent
21
+ write_line('}')
22
+ end
23
+ else
24
+ define_method(method_name) do |value|
25
+ write_line("#{property}: #{value};")
26
+ end
27
+ end
28
+ end
29
+
30
+ def s(selector, &block)
31
+ write_line("#{selector} {")
32
+ indent
33
+ if block.arity == 1
34
+ block.call(SelectorContext.new(self))
35
+ else
36
+ instance_eval(&block)
37
+ end
38
+ dedent
39
+ write_line('}')
40
+ end
41
+
42
+ def media(*args, &block)
43
+ write_line("@media #{args.join(' ')} {")
44
+ indent
45
+ instance_eval(&block) if block_given?
46
+ dedent
47
+ write_line('}')
48
+ end
49
+
50
+ def keyframes(name, &block)
51
+ write_line("@keyframes #{name} {")
52
+ indent
53
+ instance_eval(&block) if block_given?
54
+ dedent
55
+ write_line('}')
56
+ end
57
+
58
+ def mixin(name, *args, &block)
59
+ args_str = args.empty? ? '' : "(#{args.join(', ')})"
60
+ write_line("@mixin #{name}#{args_str} {")
61
+ indent
62
+ instance_eval(&block) if block_given?
63
+ dedent
64
+ write_line('}')
65
+ end
66
+
67
+ def include(name, *args)
68
+ args_str = args.empty? ? '' : "(#{args.join(', ')})"
69
+ write_line("@include #{name}#{args_str};")
70
+ end
71
+
72
+ def v(name, value)
73
+ @variables[name] = "$#{name}"
74
+ write_line("$#{name}: #{value};")
75
+ @variables[name]
76
+ end
77
+
78
+ def import(path)
79
+ write_line("@import '#{path}';")
80
+ end
81
+
82
+ def extend(selector)
83
+ write_line("@extend #{selector};")
84
+ end
85
+
86
+ def if_statement(condition, &block)
87
+ write_line("@if #{condition} {")
88
+ indent
89
+ instance_eval(&block) if block_given?
90
+ dedent
91
+ write_line('}')
92
+ end
93
+
94
+ def else_statement(&block)
95
+ write_line('@else {')
96
+ indent
97
+ instance_eval(&block) if block_given?
98
+ dedent
99
+ write_line('}')
100
+ end
101
+
102
+ def for_loop(variable, from:, to:, &block)
103
+ write_line("@for $#{variable} from #{from} through #{to} {")
104
+ indent
105
+ instance_eval(&block) if block_given?
106
+ dedent
107
+ write_line('}')
108
+ end
109
+
110
+ def each_loop(variable, list, &block)
111
+ write_line("@each $#{variable} in #{list} {")
112
+ indent
113
+ instance_eval(&block) if block_given?
114
+ dedent
115
+ write_line('}')
116
+ end
117
+
118
+ def while_loop(condition, &block)
119
+ write_line("@while #{condition} {")
120
+ indent
121
+ instance_eval(&block) if block_given?
122
+ dedent
123
+ write_line('}')
124
+ end
125
+
126
+ def function(name, *args, &block)
127
+ args_str = args.empty? ? '' : "(#{args.join(', ')})"
128
+ write_line("@function #{name}#{args_str} {")
129
+ indent
130
+ instance_eval(&block) if block_given?
131
+ dedent
132
+ write_line('}')
133
+ end
134
+
135
+ def return(value)
136
+ write_line("@return #{value};")
137
+ end
138
+
139
+ def raw(sass_content)
140
+ @output << sass_content
141
+ end
142
+
143
+ def to_sass
144
+ return @sass_output if @sass_output
145
+ instance_eval(&@input_block) if @input_block
146
+
147
+ @sass_output = @output.string
148
+ end
149
+
150
+ def to_css(include: nil, compress: false)
151
+ Ruby2sass::CssRender.new(to_sass, include, compress).render
152
+ end
153
+
154
+ def method_missing(method_name, *args)
155
+ property = method_name.to_s.tr('_', '-')
156
+ value = args.first
157
+ write_line("#{property}: #{value};")
158
+ end
159
+
160
+ private
161
+ def write_line(line)
162
+ @output.puts(' ' * @indentation + line)
163
+ end
164
+
165
+ def indent
166
+ @indentation += 1
167
+ end
168
+
169
+ def dedent
170
+ @indentation -= 1
171
+ end
172
+ end
173
+
174
+ class SelectorContext
175
+ def initialize(renderer)
176
+ @renderer = renderer
177
+ end
178
+
179
+ def method_missing(method_name, *args, &block)
180
+ selector = "&:#{method_name}"
181
+ @renderer.s(selector, &block)
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruby2sass
4
+ VERSION = '1.0.0'
5
+ end
data/lib/ruby2sass.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+ require 'sassc'
5
+
6
+ require_relative 'ruby2sass/version'
7
+ require_relative 'ruby2sass/css_properties'
8
+ Dir.glob(File.join(__dir__, 'ruby2sass', '**', '*.rb')).each do |file|
9
+ require file
10
+ end
11
+
12
+ module Ruby2sass
13
+ class Error < StandardError; end
14
+ # Your code goes here...
15
+ end
data/sig/ruby2sass.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Ruby2sass
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby2sass
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - sebi
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-08-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sassc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '2.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '2.4'
27
+ description: Ruby2sass provides a flexible and intuitive way to write SASS stylesheets
28
+ using Ruby syntax. It supports all CSS properties, nested selectors, and special
29
+ at-rules.
30
+ email:
31
+ - gore.sebyx@yahoo.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - ".rspec"
37
+ - ".rubocop.yml"
38
+ - LICENSE.txt
39
+ - README.md
40
+ - Rakefile
41
+ - lefthook.yml
42
+ - lib/ruby2sass.rb
43
+ - lib/ruby2sass/css_properties.rb
44
+ - lib/ruby2sass/css_renderer.rb
45
+ - lib/ruby2sass/renderer.rb
46
+ - lib/ruby2sass/version.rb
47
+ - sig/ruby2sass.rbs
48
+ homepage: https://github.com/sebyx07/ruby2sass
49
+ licenses:
50
+ - MIT
51
+ metadata:
52
+ allowed_push_host: https://rubygems.org
53
+ homepage_uri: https://github.com/sebyx07/ruby2sass
54
+ source_code_uri: https://github.com/sebyx07/ruby2sass
55
+ changelog_uri: https://github.com/sebyx07/ruby2sass/blob/main/CHANGELOG.md
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 3.0.0
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubygems_version: 3.5.11
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: A Ruby DSL for generating SASS stylesheets
75
+ test_files: []