sass 3.3.0.alpha.93 → 3.3.0.alpha.101

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/REVISION +1 -1
  2. data/VERSION +1 -1
  3. data/VERSION_DATE +1 -1
  4. data/bin/sass +2 -1
  5. data/bin/sass-convert +2 -1
  6. data/bin/scss +2 -1
  7. data/lib/sass/cache_stores/chain.rb +1 -1
  8. data/lib/sass/cache_stores/filesystem.rb +0 -1
  9. data/lib/sass/engine.rb +7 -1
  10. data/lib/sass/exec.rb +1 -0
  11. data/lib/sass/importers/filesystem.rb +1 -1
  12. data/lib/sass/media.rb +1 -4
  13. data/lib/sass/plugin/compiler.rb +1 -1
  14. data/lib/sass/script/funcall.rb +43 -8
  15. data/lib/sass/script/functions.rb +8 -16
  16. data/lib/sass/script/lexer.rb +0 -2
  17. data/lib/sass/script/parser.rb +26 -25
  18. data/lib/sass/scss/parser.rb +13 -1
  19. data/lib/sass/selector/simple_sequence.rb +1 -1
  20. data/lib/sass/tree/comment_node.rb +2 -2
  21. data/lib/sass/tree/visitors/cssize.rb +10 -1
  22. data/lib/sass/tree/visitors/perform.rb +4 -2
  23. data/lib/sass/util.rb +54 -1
  24. data/lib/sass/util/multibyte_string_scanner.rb +29 -8
  25. data/test/sass/engine_test.rb +20 -4
  26. data/test/sass/extend_test.rb +15 -0
  27. data/test/sass/functions_test.rb +20 -1
  28. data/test/sass/script_test.rb +5 -1
  29. data/vendor/listen/CHANGELOG.md +76 -2
  30. data/vendor/listen/CONTRIBUTING.md +38 -0
  31. data/vendor/listen/Gemfile +8 -1
  32. data/vendor/listen/Guardfile +1 -1
  33. data/vendor/listen/LICENSE +1 -1
  34. data/vendor/listen/README.md +8 -5
  35. data/vendor/listen/lib/listen.rb +7 -5
  36. data/vendor/listen/lib/listen/adapter.rb +76 -29
  37. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  38. data/vendor/listen/lib/listen/adapters/darwin.rb +11 -10
  39. data/vendor/listen/lib/listen/adapters/linux.rb +33 -30
  40. data/vendor/listen/lib/listen/adapters/polling.rb +2 -1
  41. data/vendor/listen/lib/listen/adapters/windows.rb +27 -21
  42. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  43. data/vendor/listen/lib/listen/directory_record.rb +63 -10
  44. data/vendor/listen/lib/listen/listener.rb +22 -0
  45. data/vendor/listen/lib/listen/multi_listener.rb +22 -0
  46. data/vendor/listen/lib/listen/version.rb +1 -1
  47. data/vendor/listen/listen.gemspec +0 -4
  48. data/vendor/listen/spec/listen/adapter_spec.rb +45 -4
  49. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  50. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +6 -0
  51. data/vendor/listen/spec/listen/adapters/linux_spec.rb +6 -0
  52. data/vendor/listen/spec/listen/adapters/windows_spec.rb +7 -1
  53. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  54. data/vendor/listen/spec/listen/directory_record_spec.rb +91 -4
  55. data/vendor/listen/spec/listen/listener_spec.rb +14 -0
  56. data/vendor/listen/spec/listen/multi_listener_spec.rb +19 -1
  57. data/vendor/listen/spec/spec_helper.rb +6 -3
  58. data/vendor/listen/spec/support/adapter_helper.rb +125 -212
  59. data/vendor/listen/spec/support/listeners_helper.rb +13 -1
  60. data/vendor/listen/spec/support/platform_helper.rb +4 -0
  61. metadata +11 -6
@@ -3,23 +3,44 @@ require 'strscan'
3
3
  if Sass::Util.ruby1_8?
4
4
  Sass::Util::MultibyteStringScanner = StringScanner
5
5
  else
6
+ if Sass::Util.rbx?
7
+ # Rubinius's StringScanner class implements some of its methods in terms of
8
+ # others, which causes us to double-count bytes in some cases if we do
9
+ # straightforward inheritance. To work around this, we use a delegate class.
10
+ require 'delegate'
11
+ class Sass::Util::MultibyteStringScanner < DelegateClass(StringScanner)
12
+ def initialize(str)
13
+ super(StringScanner.new(str))
14
+ @mb_pos = 0
15
+ @mb_matched_size = nil
16
+ @mb_last_pos = nil
17
+ end
18
+
19
+ def is_a?(klass)
20
+ __getobj__.is_a?(klass) || super
21
+ end
22
+ end
23
+ else
24
+ class Sass::Util::MultibyteStringScanner < StringScanner
25
+ def initialize(str)
26
+ super
27
+ @mb_pos = 0
28
+ @mb_matched_size = nil
29
+ @mb_last_pos = nil
30
+ end
31
+ end
32
+ end
33
+
6
34
  # A wrapper of the native StringScanner class that works correctly with
7
35
  # multibyte character encodings. The native class deals only in bytes, not
8
36
  # characters, for methods like [#pos] and [#matched_size]. This class deals
9
37
  # only in characters, instead.
10
- class Sass::Util::MultibyteStringScanner < StringScanner
38
+ class Sass::Util::MultibyteStringScanner
11
39
  def self.new(str)
12
40
  return StringScanner.new(str) if str.ascii_only?
13
41
  super
14
42
  end
15
43
 
16
- def initialize(str)
17
- super
18
- @mb_pos = 0
19
- @mb_matched_size = nil
20
- @mb_last_pos = nil
21
- end
22
-
23
44
  alias_method :byte_pos, :pos
24
45
  alias_method :byte_matched_size, :matched_size
25
46
 
@@ -143,13 +143,13 @@ MSG
143
143
  '+foo(1 + 1: 2)' => 'Invalid CSS after "(1 + 1": expected comma, was ": 2)"',
144
144
  '+foo($var: )' => 'Invalid CSS after "($var: ": expected mixin argument, was ")"',
145
145
  '+foo($var: a, $var: b)' => 'Keyword argument "$var" passed more than once',
146
- '+foo($var-var: a, $var_var: b)' => 'Keyword argument "$var-var" passed more than once',
147
- '+foo($var_var: a, $var-var: b)' => 'Keyword argument "$var_var" passed more than once',
146
+ '+foo($var-var: a, $var_var: b)' => 'Keyword argument "$var_var" passed more than once',
147
+ '+foo($var_var: a, $var-var: b)' => 'Keyword argument "$var-var" passed more than once',
148
148
  "a\n b: foo(1 + 1: 2)" => 'Invalid CSS after "foo(1 + 1": expected comma, was ": 2)"',
149
149
  "a\n b: foo($var: )" => 'Invalid CSS after "foo($var: ": expected function argument, was ")"',
150
150
  "a\n b: foo($var: a, $var: b)" => 'Keyword argument "$var" passed more than once',
151
- "a\n b: foo($var-var: a, $var_var: b)" => 'Keyword argument "$var-var" passed more than once',
152
- "a\n b: foo($var_var: a, $var-var: b)" => 'Keyword argument "$var_var" passed more than once',
151
+ "a\n b: foo($var-var: a, $var_var: b)" => 'Keyword argument "$var_var" passed more than once',
152
+ "a\n b: foo($var_var: a, $var-var: b)" => 'Keyword argument "$var-var" passed more than once',
153
153
  "@if foo\n @extend .bar" => ["Extend directives may only be used within rules.", 2],
154
154
  "$var: true\n@while $var\n @extend .bar\n $var: false" => ["Extend directives may only be used within rules.", 3],
155
155
  "@for $i from 0 to 1\n @extend .bar" => ["Extend directives may only be used within rules.", 2],
@@ -2416,6 +2416,22 @@ SASS
2416
2416
 
2417
2417
  # Regression tests
2418
2418
 
2419
+ def test_supports_bubbles
2420
+ assert_equal <<CSS, render(<<SASS)
2421
+ parent {
2422
+ background: orange; }
2423
+ @supports (perspective: 10px) or (-moz-perspective: 10px) {
2424
+ parent child {
2425
+ background: blue; } }
2426
+ CSS
2427
+ parent
2428
+ background: orange
2429
+ @supports (perspective: 10px) or (-moz-perspective: 10px)
2430
+ child
2431
+ background: blue
2432
+ SASS
2433
+ end
2434
+
2419
2435
  def test_line_numbers_with_dos_line_endings
2420
2436
  assert_equal <<CSS, render(<<SASS, :line_comments => true)
2421
2437
  /* line 5, test_line_numbers_with_dos_line_endings_inline.sass */
@@ -1130,6 +1130,21 @@ SCSS
1130
1130
 
1131
1131
  # Regression Tests
1132
1132
 
1133
+ def test_extend_in_double_nested_media_query
1134
+ assert_equal <<CSS, render(<<SCSS)
1135
+ @media all and (orientation: landscape) {
1136
+ .bar {
1137
+ color: blue; } }
1138
+ CSS
1139
+ @media all {
1140
+ @media (orientation: landscape) {
1141
+ %foo {color: blue}
1142
+ .bar {@extend %foo}
1143
+ }
1144
+ }
1145
+ SCSS
1146
+ end
1147
+
1133
1148
  def test_partially_failed_extend
1134
1149
  assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}
1135
1150
  .rc, test {
@@ -1103,14 +1103,17 @@ MSG
1103
1103
  def test_zip
1104
1104
  assert_equal("1 3 5, 2 4 6", evaluate("zip(1 2, 3 4, 5 6)"))
1105
1105
  assert_equal("1 4 7, 2 5 8", evaluate("zip(1 2 3, 4 5 6, 7 8)"))
1106
+ assert_equal("1 2 3", evaluate("zip(1, 2, 3)"))
1106
1107
  end
1107
1108
 
1108
1109
  def test_index
1109
1110
  assert_equal("1", evaluate("index(1px solid blue, 1px)"))
1110
1111
  assert_equal("2", evaluate("index(1px solid blue, solid)"))
1111
1112
  assert_equal("3", evaluate("index(1px solid blue, #00f)"))
1113
+ assert_equal("1", evaluate("index(1px, 1px)"))
1112
1114
  assert_equal("false", evaluate("index(1px solid blue, 1em)"))
1113
1115
  assert_equal("false", evaluate("index(1px solid blue, notfound)"))
1116
+ assert_equal("false", evaluate("index(1px, #00f)"))
1114
1117
  end
1115
1118
 
1116
1119
  def test_if
@@ -1179,21 +1182,37 @@ MSG
1179
1182
  end
1180
1183
 
1181
1184
  def test_assert_unit
1182
- ctx = Sass::Script::Functions::EvaluationContext.new({})
1185
+ ctx = Sass::Script::Functions::EvaluationContext.new(Sass::Environment.new(nil, {}))
1183
1186
  ctx.assert_unit Sass::Script::Number.new(10, ["px"], []), "px"
1184
1187
  ctx.assert_unit Sass::Script::Number.new(10, [], []), nil
1188
+
1185
1189
  begin
1186
1190
  ctx.assert_unit Sass::Script::Number.new(10, [], []), "px"
1187
1191
  fail
1188
1192
  rescue ArgumentError => e
1189
1193
  assert_equal "Expected 10 to have a unit of px", e.message
1190
1194
  end
1195
+
1191
1196
  begin
1192
1197
  ctx.assert_unit Sass::Script::Number.new(10, ["px"], []), nil
1193
1198
  fail
1194
1199
  rescue ArgumentError => e
1195
1200
  assert_equal "Expected 10px to be unitless", e.message
1196
1201
  end
1202
+
1203
+ begin
1204
+ ctx.assert_unit Sass::Script::Number.new(10, [], []), "px", "arg"
1205
+ fail
1206
+ rescue ArgumentError => e
1207
+ assert_equal "Expected $arg to have a unit of px but got 10", e.message
1208
+ end
1209
+
1210
+ begin
1211
+ ctx.assert_unit Sass::Script::Number.new(10, ["px"], []), nil, "arg"
1212
+ fail
1213
+ rescue ArgumentError => e
1214
+ assert_equal "Expected $arg to be unitless but got 10px", e.message
1215
+ end
1197
1216
  end
1198
1217
 
1199
1218
  ## Regression Tests
@@ -493,7 +493,9 @@ SASS
493
493
  # argument errors caused by programming errors in a function and
494
494
  # argument errors explicitly thrown within that function.
495
495
  return if RUBY_PLATFORM =~ /java/
496
- assert_raise_message(ArgumentError, 'wrong number of arguments (0 for 1)') {resolve("arg-error()")}
496
+
497
+ # Don't validate the message; it's different on Rubinius.
498
+ assert_raise(ArgumentError) {resolve("arg-error()")}
497
499
  end
498
500
 
499
501
  def test_shallow_argument_error_unwrapped
@@ -544,6 +546,8 @@ SASS
544
546
  assert Sass::Script::Number.new(10, "px").is_unit?("px")
545
547
  assert Sass::Script::Number.new(10).is_unit?(nil)
546
548
  assert !Sass::Script::Number.new(10, "px", "em").is_unit?("px")
549
+ assert !Sass::Script::Number.new(10, [], "em").is_unit?("em")
550
+ assert !Sass::Script::Number.new(10, ["px", "em"]).is_unit?("px")
547
551
  end
548
552
 
549
553
  private
@@ -1,3 +1,62 @@
1
+ ## 0.7.2 - January 11, 2013
2
+
3
+ ### Bug fix
4
+
5
+ - [#76] Exception on filename which is not in UTF-8. (fixed by [@piotr-sokolowski][])
6
+
7
+ ## 0.7.1 - January 6, 2013
8
+
9
+ ### Bug fix
10
+
11
+ - [#75] Default high precision off if the mtime call fails. (fixed by [@zanker][])
12
+
13
+ ## 0.7.0 - December 29, 2012
14
+
15
+ ### Bug fixes
16
+
17
+ - [#73] Rescue Errno::EOPNOTSUPP on sha1_checksum generation. (fixed by [@thibaudgg][])
18
+
19
+ ### New feature
20
+
21
+ - Add support for *BSD with rb-kqueue. ([@mat813][])
22
+
23
+ ## 0.6.0 - November 21, 2012
24
+
25
+ ### New feature
26
+
27
+ - Add bang versions for filter and ignore listener methods. ([@tarsolya][])
28
+
29
+ ## 0.5.3 - October 3, 2012
30
+
31
+ ### Bug fixes
32
+
33
+ - [#65] Fix ruby warning in adapter.rb. (fixed by [@vongruenigen][])
34
+ - [#64] ENXIO raised when hashing UNIX domain socket file. (fixed by [@sunaku][])
35
+
36
+ ## 0.5.2 - Septemper 23, 2012
37
+
38
+ ### Bug fix
39
+
40
+ - [#62] Fix double change callback with polling adapter. (fixed by [@thibaudgg][])
41
+
42
+ ## 0.5.1 - Septemper 18, 2012
43
+
44
+ ### Bug fix
45
+
46
+ - [#61] Fix a synchronisation bug that caused constant fallback to polling. (fixed by [@Maher4Ever][])
47
+
48
+ ## 0.5.0 - Septemper 1, 2012
49
+
50
+ ### New features
51
+
52
+ - Add a dependency manager to handle platform-specific gems. So there is no need anymore to install
53
+ extra gems which will never be used on the user system. ([@Maher4Ever][])
54
+ - Add a manual reporting mode to the adapters. ([@Maher4Ever][])
55
+
56
+ ### Improvements
57
+
58
+ - [#28] Enhance the speed of detecting changes on Windows by using the [WDM][] library. ([@Maher4Ever][])
59
+
1
60
  ## 0.4.7 - June 27, 2012
2
61
 
3
62
  ### Bug fixes
@@ -128,8 +187,16 @@
128
187
  [#21]: https://github.com/guard/listen/issues/21
129
188
  [#24]: https://github.com/guard/listen/issues/24
130
189
  [#27]: https://github.com/guard/listen/issues/27
190
+ [#28]: https://github.com/guard/listen/issues/28
131
191
  [#32]: https://github.com/guard/listen/issues/32
132
- [#39]: https://github.com/guard/listen/issues/39
192
+ [#41]: https://github.com/guard/listen/issues/41
193
+ [#61]: https://github.com/guard/listen/issues/61
194
+ [#62]: https://github.com/guard/listen/issues/62
195
+ [#64]: https://github.com/guard/listen/issues/64
196
+ [#65]: https://github.com/guard/listen/issues/65
197
+ [#73]: https://github.com/guard/listen/issues/73
198
+ [#75]: https://github.com/guard/listen/issues/75
199
+ [#76]: https://github.com/guard/listen/issues/76
133
200
  [@Maher4Ever]: https://github.com/Maher4Ever
134
201
  [@dkubb]: https://github.com/dkubb
135
202
  [@ebroder]: https://github.com/ebroder
@@ -138,10 +205,17 @@
138
205
  [@daemonza]: https://github.com/daemonza
139
206
  [@fny]: https://github.com/fny
140
207
  [@markiz]: https://github.com/markiz
208
+ [@mat813]: https://github.com/mat813
141
209
  [@napcs]: https://github.com/napcs
142
210
  [@netzpirat]: https://github.com/netzpirat
143
211
  [@nex3]: https://github.com/nex3
212
+ [@piotr-sokolowski]: https://github.com/piotr-sokolowski
144
213
  [@rymai]: https://github.com/rymai
145
214
  [@scottdavis]: https://github.com/scottdavis
215
+ [@sunaku]: https://github.com/sunaku
146
216
  [@textgoeshere]: https://github.com/textgoeshere
147
- [@thibaudgg]: https://github.com/thibaudgg
217
+ [@thibaudgg]: https://github.com/thibaudgg
218
+ [@tarsolya]: https://github.com/tarsolya
219
+ [@vongruenigen]: https://github.com/vongruenigen
220
+ [@zanker]: https://github.com/zanker
221
+ [WDM]: https://github.com/Maher4Ever/wdm
@@ -0,0 +1,38 @@
1
+ Contribute to Listen
2
+ ===================
3
+
4
+ File an issue
5
+ -------------
6
+
7
+ You can report bugs and feature requests to [GitHub Issues](https://github.com/guard/listen/issues).
8
+
9
+ **Please don't ask question in the issue tracker**, instead ask them in our
10
+ [Google group](http://groups.google.com/group/guard-dev) or on `#guard` (irc.freenode.net).
11
+
12
+ Try to figure out where the issue belongs to: Is it an issue with Listen itself or with Guard?
13
+
14
+ When you file a bug, please try to follow these simple rules if applicable:
15
+
16
+ * Make sure you run Listen with `bundle exec` first.
17
+ * Add your `Guardfile` (if used) and `Gemfile` to the issue.
18
+ * Make sure that the issue is reproducible with your description.
19
+
20
+ **It's most likely that your bug gets resolved faster if you provide as much information as possible!**
21
+
22
+ Development
23
+ -----------
24
+
25
+ * Documentation hosted at [RubyDoc](http://rubydoc.info/github/guard/listen/master/frames).
26
+ * Source hosted at [GitHub](https://github.com/guard/listen).
27
+
28
+ Pull requests are very welcome! Please try to follow these simple rules if applicable:
29
+
30
+ * Please create a topic branch for every separate change you make.
31
+ * Make sure your patches are well tested. All specs run with `rake spec` must pass.
32
+ * Update the [Yard](http://yardoc.org/) documentation.
33
+ * Update the [README](https://github.com/guard/listen/blob/master/README.md).
34
+ * Update the [CHANGELOG](https://github.com/guard/listen/blob/master/CHANGELOG.md) for noteworthy changes.
35
+ * Please **do not change** the version number.
36
+
37
+ For questions please join us in our [Google group](http://groups.google.com/group/guard-dev) or on
38
+ `#guard` (irc.freenode.net).
@@ -1,9 +1,16 @@
1
+ require 'rbconfig'
2
+
1
3
  source :rubygems
2
4
 
3
5
  gemspec
4
6
 
5
7
  gem 'rake'
6
8
 
9
+ gem 'rb-kqueue', '~> 0.2' if RbConfig::CONFIG['target_os'] =~ /freebsd/i
10
+ gem 'rb-fsevent', '~> 0.9.1' if RbConfig::CONFIG['target_os'] =~ /darwin(1.+)?$/i
11
+ gem 'rb-inotify', '~> 0.8.8', :github => 'mbj/rb-inotify' if RbConfig::CONFIG['target_os'] =~ /linux/i
12
+ gem 'wdm', '~> 0.0.3' if RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
13
+
7
14
  group :development do
8
15
  platform :ruby do
9
16
  gem 'coolline'
@@ -20,4 +27,4 @@ end
20
27
 
21
28
  group :test do
22
29
  gem 'rspec'
23
- end
30
+ end
@@ -1,4 +1,4 @@
1
- guard :rspec, :all_on_start => false, :all_after_pass => false, :cli => '--fail-fast --format doc' do
1
+ guard :rspec, :all_on_start => false, :all_after_pass => false do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
3
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
4
  watch('spec/support/adapter_helper.rb') { "spec/listen/adapters" }
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Thibaud Guillaume-Gentil
1
+ Copyright (c) 2013 Thibaud Guillaume-Gentil
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -6,10 +6,10 @@ The Listen gem listens to file modifications and notifies you about the changes.
6
6
 
7
7
  * Works everywhere!
8
8
  * Supports watching multiple directories from a single listener.
9
- * OS-specific adapters for Mac OS X 10.6+, Linux and Windows.
9
+ * OS-specific adapters for Mac OS X 10.6+, Linux, *BSD and Windows.
10
10
  * Automatic fallback to polling if OS-specific adapter doesn't work.
11
- * Detects files modification, addidation and removal.
12
- * Checksum comparaison for modifications made under the same second.
11
+ * Detects file modification, addition and removal.
12
+ * Checksum comparison for modifications made under the same second.
13
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
 
@@ -215,6 +215,8 @@ with a directory-separator, otherwise they won't work as expected.
215
215
  As an example: to ignore the `build` directory in a C-project, use `%r{build/}`
216
216
  and not `%r{/build/}`.
217
217
 
218
+ Use `#filter!` and `#ignore!` methods to overwrites default patterns.
219
+
218
220
  ### Non-blocking listening to changes
219
221
 
220
222
  Starting a listener blocks the current thread by default. That means any code after the
@@ -240,7 +242,7 @@ block execution. See the "Block API" section for an example.
240
242
  ## Listen adapters
241
243
 
242
244
  The Listen gem has a set of adapters to notify it when there are changes.
243
- There are 3 OS-specific adapters to support Mac, Linux and Windows. These adapters are fast
245
+ There are 3 OS-specific adapters to support Mac, Linux, *BSD and Windows. These adapters are fast
244
246
  as they use some system-calls to implement the notifying function.
245
247
 
246
248
  There is also a polling adapter which is a cross-platform adapter and it will
@@ -251,7 +253,6 @@ want to force the use of the polling adapter, either use the `:force_polling` op
251
253
  while initializing the listener or call the `force_polling` method on your listener
252
254
  before starting it.
253
255
 
254
- <a name="fallback"/>
255
256
  ## Polling fallback
256
257
 
257
258
  When a OS-specific adapter doesn't work the Listen gem automatically falls back to the polling adapter.
@@ -286,6 +287,7 @@ For questions please join us in our [Google group](http://groups.google.com/grou
286
287
  * [Michael Kessler (netzpirat)][] for having written the [initial specs](https://github.com/guard/listen/commit/1e457b13b1bb8a25d2240428ce5ed488bafbed1f).
287
288
  * [Travis Tilley (ttilley)][] for this awesome work on [fssm][] & [rb-fsevent][].
288
289
  * [Nathan Weizenbaum (nex3)][] for [rb-inotify][], a thorough inotify wrapper.
290
+ * [Mathieu Arnold (mat813)][] for [rb-kqueue][], a simple kqueue wrapper.
289
291
  * [stereobooster][] for [rb-fchange][], windows support wouldn't exist without him.
290
292
  * [Yehuda Katz (wycats)][] for [vigilo][], that has been a great source of inspiration.
291
293
 
@@ -304,6 +306,7 @@ For questions please join us in our [Google group](http://groups.google.com/grou
304
306
  [Travis Tilley (ttilley)]: https://github.com/ttilley
305
307
  [fssm]: https://github.com/ttilley/fssm
306
308
  [rb-fsevent]: https://github.com/thibaudgg/rb-fsevent
309
+ [Mathieu Arnold (mat813)]: https://github.com/mat813
307
310
  [Nathan Weizenbaum (nex3)]: https://github.com/nex3
308
311
  [rb-inotify]: https://github.com/nex3/rb-inotify
309
312
  [stereobooster]: https://github.com/stereobooster
@@ -1,14 +1,16 @@
1
1
  module Listen
2
2
 
3
- autoload :Turnstile, 'listen/turnstile'
4
- autoload :Listener, 'listen/listener'
5
- autoload :MultiListener, 'listen/multi_listener'
6
- autoload :DirectoryRecord, 'listen/directory_record'
7
- autoload :Adapter, 'listen/adapter'
3
+ autoload :Turnstile, 'listen/turnstile'
4
+ autoload :Listener, 'listen/listener'
5
+ autoload :MultiListener, 'listen/multi_listener'
6
+ autoload :DirectoryRecord, 'listen/directory_record'
7
+ autoload :DependencyManager, 'listen/dependency_manager'
8
+ autoload :Adapter, 'listen/adapter'
8
9
 
9
10
  module Adapters
10
11
  autoload :Darwin, 'listen/adapters/darwin'
11
12
  autoload :Linux, 'listen/adapters/linux'
13
+ autoload :BSD, 'listen/adapters/bsd'
12
14
  autoload :Windows, 'listen/adapters/windows'
13
15
  autoload :Polling, 'listen/adapters/polling'
14
16
  end
@@ -10,8 +10,15 @@ module Listen
10
10
  # The default delay between checking for changes.
11
11
  DEFAULT_LATENCY = 0.25
12
12
 
13
+ # The default warning message when there is a missing dependency.
14
+ MISSING_DEPENDENCY_MESSAGE = <<-EOS.gsub(/^\s*/, '')
15
+ For a better performance, it's recommended that you satisfy the missing dependency.
16
+ EOS
17
+
13
18
  # The default warning message when falling back to polling adapter.
14
- POLLING_FALLBACK_MESSAGE = "WARNING: Listen has fallen back to polling, learn more at https://github.com/guard/listen#fallback."
19
+ POLLING_FALLBACK_MESSAGE = <<-EOS.gsub(/^\s*/, '')
20
+ Listen will be polling changes. Learn more at https://github.com/guard/listen#polling-fallback.
21
+ EOS
15
22
 
16
23
  # Selects the appropriate adapter implementation for the
17
24
  # current OS and initializes it.
@@ -31,18 +38,28 @@ module Listen
31
38
  def self.select_and_initialize(directories, options = {}, &callback)
32
39
  return Adapters::Polling.new(directories, options, &callback) if options.delete(:force_polling)
33
40
 
34
- if Adapters::Darwin.usable_and_works?(directories, options)
35
- Adapters::Darwin.new(directories, options, &callback)
36
- elsif Adapters::Linux.usable_and_works?(directories, options)
37
- Adapters::Linux.new(directories, options, &callback)
38
- elsif Adapters::Windows.usable_and_works?(directories, options)
39
- Adapters::Windows.new(directories, options, &callback)
40
- else
41
- unless options[:polling_fallback_message] == false
42
- Kernel.warn(options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE)
41
+ warning = ''
42
+
43
+ begin
44
+ if Adapters::Darwin.usable_and_works?(directories, options)
45
+ return Adapters::Darwin.new(directories, options, &callback)
46
+ elsif Adapters::Linux.usable_and_works?(directories, options)
47
+ return Adapters::Linux.new(directories, options, &callback)
48
+ elsif Adapters::BSD.usable_and_works?(directories, options)
49
+ return Adapters::BSD.new(directories, options, &callback)
50
+ elsif Adapters::Windows.usable_and_works?(directories, options)
51
+ return Adapters::Windows.new(directories, options, &callback)
43
52
  end
44
- Adapters::Polling.new(directories, options, &callback)
53
+ rescue DependencyManager::Error => e
54
+ warning += e.message + "\n" + MISSING_DEPENDENCY_MESSAGE
55
+ end
56
+
57
+ unless options[:polling_fallback_message] == false
58
+ warning += options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE
59
+ Kernel.warn "[Listen warning]:\n" + warning.gsub(/^(.*)/, ' \1')
45
60
  end
61
+
62
+ Adapters::Polling.new(directories, options, &callback)
46
63
  end
47
64
 
48
65
  # Initializes the adapter.
@@ -50,6 +67,7 @@ module Listen
50
67
  # @param [String, Array<String>] directories the directories to watch
51
68
  # @param [Hash] options the adapter options
52
69
  # @option options [Float] latency the delay between checking for changes in seconds
70
+ # @option options [Boolean] report_changes whether or not to automatically report changes (run the callback)
53
71
  #
54
72
  # @yield [changed_dirs, options] callback Callback called when a change happens
55
73
  # @yieldparam [Array<String>] changed_dirs the changed directories
@@ -60,12 +78,13 @@ module Listen
60
78
  def initialize(directories, options = {}, &callback)
61
79
  @directories = Array(directories)
62
80
  @callback = callback
63
- @latency ||= DEFAULT_LATENCY
64
- @latency = options[:latency] if options[:latency]
65
81
  @paused = false
66
82
  @mutex = Mutex.new
67
83
  @changed_dirs = Set.new
68
84
  @turnstile = Turnstile.new
85
+ @latency ||= DEFAULT_LATENCY
86
+ @latency = options[:latency] if options[:latency]
87
+ @report_changes = options[:report_changes].nil? ? true : options[:report_changes]
69
88
  end
70
89
 
71
90
  # Starts the adapter.
@@ -92,12 +111,37 @@ module Listen
92
111
  end
93
112
 
94
113
  # Blocks the main thread until the poll thread
95
- # calls the callback.
114
+ # runs the callback.
96
115
  #
97
116
  def wait_for_callback
98
117
  @turnstile.wait unless @paused
99
118
  end
100
119
 
120
+ # Blocks the main thread until N changes are
121
+ # detected.
122
+ #
123
+ def wait_for_changes(goal = 0)
124
+ changes = 0
125
+
126
+ loop do
127
+ @mutex.synchronize { changes = @changed_dirs.size }
128
+
129
+ return if @paused || @stop
130
+ return if changes >= goal
131
+
132
+ sleep(@latency)
133
+ end
134
+ end
135
+
136
+ # Checks if the adapter is usable on the current OS.
137
+ #
138
+ # @return [Boolean] whether usable or not
139
+ #
140
+ def self.usable?
141
+ load_depenencies
142
+ dependencies_loaded?
143
+ end
144
+
101
145
  # Checks if the adapter is usable and works on the current OS.
102
146
  #
103
147
  # @param [String, Array<String>] directories the directories to watch
@@ -124,7 +168,7 @@ module Listen
124
168
  def self.works?(directory, options = {})
125
169
  work = false
126
170
  test_file = "#{directory}/.listen_test"
127
- callback = lambda { |changed_dirs, options| work = true }
171
+ callback = lambda { |*| work = true }
128
172
  adapter = self.new(directory, options, &callback)
129
173
  adapter.start(false)
130
174
 
@@ -140,27 +184,30 @@ module Listen
140
184
  adapter.stop if adapter && adapter.started?
141
185
  end
142
186
 
187
+ # Runs the callback and passes it the changes if there are any.
188
+ #
189
+ def report_changes
190
+ changed_dirs = nil
191
+
192
+ @mutex.synchronize do
193
+ return if @changed_dirs.empty?
194
+ changed_dirs = @changed_dirs.to_a
195
+ @changed_dirs.clear
196
+ end
197
+
198
+ @callback.call(changed_dirs, {})
199
+ @turnstile.signal
200
+ end
201
+
143
202
  private
144
203
 
145
204
  # Polls changed directories and reports them back
146
205
  # when there are changes.
147
206
  #
148
- # @option [Boolean] recursive whether or not to pass the recursive option to the callback
149
- #
150
- def poll_changed_dirs(recursive = false)
207
+ def poll_changed_dirs
151
208
  until @stop
152
209
  sleep(@latency)
153
- next if @changed_dirs.empty?
154
-
155
- changed_dirs = []
156
-
157
- @mutex.synchronize do
158
- changed_dirs = @changed_dirs.to_a
159
- @changed_dirs.clear
160
- end
161
-
162
- @callback.call(changed_dirs, recursive ? {:recursive => recursive} : {})
163
- @turnstile.signal
210
+ report_changes
164
211
  end
165
212
  end
166
213
  end