haml 3.1.3 → 3.1.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- data/Rakefile +42 -17
- data/VERSION +1 -1
- data/lib/haml/compiler.rb +3 -3
- data/lib/haml/helpers/action_view_mods.rb +4 -3
- data/lib/haml/template.rb +3 -1
- data/test/gemfiles/Gemfile.rails-2.0.x +8 -0
- data/test/gemfiles/Gemfile.rails-2.0.x.lock +38 -0
- data/test/gemfiles/Gemfile.rails-2.1.x +8 -0
- data/test/gemfiles/Gemfile.rails-2.1.x.lock +38 -0
- data/test/gemfiles/Gemfile.rails-2.2.x +8 -0
- data/test/gemfiles/Gemfile.rails-2.2.x.lock +38 -0
- data/test/gemfiles/Gemfile.rails-2.3.x +8 -0
- data/test/gemfiles/Gemfile.rails-2.3.x.lock +40 -0
- data/test/gemfiles/Gemfile.rails-3.0.x +8 -0
- data/test/gemfiles/Gemfile.rails-3.0.x.lock +85 -0
- data/test/gemfiles/Gemfile.rails-3.1.x +8 -0
- data/test/gemfiles/Gemfile.rails-3.1.x.lock +98 -0
- data/test/gemfiles/Gemfile.rails-xss-2.3.x +9 -0
- data/test/gemfiles/Gemfile.rails-xss-2.3.x.lock +42 -0
- data/test/haml/engine_test.rb +19 -0
- data/test/haml/html2haml_test.rb +1 -1
- data/test/haml/template_test.rb +20 -2
- data/test/haml/templates/partial_layout.haml +4 -1
- data/test/linked_rails.rb +4 -4
- data/vendor/sass/VERSION +1 -1
- data/vendor/sass/doc-src/SASS_CHANGELOG.md +115 -2
- data/vendor/sass/doc-src/SASS_REFERENCE.md +12 -4
- data/vendor/sass/lib/sass.rb +1 -0
- data/vendor/sass/lib/sass/cache_stores/base.rb +3 -1
- data/vendor/sass/lib/sass/cache_stores/filesystem.rb +2 -0
- data/vendor/sass/lib/sass/css.rb +2 -1
- data/vendor/sass/lib/sass/engine.rb +39 -23
- data/vendor/sass/lib/sass/environment.rb +11 -0
- data/vendor/sass/lib/sass/exec.rb +14 -1
- data/vendor/sass/lib/sass/importers/base.rb +2 -1
- data/vendor/sass/lib/sass/importers/filesystem.rb +18 -13
- data/vendor/sass/lib/sass/less.rb +2 -2
- data/vendor/sass/lib/sass/logger.rb +15 -0
- data/vendor/sass/lib/sass/logger/base.rb +32 -0
- data/vendor/sass/lib/sass/logger/log_level.rb +49 -0
- data/vendor/sass/lib/sass/plugin.rb +4 -8
- data/vendor/sass/lib/sass/plugin/compiler.rb +42 -17
- data/vendor/sass/lib/sass/plugin/configuration.rb +0 -2
- data/vendor/sass/lib/sass/railtie.rb +1 -1
- data/vendor/sass/lib/sass/script/funcall.rb +14 -1
- data/vendor/sass/lib/sass/script/functions.rb +44 -1
- data/vendor/sass/lib/sass/script/interpolation.rb +9 -0
- data/vendor/sass/lib/sass/script/lexer.rb +6 -1
- data/vendor/sass/lib/sass/script/list.rb +7 -0
- data/vendor/sass/lib/sass/script/literal.rb +5 -0
- data/vendor/sass/lib/sass/script/node.rb +8 -0
- data/vendor/sass/lib/sass/script/number.rb +28 -5
- data/vendor/sass/lib/sass/script/operation.rb +8 -0
- data/vendor/sass/lib/sass/script/parser.rb +12 -5
- data/vendor/sass/lib/sass/script/string_interpolation.rb +9 -0
- data/vendor/sass/lib/sass/script/unary_operation.rb +7 -0
- data/vendor/sass/lib/sass/script/variable.rb +5 -0
- data/vendor/sass/lib/sass/scss/parser.rb +78 -38
- data/vendor/sass/lib/sass/scss/rx.rb +2 -1
- data/vendor/sass/lib/sass/scss/static_parser.rb +2 -2
- data/vendor/sass/lib/sass/shared.rb +1 -1
- data/vendor/sass/lib/sass/tree/comment_node.rb +24 -11
- data/vendor/sass/lib/sass/tree/debug_node.rb +1 -1
- data/vendor/sass/lib/sass/tree/each_node.rb +1 -1
- data/vendor/sass/lib/sass/tree/extend_node.rb +1 -1
- data/vendor/sass/lib/sass/tree/for_node.rb +2 -2
- data/vendor/sass/lib/sass/tree/function_node.rb +1 -1
- data/vendor/sass/lib/sass/tree/if_node.rb +1 -14
- data/vendor/sass/lib/sass/tree/mixin_def_node.rb +1 -1
- data/vendor/sass/lib/sass/tree/mixin_node.rb +2 -2
- data/vendor/sass/lib/sass/tree/node.rb +2 -5
- data/vendor/sass/lib/sass/tree/prop_node.rb +2 -9
- data/vendor/sass/lib/sass/tree/return_node.rb +1 -1
- data/vendor/sass/lib/sass/tree/rule_node.rb +9 -2
- data/vendor/sass/lib/sass/tree/variable_node.rb +1 -1
- data/vendor/sass/lib/sass/tree/visitors/check_nesting.rb +17 -18
- data/vendor/sass/lib/sass/tree/visitors/convert.rb +10 -5
- data/vendor/sass/lib/sass/tree/visitors/deep_copy.rb +87 -0
- data/vendor/sass/lib/sass/tree/visitors/perform.rb +50 -19
- data/vendor/sass/lib/sass/tree/visitors/set_options.rb +97 -0
- data/vendor/sass/lib/sass/tree/visitors/to_css.rb +9 -15
- data/vendor/sass/lib/sass/tree/warn_node.rb +1 -1
- data/vendor/sass/lib/sass/tree/while_node.rb +1 -1
- data/vendor/sass/lib/sass/util.rb +58 -6
- data/vendor/sass/sass.gemspec +2 -1
- data/vendor/sass/test/Gemfile +4 -0
- data/vendor/sass/test/Gemfile.lock +19 -0
- data/vendor/sass/test/sass/cache_test.rb +15 -0
- data/vendor/sass/test/sass/conversion_test.rb +2 -6
- data/vendor/sass/test/sass/css2sass_test.rb +9 -0
- data/vendor/sass/test/sass/engine_test.rb +124 -26
- data/vendor/sass/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
- data/vendor/sass/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
- data/vendor/sass/test/sass/functions_test.rb +13 -0
- data/vendor/sass/test/sass/importer_test.rb +110 -0
- data/vendor/sass/test/sass/logger_test.rb +58 -0
- data/vendor/sass/test/sass/plugin_test.rb +16 -13
- data/vendor/sass/test/sass/script_conversion_test.rb +2 -0
- data/vendor/sass/test/sass/script_test.rb +18 -0
- data/vendor/sass/test/sass/scss/css_test.rb +7 -1
- data/vendor/sass/test/sass/scss/scss_test.rb +37 -13
- data/vendor/sass/test/sass/templates/bork5.sass +3 -0
- data/vendor/sass/test/sass/templates/nested_bork5.sass +2 -0
- data/vendor/sass/test/sass/test_helper.rb +1 -1
- data/vendor/sass/test/sass/util_test.rb +12 -0
- data/vendor/sass/vendor/fssm/Gemfile +3 -0
- data/vendor/sass/vendor/fssm/LICENSE +1 -1
- data/vendor/sass/vendor/fssm/README.markdown +55 -27
- data/vendor/sass/vendor/fssm/Rakefile +6 -54
- data/vendor/sass/vendor/fssm/example.rb +6 -3
- data/vendor/sass/vendor/fssm/fssm.gemspec +17 -70
- data/vendor/sass/vendor/fssm/lib/fssm.rb +7 -3
- data/vendor/sass/vendor/fssm/lib/fssm/backends/fsevents.rb +1 -1
- data/vendor/sass/vendor/fssm/lib/fssm/backends/inotify.rb +2 -2
- data/vendor/sass/vendor/fssm/lib/fssm/backends/polling.rb +2 -2
- data/vendor/sass/vendor/fssm/lib/fssm/backends/rbfsevent.rb +42 -0
- data/vendor/sass/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +10 -10
- data/vendor/sass/vendor/fssm/lib/fssm/monitor.rb +19 -9
- data/vendor/sass/vendor/fssm/lib/fssm/path.rb +24 -21
- data/vendor/sass/vendor/fssm/lib/fssm/pathname.rb +13 -479
- data/vendor/sass/vendor/fssm/lib/fssm/state/directory.rb +29 -11
- data/vendor/sass/vendor/fssm/lib/fssm/state/file.rb +1 -1
- data/vendor/sass/vendor/fssm/lib/fssm/support.rb +41 -12
- data/vendor/sass/vendor/fssm/lib/fssm/tree.rb +6 -6
- data/vendor/sass/vendor/fssm/lib/fssm/version.rb +3 -0
- data/vendor/sass/vendor/fssm/profile/prof-cache.rb +3 -3
- data/vendor/sass/vendor/fssm/profile/prof-pathname-rubinius.rb +35 -0
- data/vendor/sass/vendor/fssm/profile/prof-pathname.rb +7 -7
- data/vendor/sass/vendor/fssm/spec/count_down_latch.rb +151 -0
- data/vendor/sass/vendor/fssm/spec/monitor_spec.rb +202 -0
- data/vendor/sass/vendor/fssm/spec/path_spec.rb +36 -15
- data/vendor/sass/vendor/fssm/spec/spec_helper.rb +6 -6
- metadata +36 -5
- data/vendor/sass/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
|