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.

Files changed (134) hide show
  1. data/Rakefile +42 -17
  2. data/VERSION +1 -1
  3. data/lib/haml/compiler.rb +3 -3
  4. data/lib/haml/helpers/action_view_mods.rb +4 -3
  5. data/lib/haml/template.rb +3 -1
  6. data/test/gemfiles/Gemfile.rails-2.0.x +8 -0
  7. data/test/gemfiles/Gemfile.rails-2.0.x.lock +38 -0
  8. data/test/gemfiles/Gemfile.rails-2.1.x +8 -0
  9. data/test/gemfiles/Gemfile.rails-2.1.x.lock +38 -0
  10. data/test/gemfiles/Gemfile.rails-2.2.x +8 -0
  11. data/test/gemfiles/Gemfile.rails-2.2.x.lock +38 -0
  12. data/test/gemfiles/Gemfile.rails-2.3.x +8 -0
  13. data/test/gemfiles/Gemfile.rails-2.3.x.lock +40 -0
  14. data/test/gemfiles/Gemfile.rails-3.0.x +8 -0
  15. data/test/gemfiles/Gemfile.rails-3.0.x.lock +85 -0
  16. data/test/gemfiles/Gemfile.rails-3.1.x +8 -0
  17. data/test/gemfiles/Gemfile.rails-3.1.x.lock +98 -0
  18. data/test/gemfiles/Gemfile.rails-xss-2.3.x +9 -0
  19. data/test/gemfiles/Gemfile.rails-xss-2.3.x.lock +42 -0
  20. data/test/haml/engine_test.rb +19 -0
  21. data/test/haml/html2haml_test.rb +1 -1
  22. data/test/haml/template_test.rb +20 -2
  23. data/test/haml/templates/partial_layout.haml +4 -1
  24. data/test/linked_rails.rb +4 -4
  25. data/vendor/sass/VERSION +1 -1
  26. data/vendor/sass/doc-src/SASS_CHANGELOG.md +115 -2
  27. data/vendor/sass/doc-src/SASS_REFERENCE.md +12 -4
  28. data/vendor/sass/lib/sass.rb +1 -0
  29. data/vendor/sass/lib/sass/cache_stores/base.rb +3 -1
  30. data/vendor/sass/lib/sass/cache_stores/filesystem.rb +2 -0
  31. data/vendor/sass/lib/sass/css.rb +2 -1
  32. data/vendor/sass/lib/sass/engine.rb +39 -23
  33. data/vendor/sass/lib/sass/environment.rb +11 -0
  34. data/vendor/sass/lib/sass/exec.rb +14 -1
  35. data/vendor/sass/lib/sass/importers/base.rb +2 -1
  36. data/vendor/sass/lib/sass/importers/filesystem.rb +18 -13
  37. data/vendor/sass/lib/sass/less.rb +2 -2
  38. data/vendor/sass/lib/sass/logger.rb +15 -0
  39. data/vendor/sass/lib/sass/logger/base.rb +32 -0
  40. data/vendor/sass/lib/sass/logger/log_level.rb +49 -0
  41. data/vendor/sass/lib/sass/plugin.rb +4 -8
  42. data/vendor/sass/lib/sass/plugin/compiler.rb +42 -17
  43. data/vendor/sass/lib/sass/plugin/configuration.rb +0 -2
  44. data/vendor/sass/lib/sass/railtie.rb +1 -1
  45. data/vendor/sass/lib/sass/script/funcall.rb +14 -1
  46. data/vendor/sass/lib/sass/script/functions.rb +44 -1
  47. data/vendor/sass/lib/sass/script/interpolation.rb +9 -0
  48. data/vendor/sass/lib/sass/script/lexer.rb +6 -1
  49. data/vendor/sass/lib/sass/script/list.rb +7 -0
  50. data/vendor/sass/lib/sass/script/literal.rb +5 -0
  51. data/vendor/sass/lib/sass/script/node.rb +8 -0
  52. data/vendor/sass/lib/sass/script/number.rb +28 -5
  53. data/vendor/sass/lib/sass/script/operation.rb +8 -0
  54. data/vendor/sass/lib/sass/script/parser.rb +12 -5
  55. data/vendor/sass/lib/sass/script/string_interpolation.rb +9 -0
  56. data/vendor/sass/lib/sass/script/unary_operation.rb +7 -0
  57. data/vendor/sass/lib/sass/script/variable.rb +5 -0
  58. data/vendor/sass/lib/sass/scss/parser.rb +78 -38
  59. data/vendor/sass/lib/sass/scss/rx.rb +2 -1
  60. data/vendor/sass/lib/sass/scss/static_parser.rb +2 -2
  61. data/vendor/sass/lib/sass/shared.rb +1 -1
  62. data/vendor/sass/lib/sass/tree/comment_node.rb +24 -11
  63. data/vendor/sass/lib/sass/tree/debug_node.rb +1 -1
  64. data/vendor/sass/lib/sass/tree/each_node.rb +1 -1
  65. data/vendor/sass/lib/sass/tree/extend_node.rb +1 -1
  66. data/vendor/sass/lib/sass/tree/for_node.rb +2 -2
  67. data/vendor/sass/lib/sass/tree/function_node.rb +1 -1
  68. data/vendor/sass/lib/sass/tree/if_node.rb +1 -14
  69. data/vendor/sass/lib/sass/tree/mixin_def_node.rb +1 -1
  70. data/vendor/sass/lib/sass/tree/mixin_node.rb +2 -2
  71. data/vendor/sass/lib/sass/tree/node.rb +2 -5
  72. data/vendor/sass/lib/sass/tree/prop_node.rb +2 -9
  73. data/vendor/sass/lib/sass/tree/return_node.rb +1 -1
  74. data/vendor/sass/lib/sass/tree/rule_node.rb +9 -2
  75. data/vendor/sass/lib/sass/tree/variable_node.rb +1 -1
  76. data/vendor/sass/lib/sass/tree/visitors/check_nesting.rb +17 -18
  77. data/vendor/sass/lib/sass/tree/visitors/convert.rb +10 -5
  78. data/vendor/sass/lib/sass/tree/visitors/deep_copy.rb +87 -0
  79. data/vendor/sass/lib/sass/tree/visitors/perform.rb +50 -19
  80. data/vendor/sass/lib/sass/tree/visitors/set_options.rb +97 -0
  81. data/vendor/sass/lib/sass/tree/visitors/to_css.rb +9 -15
  82. data/vendor/sass/lib/sass/tree/warn_node.rb +1 -1
  83. data/vendor/sass/lib/sass/tree/while_node.rb +1 -1
  84. data/vendor/sass/lib/sass/util.rb +58 -6
  85. data/vendor/sass/sass.gemspec +2 -1
  86. data/vendor/sass/test/Gemfile +4 -0
  87. data/vendor/sass/test/Gemfile.lock +19 -0
  88. data/vendor/sass/test/sass/cache_test.rb +15 -0
  89. data/vendor/sass/test/sass/conversion_test.rb +2 -6
  90. data/vendor/sass/test/sass/css2sass_test.rb +9 -0
  91. data/vendor/sass/test/sass/engine_test.rb +124 -26
  92. data/vendor/sass/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  93. data/vendor/sass/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  94. data/vendor/sass/test/sass/functions_test.rb +13 -0
  95. data/vendor/sass/test/sass/importer_test.rb +110 -0
  96. data/vendor/sass/test/sass/logger_test.rb +58 -0
  97. data/vendor/sass/test/sass/plugin_test.rb +16 -13
  98. data/vendor/sass/test/sass/script_conversion_test.rb +2 -0
  99. data/vendor/sass/test/sass/script_test.rb +18 -0
  100. data/vendor/sass/test/sass/scss/css_test.rb +7 -1
  101. data/vendor/sass/test/sass/scss/scss_test.rb +37 -13
  102. data/vendor/sass/test/sass/templates/bork5.sass +3 -0
  103. data/vendor/sass/test/sass/templates/nested_bork5.sass +2 -0
  104. data/vendor/sass/test/sass/test_helper.rb +1 -1
  105. data/vendor/sass/test/sass/util_test.rb +12 -0
  106. data/vendor/sass/vendor/fssm/Gemfile +3 -0
  107. data/vendor/sass/vendor/fssm/LICENSE +1 -1
  108. data/vendor/sass/vendor/fssm/README.markdown +55 -27
  109. data/vendor/sass/vendor/fssm/Rakefile +6 -54
  110. data/vendor/sass/vendor/fssm/example.rb +6 -3
  111. data/vendor/sass/vendor/fssm/fssm.gemspec +17 -70
  112. data/vendor/sass/vendor/fssm/lib/fssm.rb +7 -3
  113. data/vendor/sass/vendor/fssm/lib/fssm/backends/fsevents.rb +1 -1
  114. data/vendor/sass/vendor/fssm/lib/fssm/backends/inotify.rb +2 -2
  115. data/vendor/sass/vendor/fssm/lib/fssm/backends/polling.rb +2 -2
  116. data/vendor/sass/vendor/fssm/lib/fssm/backends/rbfsevent.rb +42 -0
  117. data/vendor/sass/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +10 -10
  118. data/vendor/sass/vendor/fssm/lib/fssm/monitor.rb +19 -9
  119. data/vendor/sass/vendor/fssm/lib/fssm/path.rb +24 -21
  120. data/vendor/sass/vendor/fssm/lib/fssm/pathname.rb +13 -479
  121. data/vendor/sass/vendor/fssm/lib/fssm/state/directory.rb +29 -11
  122. data/vendor/sass/vendor/fssm/lib/fssm/state/file.rb +1 -1
  123. data/vendor/sass/vendor/fssm/lib/fssm/support.rb +41 -12
  124. data/vendor/sass/vendor/fssm/lib/fssm/tree.rb +6 -6
  125. data/vendor/sass/vendor/fssm/lib/fssm/version.rb +3 -0
  126. data/vendor/sass/vendor/fssm/profile/prof-cache.rb +3 -3
  127. data/vendor/sass/vendor/fssm/profile/prof-pathname-rubinius.rb +35 -0
  128. data/vendor/sass/vendor/fssm/profile/prof-pathname.rb +7 -7
  129. data/vendor/sass/vendor/fssm/spec/count_down_latch.rb +151 -0
  130. data/vendor/sass/vendor/fssm/spec/monitor_spec.rb +202 -0
  131. data/vendor/sass/vendor/fssm/spec/path_spec.rb +36 -15
  132. data/vendor/sass/vendor/fssm/spec/spec_helper.rb +6 -6
  133. metadata +36 -5
  134. 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 = 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