sass 3.3.0 → 3.4.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.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +58 -50
  4. data/Rakefile +1 -4
  5. data/VERSION +1 -1
  6. data/VERSION_DATE +1 -1
  7. data/VERSION_NAME +1 -1
  8. data/bin/sass +1 -1
  9. data/bin/scss +1 -1
  10. data/lib/sass/cache_stores/filesystem.rb +6 -2
  11. data/lib/sass/css.rb +1 -3
  12. data/lib/sass/engine.rb +37 -46
  13. data/lib/sass/environment.rb +13 -17
  14. data/lib/sass/error.rb +6 -9
  15. data/lib/sass/exec/base.rb +187 -0
  16. data/lib/sass/exec/sass_convert.rb +264 -0
  17. data/lib/sass/exec/sass_scss.rb +424 -0
  18. data/lib/sass/exec.rb +5 -771
  19. data/lib/sass/features.rb +7 -0
  20. data/lib/sass/importers/base.rb +7 -2
  21. data/lib/sass/importers/filesystem.rb +9 -25
  22. data/lib/sass/importers.rb +0 -1
  23. data/lib/sass/media.rb +1 -4
  24. data/lib/sass/plugin/compiler.rb +200 -83
  25. data/lib/sass/plugin/staleness_checker.rb +1 -1
  26. data/lib/sass/plugin.rb +3 -3
  27. data/lib/sass/script/css_lexer.rb +1 -1
  28. data/lib/sass/script/functions.rb +622 -268
  29. data/lib/sass/script/lexer.rb +99 -34
  30. data/lib/sass/script/parser.rb +24 -23
  31. data/lib/sass/script/tree/funcall.rb +1 -1
  32. data/lib/sass/script/tree/interpolation.rb +20 -2
  33. data/lib/sass/script/tree/selector.rb +26 -0
  34. data/lib/sass/script/tree/string_interpolation.rb +1 -1
  35. data/lib/sass/script/tree.rb +1 -0
  36. data/lib/sass/script/value/base.rb +7 -5
  37. data/lib/sass/script/value/bool.rb +0 -5
  38. data/lib/sass/script/value/color.rb +39 -21
  39. data/lib/sass/script/value/helpers.rb +107 -0
  40. data/lib/sass/script/value/list.rb +0 -15
  41. data/lib/sass/script/value/null.rb +0 -5
  42. data/lib/sass/script/value/number.rb +62 -14
  43. data/lib/sass/script/value/string.rb +59 -11
  44. data/lib/sass/script/value.rb +0 -1
  45. data/lib/sass/scss/css_parser.rb +8 -2
  46. data/lib/sass/scss/parser.rb +190 -328
  47. data/lib/sass/scss/rx.rb +15 -6
  48. data/lib/sass/scss/static_parser.rb +298 -1
  49. data/lib/sass/selector/abstract_sequence.rb +28 -13
  50. data/lib/sass/selector/comma_sequence.rb +92 -13
  51. data/lib/sass/selector/pseudo.rb +256 -0
  52. data/lib/sass/selector/sequence.rb +94 -24
  53. data/lib/sass/selector/simple.rb +14 -25
  54. data/lib/sass/selector/simple_sequence.rb +97 -33
  55. data/lib/sass/selector.rb +57 -194
  56. data/lib/sass/shared.rb +1 -1
  57. data/lib/sass/source/map.rb +26 -12
  58. data/lib/sass/stack.rb +0 -6
  59. data/lib/sass/supports.rb +2 -3
  60. data/lib/sass/tree/at_root_node.rb +1 -0
  61. data/lib/sass/tree/charset_node.rb +1 -1
  62. data/lib/sass/tree/directive_node.rb +8 -2
  63. data/lib/sass/tree/error_node.rb +18 -0
  64. data/lib/sass/tree/extend_node.rb +1 -1
  65. data/lib/sass/tree/function_node.rb +4 -0
  66. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  67. data/lib/sass/tree/prop_node.rb +1 -1
  68. data/lib/sass/tree/rule_node.rb +12 -7
  69. data/lib/sass/tree/visitors/check_nesting.rb +38 -10
  70. data/lib/sass/tree/visitors/convert.rb +16 -18
  71. data/lib/sass/tree/visitors/cssize.rb +29 -29
  72. data/lib/sass/tree/visitors/deep_copy.rb +5 -0
  73. data/lib/sass/tree/visitors/perform.rb +45 -33
  74. data/lib/sass/tree/visitors/set_options.rb +14 -0
  75. data/lib/sass/tree/visitors/to_css.rb +15 -14
  76. data/lib/sass/util/subset_map.rb +1 -1
  77. data/lib/sass/util.rb +222 -99
  78. data/lib/sass/version.rb +5 -5
  79. data/lib/sass.rb +0 -5
  80. data/test/sass/cache_test.rb +62 -20
  81. data/test/sass/callbacks_test.rb +1 -1
  82. data/test/sass/compiler_test.rb +19 -10
  83. data/test/sass/conversion_test.rb +58 -1
  84. data/test/sass/css2sass_test.rb +23 -4
  85. data/test/sass/encoding_test.rb +219 -0
  86. data/test/sass/engine_test.rb +136 -199
  87. data/test/sass/exec_test.rb +2 -2
  88. data/test/sass/extend_test.rb +236 -19
  89. data/test/sass/functions_test.rb +295 -253
  90. data/test/sass/importer_test.rb +31 -21
  91. data/test/sass/logger_test.rb +1 -1
  92. data/test/sass/more_results/more_import.css +1 -1
  93. data/test/sass/plugin_test.rb +14 -13
  94. data/test/sass/results/compact.css +1 -1
  95. data/test/sass/results/complex.css +4 -4
  96. data/test/sass/results/expanded.css +1 -1
  97. data/test/sass/results/import.css +1 -1
  98. data/test/sass/results/import_charset_ibm866.css +2 -2
  99. data/test/sass/results/mixins.css +17 -17
  100. data/test/sass/results/nested.css +1 -1
  101. data/test/sass/results/parent_ref.css +2 -2
  102. data/test/sass/results/script.css +3 -3
  103. data/test/sass/results/scss_import.css +1 -1
  104. data/test/sass/script_conversion_test.rb +10 -7
  105. data/test/sass/script_test.rb +288 -74
  106. data/test/sass/scss/css_test.rb +141 -24
  107. data/test/sass/scss/rx_test.rb +4 -4
  108. data/test/sass/scss/scss_test.rb +457 -18
  109. data/test/sass/source_map_test.rb +115 -25
  110. data/test/sass/superselector_test.rb +191 -0
  111. data/test/sass/templates/scss_import.scss +2 -1
  112. data/test/sass/test_helper.rb +1 -1
  113. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  114. data/test/sass/util/normalized_map_test.rb +1 -1
  115. data/test/sass/util/subset_map_test.rb +2 -2
  116. data/test/sass/util_test.rb +31 -1
  117. data/test/sass/value_helpers_test.rb +5 -7
  118. data/test/test_helper.rb +2 -2
  119. data/vendor/listen/CHANGELOG.md +1 -228
  120. data/vendor/listen/Gemfile +5 -15
  121. data/vendor/listen/README.md +111 -77
  122. data/vendor/listen/Rakefile +0 -42
  123. data/vendor/listen/lib/listen/adapter.rb +195 -82
  124. data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
  125. data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
  126. data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
  127. data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
  128. data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
  129. data/vendor/listen/lib/listen/directory_record.rb +96 -61
  130. data/vendor/listen/lib/listen/listener.rb +135 -37
  131. data/vendor/listen/lib/listen/turnstile.rb +9 -5
  132. data/vendor/listen/lib/listen/version.rb +1 -1
  133. data/vendor/listen/lib/listen.rb +33 -19
  134. data/vendor/listen/listen.gemspec +6 -0
  135. data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
  136. data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
  137. data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
  138. data/vendor/listen/spec/listen/listener_spec.rb +128 -39
  139. data/vendor/listen/spec/listen_spec.rb +15 -21
  140. data/vendor/listen/spec/spec_helper.rb +4 -0
  141. data/vendor/listen/spec/support/adapter_helper.rb +52 -15
  142. data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
  143. data/vendor/listen/spec/support/listeners_helper.rb +30 -7
  144. metadata +25 -22
  145. data/ext/mkrf_conf.rb +0 -27
  146. data/lib/sass/importers/deprecated_path.rb +0 -51
  147. data/lib/sass/script/value/deprecated_false.rb +0 -55
  148. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  149. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  150. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  151. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -2,14 +2,18 @@ require 'pathname'
2
2
 
3
3
  module Listen
4
4
  class Listener
5
- attr_reader :directory, :directory_record, :adapter
5
+ attr_reader :directories, :directories_records, :block, :adapter, :adapter_options, :use_relative_paths
6
6
 
7
- # The default value for using relative paths in the callback.
8
- DEFAULT_TO_RELATIVE_PATHS = false
7
+ BLOCKING_PARAMETER_DEPRECATION_MESSAGE = <<-EOS.gsub(/^\s*/, '')
8
+ The blocking parameter of Listen::Listener#start is deprecated.\n
9
+ Please use Listen::Adapter#start for a non-blocking listener and Listen::Listener#start! for a blocking one.
10
+ EOS
9
11
 
10
- # Initializes the directory listener.
12
+ RELATIVE_PATHS_WITH_MULTIPLE_DIRECTORIES_WARNING_MESSAGE = "The relative_paths option doesn't work when listening to multiple diretories."
13
+
14
+ # Initializes the directories listener.
11
15
  #
12
- # @param [String] directory the directory to listen to
16
+ # @param [String] directory the directories to listen to
13
17
  # @param [Hash] options the listen options
14
18
  # @option options [Regexp] ignore a pattern for ignoring paths
15
19
  # @option options [Regexp] filter a pattern for filtering paths
@@ -17,42 +21,55 @@ module Listen
17
21
  # @option options [Boolean] relative_paths whether or not to use relative-paths in the callback
18
22
  # @option options [Boolean] force_polling whether to force the polling adapter or not
19
23
  # @option options [String, Boolean] polling_fallback_message to change polling fallback message or remove it
24
+ # @option options [Class] force_adapter force the use of this adapter class, skipping usual adapter selection
20
25
  #
21
26
  # @yield [modified, added, removed] the changed files
22
27
  # @yieldparam [Array<String>] modified the list of modified files
23
28
  # @yieldparam [Array<String>] added the list of added files
24
29
  # @yieldparam [Array<String>] removed the list of removed files
25
30
  #
26
- def initialize(directory, options = {}, &block)
27
- @block = block
28
- @directory = Pathname.new(directory).realpath.to_s
29
- @directory_record = DirectoryRecord.new(@directory)
30
- @use_relative_paths = DEFAULT_TO_RELATIVE_PATHS
31
+ def initialize(*args, &block)
32
+ options = args.last.is_a?(Hash) ? args.pop : {}
33
+ directories = args.flatten
34
+ initialize_directories_and_directories_records(directories)
35
+ initialize_relative_paths_usage(options)
36
+ @block = block
31
37
 
32
- @use_relative_paths = options.delete(:relative_paths) if options[:relative_paths]
33
- @directory_record.ignore(*options.delete(:ignore)) if options[:ignore]
34
- @directory_record.filter(*options.delete(:filter)) if options[:filter]
38
+ ignore(*options.delete(:ignore))
39
+ filter(*options.delete(:filter))
35
40
 
36
41
  @adapter_options = options
37
42
  end
38
43
 
39
44
  # Starts the listener by initializing the adapter and building
40
45
  # the directory record concurrently, then it starts the adapter to watch
41
- # for changes.
46
+ # for changes. The current thread is not blocked after starting.
42
47
  #
43
- # @param [Boolean] blocking whether or not to block the current thread after starting
48
+ # @see Listen::Listener#start!
44
49
  #
45
- def start(blocking = true)
46
- t = Thread.new { @directory_record.build }
47
- @adapter = initialize_adapter
48
- t.join
49
- @adapter.start(blocking)
50
+ def start(deprecated_blocking = nil)
51
+ Kernel.warn "[Listen warning]:\n#{BLOCKING_PARAMETER_DEPRECATION_MESSAGE}" unless deprecated_blocking.nil?
52
+ setup
53
+ adapter.start
54
+ end
55
+
56
+ # Starts the listener by initializing the adapter and building
57
+ # the directory record concurrently, then it starts the adapter to watch
58
+ # for changes. The current thread is blocked after starting.
59
+ #
60
+ # @see Listen::Listener#start
61
+ #
62
+ # @since 1.0.0
63
+ #
64
+ def start!
65
+ setup
66
+ adapter.start!
50
67
  end
51
68
 
52
69
  # Stops the listener.
53
70
  #
54
71
  def stop
55
- @adapter.stop
72
+ adapter && adapter.stop
56
73
  end
57
74
 
58
75
  # Pauses the listener.
@@ -60,7 +77,7 @@ module Listen
60
77
  # @return [Listen::Listener] the listener
61
78
  #
62
79
  def pause
63
- @adapter.paused = true
80
+ adapter.pause
64
81
  self
65
82
  end
66
83
 
@@ -69,8 +86,8 @@ module Listen
69
86
  # @return [Listen::Listener] the listener
70
87
  #
71
88
  def unpause
72
- @directory_record.build
73
- @adapter.paused = false
89
+ build_directories_records
90
+ adapter.unpause
74
91
  self
75
92
  end
76
93
 
@@ -79,7 +96,7 @@ module Listen
79
96
  # @return [Boolean] adapter paused status
80
97
  #
81
98
  def paused?
82
- !!@adapter && @adapter.paused == true
99
+ !!adapter && adapter.paused?
83
100
  end
84
101
 
85
102
  # Adds ignoring patterns to the listener.
@@ -88,8 +105,10 @@ module Listen
88
105
  #
89
106
  # @return [Listen::Listener] the listener
90
107
  #
108
+ # @see Listen::DirectoryRecord#ignore
109
+ #
91
110
  def ignore(*regexps)
92
- @directory_record.ignore(*regexps)
111
+ directories_records.each { |r| r.ignore(*regexps) }
93
112
  self
94
113
  end
95
114
 
@@ -99,8 +118,10 @@ module Listen
99
118
  #
100
119
  # @return [Listen::Listener] the listener
101
120
  #
121
+ # @see Listen::DirectoryRecord#ignore!
122
+ #
102
123
  def ignore!(*regexps)
103
- @directory_record.ignore!(*regexps)
124
+ directories_records.each { |r| r.ignore!(*regexps) }
104
125
  self
105
126
  end
106
127
 
@@ -110,19 +131,23 @@ module Listen
110
131
  #
111
132
  # @return [Listen::Listener] the listener
112
133
  #
134
+ # @see Listen::DirectoryRecord#filter
135
+ #
113
136
  def filter(*regexps)
114
- @directory_record.filter(*regexps)
137
+ directories_records.each { |r| r.filter(*regexps) }
115
138
  self
116
139
  end
117
140
 
118
- # Replacing filtering patterns in the listener.
141
+ # Replaces filtering patterns in the listener.
119
142
  #
120
143
  # @param (see Listen::DirectoryRecord#filter!)
121
144
  #
122
145
  # @return [Listen::Listener] the listener
123
146
  #
147
+ # @see Listen::DirectoryRecord#filter!
148
+ #
124
149
  def filter!(*regexps)
125
- @directory_record.filter!(*regexps)
150
+ directories_records.each { |r| r.filter!(*regexps) }
126
151
  self
127
152
  end
128
153
 
@@ -156,6 +181,21 @@ module Listen
156
181
  self
157
182
  end
158
183
 
184
+ # Sets whether to force the use of a particular adapter, rather than
185
+ # going through usual adapter selection process on start.
186
+ #
187
+ # @example Force use of Linux polling
188
+ # force_adapter Listen::Adapters::Linux
189
+ #
190
+ # @param [Class] adapter class to use for file system event notification.
191
+ #
192
+ # @return [Listen::Listener] the listener
193
+ #
194
+ def force_adapter(adapter_class)
195
+ @adapter_options[:force_adapter] = adapter_class
196
+ self
197
+ end
198
+
159
199
  # Sets whether the paths in the callback should be
160
200
  # relative or absolute.
161
201
  #
@@ -171,7 +211,7 @@ module Listen
171
211
  self
172
212
  end
173
213
 
174
- # Defines a custom polling fallback message of disable it.
214
+ # Defines a custom polling fallback message or disable it.
175
215
  #
176
216
  # @example Disabling the polling fallback message
177
217
  # polling_fallback_message false
@@ -204,22 +244,80 @@ module Listen
204
244
  #
205
245
  # @param (see Listen::DirectoryRecord#fetch_changes)
206
246
  #
247
+ # @see Listen::DirectoryRecord#fetch_changes
248
+ #
207
249
  def on_change(directories, options = {})
208
- changes = @directory_record.fetch_changes(directories, options.merge(
209
- :relative_paths => @use_relative_paths
210
- ))
250
+ changes = fetch_records_changes(directories, options)
211
251
  unless changes.values.all? { |paths| paths.empty? }
212
- @block.call(changes[:modified],changes[:added],changes[:removed])
252
+ block.call(changes[:modified], changes[:added], changes[:removed])
213
253
  end
254
+ rescue => ex
255
+ Kernel.warn "[Listen warning]: Change block raise an execption: #{$!}"
256
+ Kernel.warn "Backtrace:\n\t#{ex.backtrace.join("\n\t")}"
214
257
  end
215
258
 
216
259
  private
217
260
 
261
+ # Initializes the directories to watch as well as the directories records.
262
+ #
263
+ # @see Listen::DirectoryRecord
264
+ #
265
+ def initialize_directories_and_directories_records(directories)
266
+ @directories = directories.map { |d| Pathname.new(d).realpath.to_s }
267
+ @directories_records = directories.map { |d| DirectoryRecord.new(d) }
268
+ end
269
+
270
+ # Initializes whether or not using relative paths.
271
+ #
272
+ def initialize_relative_paths_usage(options)
273
+ if directories.size > 1 && options[:relative_paths]
274
+ Kernel.warn "[Listen warning]: #{RELATIVE_PATHS_WITH_MULTIPLE_DIRECTORIES_WARNING_MESSAGE}"
275
+ end
276
+ @use_relative_paths = directories.one? && options.delete(:relative_paths) { false }
277
+ end
278
+
279
+ # Build the directory record concurrently and initialize the adapter.
280
+ #
281
+ def setup
282
+ t = Thread.new { build_directories_records }
283
+ @adapter = initialize_adapter
284
+ t.join
285
+ end
286
+
218
287
  # Initializes an adapter passing it the callback and adapters' options.
219
288
  #
220
289
  def initialize_adapter
221
- callback = lambda { |changed_dirs, options| self.on_change(changed_dirs, options) }
222
- Adapter.select_and_initialize(@directory, @adapter_options, &callback)
290
+ callback = lambda { |changed_directories, options| self.on_change(changed_directories, options) }
291
+ Adapter.select_and_initialize(directories, adapter_options, &callback)
223
292
  end
293
+
294
+ # Build the watched directories' records.
295
+ #
296
+ def build_directories_records
297
+ directories_records.each { |r| r.build }
298
+ end
299
+
300
+ # Returns the sum of all the changes to the directories records
301
+ #
302
+ # @param (see Listen::DirectoryRecord#fetch_changes)
303
+ #
304
+ # @return [Hash] the changes
305
+ #
306
+ def fetch_records_changes(directories_to_search, options)
307
+ directories_records.inject({}) do |h, r|
308
+ # directory records skips paths outside their range, so passing the
309
+ # whole `directories` array is not a problem.
310
+ record_changes = r.fetch_changes(directories_to_search, options.merge(:relative_paths => use_relative_paths))
311
+
312
+ if h.empty?
313
+ h.merge!(record_changes)
314
+ else
315
+ h.each { |k, v| h[k] += record_changes[k] }
316
+ end
317
+
318
+ h
319
+ end
320
+ end
321
+
224
322
  end
225
323
  end
@@ -1,28 +1,32 @@
1
1
  module Listen
2
+
2
3
  # Allows two threads to wait on eachother.
3
4
  #
4
5
  # @note Only two threads can be used with this Turnstile
5
6
  # because of the current implementation.
6
7
  class Turnstile
8
+ attr_accessor :queue
7
9
 
8
10
  # Initialize the turnstile.
9
11
  #
10
12
  def initialize
11
- # Until ruby offers semahpores, only queues can be used
13
+ # Until Ruby offers semahpores, only queues can be used
12
14
  # to implement a turnstile.
13
- @q = Queue.new
15
+ @queue = Queue.new
14
16
  end
15
17
 
16
18
  # Blocks the current thread until a signal is received.
17
19
  #
18
20
  def wait
19
- @q.pop if @q.num_waiting == 0
21
+ queue.pop if queue.num_waiting == 0
20
22
  end
21
23
 
22
- # Unblocks the waiting thread if there is one.
24
+ # Unblocks the waiting thread if any.
23
25
  #
24
26
  def signal
25
- @q.push :dummy if @q.num_waiting == 1
27
+ queue.push(:dummy) if queue.num_waiting == 1
26
28
  end
29
+
27
30
  end
31
+
28
32
  end
@@ -1,3 +1,3 @@
1
1
  module Listen
2
- VERSION = '0.7.3'
2
+ VERSION = '1.3.1'
3
3
  end
@@ -1,24 +1,20 @@
1
- module Listen
1
+ require 'listen/turnstile'
2
+ require 'listen/listener'
3
+ require 'listen/directory_record'
4
+ require 'listen/adapter'
2
5
 
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'
6
+ module Listen
9
7
 
10
8
  module Adapters
11
- autoload :Darwin, 'listen/adapters/darwin'
12
- autoload :Linux, 'listen/adapters/linux'
13
- autoload :BSD, 'listen/adapters/bsd'
14
- autoload :Windows, 'listen/adapters/windows'
15
- autoload :Polling, 'listen/adapters/polling'
9
+ Adapter::ADAPTERS.each do |adapter|
10
+ require "listen/adapters/#{adapter.downcase}"
11
+ end
16
12
  end
17
13
 
18
- # Listens to filesystem modifications on a either single directory or multiple directories.
14
+ # Listens to file system modifications on a either single directory or multiple directories.
15
+ # When calling this method, the current thread is not blocked.
19
16
  #
20
17
  # @param (see Listen::Listener#new)
21
- # @param (see Listen::MultiListener#new)
22
18
  #
23
19
  # @yield [modified, added, removed] the changed files
24
20
  # @yieldparam [Array<String>] modified the list of modified files
@@ -28,13 +24,31 @@ module Listen
28
24
  # @return [Listen::Listener] the file listener if no block given
29
25
  #
30
26
  def self.to(*args, &block)
31
- listener = if args.length == 1 || ! args[1].is_a?(String)
32
- Listener.new(*args, &block)
33
- else
34
- MultiListener.new(*args, &block)
35
- end
27
+ listener = _init_listener(*args, &block)
36
28
 
37
29
  block ? listener.start : listener
38
30
  end
39
31
 
32
+ # Listens to file system modifications on a either single directory or multiple directories.
33
+ # When calling this method, the current thread is blocked.
34
+ #
35
+ # @param (see Listen::Listener#new)
36
+ #
37
+ # @yield [modified, added, removed] the changed files
38
+ # @yieldparam [Array<String>] modified the list of modified files
39
+ # @yieldparam [Array<String>] added the list of added files
40
+ # @yieldparam [Array<String>] removed the list of removed files
41
+ #
42
+ # @since 1.0.0
43
+ #
44
+ def self.to!(*args, &block)
45
+ _init_listener(*args, &block).start!
46
+ end
47
+
48
+ # @private
49
+ #
50
+ def self._init_listener(*args, &block)
51
+ Listener.new(*args, &block)
52
+ end
53
+
40
54
  end
@@ -9,13 +9,19 @@ Gem::Specification.new do |s|
9
9
  s.authors = ['Thibaud Guillaume-Gentil', 'Maher Sallam']
10
10
  s.email = ['thibaud@thibaud.me', 'maher@sallam.me']
11
11
  s.homepage = 'https://github.com/guard/listen'
12
+ s.license = 'MIT'
12
13
  s.summary = 'Listen to file modifications'
13
14
  s.description = 'The Listen gem listens to file modifications and notifies you about the changes. Works everywhere!'
14
15
 
15
16
  s.required_rubygems_version = '>= 1.3.6'
16
17
  s.rubyforge_project = 'listen'
17
18
 
19
+ s.add_dependency 'rb-fsevent', '>= 0.9.3'
20
+ s.add_dependency 'rb-inotify', '>= 0.9'
21
+ s.add_dependency 'rb-kqueue', '>= 0.2'
22
+
18
23
  s.add_development_dependency 'bundler'
24
+ s.add_development_dependency 'rspec'
19
25
 
20
26
  s.files = Dir.glob('{lib}/**/*') + %w[CHANGELOG.md LICENSE README.md]
21
27
  s.require_path = 'lib'
@@ -19,10 +19,23 @@ describe Listen::Adapter do
19
19
 
20
20
  describe ".select_and_initialize" do
21
21
  before do
22
- Listen::Adapters::Darwin.stub(:usable_and_works?) { false }
23
- Listen::Adapters::Linux.stub(:usable_and_works?) { false }
24
- Listen::Adapters::BSD.stub(:usable_and_works?) { false }
25
- Listen::Adapters::Windows.stub(:usable_and_works?) { false }
22
+ Listen::Adapter::OPTIMIZED_ADAPTERS.each do |adapter|
23
+ Listen::Adapters.const_get(adapter).stub(:usable_and_works?) { false }
24
+ end
25
+ end
26
+
27
+ context "with force_adapter option" do
28
+ it "returns an instance of the given adapter class" do
29
+ expected_adapter = Object.new
30
+ adapter_class = double('adapter_class')
31
+ options = {:force_adapter => adapter_class}
32
+
33
+ adapter_class.should_receive(:load_dependent_adapter)
34
+ adapter_class.should_receive(:new).with('dir', options) { expected_adapter }
35
+
36
+ adapter = described_class.select_and_initialize('dir', options)
37
+ adapter.should be(expected_adapter)
38
+ end
26
39
  end
27
40
 
28
41
  context "with no specific adapter usable" do
@@ -37,20 +50,6 @@ describe Listen::Adapter do
37
50
  described_class.select_and_initialize('dir')
38
51
  end
39
52
 
40
- context 'when the dependencies of an adapter are not satisfied' do
41
- before do
42
- Listen::Adapters::Darwin.stub(:usable_and_works?).and_raise(Listen::DependencyManager::Error)
43
- Listen::Adapters::Linux.stub(:usable_and_works?).and_raise(Listen::DependencyManager::Error)
44
- Listen::Adapters::BSD.stub(:usable_and_works?).and_raise(Listen::DependencyManager::Error)
45
- Listen::Adapters::Windows.stub(:usable_and_works?).and_raise(Listen::DependencyManager::Error)
46
- end
47
-
48
- it 'invites the user to satisfy the dependencies of the adapter in the warning' do
49
- Kernel.should_receive(:warn).with(/#{Listen::Adapter::MISSING_DEPENDENCY_MESSAGE}/)
50
- described_class.select_and_initialize('dir')
51
- end
52
- end
53
-
54
53
  context "with custom polling_fallback_message option" do
55
54
  it "warns with the custom polling fallback message" do
56
55
  Kernel.should_receive(:warn).with(/custom/)
@@ -66,83 +65,50 @@ describe Listen::Adapter do
66
65
  end
67
66
  end
68
67
 
69
- context "on Mac OX >= 10.6" do
70
- before { Listen::Adapters::Darwin.stub(:usable_and_works?) { true } }
68
+ Listen::Adapter::OPTIMIZED_ADAPTERS.each do |adapter|
69
+ adapter_class = Listen::Adapters.const_get(adapter)
71
70
 
72
- it "uses Listen::Adapters::Darwin" do
73
- Listen::Adapters::Darwin.should_receive(:new).with('dir', {})
74
- described_class.select_and_initialize('dir')
75
- end
71
+ context "on #{adapter}" do
72
+ before { adapter_class.stub(:usable_and_works?) { true } }
76
73
 
77
- context 'when the use of the polling adapter is forced' do
78
- it 'uses Listen::Adapters::Polling' do
79
- Listen::Adapters::Polling.should_receive(:new).with('dir', {})
80
- described_class.select_and_initialize('dir', :force_polling => true)
74
+ it "uses Listen::Adapters::#{adapter}" do
75
+ adapter_class.should_receive(:new).with('dir', {})
76
+ described_class.select_and_initialize('dir')
81
77
  end
82
- end
83
- end
84
78
 
85
- context "on Linux" do
86
- before { Listen::Adapters::Linux.stub(:usable_and_works?) { true } }
87
-
88
- it "uses Listen::Adapters::Linux" do
89
- Listen::Adapters::Linux.should_receive(:new).with('dir', {})
90
- described_class.select_and_initialize('dir')
91
- end
92
-
93
- context 'when the use of the polling adapter is forced' do
94
- it 'uses Listen::Adapters::Polling' do
95
- Listen::Adapters::Polling.should_receive(:new).with('dir', {})
96
- described_class.select_and_initialize('dir', :force_polling => true)
79
+ context 'when the use of the polling adapter is forced' do
80
+ it 'uses Listen::Adapters::Polling' do
81
+ Listen::Adapters::Polling.should_receive(:new).with('dir', {})
82
+ described_class.select_and_initialize('dir', :force_polling => true)
83
+ end
97
84
  end
98
85
  end
99
86
  end
87
+ end
100
88
 
101
- context "on BSD" do
102
- before { Listen::Adapters::BSD.stub(:usable_and_works?) { true } }
89
+ describe '.load_dependend_adapter' do
90
+ after(:each) { described_class.instance_variable_set('@loaded', nil) }
103
91
 
104
- it "uses Listen::Adapters::BSD" do
105
- Listen::Adapters::BSD.should_receive(:new).with('dir', {})
106
- described_class.select_and_initialize('dir')
107
- end
92
+ it 'returns true (success) even if the adapter_gem has already been required' do
93
+ described_class.stub(:adapter_gem => 'already_loaded_gem')
94
+ described_class.stub(:require => false)
108
95
 
109
- context 'when the use of the polling adapter is forced' do
110
- it 'uses Listen::Adapters::Polling' do
111
- Listen::Adapters::Polling.should_receive(:new).with('dir', {})
112
- described_class.select_and_initialize('dir', :force_polling => true)
113
- end
114
- end
96
+ described_class.load_dependent_adapter.should be_true
115
97
  end
116
98
 
117
- context "on Windows" do
118
- before { Listen::Adapters::Windows.stub(:usable_and_works?) { true } }
119
-
120
- it "uses Listen::Adapters::Windows" do
121
- Listen::Adapters::Windows.should_receive(:new).with('dir', {})
122
- described_class.select_and_initialize('dir')
99
+ it 'returns false (failure) if the adapter_gem cannot be required' do
100
+ described_class.stub(:adapter_gem => 'unloadable_gem')
101
+ described_class.stub(:require) do
102
+ raise LoadError.new('no such file to load -- unloadable_gem')
123
103
  end
124
104
 
125
- context 'when the use of the polling adapter is forced' do
126
- it 'uses Listen::Adapters::Polling' do
127
- Listen::Adapters::Polling.should_receive(:new).with('dir', {})
128
- described_class.select_and_initialize('dir', :force_polling => true)
129
- end
130
- end
105
+ described_class.load_dependent_adapter.should be_false
131
106
  end
132
107
  end
133
108
 
134
- [Listen::Adapters::Darwin, Listen::Adapters::Linux,
135
- Listen::Adapters::BSD, Listen::Adapters::Windows].each do
136
- |adapter_class|
109
+ Listen::Adapter::OPTIMIZED_ADAPTERS.each do |adapter|
110
+ adapter_class = Listen::Adapters.const_get(adapter)
137
111
  if adapter_class.usable?
138
- describe '.usable?' do
139
- it 'checks the dependencies' do
140
- adapter_class.should_receive(:load_depenencies)
141
- adapter_class.should_receive(:dependencies_loaded?)
142
- adapter_class.usable?
143
- end
144
- end
145
-
146
112
  describe '.usable_and_works?' do
147
113
  it 'checks if the adapter is usable' do
148
114
  adapter_class.stub(:works?)
@@ -12,8 +12,8 @@ describe Listen::Adapters::Polling do
12
12
  end
13
13
 
14
14
  describe '#poll' do
15
- let(:listener) { mock(Listen::Listener) }
16
- let(:callback) { lambda { |changed_dirs, options| @called = true; listener.on_change(changed_dirs, options) } }
15
+ let(:listener) { double(Listen::Listener) }
16
+ let(:callback) { lambda { |changed_directories, options| @called = true; listener.on_change(changed_directories, options) } }
17
17
 
18
18
  after { subject.stop }
19
19
 
@@ -22,20 +22,20 @@ describe Listen::Adapters::Polling do
22
22
 
23
23
  it 'calls listener.on_change' do
24
24
  listener.should_receive(:on_change).at_least(1).times.with(['dir'], :recursive => true)
25
- subject.start(false)
25
+ subject.start
26
26
  subject.wait_for_callback
27
27
  end
28
28
 
29
29
  it 'calls listener.on_change continuously' do
30
30
  subject.latency = 0.001
31
31
  listener.should_receive(:on_change).at_least(10).times.with(['dir'], :recursive => true)
32
- subject.start(false)
32
+ subject.start
33
33
  10.times { subject.wait_for_callback }
34
34
  end
35
35
 
36
36
  it "doesn't call listener.on_change if paused" do
37
37
  subject.paused = true
38
- subject.start(false)
38
+ subject.start
39
39
  subject.wait_for_callback
40
40
  @called.should be_nil
41
41
  end
@@ -46,20 +46,20 @@ describe Listen::Adapters::Polling do
46
46
 
47
47
  it 'calls listener.on_change' do
48
48
  listener.should_receive(:on_change).at_least(1).times.with(%w{dir1 dir2}, :recursive => true)
49
- subject.start(false)
49
+ subject.start
50
50
  subject.wait_for_callback
51
51
  end
52
52
 
53
53
  it 'calls listener.on_change continuously' do
54
54
  subject.latency = 0.001
55
55
  listener.should_receive(:on_change).at_least(10).times.with(%w{dir1 dir2}, :recursive => true)
56
- subject.start(false)
56
+ subject.start
57
57
  10.times { subject.wait_for_callback }
58
58
  end
59
59
 
60
60
  it "doesn't call listener.on_change if paused" do
61
61
  subject.paused = true
62
- subject.start(false)
62
+ subject.start
63
63
  subject.wait_for_callback
64
64
  @called.should be_nil
65
65
  end