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

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.
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