sass 3.2.0.alpha.11 → 3.2.0.alpha.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/REVISION +1 -1
  2. data/VERSION +1 -1
  3. data/lib/sass/cache_stores/base.rb +4 -9
  4. data/lib/sass/cache_stores/filesystem.rb +2 -0
  5. data/lib/sass/css.rb +2 -1
  6. data/lib/sass/engine.rb +28 -8
  7. data/lib/sass/environment.rb +26 -0
  8. data/lib/sass/exec.rb +13 -0
  9. data/lib/sass/importers/base.rb +2 -1
  10. data/lib/sass/script/funcall.rb +8 -0
  11. data/lib/sass/script/interpolation.rb +9 -0
  12. data/lib/sass/script/list.rb +7 -0
  13. data/lib/sass/script/literal.rb +5 -0
  14. data/lib/sass/script/node.rb +8 -0
  15. data/lib/sass/script/number.rb +28 -5
  16. data/lib/sass/script/operation.rb +8 -0
  17. data/lib/sass/script/string_interpolation.rb +9 -0
  18. data/lib/sass/script/unary_operation.rb +7 -0
  19. data/lib/sass/script/variable.rb +5 -0
  20. data/lib/sass/scss/parser.rb +26 -13
  21. data/lib/sass/scss/rx.rb +1 -1
  22. data/lib/sass/scss/static_parser.rb +2 -2
  23. data/lib/sass/tree/content_node.rb +9 -0
  24. data/lib/sass/tree/debug_node.rb +1 -6
  25. data/lib/sass/tree/each_node.rb +1 -7
  26. data/lib/sass/tree/extend_node.rb +1 -1
  27. data/lib/sass/tree/for_node.rb +2 -7
  28. data/lib/sass/tree/function_node.rb +1 -6
  29. data/lib/sass/tree/if_node.rb +1 -19
  30. data/lib/sass/tree/mixin_def_node.rb +5 -6
  31. data/lib/sass/tree/mixin_node.rb +2 -7
  32. data/lib/sass/tree/node.rb +4 -19
  33. data/lib/sass/tree/prop_node.rb +0 -5
  34. data/lib/sass/tree/return_node.rb +1 -6
  35. data/lib/sass/tree/rule_node.rb +9 -7
  36. data/lib/sass/tree/trace_node.rb +32 -0
  37. data/lib/sass/tree/variable_node.rb +1 -7
  38. data/lib/sass/tree/visitors/check_nesting.rb +30 -13
  39. data/lib/sass/tree/visitors/convert.rb +5 -1
  40. data/lib/sass/tree/visitors/cssize.rb +3 -3
  41. data/lib/sass/tree/visitors/deep_copy.rb +87 -0
  42. data/lib/sass/tree/visitors/perform.rb +36 -16
  43. data/lib/sass/tree/visitors/set_options.rb +97 -0
  44. data/lib/sass/tree/visitors/to_css.rb +5 -1
  45. data/lib/sass/tree/warn_node.rb +1 -7
  46. data/lib/sass/tree/while_node.rb +1 -7
  47. data/test/sass/cache_test.rb +15 -0
  48. data/test/sass/conversion_test.rb +38 -0
  49. data/test/sass/css2sass_test.rb +9 -0
  50. data/test/sass/engine_test.rb +248 -17
  51. data/test/sass/scss/css_test.rb +4 -2
  52. data/test/sass/scss/scss_test.rb +53 -12
  53. data/vendor/fssm/Gemfile +3 -0
  54. data/vendor/fssm/LICENSE +1 -1
  55. data/vendor/fssm/README.markdown +55 -27
  56. data/vendor/fssm/Rakefile +6 -54
  57. data/vendor/fssm/example.rb +6 -3
  58. data/vendor/fssm/fssm.gemspec +17 -70
  59. data/vendor/fssm/lib/fssm.rb +7 -3
  60. data/vendor/fssm/lib/fssm/backends/fsevents.rb +1 -1
  61. data/vendor/fssm/lib/fssm/backends/inotify.rb +2 -2
  62. data/vendor/fssm/lib/fssm/backends/polling.rb +2 -2
  63. data/vendor/fssm/lib/fssm/backends/rbfsevent.rb +42 -0
  64. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +10 -10
  65. data/vendor/fssm/lib/fssm/monitor.rb +19 -9
  66. data/vendor/fssm/lib/fssm/path.rb +24 -21
  67. data/vendor/fssm/lib/fssm/pathname.rb +13 -479
  68. data/vendor/fssm/lib/fssm/state/directory.rb +29 -11
  69. data/vendor/fssm/lib/fssm/state/file.rb +1 -1
  70. data/vendor/fssm/lib/fssm/support.rb +41 -12
  71. data/vendor/fssm/lib/fssm/tree.rb +6 -6
  72. data/vendor/fssm/lib/fssm/version.rb +3 -0
  73. data/vendor/fssm/profile/prof-cache.rb +3 -3
  74. data/vendor/fssm/profile/prof-pathname-rubinius.rb +35 -0
  75. data/vendor/fssm/profile/prof-pathname.rb +7 -7
  76. data/vendor/fssm/spec/count_down_latch.rb +151 -0
  77. data/vendor/fssm/spec/monitor_spec.rb +202 -0
  78. data/vendor/fssm/spec/path_spec.rb +36 -15
  79. data/vendor/fssm/spec/spec_helper.rb +6 -6
  80. metadata +14 -4
  81. data/vendor/fssm/VERSION.yml +0 -5
@@ -2,13 +2,15 @@ module FSSM::State
2
2
  class Directory
3
3
  attr_reader :path
4
4
 
5
- def initialize(path)
6
- @path = path
7
- @cache = FSSM::Tree::Cache.new
5
+ def initialize(path, options={})
6
+ @path = path
7
+ @options = options
8
+ @cache = FSSM::Tree::Cache.new
8
9
  end
9
10
 
10
11
  def refresh(base=nil, skip_callbacks=false)
11
- previous, current = recache(base || @path.to_pathname)
12
+ base_path = FSSM::Pathname.for(base || @path.to_pathname).expand_path
13
+ previous, current = recache(base_path)
12
14
 
13
15
  unless skip_callbacks
14
16
  deleted(previous, current)
@@ -20,31 +22,36 @@ module FSSM::State
20
22
  private
21
23
 
22
24
  def created(previous, current)
23
- (current.keys - previous.keys).each {|created| @path.create(created)}
25
+ (current.keys - previous.keys).sort.each do |file|
26
+ @path.create(file, current[file][1])
27
+ end
24
28
  end
25
29
 
26
30
  def deleted(previous, current)
27
- (previous.keys - current.keys).each {|deleted| @path.delete(deleted)}
31
+ (previous.keys - current.keys).sort.reverse.each do |file|
32
+ @path.delete(file, previous[file][1])
33
+ end
28
34
  end
29
35
 
30
36
  def modified(previous, current)
31
37
  (current.keys & previous.keys).each do |file|
32
- @path.update(file) if (current[file] <=> previous[file]) != 0
38
+ current_data = current[file]
39
+ @path.update(file, current_data[1]) if (current_data[0] <=> previous[file][0]) != 0
33
40
  end
34
41
  end
35
42
 
36
43
  def recache(base)
37
- base = FSSM::Pathname.for(base)
38
- previous = @cache.files
44
+ base = FSSM::Pathname.for(base)
45
+ previous = cache_entries
39
46
  snapshot(base)
40
- current = @cache.files
47
+ current = cache_entries
41
48
  [previous, current]
42
49
  end
43
50
 
44
51
  def snapshot(base)
45
52
  base = FSSM::Pathname.for(base)
46
53
  @cache.unset(base)
47
- @path.glob.each {|glob| add_glob(base, glob)}
54
+ @path.glob.each { |glob| add_glob(base, glob) }
48
55
  end
49
56
 
50
57
  def add_glob(base, glob)
@@ -53,5 +60,16 @@ module FSSM::State
53
60
  end
54
61
  end
55
62
 
63
+ def cache_entries
64
+ entries = tag_entries(@cache.files, :file)
65
+ entries.merge! tag_entries(@cache.directories, :directory) if @options[:directories]
66
+ entries
67
+ end
68
+
69
+ def tag_entries(entries, tag)
70
+ tagged_entries = {}
71
+ entries.each_pair { |fname, mtime| tagged_entries[fname] = [mtime, tag] }
72
+ tagged_entries
73
+ end
56
74
  end
57
75
  end
@@ -8,7 +8,7 @@ module FSSM::State
8
8
 
9
9
  def refresh(base=nil, skip_callbacks=false)
10
10
  base ||= @path.to_pathname
11
- used_to_exist, @exists = @exists, base.exists?
11
+ used_to_exist, @exists = @exists, base.exist?
12
12
  # this handles bad symlinks without failing. why handle bad symlinks at
13
13
  # all? well, we could still be interested in their creation and deletion.
14
14
  old_mtime, @mtime = @mtime, base.symlink? ? Time.at(0) : base.mtime if @exists
@@ -2,15 +2,34 @@ require 'rbconfig'
2
2
 
3
3
  module FSSM::Support
4
4
  class << self
5
- def backend
6
- @@backend ||= case
7
- when mac? && !jruby? && carbon_core?
8
- 'FSEvents'
9
- when linux? && rb_inotify?
10
- 'Inotify'
11
- else
12
- 'Polling'
5
+ def usable_backend
6
+ choice = case
7
+ when mac? && !lion? && !jruby? && carbon_core?
8
+ 'FSEvents'
9
+ when mac? && rb_fsevent?
10
+ 'RBFSEvent'
11
+ when linux? && rb_inotify?
12
+ 'Inotify'
13
+ else
14
+ 'Polling'
15
+ end
16
+
17
+ if (mac? || linux?) && choice == 'Polling'
18
+ optimal = case
19
+ when mac?
20
+ 'rb-fsevent'
21
+ when linux?
22
+ 'rb-inotify'
23
+ end
24
+ FSSM.dbg("An optimized backend is available for this platform!")
25
+ FSSM.dbg(" gem install #{optimal}")
13
26
  end
27
+
28
+ choice
29
+ end
30
+
31
+ def backend
32
+ @@backend ||= usable_backend
14
33
  end
15
34
 
16
35
  def jruby?
@@ -21,6 +40,10 @@ module FSSM::Support
21
40
  Config::CONFIG['target_os'] =~ /darwin/i
22
41
  end
23
42
 
43
+ def lion?
44
+ Config::CONFIG['target_os'] =~ /darwin11/i
45
+ end
46
+
24
47
  def linux?
25
48
  Config::CONFIG['target_os'] =~ /linux/i
26
49
  end
@@ -31,13 +54,21 @@ module FSSM::Support
31
54
  OSX.require_framework '/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework'
32
55
  true
33
56
  rescue LoadError
34
- STDERR.puts("Warning: Unable to load CarbonCore. FSEvents will be unavailable.")
57
+ false
58
+ end
59
+ end
60
+
61
+ def rb_fsevent?
62
+ begin
63
+ require 'rb-fsevent'
64
+ defined?(FSEvent::VERSION) ? FSEvent::VERSION.to_f >= 0.4 : false
65
+ rescue LoadError
35
66
  false
36
67
  end
37
68
  end
38
69
 
39
70
  def rb_inotify?
40
- found = begin
71
+ begin
41
72
  require 'rb-inotify'
42
73
  if defined?(INotify::VERSION)
43
74
  version = INotify::VERSION
@@ -46,8 +77,6 @@ module FSSM::Support
46
77
  rescue LoadError
47
78
  false
48
79
  end
49
- STDERR.puts("Warning: Unable to load rb-inotify >= 0.5.1. Inotify will be unavailable.") unless found
50
- found
51
80
  end
52
81
 
53
82
  def use_block(context, block)
@@ -34,8 +34,8 @@ module FSSM::Tree
34
34
  def each(prefix=nil, &block)
35
35
  @children.each do |segment, node|
36
36
  cprefix = prefix ?
37
- FSSM::Pathname.for(prefix).join(segment) :
38
- FSSM::Pathname.for(segment)
37
+ FSSM::Pathname.for(prefix).join(segment) :
38
+ FSSM::Pathname.for(segment)
39
39
  block.call([cprefix, node])
40
40
  node.each(cprefix, &block)
41
41
  end
@@ -54,7 +54,7 @@ module FSSM::Tree
54
54
  end
55
55
 
56
56
  segment = key.pop
57
- node = descendant(key)
57
+ node = descendant(key)
58
58
 
59
59
  return unless node
60
60
 
@@ -84,12 +84,12 @@ module FSSM::Tree
84
84
  end
85
85
 
86
86
  def recurse(key, create=false)
87
- key = key_segments(key)
87
+ key = key_segments(key)
88
88
  node = self
89
89
 
90
90
  until key.empty?
91
91
  segment = key.shift
92
- node = create ? node.child!(segment) : node.child(segment)
92
+ node = create ? node.child!(segment) : node.child(segment)
93
93
  return nil unless node
94
94
  end
95
95
 
@@ -127,7 +127,7 @@ module FSSM::Tree
127
127
  end
128
128
 
129
129
  def from_path(path)
130
- path = FSSM::Pathname.for(path)
130
+ path = FSSM::Pathname.for(path)
131
131
  @ftype = path.ftype
132
132
  # this handles bad symlinks without failing. why handle bad symlinks at
133
133
  # all? well, we could still be interested in their creation and deletion.
@@ -0,0 +1,3 @@
1
+ module FSSM
2
+ VERSION = "0.2.7"
3
+ end
@@ -5,7 +5,7 @@ require 'fssm'
5
5
  require 'rubygems'
6
6
  require 'ruby-prof'
7
7
 
8
- $test_path = FSSM::Pathname.new('..').expand_path
8
+ $test_path = FSSM::Pathname.new('..').expand_path
9
9
  $test_files = FSSM::Pathname.glob(File.join($test_path, '**', '*'))
10
10
 
11
11
  RubyProf.start
@@ -33,8 +33,8 @@ cache = FSSM::Tree::Cache.new
33
33
  print "\n\n"
34
34
  end
35
35
 
36
- result = RubyProf.stop
37
- output = File.new('prof.html', 'w+')
36
+ result = RubyProf.stop
37
+ output = File.new('prof.html', 'w+')
38
38
 
39
39
  printer = RubyProf::GraphHtmlPrinter.new(result)
40
40
  printer.print(output, :min_percent => 1)
@@ -0,0 +1,35 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
3
+ require 'pathname'
4
+
5
+ $test_path = "#{Pathname.new('..').expand_path}"
6
+ $iterations = 900000
7
+
8
+ if ARGV.first == 'native'
9
+ puts "Using native Pathname"
10
+
11
+ class Pathname
12
+ # original segments implementation I was using with
13
+ # the plain ruby Pathname library.
14
+ def segments
15
+ prefix, names = split_names(@path)
16
+ names.unshift(prefix) unless prefix.empty?
17
+ names.shift if names[0] == '.'
18
+ names
19
+ end
20
+ end
21
+
22
+ $iterations.times do |num|
23
+ p = ::Pathname.new($test_path)
24
+ segments = p.segments
25
+ end
26
+ else
27
+ puts "Using FSSM::Pathname"
28
+
29
+ require 'fssm'
30
+
31
+ $iterations.times do |num|
32
+ p = FSSM::Pathname.new($test_path)
33
+ segments = p.segments
34
+ end
35
+ end
@@ -6,7 +6,7 @@ require 'pathname'
6
6
  require 'rubygems'
7
7
  require 'ruby-prof'
8
8
 
9
- $test_path = "#{Pathname.new('..').expand_path}"
9
+ $test_path = "#{Pathname.new('..').expand_path}"
10
10
  $iterations = 90000
11
11
 
12
12
  class Pathname
@@ -32,15 +32,15 @@ $iterations.times do |num|
32
32
  puts "FSSM::Pathname iteration #{iteration}"
33
33
 
34
34
  RubyProf.resume
35
- p = FSSM::Pathname.new($test_path)
35
+ p = FSSM::Pathname.new($test_path)
36
36
  segments = p.segments
37
37
  RubyProf.pause
38
38
  end
39
39
 
40
40
  puts "\nFSSM Pathname profile finished\n\n"
41
41
 
42
- result = RubyProf.stop
43
- output = File.new('prof-fssm-pathname.html', 'w+')
42
+ result = RubyProf.stop
43
+ output = File.new('prof-fssm-pathname.html', 'w+')
44
44
 
45
45
  printer = RubyProf::GraphHtmlPrinter.new(result)
46
46
  printer.print(output, :min_percent => 1)
@@ -54,15 +54,15 @@ $iterations.times do |num|
54
54
  puts "::Pathname iteration #{iteration}"
55
55
 
56
56
  RubyProf.resume
57
- p = ::Pathname.new($test_path)
57
+ p = ::Pathname.new($test_path)
58
58
  segments = p.segments
59
59
  RubyProf.pause
60
60
  end
61
61
 
62
62
  puts "\nruby Pathname profile finished\n\n"
63
63
 
64
- result = RubyProf.stop
65
- output = File.new('prof-plain-pathname.html', 'w+')
64
+ result = RubyProf.stop
65
+ output = File.new('prof-plain-pathname.html', 'w+')
66
66
 
67
67
  printer = RubyProf::GraphHtmlPrinter.new(result)
68
68
  printer.print(output, :min_percent => 1)
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'thread'
5
+
6
+ class CountDownLatch
7
+ attr_reader :count
8
+
9
+ def initialize(to)
10
+ @count = to.to_i
11
+ raise ArgumentError, "cannot count down from negative integer" unless @count >= 0
12
+ @lock = Mutex.new
13
+ @condition = ConditionVariable.new
14
+ end
15
+
16
+ def count_down
17
+ @lock.synchronize do
18
+ @count -= 1 if @count > 0
19
+ @condition.broadcast if @count == 0
20
+ end
21
+ end
22
+
23
+ def wait
24
+ @lock.synchronize do
25
+ @condition.wait(@lock) while @count > 0
26
+ end
27
+ end
28
+ end
29
+
30
+ if $0 == __FILE__
31
+ require 'test/unit'
32
+
33
+ class CountDownLatchTest < Test::Unit::TestCase
34
+ def test_requires_positive_count
35
+ assert_raise(ArgumentError) { CountDownLatch.new(-1) }
36
+ end
37
+
38
+ def test_basic_latch_usage
39
+ latch = CountDownLatch.new(1)
40
+ name = "foo"
41
+ Thread.new do
42
+ name = "bar"
43
+ latch.count_down
44
+ end
45
+ latch.wait
46
+ assert_equal(0, latch.count)
47
+ assert_equal("bar", name)
48
+ end
49
+
50
+ def test_basic_latch_usage_inverted
51
+ latch = CountDownLatch.new(1)
52
+ name = "foo"
53
+ Thread.new do
54
+ latch.wait
55
+ assert_equal(0, latch.count)
56
+ assert_equal("bar", name)
57
+ end
58
+ name = "bar"
59
+ latch.count_down
60
+ end
61
+
62
+ def test_count_down_from_zero_skips_wait
63
+ latch = CountDownLatch.new(0)
64
+ latch.wait
65
+ assert_equal(0, latch.count)
66
+ end
67
+
68
+ def test_count_down_twice_with_thread
69
+ latch = CountDownLatch.new(2)
70
+ name = "foo"
71
+ Thread.new do
72
+ latch.count_down
73
+ name = "bar"
74
+ latch.count_down
75
+ end
76
+ latch.wait
77
+ assert_equal(0, latch.count)
78
+ assert_equal("bar", name)
79
+ end
80
+
81
+ def test_count_down_twice_with_two_parallel_threads
82
+ latch = CountDownLatch.new(2)
83
+ name = "foo"
84
+ Thread.new { latch.count_down }
85
+ Thread.new do
86
+ name = "bar"
87
+ latch.count_down
88
+ end
89
+ latch.wait
90
+ assert_equal(0, latch.count)
91
+ assert_equal("bar", name)
92
+ end
93
+
94
+ def test_count_down_twice_with_two_chained_threads
95
+ latch = CountDownLatch.new(2)
96
+ name = "foo"
97
+ Thread.new do
98
+ latch.count_down
99
+ Thread.new do
100
+ name = "bar"
101
+ latch.count_down
102
+ end
103
+ end
104
+ latch.wait
105
+ assert_equal(0, latch.count)
106
+ assert_equal("bar", name)
107
+ end
108
+
109
+ def test_count_down_with_multiple_waiters
110
+ proceed_latch = CountDownLatch.new(2)
111
+ check_latch = CountDownLatch.new(2)
112
+ results = {}
113
+ Thread.new do
114
+ proceed_latch.wait
115
+ results[:first] = 1
116
+ check_latch.count_down
117
+ end
118
+ Thread.new do
119
+ proceed_latch.wait
120
+ results[:second] = 2
121
+ check_latch.count_down
122
+ end
123
+ assert_equal({}, results)
124
+ proceed_latch.count_down
125
+ proceed_latch.count_down
126
+ check_latch.wait
127
+ assert_equal(0, proceed_latch.count)
128
+ assert_equal(0, check_latch.count)
129
+ assert_equal({:first => 1, :second => 2}, results)
130
+ end
131
+
132
+ def test_interleaved_latches
133
+ change_1_latch = CountDownLatch.new(1)
134
+ check_latch = CountDownLatch.new(1)
135
+ change_2_latch = CountDownLatch.new(1)
136
+ name = "foo"
137
+ Thread.new do
138
+ name = "bar"
139
+ change_1_latch.count_down
140
+ check_latch.wait
141
+ name = "man"
142
+ change_2_latch.count_down
143
+ end
144
+ change_1_latch.wait
145
+ assert_equal("bar", name)
146
+ check_latch.count_down
147
+ change_2_latch.wait
148
+ assert_equal("man", name)
149
+ end
150
+ end
151
+ end