sass 3.2.0.alpha.104 → 3.2.0.alpha.236
Sign up to get free protection for your applications and to get access to all the features.
- data/REVISION +1 -1
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/lib/sass/engine.rb +8 -1
- data/lib/sass/exec.rb +2 -2
- data/lib/sass/plugin/compiler.rb +51 -43
- data/lib/sass/script/color.rb +4 -9
- data/lib/sass/script/funcall.rb +11 -2
- data/lib/sass/script/functions.rb +16 -30
- data/lib/sass/script/lexer.rb +7 -1
- data/lib/sass/script/list.rb +2 -2
- data/lib/sass/script/literal.rb +8 -0
- data/lib/sass/script/null.rb +34 -0
- data/lib/sass/script/operation.rb +4 -0
- data/lib/sass/script/parser.rb +4 -2
- data/lib/sass/scss/parser.rb +1 -5
- data/lib/sass/scss/rx.rb +1 -1
- data/lib/sass/tree/directive_node.rb +5 -0
- data/lib/sass/tree/media_node.rb +3 -0
- data/lib/sass/tree/prop_node.rb +7 -3
- data/lib/sass/tree/visitors/base.rb +1 -1
- data/lib/sass/tree/visitors/check_nesting.rb +21 -18
- data/lib/sass/tree/visitors/convert.rb +1 -0
- data/lib/sass/tree/visitors/perform.rb +3 -2
- data/lib/sass/tree/visitors/to_css.rb +1 -0
- data/lib/sass/util.rb +28 -0
- data/test/sass/conversion_test.rb +33 -0
- data/test/sass/engine_test.rb +118 -3
- data/test/sass/functions_test.rb +56 -24
- data/test/sass/script_test.rb +60 -4
- data/test/sass/scss/scss_test.rb +10 -0
- data/vendor/listen/CHANGELOG.md +19 -1
- data/vendor/listen/README.md +27 -12
- data/vendor/listen/lib/listen/adapter.rb +9 -1
- data/vendor/listen/lib/listen/adapters/linux.rb +18 -7
- data/vendor/listen/lib/listen/adapters/windows.rb +7 -8
- data/vendor/listen/lib/listen/directory_record.rb +108 -48
- data/vendor/listen/lib/listen/listener.rb +28 -11
- data/vendor/listen/lib/listen/multi_listener.rb +6 -6
- data/vendor/listen/lib/listen/version.rb +1 -1
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +11 -0
- data/vendor/listen/spec/listen/directory_record_spec.rb +268 -41
- data/vendor/listen/spec/listen/listener_spec.rb +8 -4
- data/vendor/listen/spec/listen/multi_listener_spec.rb +9 -4
- data/vendor/listen/spec/support/adapter_helper.rb +178 -0
- data/vendor/listen/spec/support/directory_record_helper.rb +24 -4
- data/vendor/listen/spec/support/listeners_helper.rb +11 -0
- metadata +11 -11
- data/lib/sass/plugin/listener.rb +0 -61
data/test/sass/functions_test.rb
CHANGED
@@ -76,7 +76,7 @@ class SassFunctionTest < Test::Unit::TestCase
|
|
76
76
|
|
77
77
|
def test_hsl_checks_bounds
|
78
78
|
assert_error_message("Saturation -114 must be between 0% and 100% for `hsl'", "hsl(10, -114, 12)");
|
79
|
-
assert_error_message("Lightness 256 must be between 0% and 100% for `hsl'", "hsl(10, 10, 256%)");
|
79
|
+
assert_error_message("Lightness 256% must be between 0% and 100% for `hsl'", "hsl(10, 10, 256%)");
|
80
80
|
end
|
81
81
|
|
82
82
|
def test_hsl_checks_types
|
@@ -94,7 +94,7 @@ class SassFunctionTest < Test::Unit::TestCase
|
|
94
94
|
|
95
95
|
def test_hsla_checks_bounds
|
96
96
|
assert_error_message("Saturation -114 must be between 0% and 100% for `hsla'", "hsla(10, -114, 12, 1)");
|
97
|
-
assert_error_message("Lightness 256 must be between 0% and 100% for `hsla'", "hsla(10, 10, 256%, 0)");
|
97
|
+
assert_error_message("Lightness 256% must be between 0% and 100% for `hsla'", "hsla(10, 10, 256%, 0)");
|
98
98
|
assert_error_message("Alpha channel -0.1 must be between 0 and 1 for `hsla'", "hsla(10, 10, 10, -0.1)");
|
99
99
|
assert_error_message("Alpha channel 1.1 must be between 0 and 1 for `hsla'", "hsla(10, 10, 10, 1.1)");
|
100
100
|
end
|
@@ -189,24 +189,24 @@ class SassFunctionTest < Test::Unit::TestCase
|
|
189
189
|
end
|
190
190
|
|
191
191
|
def test_rgb_tests_bounds
|
192
|
-
assert_error_message("Color value 256 must be between 0 and 255
|
192
|
+
assert_error_message("Color value 256 must be between 0 and 255 for `rgb'",
|
193
193
|
"rgb(256, 1, 1)")
|
194
|
-
assert_error_message("Color value 256 must be between 0 and 255
|
194
|
+
assert_error_message("Color value 256 must be between 0 and 255 for `rgb'",
|
195
195
|
"rgb(1, 256, 1)")
|
196
|
-
assert_error_message("Color value 256 must be between 0 and 255
|
196
|
+
assert_error_message("Color value 256 must be between 0 and 255 for `rgb'",
|
197
197
|
"rgb(1, 1, 256)")
|
198
|
-
assert_error_message("Color value 256 must be between 0 and 255
|
198
|
+
assert_error_message("Color value 256 must be between 0 and 255 for `rgb'",
|
199
199
|
"rgb(1, 256, 257)")
|
200
|
-
assert_error_message("Color value -1 must be between 0 and 255
|
200
|
+
assert_error_message("Color value -1 must be between 0 and 255 for `rgb'",
|
201
201
|
"rgb(-1, 1, 1)")
|
202
202
|
end
|
203
203
|
|
204
204
|
def test_rgb_test_percent_bounds
|
205
|
-
assert_error_message("Color value 100.1% must be between 0% and 100%
|
205
|
+
assert_error_message("Color value 100.1% must be between 0% and 100% for `rgb'",
|
206
206
|
"rgb(100.1%, 0, 0)")
|
207
|
-
assert_error_message("Color value -0.1% must be between 0% and 100%
|
207
|
+
assert_error_message("Color value -0.1% must be between 0% and 100% for `rgb'",
|
208
208
|
"rgb(0, -0.1%, 0)")
|
209
|
-
assert_error_message("Color value 101% must be between 0% and 100%
|
209
|
+
assert_error_message("Color value 101% must be between 0% and 100% for `rgb'",
|
210
210
|
"rgb(0, 0, 101%)")
|
211
211
|
end
|
212
212
|
|
@@ -224,19 +224,19 @@ class SassFunctionTest < Test::Unit::TestCase
|
|
224
224
|
end
|
225
225
|
|
226
226
|
def test_rgb_tests_bounds
|
227
|
-
assert_error_message("Color value 256 must be between 0 and 255
|
227
|
+
assert_error_message("Color value 256 must be between 0 and 255 for `rgba'",
|
228
228
|
"rgba(256, 1, 1, 0.3)")
|
229
|
-
assert_error_message("Color value 256 must be between 0 and 255
|
229
|
+
assert_error_message("Color value 256 must be between 0 and 255 for `rgba'",
|
230
230
|
"rgba(1, 256, 1, 0.3)")
|
231
|
-
assert_error_message("Color value 256 must be between 0 and 255
|
231
|
+
assert_error_message("Color value 256 must be between 0 and 255 for `rgba'",
|
232
232
|
"rgba(1, 1, 256, 0.3)")
|
233
|
-
assert_error_message("Color value 256 must be between 0 and 255
|
233
|
+
assert_error_message("Color value 256 must be between 0 and 255 for `rgba'",
|
234
234
|
"rgba(1, 256, 257, 0.3)")
|
235
|
-
assert_error_message("Color value -1 must be between 0 and 255
|
235
|
+
assert_error_message("Color value -1 must be between 0 and 255 for `rgba'",
|
236
236
|
"rgba(-1, 1, 1, 0.3)")
|
237
|
-
assert_error_message("Alpha channel -0.2 must be between 0 and 1
|
237
|
+
assert_error_message("Alpha channel -0.2 must be between 0 and 1 for `rgba'",
|
238
238
|
"rgba(1, 1, 1, -0.2)")
|
239
|
-
assert_error_message("Alpha channel 1.2 must be between 0 and 1
|
239
|
+
assert_error_message("Alpha channel 1.2 must be between 0 and 1 for `rgba'",
|
240
240
|
"rgba(1, 1, 1, 1.2)")
|
241
241
|
end
|
242
242
|
|
@@ -733,15 +733,15 @@ class SassFunctionTest < Test::Unit::TestCase
|
|
733
733
|
|
734
734
|
def test_change_color_argument_errors
|
735
735
|
# Range
|
736
|
-
assert_error_message("Saturation must be between 0 and 100 for `change-color'",
|
736
|
+
assert_error_message("Saturation 101% must be between 0% and 100% for `change-color'",
|
737
737
|
"change-color(blue, $saturation: 101%)")
|
738
|
-
assert_error_message("Lightness must be between 0 and 100 for `change-color'",
|
738
|
+
assert_error_message("Lightness 101% must be between 0% and 100% for `change-color'",
|
739
739
|
"change-color(blue, $lightness: 101%)")
|
740
|
-
assert_error_message("Red value must be between 0 and 255 for `change-color'",
|
740
|
+
assert_error_message("Red value -1 must be between 0 and 255 for `change-color'",
|
741
741
|
"change-color(blue, $red: -1)")
|
742
|
-
assert_error_message("Green value must be between 0 and 255 for `change-color'",
|
742
|
+
assert_error_message("Green value 256 must be between 0 and 255 for `change-color'",
|
743
743
|
"change-color(blue, $green: 256)")
|
744
|
-
assert_error_message("Blue value must be between 0 and 255 for `change-color'",
|
744
|
+
assert_error_message("Blue value 500 must be between 0 and 255 for `change-color'",
|
745
745
|
"change-color(blue, $blue: 500)")
|
746
746
|
|
747
747
|
# Unknown argument
|
@@ -871,6 +871,7 @@ MSG
|
|
871
871
|
assert_equal("bool", evaluate("type-of(true)"))
|
872
872
|
assert_equal("color", evaluate("type-of(#fff)"))
|
873
873
|
assert_equal("color", evaluate("type-of($value: #fff)"))
|
874
|
+
assert_equal("null", evaluate("type-of(null)"))
|
874
875
|
end
|
875
876
|
|
876
877
|
def test_unit
|
@@ -1011,6 +1012,7 @@ MSG
|
|
1011
1012
|
def test_if
|
1012
1013
|
assert_equal("1px", evaluate("if(true, 1px, 2px)"))
|
1013
1014
|
assert_equal("2px", evaluate("if(false, 1px, 2px)"))
|
1015
|
+
assert_equal("2px", evaluate("if(null, 1px, 2px)"))
|
1014
1016
|
end
|
1015
1017
|
|
1016
1018
|
def test_keyword_args_rgb
|
@@ -1023,23 +1025,47 @@ MSG
|
|
1023
1025
|
end
|
1024
1026
|
|
1025
1027
|
def test_keyword_args_rgba_with_extra_args
|
1026
|
-
|
1028
|
+
evaluate("rgba($red: 255, $green: 255, $blue: 255, $alpha: 0.5, $extra: error)")
|
1029
|
+
flunk("Expected exception")
|
1027
1030
|
rescue Sass::SyntaxError => e
|
1028
|
-
assert_equal("Function rgba doesn't
|
1031
|
+
assert_equal("Function rgba doesn't have an argument named $extra", e.message)
|
1029
1032
|
end
|
1030
1033
|
|
1031
1034
|
def test_keyword_args_must_have_signature
|
1032
1035
|
evaluate("no-kw-args($fake: value)")
|
1036
|
+
flunk("Expected exception")
|
1033
1037
|
rescue Sass::SyntaxError => e
|
1034
1038
|
assert_equal("Function no_kw_args doesn't support keyword arguments", e.message)
|
1035
1039
|
end
|
1036
1040
|
|
1037
1041
|
def test_keyword_args_with_missing_argument
|
1038
1042
|
evaluate("rgb($red: 255, $green: 255)")
|
1043
|
+
flunk("Expected exception")
|
1039
1044
|
rescue Sass::SyntaxError => e
|
1040
1045
|
assert_equal("Function rgb requires an argument named $blue", e.message)
|
1041
1046
|
end
|
1042
1047
|
|
1048
|
+
def test_keyword_args_with_extra_argument
|
1049
|
+
evaluate("rgb($red: 255, $green: 255, $blue: 255, $purple: 255)")
|
1050
|
+
flunk("Expected exception")
|
1051
|
+
rescue Sass::SyntaxError => e
|
1052
|
+
assert_equal("Function rgb doesn't have an argument named $purple", e.message)
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
def test_keyword_args_with_positional_and_keyword_argument
|
1056
|
+
evaluate("rgb(255, 255, 255, $red: 255)")
|
1057
|
+
flunk("Expected exception")
|
1058
|
+
rescue Sass::SyntaxError => e
|
1059
|
+
assert_equal("Function rgb was passed argument $red both by position and by name", e.message)
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
def test_keyword_args_with_keyword_before_positional_argument
|
1063
|
+
evaluate("rgb($red: 255, 255, 255)")
|
1064
|
+
flunk("Expected exception")
|
1065
|
+
rescue Sass::SyntaxError => e
|
1066
|
+
assert_equal("Positional arguments must come before keyword arguments", e.message)
|
1067
|
+
end
|
1068
|
+
|
1043
1069
|
def test_only_var_args
|
1044
1070
|
assert_equal "only-var-args(2px, 3px, 4px)", evaluate("only-var-args(1px, 2px, 3px)")
|
1045
1071
|
end
|
@@ -1048,6 +1074,12 @@ MSG
|
|
1048
1074
|
assert_equal "only-kw-args(a, b, c)", evaluate("only-kw-args($a: 1, $b: 2, $c: 3)")
|
1049
1075
|
end
|
1050
1076
|
|
1077
|
+
## Regression Tests
|
1078
|
+
|
1079
|
+
def test_saturation_bounds
|
1080
|
+
assert_equal "#fbfdff", evaluate("hsl(hue(#fbfdff), saturation(#fbfdff), lightness(#fbfdff))")
|
1081
|
+
end
|
1082
|
+
|
1051
1083
|
private
|
1052
1084
|
|
1053
1085
|
def evaluate(value)
|
data/test/sass/script_test.rb
CHANGED
@@ -21,13 +21,13 @@ class SassScriptTest < Test::Unit::TestCase
|
|
21
21
|
include Sass::Script
|
22
22
|
|
23
23
|
def test_color_checks_input
|
24
|
-
assert_raise_message(ArgumentError, "Blue value must be between 0 and 255") {Color.new([1, 2, -1])}
|
25
|
-
assert_raise_message(ArgumentError, "Red value must be between 0 and 255") {Color.new([256, 2, 3])}
|
24
|
+
assert_raise_message(ArgumentError, "Blue value -1 must be between 0 and 255") {Color.new([1, 2, -1])}
|
25
|
+
assert_raise_message(ArgumentError, "Red value 256 must be between 0 and 255") {Color.new([256, 2, 3])}
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_color_checks_rgba_input
|
29
|
-
assert_raise_message(ArgumentError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, 1.1])}
|
30
|
-
assert_raise_message(ArgumentError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, -0.1])}
|
29
|
+
assert_raise_message(ArgumentError, "Alpha channel 1.1 must be between 0 and 1") {Color.new([1, 2, 3, 1.1])}
|
30
|
+
assert_raise_message(ArgumentError, "Alpha channel -0.1 must be between 0 and 1") {Color.new([1, 2, 3, -0.1])}
|
31
31
|
end
|
32
32
|
|
33
33
|
def test_string_escapes
|
@@ -263,6 +263,10 @@ SASS
|
|
263
263
|
assert_equal "false", resolve("false")
|
264
264
|
end
|
265
265
|
|
266
|
+
def test_null
|
267
|
+
assert_equal "", resolve("null")
|
268
|
+
end
|
269
|
+
|
266
270
|
def test_boolean_ops
|
267
271
|
assert_equal "true", resolve("true and true")
|
268
272
|
assert_equal "true", resolve("false or true")
|
@@ -281,6 +285,18 @@ SASS
|
|
281
285
|
assert_equal "false", resolve("false and 1")
|
282
286
|
assert_equal "2", resolve("2 or 3")
|
283
287
|
assert_equal "3", resolve("2 and 3")
|
288
|
+
|
289
|
+
assert_equal "true", resolve("null or true")
|
290
|
+
assert_equal "true", resolve("true or null")
|
291
|
+
assert_equal "", resolve("null or null")
|
292
|
+
assert_equal "", resolve("null and true")
|
293
|
+
assert_equal "", resolve("true and null")
|
294
|
+
assert_equal "", resolve("null and null")
|
295
|
+
|
296
|
+
assert_equal "true", resolve("not null")
|
297
|
+
|
298
|
+
assert_equal "1", resolve("null or 1")
|
299
|
+
assert_equal "", resolve("null and 1")
|
284
300
|
end
|
285
301
|
|
286
302
|
def test_arithmetic_ops
|
@@ -326,6 +342,37 @@ SASS
|
|
326
342
|
assert_equal "false", resolve("3 <= 2")
|
327
343
|
end
|
328
344
|
|
345
|
+
def test_null_ops
|
346
|
+
assert_raise_message(Sass::SyntaxError,
|
347
|
+
'Invalid null operation: "null plus 1".') {eval("null + 1")}
|
348
|
+
assert_raise_message(Sass::SyntaxError,
|
349
|
+
'Invalid null operation: "null minus 1".') {eval("null - 1")}
|
350
|
+
assert_raise_message(Sass::SyntaxError,
|
351
|
+
'Invalid null operation: "null times 1".') {eval("null * 1")}
|
352
|
+
assert_raise_message(Sass::SyntaxError,
|
353
|
+
'Invalid null operation: "null div 1".') {eval("null / 1")}
|
354
|
+
assert_raise_message(Sass::SyntaxError,
|
355
|
+
'Invalid null operation: "null mod 1".') {eval("null % 1")}
|
356
|
+
assert_raise_message(Sass::SyntaxError,
|
357
|
+
'Invalid null operation: "1 plus null".') {eval("1 + null")}
|
358
|
+
assert_raise_message(Sass::SyntaxError,
|
359
|
+
'Invalid null operation: "1 minus null".') {eval("1 - null")}
|
360
|
+
assert_raise_message(Sass::SyntaxError,
|
361
|
+
'Invalid null operation: "1 times null".') {eval("1 * null")}
|
362
|
+
assert_raise_message(Sass::SyntaxError,
|
363
|
+
'Invalid null operation: "1 div null".') {eval("1 / null")}
|
364
|
+
assert_raise_message(Sass::SyntaxError,
|
365
|
+
'Invalid null operation: "1 mod null".') {eval("1 % null")}
|
366
|
+
assert_raise_message(Sass::SyntaxError,
|
367
|
+
'Invalid null operation: "1 gt null".') {eval("1 > null")}
|
368
|
+
assert_raise_message(Sass::SyntaxError,
|
369
|
+
'Invalid null operation: "null lt 1".') {eval("null < 1")}
|
370
|
+
assert_raise_message(Sass::SyntaxError,
|
371
|
+
'Invalid null operation: "null plus null".') {eval("null + null")}
|
372
|
+
assert_raise_message(Sass::SyntaxError,
|
373
|
+
'Invalid null operation: ""foo" plus null".') {eval("foo + null")}
|
374
|
+
end
|
375
|
+
|
329
376
|
def test_equals
|
330
377
|
assert_equal("true", resolve('"foo" == $foo', {},
|
331
378
|
env("foo" => Sass::Script::String.new("foo"))))
|
@@ -424,6 +471,15 @@ SASS
|
|
424
471
|
assert_raise_message(Sass::SyntaxError, "() isn't a valid CSS value.") {resolve("nth(append((), ()), 1)")}
|
425
472
|
end
|
426
473
|
|
474
|
+
def test_list_with_nulls
|
475
|
+
assert_equal "1, 2, 3", resolve("1, 2, null, 3")
|
476
|
+
assert_equal "1 2 3", resolve("1 2 null 3")
|
477
|
+
assert_equal "1, 2, 3", resolve("1, 2, 3, null")
|
478
|
+
assert_equal "1 2 3", resolve("1 2 3 null")
|
479
|
+
assert_equal "1, 2, 3", resolve("null, 1, 2, 3")
|
480
|
+
assert_equal "1 2 3", resolve("null 1 2 3")
|
481
|
+
end
|
482
|
+
|
427
483
|
def test_deep_argument_error_not_unwrapped
|
428
484
|
assert_raise_message(ArgumentError, 'wrong number of arguments (0 for 1)') {resolve("arg-error()")}
|
429
485
|
end
|
data/test/sass/scss/scss_test.rb
CHANGED
@@ -850,6 +850,16 @@ $zzz: zzz;
|
|
850
850
|
SCSS
|
851
851
|
end
|
852
852
|
|
853
|
+
def test_selector_interpolation_at_attr_end
|
854
|
+
assert_equal <<CSS, render(<<SCSS)
|
855
|
+
[foo=zzz] {
|
856
|
+
a: b; }
|
857
|
+
CSS
|
858
|
+
$zzz: zzz;
|
859
|
+
[foo=\#{$zzz}] { a: b; }
|
860
|
+
SCSS
|
861
|
+
end
|
862
|
+
|
853
863
|
def test_selector_interpolation_at_dashes
|
854
864
|
assert_equal <<CSS, render(<<SCSS)
|
855
865
|
div {
|
data/vendor/listen/CHANGELOG.md
CHANGED
@@ -1,8 +1,23 @@
|
|
1
|
+
## 0.4.2 - May 1, 2012
|
2
|
+
|
3
|
+
### Bug fixes
|
4
|
+
|
5
|
+
- [#21](https://github.com/guard/listen/issues/21): Issues when listening to changes in relative paths. (reported by [@akerbos][], fixed by [@Maher4Ever][])
|
6
|
+
- [#27](https://github.com/guard/listen/issues/27): Wrong reports for files modifications. (reported by [@cobychapple][], fixed by [@Maher4Ever][])
|
7
|
+
- Fix segmentation fault when profiling on Windows. ([@Maher4Ever][])
|
8
|
+
- Fix redundant watchers on Windows. ([@Maher4Ever][])
|
9
|
+
|
10
|
+
### Improvements
|
11
|
+
|
12
|
+
- [#17](https://github.com/guard/listen/issues/17): Use regexp-patterns with the `ignore` method instead of supplying paths. (reported by [@fny][], added by [@Maher4Ever][])
|
13
|
+
- Speed improvement when listening to changes in directories with ignored paths. ([@Maher4Ever][])
|
14
|
+
- Added `.rbx` and `.svn` to ignored directories. ([@Maher4Ever][])
|
15
|
+
|
1
16
|
## 0.4.1 - April 15, 2012
|
2
17
|
|
3
18
|
### Bug fixes
|
4
19
|
|
5
|
-
- [#18](https://github.com/guard/listen/issues/18): Listener crashes when removing directories with nested paths (reported by [@daemonza][], fixed by [@Maher4Ever][])
|
20
|
+
- [#18]((https://github.com/guard/listen/issues/18): Listener crashes when removing directories with nested paths. (reported by [@daemonza][], fixed by [@Maher4Ever][])
|
6
21
|
|
7
22
|
## 0.4.0 - April 9, 2012
|
8
23
|
|
@@ -70,3 +85,6 @@
|
|
70
85
|
[@thibaudgg]: https://github.com/thibaudgg
|
71
86
|
[@Maher4Ever]: https://github.com/Maher4Ever
|
72
87
|
[@daemonza]: https://github.com/daemonza
|
88
|
+
[@akerbos]: https://github.com/akerbos
|
89
|
+
[@fny]: https://github.com/fny
|
90
|
+
[@cobychapple]: https://github.com/cobychapple
|
data/vendor/listen/README.md
CHANGED
@@ -10,7 +10,7 @@ The Listen gem listens to file modifications and notifies you about the changes.
|
|
10
10
|
* Automatic fallback to polling if OS-specific adapter doesn't work.
|
11
11
|
* Detects files modification, addidation and removal.
|
12
12
|
* Checksum comparaison for modifications made under the same second.
|
13
|
-
* Allows
|
13
|
+
* Allows supplying regexp-patterns to ignore and filter paths for better results.
|
14
14
|
* Tested on all Ruby environments via [travis-ci](http://travis-ci.org/guard/listen).
|
15
15
|
|
16
16
|
## Install
|
@@ -26,18 +26,18 @@ There are **two ways** to use Listen:
|
|
26
26
|
1. Call `Listen.to` with either a single directory or multiple directories, then define the `change` callback in a block.
|
27
27
|
2. Create a `listener` object and use it in an (ARel style) chainable way.
|
28
28
|
|
29
|
-
Feel free to give your feeback via [Listen issues](https://github.com/guard/
|
29
|
+
Feel free to give your feeback via [Listen issues](https://github.com/guard/listen/issues)
|
30
30
|
|
31
31
|
### Block API
|
32
32
|
|
33
33
|
``` ruby
|
34
34
|
# Listen to a single directory.
|
35
|
-
Listen.to('dir/path/to/listen', filter:
|
35
|
+
Listen.to('dir/path/to/listen', filter: /\.rb$/, ignore: %r{ignored/path/}) do |modified, added, removed|
|
36
36
|
# ...
|
37
37
|
end
|
38
38
|
|
39
39
|
# Listen to multiple directories.
|
40
|
-
Listen.to('dir/to/awesome_app', 'dir/to/other_app', filter:
|
40
|
+
Listen.to('dir/to/awesome_app', 'dir/to/other_app', filter: /\.rb$/, latency: 0.1) do |modified, added, removed|
|
41
41
|
# ...
|
42
42
|
end
|
43
43
|
```
|
@@ -46,8 +46,8 @@ end
|
|
46
46
|
|
47
47
|
``` ruby
|
48
48
|
listener = Listen.to('dir/path/to/listen')
|
49
|
-
listener = listener.ignore(
|
50
|
-
listener = listener.filter(
|
49
|
+
listener = listener.ignore(%r{^ignored/path/})
|
50
|
+
listener = listener.filter(/\.rb$/)
|
51
51
|
listener = listener.latency(0.5)
|
52
52
|
listener = listener.force_polling(true)
|
53
53
|
listener = listener.polling_fallback_message(false)
|
@@ -59,8 +59,8 @@ listener.start # blocks execution!
|
|
59
59
|
|
60
60
|
``` ruby
|
61
61
|
Listen.to('dir/path/to/listen')
|
62
|
-
.ignore(
|
63
|
-
.filter(
|
62
|
+
.ignore(%r{^ignored/path/})
|
63
|
+
.filter(/\.rb$/)
|
64
64
|
.latency(0.5)
|
65
65
|
.force_polling(true)
|
66
66
|
.polling_fallback_message('custom message')
|
@@ -99,7 +99,7 @@ For an easier access, the `Listen.to` method can also be used to create a multi-
|
|
99
99
|
|
100
100
|
``` ruby
|
101
101
|
listener = Listen.to('app/css', 'app/js')
|
102
|
-
.ignore(
|
102
|
+
.ignore(%r{^vendor/}) # both js/vendor and css/vendor will be ignored
|
103
103
|
.change(&assets_callback)
|
104
104
|
|
105
105
|
listener.start # blocks execution!
|
@@ -184,15 +184,18 @@ end
|
|
184
184
|
These options can be set through `Listen.to` params or via methods (see the "Object" API)
|
185
185
|
|
186
186
|
```ruby
|
187
|
-
:filter =>
|
187
|
+
:filter => /\.rb$/, /\.coffee$/ # Filter files to listen to via a regexps list.
|
188
188
|
# default: none
|
189
189
|
|
190
|
-
:ignore =>
|
191
|
-
# default:
|
190
|
+
:ignore => %r{app/CMake/}, /\.pid$/ # Ignore a list of paths (root directory or sub-dir)
|
191
|
+
# default: See DEFAULT_IGNORED_DIRECTORIES and DEFAULT_IGNORED_EXTENSIONS in Listen::DirectoryRecord
|
192
192
|
|
193
193
|
:latency => 0.5 # Set the delay (**in seconds**) between checking for changes
|
194
194
|
# default: 0.1 sec (1.0 sec for polling)
|
195
195
|
|
196
|
+
:relative_paths => true # Enable the use of relative paths in the callback.
|
197
|
+
# default: false
|
198
|
+
|
196
199
|
:force_polling => true # Force the use of the polling adapter
|
197
200
|
# default: none
|
198
201
|
|
@@ -200,6 +203,18 @@ These options can be set through `Listen.to` params or via methods (see the "Obj
|
|
200
203
|
# default: "WARNING: Listen fallen back to polling, learn more at https://github.com/guard/listen#fallback."
|
201
204
|
```
|
202
205
|
|
206
|
+
### The patterns for filtering and ignoring paths
|
207
|
+
|
208
|
+
Just like the unix convention of beginning absolute paths with the
|
209
|
+
directory-separator (forward slash `/` in unix) and with no prefix for relative paths,
|
210
|
+
Listen doesn't prefix relative paths (to the watched directory) with a directory-separator.
|
211
|
+
|
212
|
+
Therefore make sure _NOT_ to prefix your regexp-patterns for filtering or ignoring paths
|
213
|
+
with a directory-separator, otherwise they won't work as expected.
|
214
|
+
|
215
|
+
As an example: to ignore the `build` directory in a C-project, use `%r{build/}`
|
216
|
+
and not `%r{/build/}`.
|
217
|
+
|
203
218
|
### Non-blocking listening to changes
|
204
219
|
|
205
220
|
Starting a listener blocks the current thread by default. That means any code after the
|
@@ -83,6 +83,14 @@ module Listen
|
|
83
83
|
@turnstile.signal # ensure no thread is blocked
|
84
84
|
end
|
85
85
|
|
86
|
+
# Returns whether the adapter is statred or not
|
87
|
+
#
|
88
|
+
# @return [Boolean] whether the adapter is started or not
|
89
|
+
#
|
90
|
+
def started?
|
91
|
+
@stop.nil? ? false : !@stop
|
92
|
+
end
|
93
|
+
|
86
94
|
# Blocks the main thread until the poll thread
|
87
95
|
# calls the callback.
|
88
96
|
#
|
@@ -129,7 +137,7 @@ module Listen
|
|
129
137
|
ensure
|
130
138
|
Thread.kill(t) if t
|
131
139
|
FileUtils.rm(test_file) if File.exists?(test_file)
|
132
|
-
adapter.stop
|
140
|
+
adapter.stop if adapter && adapter.started?
|
133
141
|
end
|
134
142
|
|
135
143
|
private
|
@@ -1,22 +1,33 @@
|
|
1
1
|
module Listen
|
2
2
|
module Adapters
|
3
3
|
|
4
|
-
# Watched INotify EVENTS
|
5
|
-
#
|
6
|
-
# @see http://www.tin.org/bin/man.cgi?section=7&topic=inotify
|
7
|
-
# @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
|
8
|
-
#
|
9
|
-
EVENTS = %w[recursive attrib close modify move create delete delete_self move_self]
|
10
|
-
|
11
4
|
# Listener implementation for Linux `inotify`.
|
12
5
|
#
|
13
6
|
class Linux < Adapter
|
14
7
|
|
8
|
+
# Watched inotify events
|
9
|
+
#
|
10
|
+
# @see http://www.tin.org/bin/man.cgi?section=7&topic=inotify
|
11
|
+
# @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
|
12
|
+
#
|
13
|
+
EVENTS = %w[recursive attrib close modify move create delete delete_self move_self]
|
14
|
+
|
15
|
+
# The message to show when the limit of inotify watchers is not enough
|
16
|
+
#
|
17
|
+
INOTIFY_LIMIT_MESSAGE = <<-EOS.gsub(/^\s*/, '')
|
18
|
+
Listen error: unable to monitor directories for changes.
|
19
|
+
|
20
|
+
Please head to https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers
|
21
|
+
for information on how to solve this issue.
|
22
|
+
EOS
|
23
|
+
|
15
24
|
# Initializes the Adapter. See {Listen::Adapter#initialize} for more info.
|
16
25
|
#
|
17
26
|
def initialize(directories, options = {}, &callback)
|
18
27
|
super
|
19
28
|
@worker = init_worker
|
29
|
+
rescue Errno::ENOSPC
|
30
|
+
abort(INOTIFY_LIMIT_MESSAGE)
|
20
31
|
end
|
21
32
|
|
22
33
|
# Starts the adapter.
|