sass-embedded 0.1.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/.github/workflows/build.yml +47 -0
- data/.gitignore +45 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.md +19 -0
- data/Rakefile +14 -0
- data/ext/sass_embedded/.gitignore +2 -0
- data/ext/sass_embedded/Makefile +23 -0
- data/ext/sass_embedded/extconf.rb +72 -0
- data/lib/sass.rb +37 -0
- data/lib/sass/embedded/compiler.rb +250 -0
- data/lib/sass/embedded/transport.rb +147 -0
- data/lib/sass/error.rb +29 -0
- data/lib/sass/platform.rb +56 -0
- data/lib/sass/util.rb +23 -0
- data/lib/sass/version.rb +6 -0
- data/sass-embedded.gemspec +37 -0
- data/test/compiler_test.rb +278 -0
- data/test/custom_importer_test.rb +160 -0
- data/test/error_test.rb +33 -0
- data/test/functions_test.rb +375 -0
- data/test/output_style_test.rb +93 -0
- data/test/test_helper.rb +29 -0
- metadata +158 -0
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "test_helper"
|
4
|
+
|
5
|
+
module Sass
|
6
|
+
class CustomImporterTest < MiniTest::Test
|
7
|
+
include TempFileTest
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@compiler = Embedded::Compiler.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
end
|
15
|
+
|
16
|
+
def render(data, importer)
|
17
|
+
@compiler.render({ data: data, importer: importer })[:css]
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_custom_importer_works
|
21
|
+
temp_file("fonts.scss", ".font { color: $var1; }")
|
22
|
+
|
23
|
+
data = <<SCSS
|
24
|
+
@import "styles";
|
25
|
+
@import "fonts";
|
26
|
+
SCSS
|
27
|
+
|
28
|
+
output = render(data, [
|
29
|
+
lambda { |url, prev|
|
30
|
+
if url =~ /styles/
|
31
|
+
{ contents: "$var1: #000; .hi { color: $var1; }" }
|
32
|
+
end
|
33
|
+
}
|
34
|
+
])
|
35
|
+
|
36
|
+
assert_equal <<CSS.chomp, output
|
37
|
+
.hi {
|
38
|
+
color: #000;
|
39
|
+
}
|
40
|
+
|
41
|
+
.font {
|
42
|
+
color: #000;
|
43
|
+
}
|
44
|
+
CSS
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_custom_importer_works_with_empty_contents
|
48
|
+
output = render("@import 'fake.scss';", [
|
49
|
+
lambda { |url, prev|
|
50
|
+
{ contents: "" }
|
51
|
+
}
|
52
|
+
])
|
53
|
+
|
54
|
+
assert_equal "", output
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_custom_importer_works_with_file
|
58
|
+
temp_file("test.scss", ".test { color: #000; }")
|
59
|
+
|
60
|
+
output = render("@import 'fake.scss';", [
|
61
|
+
lambda { |url, prev|
|
62
|
+
{ file: File.absolute_path("test.scss") }
|
63
|
+
}
|
64
|
+
])
|
65
|
+
|
66
|
+
assert_equal <<CSS.chomp, output
|
67
|
+
.test {
|
68
|
+
color: #000;
|
69
|
+
}
|
70
|
+
CSS
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_custom_importer_comes_after_local_file
|
74
|
+
temp_file("test.scss", ".test { color: #000; }")
|
75
|
+
|
76
|
+
output = render("@import 'test.scss';", [
|
77
|
+
lambda { |url, prev|
|
78
|
+
return { contents: '.h1 { color: #fff; }' }
|
79
|
+
}
|
80
|
+
])
|
81
|
+
|
82
|
+
assert_equal <<CSS.chomp, output
|
83
|
+
.test {
|
84
|
+
color: #000;
|
85
|
+
}
|
86
|
+
CSS
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_custom_importer_that_does_not_resolve
|
90
|
+
assert_raises(CompilationError) do
|
91
|
+
output = render("@import 'test.scss';", [
|
92
|
+
lambda { |url, prev|
|
93
|
+
return nil
|
94
|
+
}
|
95
|
+
])
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_custom_importer_that_returns_error
|
100
|
+
assert_raises(CompilationError) do
|
101
|
+
output = render("@import 'test.scss';", [
|
102
|
+
lambda { |url, prev|
|
103
|
+
IOError.new "test error"
|
104
|
+
}
|
105
|
+
])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_custom_importer_that_raises_error
|
110
|
+
assert_raises(CompilationError) do
|
111
|
+
output = render("@import 'test.scss';", [
|
112
|
+
lambda { |url, prev|
|
113
|
+
raise IOError.new "test error"
|
114
|
+
}
|
115
|
+
])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_parent_path_is_accessible
|
120
|
+
output = @compiler.render({
|
121
|
+
data: "@import 'parent.scss';",
|
122
|
+
file: "import-parent-filename.scss",
|
123
|
+
importer: [
|
124
|
+
lambda { |url, prev|
|
125
|
+
{ contents: ".#{prev} { color: red; }" }
|
126
|
+
}
|
127
|
+
]})[:css]
|
128
|
+
|
129
|
+
assert_equal <<CSS.chomp, output
|
130
|
+
.import-parent-filename.scss {
|
131
|
+
color: red;
|
132
|
+
}
|
133
|
+
CSS
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_call_compiler_importer
|
137
|
+
output = @compiler.render({
|
138
|
+
data: "@import 'parent.scss';",
|
139
|
+
importer: [
|
140
|
+
lambda { |url, prev|
|
141
|
+
{
|
142
|
+
contents: @compiler.render({
|
143
|
+
data: "@import 'parent-parent.scss'",
|
144
|
+
importer: [
|
145
|
+
lambda { |url, prev|
|
146
|
+
{ contents: 'h1 { color: black; }' }
|
147
|
+
}
|
148
|
+
]})[:css]
|
149
|
+
}
|
150
|
+
}
|
151
|
+
]})[:css]
|
152
|
+
|
153
|
+
assert_equal <<CSS.chomp, output
|
154
|
+
h1 {
|
155
|
+
color: black;
|
156
|
+
}
|
157
|
+
CSS
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/test/error_test.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "test_helper"
|
4
|
+
|
5
|
+
module Sass
|
6
|
+
class ErrorTest < MiniTest::Test
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@compiler = Embedded::Compiler.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_first_backtrace_is_sass
|
16
|
+
begin
|
17
|
+
template = <<-SCSS
|
18
|
+
.foo {
|
19
|
+
baz: bang;
|
20
|
+
padding top: 10px;
|
21
|
+
}
|
22
|
+
SCSS
|
23
|
+
|
24
|
+
@compiler.render({
|
25
|
+
data: template,
|
26
|
+
})
|
27
|
+
rescue Sass::CompilationError => err
|
28
|
+
expected = "stdin:3:20"
|
29
|
+
assert_equal expected, err.backtrace.first
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,375 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "test_helper"
|
4
|
+
require "stringio"
|
5
|
+
|
6
|
+
module Sass
|
7
|
+
class FunctionsTest < MiniTest::Test
|
8
|
+
def setup
|
9
|
+
@compiler = Embedded::Compiler.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
end
|
14
|
+
|
15
|
+
def render(sass)
|
16
|
+
@compiler.render({
|
17
|
+
data: sass,
|
18
|
+
functions: {
|
19
|
+
'javascript_path($path)': lambda { |path|
|
20
|
+
path.string.text = "/js/#{path.string.text}"
|
21
|
+
path
|
22
|
+
},
|
23
|
+
'stylesheet_path($path)': lambda { |path|
|
24
|
+
path.string.text = "/css/#{path.string.text}"
|
25
|
+
path
|
26
|
+
},
|
27
|
+
'sass_return_path($path)': lambda { |path|
|
28
|
+
path
|
29
|
+
},
|
30
|
+
'no_return_path($path)': lambda { |path|
|
31
|
+
Sass::EmbeddedProtocol::Value.new(
|
32
|
+
:singleton => Sass::EmbeddedProtocol::SingletonValue::NULL
|
33
|
+
)
|
34
|
+
},
|
35
|
+
'optional_arguments($path, $optional: null)': lambda { |path, optional|
|
36
|
+
Sass::EmbeddedProtocol::Value.new(
|
37
|
+
:string => Sass::EmbeddedProtocol::Value::String.new(
|
38
|
+
:text => "#{path.string.text}/#{optional.singleton == :NULL ? "bar" : optional.string.text}",
|
39
|
+
:quoted => true
|
40
|
+
)
|
41
|
+
)
|
42
|
+
},
|
43
|
+
'function_that_raises_errors()': lambda {
|
44
|
+
raise StandardError, "Intentional wrong thing happened somewhere inside the custom function"
|
45
|
+
},
|
46
|
+
'nice_color_argument($color)': lambda { |color|
|
47
|
+
color
|
48
|
+
},
|
49
|
+
'returns_a_color()': lambda {
|
50
|
+
Sass::EmbeddedProtocol::Value.new(
|
51
|
+
:rgb_color => Sass::EmbeddedProtocol::Value::RgbColor.new(
|
52
|
+
:red => 0,
|
53
|
+
:green => 0,
|
54
|
+
:blue => 0,
|
55
|
+
:alpha => 1
|
56
|
+
)
|
57
|
+
)
|
58
|
+
},
|
59
|
+
'returns_a_number()': lambda {
|
60
|
+
Sass::EmbeddedProtocol::Value.new(
|
61
|
+
:number => Sass::EmbeddedProtocol::Value::Number.new(
|
62
|
+
:value => -312,
|
63
|
+
:numerators => ['rem']
|
64
|
+
)
|
65
|
+
)
|
66
|
+
},
|
67
|
+
'returns_a_bool()': lambda {
|
68
|
+
Sass::EmbeddedProtocol::Value.new(
|
69
|
+
:singleton => Sass::EmbeddedProtocol::SingletonValue::TRUE
|
70
|
+
)
|
71
|
+
},
|
72
|
+
'inspect_bool($argument)': lambda { |argument|
|
73
|
+
raise StandardError.new "passed value is not a Sass::EmbeddedProtocol::SingletonValue::TRUE or Sass::EmbeddedProtocol::SingletonValue::FALSE" unless argument&.singleton == :TRUE || argument.singleton == :FALSE
|
74
|
+
argument
|
75
|
+
},
|
76
|
+
'inspect_number($argument)': lambda { |argument|
|
77
|
+
raise StandardError.new "passed value is not a Sass::EmbeddedProtocol::Value::Number" unless argument&.number&.is_a? Sass::EmbeddedProtocol::Value::Number
|
78
|
+
argument
|
79
|
+
},
|
80
|
+
'inspect_map($argument)': lambda { |argument|
|
81
|
+
raise StandardError.new "passed value is not a Sass::EmbeddedProtocol::Value::Map" unless argument&.map&.is_a? Sass::EmbeddedProtocol::Value::Map
|
82
|
+
argument
|
83
|
+
},
|
84
|
+
'inspect_list($argument)': lambda { |argument|
|
85
|
+
raise StandardError.new "passed value is not a Sass::EmbeddedProtocol::Value::List" unless argument&.list&.is_a? Sass::EmbeddedProtocol::Value::List
|
86
|
+
argument
|
87
|
+
},
|
88
|
+
'returns_sass_value()': lambda {
|
89
|
+
Sass::EmbeddedProtocol::Value.new(
|
90
|
+
:rgb_color => Sass::EmbeddedProtocol::Value::RgbColor.new(
|
91
|
+
:red => 0,
|
92
|
+
:green => 0,
|
93
|
+
:blue => 0,
|
94
|
+
:alpha => 1
|
95
|
+
)
|
96
|
+
)
|
97
|
+
},
|
98
|
+
'returns_sass_map()': lambda {
|
99
|
+
Sass::EmbeddedProtocol::Value.new(
|
100
|
+
:map => Sass::EmbeddedProtocol::Value::Map.new(
|
101
|
+
:entries => [
|
102
|
+
Sass::EmbeddedProtocol::Value::Map::Entry.new(
|
103
|
+
:key => Sass::EmbeddedProtocol::Value.new(
|
104
|
+
:string => Sass::EmbeddedProtocol::Value::String.new(
|
105
|
+
:text => "color",
|
106
|
+
:quoted => true
|
107
|
+
)
|
108
|
+
),
|
109
|
+
:value => Sass::EmbeddedProtocol::Value.new(
|
110
|
+
:rgb_color => Sass::EmbeddedProtocol::Value::RgbColor.new(
|
111
|
+
:red => 0,
|
112
|
+
:green => 0,
|
113
|
+
:blue => 0,
|
114
|
+
:alpha => 1
|
115
|
+
)
|
116
|
+
)
|
117
|
+
)
|
118
|
+
]
|
119
|
+
)
|
120
|
+
)
|
121
|
+
},
|
122
|
+
'returns_sass_list()': lambda {
|
123
|
+
Sass::EmbeddedProtocol::Value.new(
|
124
|
+
:list => Sass::EmbeddedProtocol::Value::List.new(
|
125
|
+
:separator => Sass::EmbeddedProtocol::ListSeparator::COMMA,
|
126
|
+
:has_brackets => true,
|
127
|
+
:contents => [
|
128
|
+
Sass::EmbeddedProtocol::Value.new(
|
129
|
+
:number => Sass::EmbeddedProtocol::Value::Number.new(
|
130
|
+
:value => 10
|
131
|
+
)
|
132
|
+
),
|
133
|
+
Sass::EmbeddedProtocol::Value.new(
|
134
|
+
:number => Sass::EmbeddedProtocol::Value::Number.new(
|
135
|
+
:value => 20
|
136
|
+
)
|
137
|
+
),
|
138
|
+
Sass::EmbeddedProtocol::Value.new(
|
139
|
+
:number => Sass::EmbeddedProtocol::Value::Number.new(
|
140
|
+
:value => 30
|
141
|
+
)
|
142
|
+
),
|
143
|
+
]
|
144
|
+
)
|
145
|
+
)
|
146
|
+
}
|
147
|
+
}
|
148
|
+
})[:css]
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_functions_may_return_sass_string_type
|
152
|
+
assert_sass <<-SCSS, <<-CSS
|
153
|
+
div { url: url(sass_return_path("foo.svg")); }
|
154
|
+
SCSS
|
155
|
+
div { url: url("foo.svg"); }
|
156
|
+
CSS
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_functions_work_with_varying_quotes_and_string_types
|
160
|
+
assert_sass <<-SCSS, <<-CSS
|
161
|
+
div {
|
162
|
+
url: url(asset-path("foo.svg"));
|
163
|
+
url: url(image-path("foo.png"));
|
164
|
+
url: url(video-path("foo.mov"));
|
165
|
+
url: url(audio-path("foo.mp3"));
|
166
|
+
url: url(font-path("foo.woff"));
|
167
|
+
url: url(javascript-path('foo.js'));
|
168
|
+
url: url(javascript-path("foo.js"));
|
169
|
+
url: url(stylesheet-path("foo.css"));
|
170
|
+
}
|
171
|
+
SCSS
|
172
|
+
div {
|
173
|
+
url: url(asset-path("foo.svg"));
|
174
|
+
url: url(image-path("foo.png"));
|
175
|
+
url: url(video-path("foo.mov"));
|
176
|
+
url: url(audio-path("foo.mp3"));
|
177
|
+
url: url(font-path("foo.woff"));
|
178
|
+
url: url("/js/foo.js");
|
179
|
+
url: url("/js/foo.js");
|
180
|
+
url: url("/css/foo.css");
|
181
|
+
}
|
182
|
+
CSS
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_function_with_empty_unquoted_string
|
186
|
+
assert_sass <<-SCSS, <<-CSS
|
187
|
+
div {url: url(no-return-path('foo.svg'));}
|
188
|
+
SCSS
|
189
|
+
div { url: url(); }
|
190
|
+
CSS
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_function_that_returns_a_color
|
194
|
+
assert_sass <<-SCSS, <<-CSS
|
195
|
+
div { background: returns-a-color(); }
|
196
|
+
SCSS
|
197
|
+
div { background: black; }
|
198
|
+
CSS
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_function_that_returns_a_number
|
202
|
+
assert_sass <<-SCSS, <<-CSS
|
203
|
+
div { width: returns-a-number(); }
|
204
|
+
SCSS
|
205
|
+
div { width: -312rem; }
|
206
|
+
CSS
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_function_that_takes_a_number
|
210
|
+
assert_sass <<-SCSS, <<-CSS
|
211
|
+
div { display: inspect-number(42.1px); }
|
212
|
+
SCSS
|
213
|
+
div { display: 42.1px; }
|
214
|
+
CSS
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_function_that_returns_a_bool
|
218
|
+
assert_sass <<-SCSS, <<-CSS
|
219
|
+
div { width: returns-a-bool(); }
|
220
|
+
SCSS
|
221
|
+
div { width: true; }
|
222
|
+
CSS
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_function_that_takes_a_bool
|
226
|
+
assert_sass <<-SCSS, <<-CSS
|
227
|
+
div { display: inspect-bool(true)}
|
228
|
+
SCSS
|
229
|
+
div { display: true; }
|
230
|
+
CSS
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_function_with_optional_arguments
|
234
|
+
assert_sass <<-SCSS, <<-EXPECTED_CSS
|
235
|
+
div {
|
236
|
+
url: optional_arguments('first');
|
237
|
+
url: optional_arguments('second', 'qux');
|
238
|
+
}
|
239
|
+
SCSS
|
240
|
+
div {
|
241
|
+
url: "first/bar";
|
242
|
+
url: "second/qux";
|
243
|
+
}
|
244
|
+
EXPECTED_CSS
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_functions_may_accept_sass_color_type
|
248
|
+
assert_sass <<-SCSS, <<-EXPECTED_CSS
|
249
|
+
div { color: nice_color_argument(red); }
|
250
|
+
SCSS
|
251
|
+
div { color: red; }
|
252
|
+
EXPECTED_CSS
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_function_with_error
|
256
|
+
exception = assert_raises(Sass::CompilationError) do
|
257
|
+
render("div {url: function_that_raises_errors();}")
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_function_that_returns_a_sass_value
|
262
|
+
assert_sass <<-SCSS, <<-CSS
|
263
|
+
div { background: returns-sass-value(); }
|
264
|
+
SCSS
|
265
|
+
div { background: black; }
|
266
|
+
CSS
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_function_that_returns_a_sass_map
|
270
|
+
assert_sass <<-SCSS, <<-CSS
|
271
|
+
$my-map: returns-sass-map();
|
272
|
+
div { background: map-get( $my-map, color ); }
|
273
|
+
SCSS
|
274
|
+
div { background: black; }
|
275
|
+
CSS
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_function_that_takes_a_sass_map
|
279
|
+
assert_sass <<-SCSS, <<-CSS
|
280
|
+
div { background-color: map-get( inspect-map(( color: black, number: 1.23px, string: "abc", map: ( x: 'y' ))), color ); }
|
281
|
+
SCSS
|
282
|
+
div { background-color: black; }
|
283
|
+
CSS
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_function_that_returns_a_sass_list
|
287
|
+
assert_sass <<-SCSS, <<-CSS
|
288
|
+
$my-list: returns-sass-list();
|
289
|
+
div { width: nth( $my-list, 2 ); }
|
290
|
+
SCSS
|
291
|
+
div { width: 20; }
|
292
|
+
CSS
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_function_that_takes_a_sass_list
|
296
|
+
assert_sass <<-SCSS, <<-CSS
|
297
|
+
div { width: nth(inspect-list((10 20 30)), 2); }
|
298
|
+
SCSS
|
299
|
+
div { width: 20; }
|
300
|
+
CSS
|
301
|
+
end
|
302
|
+
|
303
|
+
def test_concurrency
|
304
|
+
skip 'ProtocolError: Bad state: Future already completed'
|
305
|
+
10.times do
|
306
|
+
threads = []
|
307
|
+
2.times do |i|
|
308
|
+
threads << Thread.new(i) do |id|
|
309
|
+
output = @compiler.render({
|
310
|
+
data: "div { url: test-function() }",
|
311
|
+
functions: {
|
312
|
+
'test_function()': lambda {
|
313
|
+
Sass::EmbeddedProtocol::Value.new(
|
314
|
+
:string => Sass::EmbeddedProtocol::Value::String.new(
|
315
|
+
:text => "{test_key1: 'test_value', test_key2: #{id}}",
|
316
|
+
:quoted => true
|
317
|
+
)
|
318
|
+
)
|
319
|
+
}
|
320
|
+
}
|
321
|
+
})[:css]
|
322
|
+
assert_match /test_key1/, output
|
323
|
+
assert_match /test_key2/, output
|
324
|
+
assert_match /test_value/, output
|
325
|
+
assert_match /#{id}/, output
|
326
|
+
end
|
327
|
+
end
|
328
|
+
threads.each(&:join)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def test_pass_custom_functions_as_a_parameter
|
333
|
+
output = @compiler.render({
|
334
|
+
data: "div { url: test-function(); }",
|
335
|
+
functions: {
|
336
|
+
'test_function()': lambda {
|
337
|
+
Sass::EmbeddedProtocol::Value.new(
|
338
|
+
:string => Sass::EmbeddedProtocol::Value::String.new(
|
339
|
+
:text => "custom_function",
|
340
|
+
:quoted => true
|
341
|
+
)
|
342
|
+
)
|
343
|
+
}
|
344
|
+
}
|
345
|
+
})[:css]
|
346
|
+
|
347
|
+
assert_match /custom_function/, output
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_pass_incompatible_type_to_custom_functions
|
351
|
+
assert_raises(CompilationError) do
|
352
|
+
output = @compiler.render({
|
353
|
+
data: "div { url: test-function(); }",
|
354
|
+
functions: {
|
355
|
+
'test_function()': lambda {
|
356
|
+
Class.new
|
357
|
+
}
|
358
|
+
}
|
359
|
+
})[:css]
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
private
|
364
|
+
|
365
|
+
def assert_sass(sass, expected_css)
|
366
|
+
output = render(sass)
|
367
|
+
assert_equal expected_css.strip.gsub!(/\s+/, " "), # poor man's String#squish
|
368
|
+
output.strip.gsub!(/\s+/, " ")
|
369
|
+
end
|
370
|
+
|
371
|
+
def stderr_output
|
372
|
+
$stderr.string.gsub("\u0000\n", '').chomp
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|