sass 3.1.16 → 3.1.17

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.
@@ -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
@@ -830,6 +830,16 @@ $zzz: zzz;
830
830
  SCSS
831
831
  end
832
832
 
833
+ def test_selector_interpolation_at_attr_end
834
+ assert_equal <<CSS, render(<<SCSS)
835
+ [foo=zzz] {
836
+ a: b; }
837
+ CSS
838
+ $zzz: zzz;
839
+ [foo=\#{$zzz}] { a: b; }
840
+ SCSS
841
+ end
842
+
833
843
  def test_selector_interpolation_at_dashes
834
844
  assert_equal <<CSS, render(<<SCSS)
835
845
  div {
@@ -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
@@ -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 ignoring paths and supplying filters for better results.
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/listener/issues)
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: /.*\.rb/, ignore: '/ignored/path') do |modified, added, removed|
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: /.*\.rb/, latency: 0.1) do |modified, added, removed|
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('/ignored/path')
50
- listener = listener.filter(/.*\.rb/)
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('/ignored/path')
63
- .filter(/.*\.rb/)
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('vendor') # both js/vendor and css/vendor will be ignored
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,11 +184,11 @@ 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 => /.*\.rb/, /.*\.coffee/ # Filter files to listen to via a regexps list.
187
+ :filter => /\.rb$/, /\.coffee$/ # Filter files to listen to via a regexps list.
188
188
  # default: none
189
189
 
190
- :ignore => 'path1', 'path2' # Ignore a list of paths (root directory or sub-dir)
191
- # default: '.bundle', '.git', '.DS_Store', 'log', 'tmp', 'vendor'
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)
@@ -200,6 +200,18 @@ These options can be set through `Listen.to` params or via methods (see the "Obj
200
200
  # default: "WARNING: Listen fallen back to polling, learn more at https://github.com/guard/listen#fallback."
201
201
  ```
202
202
 
203
+ ### The patterns for filtering and ignoring paths
204
+
205
+ Just like the unix convention of beginning absolute paths with the
206
+ directory-separator (forward slash `/` in unix) and with no prefix for relative paths,
207
+ Listen doesn't prefix relative paths (to the watched directory) with a directory-separator.
208
+
209
+ Therefore make sure _NOT_ to prefix your regexp-patterns for filtering or ignoring paths
210
+ with a directory-separator, otherwise they won't work as expected.
211
+
212
+ As an example: to ignore the `build` directory in a C-project, use `%r{build/}`
213
+ and not `%r{/build/}`.
214
+
203
215
  ### Non-blocking listening to changes
204
216
 
205
217
  Starting a listener blocks the current thread by default. That means any code after the
@@ -63,17 +63,16 @@ module Listen
63
63
  # @return [FChange::Notifier] initialized worker
64
64
  #
65
65
  def init_worker
66
- worker = FChange::Notifier.new
67
- @directories.each do |directory|
68
- watcher = worker.watch(directory, :all_events, :recursive) do |event|
69
- next if @paused
70
- @mutex.synchronize do
71
- @changed_dirs << File.expand_path(event.watcher.path)
66
+ FChange::Notifier.new.tap do |worker|
67
+ @directories.each do |directory|
68
+ worker.watch(directory, :all_events, :recursive) do |event|
69
+ next if @paused
70
+ @mutex.synchronize do
71
+ @changed_dirs << File.expand_path(event.watcher.path)
72
+ end
72
73
  end
73
74
  end
74
- worker.add_watcher(watcher)
75
75
  end
76
- worker
77
76
  end
78
77
 
79
78
  end
@@ -1,6 +1,5 @@
1
1
  require 'set'
2
2
  require 'find'
3
- require 'pathname'
4
3
  require 'digest/sha1'
5
4
 
6
5
  module Listen
@@ -12,61 +11,85 @@ module Listen
12
11
  class DirectoryRecord
13
12
  attr_reader :directory, :paths, :sha1_checksums
14
13
 
15
- # Default paths' beginnings that doesn't get stored in the record
16
- DEFAULT_IGNORED_PATHS = %w[.bundle .git .DS_Store log tmp vendor]
14
+ DEFAULT_IGNORED_DIRECTORIES = %w[.rbx .bundle .git .svn log tmp vendor]
15
+
16
+ DEFAULT_IGNORED_EXTENSIONS = %w[.DS_Store]
17
+
18
+ # Class methods
19
+ #
20
+ class << self
21
+
22
+ # Creates the ignoring patterns from the default ignored
23
+ # directories and extensions. It memoizes the generated patterns
24
+ # to avoid unnecessary computation.
25
+ #
26
+ def generate_default_ignoring_patterns
27
+ @@default_ignoring_patterns ||= Array.new.tap do |default_patterns|
28
+ # Add directories
29
+ ignored_directories = DEFAULT_IGNORED_DIRECTORIES.map { |d| Regexp.escape(d) }
30
+ default_patterns << %r{^(?:#{ignored_directories.join('|')})/}
31
+
32
+ # Add extensions
33
+ ignored_extensions = DEFAULT_IGNORED_EXTENSIONS.map { |e| Regexp.escape(e) }
34
+ default_patterns << %r{(?:#{ignored_extensions.join('|')})$}
35
+ end
36
+ end
37
+ end
17
38
 
18
39
  # Initializes a directory record.
19
40
  #
20
41
  # @option [String] directory the directory to keep track of
21
42
  #
22
43
  def initialize(directory)
23
- @directory = directory
24
- raise ArgumentError, "The path '#{directory}' is not a directory!" unless File.directory?(@directory)
44
+ raise ArgumentError, "The path '#{directory}' is not a directory!" unless File.directory?(directory)
25
45
 
26
- @ignored_paths = Set.new(DEFAULT_IGNORED_PATHS)
27
- @filters = Set.new
28
- @sha1_checksums = Hash.new
46
+ @directory = directory
47
+ @ignoring_patterns = Set.new
48
+ @filtering_patterns = Set.new
49
+ @sha1_checksums = Hash.new
50
+
51
+ @ignoring_patterns.merge(DirectoryRecord.generate_default_ignoring_patterns)
29
52
  end
30
53
 
31
- # Returns the ignored paths in the record
54
+ # Returns the ignoring patterns in the record
32
55
  #
33
- # @return [Array<String>] the ignored paths
56
+ # @return [Array<Regexp>] the ignoring patterns
34
57
  #
35
- def ignored_paths
36
- @ignored_paths.to_a
58
+ def ignoring_patterns
59
+ @ignoring_patterns.to_a
37
60
  end
38
61
 
39
- # Returns the filters used in the record to know
62
+ # Returns the filtering patterns used in the record to know
40
63
  # which paths should be stored.
41
64
  #
42
- # @return [Array<String>] the used filters
65
+ # @return [Array<Regexp>] the filtering patterns
43
66
  #
44
- def filters
45
- @filters.to_a
67
+ def filtering_patterns
68
+ @filtering_patterns.to_a
46
69
  end
47
70
 
48
- # Adds ignored path to the record.
71
+ # Adds ignoring patterns to the record.
49
72
  #
50
73
  # @example Ignore some paths
51
74
  # ignore ".git", ".svn"
52
75
  #
53
- # @param [String, Array<String>] paths a path or a list of paths to ignore
76
+ # @param [Regexp] regexp a pattern for ignoring paths
54
77
  #
55
- def ignore(*paths)
56
- @ignored_paths.merge(paths)
78
+ def ignore(*regexps)
79
+ @ignoring_patterns.merge(regexps)
57
80
  end
58
81
 
59
- # Adds file filters to the listener.
82
+ # Adds filtering patterns to the listener.
60
83
  #
61
84
  # @example Filter some files
62
85
  # ignore /\.txt$/, /.*\.zip/
63
86
  #
64
- # @param [Array<Regexp>] regexps a list of regexps file filters
87
+ # @param [Regexp] regexp a pattern for filtering paths
65
88
  #
66
89
  # @return [Listen::Listener] the listener itself
67
90
  #
68
91
  def filter(*regexps)
69
- @filters.merge(regexps)
92
+ @filtering_patterns.merge(regexps)
70
93
  end
71
94
 
72
95
  # Returns whether a path should be ignored or not.
@@ -76,7 +99,8 @@ module Listen
76
99
  # @return [Boolean]
77
100
  #
78
101
  def ignored?(path)
79
- @ignored_paths.any? { |ignored_path| path =~ /#{ignored_path}$/ }
102
+ path = relative_to_base(path)
103
+ @ignoring_patterns.any? { |pattern| pattern =~ path }
80
104
  end
81
105
 
82
106
  # Returns whether a path should be filtered or not.
@@ -86,7 +110,11 @@ module Listen
86
110
  # @return [Boolean]
87
111
  #
88
112
  def filtered?(path)
89
- @filters.empty? || @filters.any? { |filter| path =~ filter }
113
+ # When no filtering patterns are set, ALL files are stored.
114
+ return true if @filtering_patterns.empty?
115
+
116
+ path = relative_to_base(path)
117
+ @filtering_patterns.any? { |pattern| pattern =~ path }
90
118
  end
91
119
 
92
120
  # Finds the paths that should be stored and adds them
@@ -111,15 +139,27 @@ module Listen
111
139
  def fetch_changes(directories, options = {})
112
140
  @changes = { :modified => [], :added => [], :removed => [] }
113
141
  directories = directories.sort_by { |el| el.length }.reverse # diff sub-dir first
142
+ update_time = Time.now.to_i
114
143
  directories.each do |directory|
115
144
  next unless directory[@directory] # Path is or inside directory
116
145
  detect_modifications_and_removals(directory, options)
117
146
  detect_additions(directory, options)
118
147
  end
119
- @updated_at = Time.now.to_i
148
+ @updated_at = update_time
120
149
  @changes
121
150
  end
122
151
 
152
+ # Converts an absolute path to a path that's relative to the base directory.
153
+ #
154
+ # @param [String] path the path to convert
155
+ #
156
+ # @return [String] the relative path
157
+ #
158
+ def relative_to_base(path)
159
+ return nil unless path[@directory]
160
+ path.sub(%r{^#{@directory}#{File::SEPARATOR}?}, '')
161
+ end
162
+
123
163
  private
124
164
 
125
165
  # Detects modifications and removals recursively in a directory.
@@ -176,7 +216,9 @@ module Listen
176
216
  next if path == @directory
177
217
 
178
218
  if File.directory?(path)
179
- if ignored?(path) || (directory != path && (!options[:recursive] && existing_path?(path)))
219
+ # Add a trailing slash to directories when checking if a directory is
220
+ # ignored to optimize finding them as Find.find doesn't.
221
+ if ignored?(path + File::SEPARATOR) || (directory != path && (!options[:recursive] && existing_path?(path)))
180
222
  Find.prune # Don't look any further into this directory.
181
223
  else
182
224
  insert_path(path)
@@ -215,7 +257,9 @@ module Listen
215
257
  next if path == @directory
216
258
 
217
259
  if File.directory?(path)
218
- if ignored?(path)
260
+ # Add a trailing slash to directories when checking if a directory is
261
+ # ignored to optimize finding them as Find.find doesn't.
262
+ if ignored?(path + File::SEPARATOR)
219
263
  Find.prune # Don't look any further into this directory.
220
264
  else
221
265
  yield(path)
@@ -243,15 +287,5 @@ module Listen
243
287
  def existing_path?(path)
244
288
  @paths[File.dirname(path)][File.basename(path)] != nil
245
289
  end
246
-
247
- # Converts an absolute path to a path that's relative to the base directory.
248
- #
249
- # @param [String] path the path to convert
250
- #
251
- # @return [String] the relative path
252
- #
253
- def relative_to_base(path)
254
- path.sub(%r(^#{@directory}/?/), '')
255
- end
256
290
  end
257
291
  end
@@ -1,3 +1,5 @@
1
+ require 'pathname'
2
+
1
3
  module Listen
2
4
  class Listener
3
5
  attr_reader :directory, :directory_record, :adapter
@@ -9,8 +11,8 @@ module Listen
9
11
  #
10
12
  # @param [String] directory the directory to listen to
11
13
  # @param [Hash] options the listen options
12
- # @option options [String] ignore a list of paths to ignore
13
- # @option options [Regexp] filter a list of regexps file filters
14
+ # @option options [Regexp] ignore a pattern for ignoring paths
15
+ # @option options [Regexp] filter a pattern for filtering paths
14
16
  # @option options [Float] latency the delay between checking for changes in seconds
15
17
  # @option options [Boolean] relative_paths whether or not to use relative-paths in the callback
16
18
  # @option options [Boolean] force_polling whether to force the polling adapter or not
@@ -23,8 +25,8 @@ module Listen
23
25
  #
24
26
  def initialize(directory, options = {}, &block)
25
27
  @block = block
26
- @directory = directory
27
- @directory_record = DirectoryRecord.new(directory)
28
+ @directory = Pathname.new(directory).realpath.to_s
29
+ @directory_record = DirectoryRecord.new(@directory)
28
30
  @use_relative_paths = DEFAULT_TO_RELATIVE_PATHS
29
31
 
30
32
  @use_relative_paths = options.delete(:relative_paths) if options[:relative_paths]
@@ -41,8 +43,8 @@ module Listen
41
43
  # @param [Boolean] blocking whether or not to block the current thread after starting
42
44
  #
43
45
  def start(blocking = true)
44
- t = Thread.new { @adapter = initialize_adapter }
45
- @directory_record.build
46
+ t = Thread.new { @directory_record.build }
47
+ @adapter = initialize_adapter
46
48
  t.join
47
49
  @adapter.start(blocking)
48
50
  end
@@ -80,18 +82,18 @@ module Listen
80
82
  !!@adapter && @adapter.paused == true
81
83
  end
82
84
 
83
- # Adds ignored paths to the listener.
85
+ # Adds ignoring patterns to the listener.
84
86
  #
85
87
  # @param (see Listen::DirectoryRecord#ignore)
86
88
  #
87
89
  # @return [Listen::Listener] the listener
88
90
  #
89
- def ignore(*paths)
90
- @directory_record.ignore(*paths)
91
+ def ignore(*regexps)
92
+ @directory_record.ignore(*regexps)
91
93
  self
92
94
  end
93
95
 
94
- # Adds file filters to the listener.
96
+ # Adds filtering patterns to the listener.
95
97
  #
96
98
  # @param (see Listen::DirectoryRecord#filter)
97
99
  #
@@ -6,8 +6,8 @@ module Listen
6
6
  #
7
7
  # @param [String] directories the directories to listen to
8
8
  # @param [Hash] options the listen options
9
- # @option options [String] ignore a list of paths to ignore
10
- # @option options [Regexp] filter a list of regexps file filters
9
+ # @option options [Regexp] ignore a pattern for ignoring paths
10
+ # @option options [Regexp] filter a pattern for filtering paths
11
11
  # @option options [Float] latency the delay between checking for changes in seconds
12
12
  # @option options [Boolean] force_polling whether to force the polling adapter or not
13
13
  # @option options [String, Boolean] polling_fallback_message to change polling fallback message or remove it
@@ -22,8 +22,8 @@ module Listen
22
22
  directories = args
23
23
 
24
24
  @block = block
25
- @directories = directories
26
- @directories_records = directories.map { |d| DirectoryRecord.new(d) }
25
+ @directories = directories.map { |d| Pathname.new(d).realpath.to_s }
26
+ @directories_records = @directories.map { |d| DirectoryRecord.new(d) }
27
27
 
28
28
  ignore(*options.delete(:ignore)) if options[:ignore]
29
29
  filter(*options.delete(:filter)) if options[:filter]
@@ -38,8 +38,8 @@ module Listen
38
38
  # @param [Boolean] blocking whether or not to block the current thread after starting
39
39
  #
40
40
  def start(blocking = true)
41
- t = Thread.new { @adapter = initialize_adapter }
42
- @directories_records.each { |r| r.build }
41
+ t = Thread.new { @directories_records.each { |r| r.build } }
42
+ @adapter = initialize_adapter
43
43
  t.join
44
44
  @adapter.start(blocking)
45
45
  end