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
@@ -0,0 +1,112 @@
1
+ module Listen
2
+ module Adapters
3
+
4
+ # Listener implementation for BSD's `kqueue`.
5
+ #
6
+ class BSD < Adapter
7
+ extend DependencyManager
8
+
9
+ # Declare the adapter's dependencies
10
+ dependency 'rb-kqueue', '~> 0.2'
11
+
12
+ # Watched kqueue events
13
+ #
14
+ # @see http://www.freebsd.org/cgi/man.cgi?query=kqueue
15
+ # @see https://github.com/nex3/rb-kqueue/blob/master/lib/rb-kqueue/queue.rb
16
+ #
17
+ EVENTS = [ :delete, :write, :extend, :attrib, :link, :rename, :revoke ]
18
+
19
+ # Initializes the Adapter. See {Listen::Adapter#initialize} for
20
+ # more info.
21
+ #
22
+ def initialize(directories, options = {}, &callback)
23
+ super
24
+ @kqueue = init_kqueue
25
+ end
26
+
27
+ # Starts the adapter.
28
+ #
29
+ # @param [Boolean] blocking whether or not to block the current thread after starting
30
+ #
31
+ def start(blocking = true)
32
+ @mutex.synchronize do
33
+ return if @stop == false
34
+ super
35
+ end
36
+
37
+ @kqueue_thread = Thread.new do
38
+ until @stop
39
+ @kqueue.poll
40
+ sleep(@latency)
41
+ end
42
+ end
43
+ @poll_thread = Thread.new { poll_changed_dirs } if @report_changes
44
+
45
+ @kqueue_thread.join if blocking
46
+ end
47
+
48
+ # Stops the adapter.
49
+ #
50
+ def stop
51
+ @mutex.synchronize do
52
+ return if @stop == true
53
+ super
54
+ end
55
+
56
+ @kqueue.stop
57
+ Thread.kill(@kqueue_thread) if @kqueue_thread
58
+ @poll_thread.join if @poll_thread
59
+ end
60
+
61
+ # Checks if the adapter is usable on the current OS.
62
+ #
63
+ # @return [Boolean] whether usable or not
64
+ #
65
+ def self.usable?
66
+ return false unless RbConfig::CONFIG['target_os'] =~ /freebsd/i
67
+ super
68
+ end
69
+
70
+ private
71
+
72
+ # Initializes a kqueue Queue and adds a watcher for each files in
73
+ # the directories passed to the adapter.
74
+ #
75
+ # @return [INotify::Notifier] initialized kqueue
76
+ #
77
+ def init_kqueue
78
+ require 'find'
79
+
80
+ callback = lambda do |event|
81
+ path = event.watcher.path
82
+ @mutex.synchronize do
83
+ # kqueue watches everything, but Listen only needs the
84
+ # directory where stuffs happens.
85
+ @changed_dirs << (File.directory?(path) ? path : File.dirname(path))
86
+
87
+ # If it is a directory, and it has a write flag, it means a
88
+ # file has been added so find out which and deal with it.
89
+ # No need to check for removed file, kqueue will forget them
90
+ # when the vfs does..
91
+ if File.directory?(path) && !(event.flags & [:write]).empty?
92
+ queue = event.watcher.queue
93
+ Find.find(path) do |file|
94
+ unless queue.watchers.detect {|k,v| v.path == file.to_s}
95
+ queue.watch_file(file, *EVENTS, &callback)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ KQueue::Queue.new.tap do |queue|
103
+ @directories.each do |directory|
104
+ Find.find(directory) do |path|
105
+ queue.watch_file(path, *EVENTS, &callback)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -4,6 +4,10 @@ module Listen
4
4
  # Adapter implementation for Mac OS X `FSEvents`.
5
5
  #
6
6
  class Darwin < Adapter
7
+ extend DependencyManager
8
+
9
+ # Declare the adapter's dependencies
10
+ dependency 'rb-fsevent', '~> 0.9.1'
7
11
 
8
12
  LAST_SEPARATOR_REGEX = /\/$/
9
13
 
@@ -25,13 +29,14 @@ module Listen
25
29
  end
26
30
 
27
31
  @worker_thread = Thread.new { @worker.run }
28
- @poll_thread = Thread.new { poll_changed_dirs }
29
32
 
30
33
  # The FSEvent worker needs sometime to startup. Turnstiles can't
31
34
  # be used to wait for it as it runs in a loop.
32
35
  # TODO: Find a better way to block until the worker starts.
33
- sleep @latency
34
- @poll_thread.join if blocking
36
+ sleep 0.1
37
+
38
+ @poll_thread = Thread.new { poll_changed_dirs } if @report_changes
39
+ @worker_thread.join if blocking
35
40
  end
36
41
 
37
42
  # Stops the adapter.
@@ -43,8 +48,8 @@ module Listen
43
48
  end
44
49
 
45
50
  @worker.stop
46
- Thread.kill(@worker_thread) if @worker_thread
47
- @poll_thread.join
51
+ @worker_thread.join if @worker_thread
52
+ @poll_thread.join if @poll_thread
48
53
  end
49
54
 
50
55
  # Checks if the adapter is usable on the current OS.
@@ -53,11 +58,7 @@ module Listen
53
58
  #
54
59
  def self.usable?
55
60
  return false unless RbConfig::CONFIG['target_os'] =~ /darwin(1.+)?$/i
56
-
57
- require 'rb-fsevent'
58
- true
59
- rescue LoadError
60
- false
61
+ super
61
62
  end
62
63
 
63
64
  private
@@ -4,6 +4,10 @@ module Listen
4
4
  # Listener implementation for Linux `inotify`.
5
5
  #
6
6
  class Linux < Adapter
7
+ extend DependencyManager
8
+
9
+ # Declare the adapter's dependencies
10
+ dependency 'rb-inotify', '~> 0.8.8'
7
11
 
8
12
  # Watched inotify events
9
13
  #
@@ -41,8 +45,9 @@ module Listen
41
45
  end
42
46
 
43
47
  @worker_thread = Thread.new { @worker.run }
44
- @poll_thread = Thread.new { poll_changed_dirs }
45
- @poll_thread.join if blocking
48
+ @poll_thread = Thread.new { poll_changed_dirs } if @report_changes
49
+
50
+ @worker_thread.join if blocking
46
51
  end
47
52
 
48
53
  # Stops the adapter.
@@ -55,20 +60,16 @@ module Listen
55
60
 
56
61
  @worker.stop
57
62
  Thread.kill(@worker_thread) if @worker_thread
58
- @poll_thread.join
63
+ @poll_thread.join if @poll_thread
59
64
  end
60
65
 
61
- # Check if the adapter is usable on the current OS.
66
+ # Checks if the adapter is usable on the current OS.
62
67
  #
63
68
  # @return [Boolean] whether usable or not
64
69
  #
65
70
  def self.usable?
66
71
  return false unless RbConfig::CONFIG['target_os'] =~ /linux/i
67
-
68
- require 'rb-inotify'
69
- true
70
- rescue LoadError
71
- false
72
+ super
72
73
  end
73
74
 
74
75
  private
@@ -79,29 +80,31 @@ module Listen
79
80
  # @return [INotify::Notifier] initialized worker
80
81
  #
81
82
  def init_worker
82
- worker = INotify::Notifier.new
83
- @directories.each do |directory|
84
- worker.watch(directory, *EVENTS.map(&:to_sym)) do |event|
85
- if @paused || (
86
- # Event on root directory
87
- event.name == ""
88
- ) || (
89
- # INotify reports changes to files inside directories as events
90
- # on the directories themselves too.
91
- #
92
- # @see http://linux.die.net/man/7/inotify
93
- event.flags.include?(:isdir) and event.flags & [:close, :modify] != []
94
- )
95
- # Skip all of these!
96
- next
97
- end
98
-
99
- @mutex.synchronize do
100
- @changed_dirs << File.dirname(event.absolute_name)
101
- end
83
+ callback = lambda do |event|
84
+ if @paused || (
85
+ # Event on root directory
86
+ event.name == ""
87
+ ) || (
88
+ # INotify reports changes to files inside directories as events
89
+ # on the directories themselves too.
90
+ #
91
+ # @see http://linux.die.net/man/7/inotify
92
+ event.flags.include?(:isdir) and event.flags & [:close, :modify] != []
93
+ )
94
+ # Skip all of these!
95
+ next
96
+ end
97
+
98
+ @mutex.synchronize do
99
+ @changed_dirs << File.dirname(event.absolute_name)
100
+ end
101
+ end
102
+
103
+ INotify::Notifier.new.tap do |worker|
104
+ @directories.each do |directory|
105
+ worker.watch(directory, *EVENTS.map(&:to_sym), &callback)
102
106
  end
103
107
  end
104
- worker
105
108
  end
106
109
 
107
110
  end
@@ -10,6 +10,7 @@ module Listen
10
10
  # file IO that the other implementations.
11
11
  #
12
12
  class Polling < Adapter
13
+ extend DependencyManager
13
14
 
14
15
  # Initialize the Adapter. See {Listen::Adapter#initialize} for more info.
15
16
  #
@@ -49,7 +50,7 @@ module Listen
49
50
  #
50
51
  def poll
51
52
  until @stop
52
- sleep(0.1) && next if @paused
53
+ next if @paused
53
54
 
54
55
  start = Time.now.to_f
55
56
  @callback.call(@directories.dup, :recursive => true)
@@ -3,9 +3,13 @@ require 'set'
3
3
  module Listen
4
4
  module Adapters
5
5
 
6
- # Adapter implementation for Windows `fchange`.
6
+ # Adapter implementation for Windows `wdm`.
7
7
  #
8
8
  class Windows < Adapter
9
+ extend DependencyManager
10
+
11
+ # Declare the adapter's dependencies
12
+ dependency 'wdm', '~> 0.0.3'
9
13
 
10
14
  # Initializes the Adapter. See {Listen::Adapter#initialize} for more info.
11
15
  #
@@ -24,9 +28,15 @@ module Listen
24
28
  super
25
29
  end
26
30
 
27
- @worker_thread = Thread.new { @worker.run }
28
- @poll_thread = Thread.new { poll_changed_dirs(true) }
29
- @poll_thread.join if blocking
31
+ @worker_thread = Thread.new { @worker.run! }
32
+
33
+ # Wait for the worker to start. This is needed to avoid a deadlock
34
+ # when stopping immediately after starting.
35
+ sleep 0.1
36
+
37
+ @poll_thread = Thread.new { poll_changed_dirs } if @report_changes
38
+
39
+ @worker_thread.join if blocking
30
40
  end
31
41
 
32
42
  # Stops the adapter.
@@ -38,8 +48,8 @@ module Listen
38
48
  end
39
49
 
40
50
  @worker.stop
41
- Thread.kill(@worker_thread) if @worker_thread
42
- @poll_thread.join
51
+ @worker_thread.join if @worker_thread
52
+ @poll_thread.join if @poll_thread
43
53
  end
44
54
 
45
55
  # Checks if the adapter is usable on the current OS.
@@ -48,31 +58,27 @@ module Listen
48
58
  #
49
59
  def self.usable?
50
60
  return false unless RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
51
-
52
- require 'rb-fchange'
53
- true
54
- rescue LoadError
55
- false
61
+ super
56
62
  end
57
63
 
58
64
  private
59
65
 
60
- # Initializes a FChange worker and adds a watcher for
66
+ # Initializes a WDM monitor and adds a watcher for
61
67
  # each directory passed to the adapter.
62
68
  #
63
- # @return [FChange::Notifier] initialized worker
69
+ # @return [WDM::Monitor] initialized worker
64
70
  #
65
71
  def init_worker
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
73
- end
72
+ callback = Proc.new do |change|
73
+ next if @paused
74
+ @mutex.synchronize do
75
+ @changed_dirs << File.dirname(change.path)
74
76
  end
75
77
  end
78
+
79
+ WDM::Monitor.new.tap do |worker|
80
+ @directories.each { |d| worker.watch_recursively(d, &callback) }
81
+ end
76
82
  end
77
83
 
78
84
  end
@@ -0,0 +1,126 @@
1
+ require 'set'
2
+
3
+ module Listen
4
+
5
+ # The dependency-manager offers a simple DSL which allows
6
+ # classes to declare their gem dependencies and load them when
7
+ # needed.
8
+ # It raises a user-friendly exception when the dependencies
9
+ # can't be loaded which has the install command in the message.
10
+ #
11
+ module DependencyManager
12
+
13
+ GEM_LOAD_MESSAGE = <<-EOS.gsub(/^ {6}/, '')
14
+ Missing dependency '%s' (version '%s')!
15
+ EOS
16
+
17
+ GEM_INSTALL_COMMAND = <<-EOS.gsub(/^ {6}/, '')
18
+ Please run the following to satisfy the dependency:
19
+ gem install --version '%s' %s
20
+ EOS
21
+
22
+ BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
23
+ Please add the following to your Gemfile to satisfy the dependency:
24
+ gem '%s', '%s'
25
+ EOS
26
+
27
+ Dependency = Struct.new(:name, :version)
28
+
29
+ # The error raised when a dependency can't be loaded.
30
+ class Error < StandardError; end
31
+
32
+ # A list of all loaded dependencies in the dependency manager.
33
+ @_loaded_dependencies = Set.new
34
+
35
+ # class methods
36
+ class << self
37
+
38
+ # Initializes the extended class.
39
+ #
40
+ # @param [Class] the class for which some dependencies must be managed
41
+ #
42
+ def extended(base)
43
+ base.class_eval do
44
+ @_dependencies = Set.new
45
+ end
46
+ end
47
+
48
+ # Adds a loaded dependency to a list so that it doesn't have
49
+ # to be loaded again by another classes.
50
+ #
51
+ # @param [Dependency] dependency
52
+ #
53
+ def add_loaded(dependency)
54
+ @_loaded_dependencies << dependency
55
+ end
56
+
57
+ # Returns whether the dependency is alread loaded or not.
58
+ #
59
+ # @param [Dependency] dependency
60
+ # @return [Boolean]
61
+ #
62
+ def already_loaded?(dependency)
63
+ @_loaded_dependencies.include?(dependency)
64
+ end
65
+
66
+ # Clears the list of loaded dependencies.
67
+ #
68
+ def clear_loaded
69
+ @_loaded_dependencies.clear
70
+ end
71
+ end
72
+
73
+ # Registers a new dependency.
74
+ #
75
+ # @param [String] name the name of the gem
76
+ # @param [String] version the version of the gem
77
+ #
78
+ def dependency(name, version)
79
+ @_dependencies << Dependency.new(name, version)
80
+ end
81
+
82
+ # Loads the registered dependencies.
83
+ #
84
+ # @raise DependencyManager::Error if the dependency can't be loaded.
85
+ #
86
+ def load_depenencies
87
+ @_dependencies.each do |dependency|
88
+ begin
89
+ next if DependencyManager.already_loaded?(dependency)
90
+ gem(dependency.name, dependency.version)
91
+ require(dependency.name)
92
+ DependencyManager.add_loaded(dependency)
93
+ @_dependencies.delete(dependency)
94
+ rescue Gem::LoadError
95
+ args = [dependency.name, dependency.version]
96
+ command = if running_under_bundler?
97
+ BUNDLER_DECLARE_GEM % args
98
+ else
99
+ GEM_INSTALL_COMMAND % args.reverse
100
+ end
101
+ message = GEM_LOAD_MESSAGE % args
102
+
103
+ raise Error.new(message + command)
104
+ end
105
+ end
106
+ end
107
+
108
+ # Returns whether all the dependencies has been loaded or not.
109
+ #
110
+ # @return [Boolean]
111
+ #
112
+ def dependencies_loaded?
113
+ @_dependencies.empty?
114
+ end
115
+
116
+ private
117
+
118
+ # Returns whether we are running under bundler or not
119
+ #
120
+ # @return [Boolean]
121
+ #
122
+ def running_under_bundler?
123
+ !!(File.exists?('Gemfile') && ENV['BUNDLE_GEMFILE'])
124
+ end
125
+ end
126
+ end