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.
- data/REVISION +1 -1
- data/VERSION +1 -1
- data/lib/sass/cache_stores/base.rb +4 -9
- data/lib/sass/cache_stores/filesystem.rb +2 -0
- data/lib/sass/css.rb +2 -1
- data/lib/sass/engine.rb +28 -8
- data/lib/sass/environment.rb +26 -0
- data/lib/sass/exec.rb +13 -0
- data/lib/sass/importers/base.rb +2 -1
- data/lib/sass/script/funcall.rb +8 -0
- data/lib/sass/script/interpolation.rb +9 -0
- data/lib/sass/script/list.rb +7 -0
- data/lib/sass/script/literal.rb +5 -0
- data/lib/sass/script/node.rb +8 -0
- data/lib/sass/script/number.rb +28 -5
- data/lib/sass/script/operation.rb +8 -0
- data/lib/sass/script/string_interpolation.rb +9 -0
- data/lib/sass/script/unary_operation.rb +7 -0
- data/lib/sass/script/variable.rb +5 -0
- data/lib/sass/scss/parser.rb +26 -13
- data/lib/sass/scss/rx.rb +1 -1
- data/lib/sass/scss/static_parser.rb +2 -2
- data/lib/sass/tree/content_node.rb +9 -0
- data/lib/sass/tree/debug_node.rb +1 -6
- data/lib/sass/tree/each_node.rb +1 -7
- data/lib/sass/tree/extend_node.rb +1 -1
- data/lib/sass/tree/for_node.rb +2 -7
- data/lib/sass/tree/function_node.rb +1 -6
- data/lib/sass/tree/if_node.rb +1 -19
- data/lib/sass/tree/mixin_def_node.rb +5 -6
- data/lib/sass/tree/mixin_node.rb +2 -7
- data/lib/sass/tree/node.rb +4 -19
- data/lib/sass/tree/prop_node.rb +0 -5
- data/lib/sass/tree/return_node.rb +1 -6
- data/lib/sass/tree/rule_node.rb +9 -7
- data/lib/sass/tree/trace_node.rb +32 -0
- data/lib/sass/tree/variable_node.rb +1 -7
- data/lib/sass/tree/visitors/check_nesting.rb +30 -13
- data/lib/sass/tree/visitors/convert.rb +5 -1
- data/lib/sass/tree/visitors/cssize.rb +3 -3
- data/lib/sass/tree/visitors/deep_copy.rb +87 -0
- data/lib/sass/tree/visitors/perform.rb +36 -16
- data/lib/sass/tree/visitors/set_options.rb +97 -0
- data/lib/sass/tree/visitors/to_css.rb +5 -1
- data/lib/sass/tree/warn_node.rb +1 -7
- data/lib/sass/tree/while_node.rb +1 -7
- data/test/sass/cache_test.rb +15 -0
- data/test/sass/conversion_test.rb +38 -0
- data/test/sass/css2sass_test.rb +9 -0
- data/test/sass/engine_test.rb +248 -17
- data/test/sass/scss/css_test.rb +4 -2
- data/test/sass/scss/scss_test.rb +53 -12
- data/vendor/fssm/Gemfile +3 -0
- data/vendor/fssm/LICENSE +1 -1
- data/vendor/fssm/README.markdown +55 -27
- data/vendor/fssm/Rakefile +6 -54
- data/vendor/fssm/example.rb +6 -3
- data/vendor/fssm/fssm.gemspec +17 -70
- data/vendor/fssm/lib/fssm.rb +7 -3
- data/vendor/fssm/lib/fssm/backends/fsevents.rb +1 -1
- data/vendor/fssm/lib/fssm/backends/inotify.rb +2 -2
- data/vendor/fssm/lib/fssm/backends/polling.rb +2 -2
- data/vendor/fssm/lib/fssm/backends/rbfsevent.rb +42 -0
- data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +10 -10
- data/vendor/fssm/lib/fssm/monitor.rb +19 -9
- data/vendor/fssm/lib/fssm/path.rb +24 -21
- data/vendor/fssm/lib/fssm/pathname.rb +13 -479
- data/vendor/fssm/lib/fssm/state/directory.rb +29 -11
- data/vendor/fssm/lib/fssm/state/file.rb +1 -1
- data/vendor/fssm/lib/fssm/support.rb +41 -12
- data/vendor/fssm/lib/fssm/tree.rb +6 -6
- data/vendor/fssm/lib/fssm/version.rb +3 -0
- data/vendor/fssm/profile/prof-cache.rb +3 -3
- data/vendor/fssm/profile/prof-pathname-rubinius.rb +35 -0
- data/vendor/fssm/profile/prof-pathname.rb +7 -7
- data/vendor/fssm/spec/count_down_latch.rb +151 -0
- data/vendor/fssm/spec/monitor_spec.rb +202 -0
- data/vendor/fssm/spec/path_spec.rb +36 -15
- data/vendor/fssm/spec/spec_helper.rb +6 -6
- metadata +14 -4
- 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
|
7
|
-
@
|
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
|
-
|
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
|
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
|
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
|
-
|
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
|
38
|
-
previous =
|
44
|
+
base = FSSM::Pathname.for(base)
|
45
|
+
previous = cache_entries
|
39
46
|
snapshot(base)
|
40
|
-
current =
|
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.
|
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
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
38
|
-
|
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
|
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
|
87
|
+
key = key_segments(key)
|
88
88
|
node = self
|
89
89
|
|
90
90
|
until key.empty?
|
91
91
|
segment = key.shift
|
92
|
-
node
|
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
|
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.
|
@@ -5,7 +5,7 @@ require 'fssm'
|
|
5
5
|
require 'rubygems'
|
6
6
|
require 'ruby-prof'
|
7
7
|
|
8
|
-
$test_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
|
37
|
-
output
|
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
|
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
|
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
|
43
|
-
output
|
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
|
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
|
65
|
-
output
|
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
|