ruby2sass 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/LICENSE.txt +21 -0
- data/README.md +478 -0
- data/Rakefile +8 -0
- data/lefthook.yml +7 -0
- data/lib/ruby2sass/css_properties.rb +64 -0
- data/lib/ruby2sass/css_renderer.rb +41 -0
- data/lib/ruby2sass/renderer.rb +184 -0
- data/lib/ruby2sass/version.rb +5 -0
- data/lib/ruby2sass.rb +15 -0
- data/sig/ruby2sass.rbs +4 -0
- metadata +75 -0
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
data/.rubocop.yml
ADDED
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
data/lefthook.yml
ADDED
@@ -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
|
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
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: []
|