comp_tree 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES CHANGED
@@ -1,6 +1,11 @@
1
1
 
2
2
  = CompTree ChangeLog
3
3
 
4
+ == Version 0.7.1
5
+
6
+ * rename README to README.rdoc for github display
7
+ * internal cleanup
8
+
4
9
  == Version 0.7.0
5
10
 
6
11
  * remove fork and discard_result options
@@ -54,7 +54,7 @@ function you define must explicitly depend on the data it uses.
54
54
  }
55
55
 
56
56
  Unless <em>offset</em> is really a constant, the result of
57
- <tt>driver.compute(:area, :num_threads => n)</tt> is not well-defined
57
+ <tt>driver.compute(:area, :threads => n)</tt> is not well-defined
58
58
  for _n_ > 1.
59
59
 
60
60
  Just as depending on some changeable state is bad, it is likewise bad
@@ -64,12 +64,12 @@ to affect a state (to produce a <em>side effect</em>).
64
64
  # BAD example: affecting state
65
65
  #
66
66
  driver.define(:area, :width, :height) { |width, height|
67
- ACCUMULATOR.add "more data"
67
+ accumulator.add "more data"
68
68
  width*height
69
69
  }
70
70
 
71
- Given a tree where nodes are modifying _ACCUMULATOR_, the end state of
72
- _ACCUMULATOR_ is not well-defined. Moreover if _ACCUMULATOR_ is not
71
+ Given a tree where nodes are modifying _accumulator_, the end state of
72
+ _accumulator_ is not well-defined. Moreover if _accumulator_ is not
73
73
  thread-safe, the result will be even worse.
74
74
 
75
75
  Note however it is OK affect a state as long as <em>no other function
@@ -80,7 +80,7 @@ depends on that state</em>. This is the principle under which
80
80
 
81
81
  % gem install comp_tree
82
82
 
83
- Or for the regular (non-gem) .tgz package,
83
+ Or for the (non-gem) .tgz package,
84
84
 
85
85
  % ruby install.rb [--uninstall]
86
86
 
data/comp_tree.gemspec CHANGED
@@ -6,11 +6,11 @@ Gem::Specification.new { |g|
6
6
  g.name = "comp_tree"
7
7
  g.rubyforge_project = "comptree"
8
8
  g.homepage = "comptree.rubyforge.org"
9
- g.version = "0.7.0"
9
+ g.version = "0.7.1"
10
10
  g.description =
11
11
  "Build a computation tree and execute it with N parallel threads."
12
12
 
13
- readme = "README"
13
+ readme = "README.rdoc"
14
14
 
15
15
  g.files = %W[
16
16
  CHANGES
@@ -19,14 +19,15 @@ Gem::Specification.new { |g|
19
19
  #{g.name}.gemspec
20
20
  install.rb
21
21
  ] + %w[lib rakelib test].inject(Array.new) { |acc, dir|
22
- acc + Dir[dir + "/**/*.rb"]
22
+ acc + Dir[dir + "/**/*.{rake,rb}"]
23
23
  }
24
24
  g.has_rdoc = true
25
25
  rdoc_files = [
26
26
  readme,
27
27
  "lib/comp_tree.rb",
28
28
  "lib/comp_tree/driver.rb",
29
- "lib/comp_tree/error.rb"
29
+ "lib/comp_tree/error.rb",
30
+ "lib/comp_tree/node.rb",
30
31
  ]
31
32
  g.extra_rdoc_files += [readme]
32
33
 
data/lib/comp_tree.rb CHANGED
@@ -25,19 +25,21 @@ require 'comp_tree/driver'
25
25
  #
26
26
  # CompTree -- Parallel Computation Tree.
27
27
  #
28
- # See README.
28
+ # See README.rdoc.
29
29
  #
30
30
  module CompTree
31
31
  class << self
32
32
  #
33
- # Build and run a new computation tree.
33
+ # :call-seq:
34
+ # build { |driver| ... }
34
35
  #
35
- # A Driver instance is passed to the given block.
36
+ # Build a new computation tree. A Driver instance is passed to the
37
+ # given block.
36
38
  #
37
39
  # Options hash:
38
40
  #
39
- # <tt>:node_class</tt> -- (Class) CompTree::Node subclass from
40
- # which nodes are created.
41
+ # <tt>:node_class</tt> -- CompTree::Node subclass from which nodes
42
+ # are created.
41
43
  #
42
44
  # Example:
43
45
  # CompTree.build do |driver|
@@ -1,6 +1,9 @@
1
1
 
2
2
  module CompTree
3
3
  module Algorithm
4
+ LEAVE = :__comp_tree_leave
5
+ AGAIN = :__comp_tree_again
6
+
4
7
  module_function
5
8
 
6
9
  def loop_with(leave, again)
@@ -13,13 +16,12 @@ module CompTree
13
16
  }
14
17
  end
15
18
 
16
- def compute_multithreaded(root, num_threads)
19
+ def compute_parallel(root, num_threads)
17
20
  #trace "Computing #{root.name} with #{num_threads} threads"
18
21
  finished = nil
19
22
  tree_mutex = Mutex.new
20
- node_finished_condition = ConditionVariable.new
21
- thread_wake_condition = ConditionVariable.new
22
- num_threads_in_use = 0
23
+ condition = ConditionVariable.new
24
+ num_threads_ready = 0
23
25
 
24
26
  threads = (0...num_threads).map { |thread_index|
25
27
  Thread.new {
@@ -28,17 +30,17 @@ module CompTree
28
30
  #
29
31
  tree_mutex.synchronize {
30
32
  #trace "Thread #{thread_index} waiting to start"
31
- num_threads_in_use += 1
32
- thread_wake_condition.wait(tree_mutex)
33
+ num_threads_ready += 1
34
+ condition.wait(tree_mutex)
33
35
  }
34
36
 
35
- loop_with(:leave, :again) {
37
+ loop_with(LEAVE, AGAIN) {
36
38
  node = tree_mutex.synchronize {
37
39
  #trace "Thread #{thread_index} acquired tree lock; begin search"
38
40
  if finished
39
41
  #trace "Thread #{thread_index} detected finish"
40
- num_threads_in_use -= 1
41
- throw :leave
42
+ num_threads_ready -= 1
43
+ throw LEAVE
42
44
  else
43
45
  #
44
46
  # Find a node. The node we obtain, if any, will be locked.
@@ -49,8 +51,8 @@ module CompTree
49
51
  node
50
52
  else
51
53
  #trace "Thread #{thread_index}: no node found; sleeping."
52
- thread_wake_condition.wait(tree_mutex)
53
- throw :again
54
+ condition.wait(tree_mutex)
55
+ throw AGAIN
54
56
  end
55
57
  end
56
58
  }
@@ -92,7 +94,7 @@ module CompTree
92
94
  #
93
95
  # Tell the main thread that another node was computed.
94
96
  #
95
- node_finished_condition.signal
97
+ condition.signal
96
98
  }
97
99
  }
98
100
  #trace "Thread #{thread_index} exiting"
@@ -100,15 +102,15 @@ module CompTree
100
102
  }
101
103
 
102
104
  #trace "Main: waiting for threads to launch and block."
103
- until tree_mutex.synchronize { num_threads_in_use == num_threads }
105
+ until tree_mutex.synchronize { num_threads_ready == num_threads }
104
106
  Thread.pass
105
107
  end
106
108
 
107
109
  tree_mutex.synchronize {
108
110
  #trace "Main: entering main loop"
109
- until num_threads_in_use == 0
111
+ until num_threads_ready == 0
110
112
  #trace "Main: waking threads"
111
- thread_wake_condition.broadcast
113
+ condition.broadcast
112
114
 
113
115
  if finished
114
116
  #trace "Main: detected finish."
@@ -116,21 +118,13 @@ module CompTree
116
118
  end
117
119
 
118
120
  #trace "Main: waiting for a node"
119
- node_finished_condition.wait(tree_mutex)
121
+ condition.wait(tree_mutex)
120
122
  #trace "Main: got a node"
121
123
  end
122
124
  }
123
125
 
124
126
  #trace "Main: waiting for threads to finish."
125
- loop_with(:leave, :again) {
126
- tree_mutex.synchronize {
127
- if threads.all? { |thread| thread.status == false }
128
- throw :leave
129
- end
130
- thread_wake_condition.broadcast
131
- }
132
- Thread.pass
133
- }
127
+ threads.each { |t| t.join }
134
128
 
135
129
  #trace "Main: computation done."
136
130
  if finished.is_a? Exception
@@ -14,21 +14,15 @@ module CompTree
14
14
  include Algorithm
15
15
 
16
16
  #
17
- # Build and run a new computation tree.
17
+ # See CompTree.build.
18
18
  #
19
- # Options hash:
20
- #
21
- # <tt>:node_class</tt> -- (Class) CompTree::Node subclass from
22
- # which nodes are created.
23
- #
24
- def initialize(opts = nil)
25
- @node_class = (
19
+ def initialize(opts = nil) #:nodoc:
20
+ @node_class =
26
21
  if opts and opts[:node_class]
27
22
  opts[:node_class]
28
23
  else
29
24
  Node
30
25
  end
31
- )
32
26
  @nodes = Hash.new
33
27
  end
34
28
 
@@ -38,13 +32,15 @@ module CompTree
38
32
  attr_reader :nodes
39
33
 
40
34
  #
41
- # Define a computation node.
35
+ # _name_ -- unique node identifier (for example a symbol).
42
36
  #
43
- # The first argument is the name of the node to define.
44
- # Subsequent arguments are the names of this node's children.
37
+ # _child_names_ -- unique node identifiers for children.
38
+ #
39
+ # Define a computation node.
45
40
  #
46
- # The values of the child nodes are passed to the block. The
47
- # block returns the result of this node.
41
+ # During a computation, the results of the child nodes are passed
42
+ # to the block. The block returns the result of this node's
43
+ # computation.
48
44
  #
49
45
  # In this example, a computation node named +area+ is defined
50
46
  # which depends on the nodes +width+ and +height+.
@@ -53,27 +49,18 @@ module CompTree
53
49
  # width*height
54
50
  # }
55
51
  #
56
- def define(*args, &block)
57
- parent_name = args.first
58
- children_names = args[1..-1]
59
-
60
- unless parent_name
61
- raise ArgumentError, "No name given for node"
62
- end
63
-
52
+ def define(name, *child_names, &block)
64
53
  #
65
54
  # retrieve or create parent and children
66
55
  #
67
- parent = @nodes[parent_name] || (
68
- @nodes[parent_name] = @node_class.new(parent_name)
69
- )
70
56
 
57
+ parent = @nodes[name] || (@nodes[name] = @node_class.new(name))
71
58
  if parent.function
72
59
  raise RedefinitionError, "Node `#{parent.name.inspect}' redefined."
73
60
  end
74
61
  parent.function = block
75
62
 
76
- children = children_names.map { |child_name|
63
+ children = child_names.map { |child_name|
77
64
  @nodes[child_name] || (
78
65
  @nodes[child_name] = @node_class.new(child_name)
79
66
  )
@@ -89,25 +76,21 @@ module CompTree
89
76
  end
90
77
 
91
78
  #
92
- # Mark this node and all its children as uncomputed.
79
+ # _name_ -- unique node identifier (for example a symbol).
93
80
  #
94
- # Arguments:
95
- #
96
- # +name+ -- unique node identifier (usually a symbol).
81
+ # Mark this node and all its children as uncomputed.
97
82
  #
98
83
  def reset(name)
99
84
  @nodes[name].reset
100
85
  end
101
86
 
87
+ #
88
+ # _name_ -- unique node identifier (for example a symbol).
102
89
  #
103
90
  # Check for a cyclic graph below the given node. If found,
104
91
  # returns the names of the nodes (in order) which form a loop.
105
92
  # Otherwise returns nil.
106
93
  #
107
- # Arguments:
108
- #
109
- # +name+ -- unique node identifier (usually a symbol).
110
- #
111
94
  def check_circular(name)
112
95
  helper = Proc.new { |root, chain|
113
96
  if chain.include? root
@@ -122,30 +105,27 @@ module CompTree
122
105
  end
123
106
 
124
107
  #
125
- # Compute this node.
108
+ # :call-seq:
109
+ # compute(name, threads)
110
+ # compute(name, :threads => threads)
126
111
  #
127
- # Arguments:
112
+ # _name_ -- unique node identifier (for example a symbol).
128
113
  #
129
- # +name+ -- unique node identifier (usually a symbol).
114
+ # _threads_ -- number of threads.
130
115
  #
131
- # +threads+ -- (Integer) number of threads.
116
+ # Compute this node, returning its result.
132
117
  #
133
- # compute(:volume, :threads => 4) syntax is also accepted.
118
+ # Any uncomputed children are computed first.
134
119
  #
135
120
  def compute(name, opts)
136
121
  threads = opts.is_a?(Hash) ? opts[:threads] : opts
137
122
  root = @nodes[name]
138
-
139
- if threads < 1
140
- raise ArgumentError, "threads is #{threads}"
141
- end
142
-
143
123
  if root.computed
144
124
  root.result
145
125
  elsif threads == 1
146
126
  root.result = root.compute_now
147
127
  else
148
- compute_multithreaded(root, threads)
128
+ compute_parallel(root, threads)
149
129
  end
150
130
  end
151
131
  end
@@ -3,20 +3,18 @@ module CompTree
3
3
  # Base class for CompTree errors.
4
4
  class Error < StandardError ; end
5
5
 
6
- # Internal error inside CompTree. Please send a bug report.
7
- class AssertionFailedError < Error ; end
8
-
9
- # Bad arguments were passed to a method.
10
- class ArgumentError < Error ; end
11
-
12
6
  #
13
7
  # Attempt to redefine a Node.
14
8
  #
15
9
  # If you wish to only replace the function, set
16
- # driver.nodes[name].function = some_new_lambda
10
+ # driver.nodes[name].function = lambda { ... }
17
11
  #
18
12
  class RedefinitionError < Error ; end
19
13
 
20
- # No function was defined for this node.
14
+ # Encountered a node without a function during a computation.
21
15
  class NoFunctionError < Error ; end
16
+
17
+ #debug {
18
+ # class AssertionFailedError < Error ; end
19
+ #}
22
20
  end
@@ -69,8 +69,8 @@ module CompTree
69
69
  end
70
70
 
71
71
  #
72
- # Force computation of all children; intended for
73
- # single-threaded mode.
72
+ # Force all children and self to be computed; no locking required.
73
+ # Intended to be used outside of parallel computations.
74
74
  #
75
75
  def compute_now #:nodoc:
76
76
  unless @children_results
@@ -0,0 +1,365 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+
3
+ require 'rake/gempackagetask'
4
+ require 'rake/contrib/sshpublisher'
5
+ require 'rake/clean'
6
+ require 'rdoc/rdoc'
7
+
8
+ require "jumpstart/simple_installer"
9
+ require "jumpstart/ruby"
10
+
11
+ ######################################################################
12
+ # constants
13
+
14
+ unless defined?(RUBYFORGE_USER)
15
+ RUBYFORGE_USER = "quix"
16
+ end
17
+
18
+ GEMSPEC = eval(File.read(Dir["*.gemspec"].last))
19
+
20
+ DOC_DIR = "documentation"
21
+ SPEC_FILES = Dir['spec/*_spec.rb'] + Dir['examples/*_example.rb']
22
+ TEST_FILES = Dir['test/test_*.rb']
23
+ RCOV_DIR = "coverage"
24
+ SPEC_OUTPUT = "spec.html"
25
+
26
+ RCOV_OPTIONS = Dir["*"].select { |file|
27
+ File.directory?(file) and file != "lib"
28
+ }.inject(Array.new) { |acc, file|
29
+ acc + ["--exclude", file + "/"]
30
+ }
31
+
32
+ ######################################################################
33
+ # spec
34
+
35
+ unless SPEC_FILES.empty?
36
+ require 'spec/rake/spectask'
37
+
38
+ desc "run specs"
39
+ Spec::Rake::SpecTask.new('spec') do |t|
40
+ t.spec_files = SPEC_FILES
41
+ end
42
+
43
+ desc "run specs with text output"
44
+ Spec::Rake::SpecTask.new('text_spec') do |t|
45
+ t.spec_files = SPEC_FILES
46
+ t.spec_opts = ['-fs']
47
+ end
48
+
49
+ desc "run specs with html output"
50
+ Spec::Rake::SpecTask.new('full_spec') do |t|
51
+ t.spec_files = SPEC_FILES
52
+ t.rcov = true
53
+ t.rcov_opts = RCOV_OPTIONS
54
+ t.spec_opts = ["-fh:#{SPEC_OUTPUT}"]
55
+ end
56
+
57
+ desc "run full_spec then open browser"
58
+ task :show_spec => :full_spec do
59
+ open_browser(SPEC_OUTPUT, RCOV_DIR + "/index.html")
60
+ end
61
+
62
+ desc "run specs individually"
63
+ task :spec_deps do
64
+ run_ruby_on_each(*SPEC_FILES)
65
+ end
66
+
67
+ task :prerelease => :spec_deps
68
+
69
+ task :default => :spec
70
+
71
+ CLEAN.include(SPEC_OUTPUT)
72
+ end
73
+
74
+ ######################################################################
75
+ # test
76
+
77
+ unless TEST_FILES.empty?
78
+ desc "run tests"
79
+ task :test do
80
+ TEST_FILES.each { |file|
81
+ require file
82
+ }
83
+ end
84
+
85
+ desc "run tests with rcov"
86
+ task :full_test do
87
+ previous = RakeFileUtils.verbose_flag
88
+ begin
89
+ sh("rcov", "-o", RCOV_DIR, *(TEST_FILES + RCOV_OPTIONS))
90
+ ensure
91
+ RakeFileUtils.verbose_flag = previous
92
+ end
93
+ end
94
+
95
+ desc "run full_test then open browser"
96
+ task :show_test => :full_test do
97
+ open_browser(RCOV_DIR + "/index.html")
98
+ end
99
+
100
+ desc "run tests individually"
101
+ task :test_deps do
102
+ run_ruby_on_each(*TEST_FILES)
103
+ end
104
+
105
+ task :prerelease => :test_deps
106
+ task :default => :test
107
+
108
+ CLEAN.include RCOV_DIR
109
+ end
110
+
111
+ ######################################################################
112
+ # clean
113
+
114
+ task :clean do
115
+ Rake::Task[:clobber].invoke
116
+ end
117
+
118
+ ######################################################################
119
+ # package
120
+
121
+ task :package => :clean
122
+ task :gem => :clean
123
+
124
+ Rake::GemPackageTask.new(GEMSPEC) { |t|
125
+ t.need_tar = true
126
+ }
127
+
128
+ ######################################################################
129
+ # doc
130
+
131
+ #
132
+ # Try to mimic the gem documentation
133
+ #
134
+ desc "run rdoc"
135
+ task :doc => :clean_doc do
136
+ args = (
137
+ GEMSPEC.rdoc_options +
138
+ GEMSPEC.require_paths.clone +
139
+ GEMSPEC.extra_rdoc_files +
140
+ ["-o", DOC_DIR]
141
+ ).flatten.map { |t| t.to_s }
142
+ RDoc::RDoc.new.document args
143
+ end
144
+
145
+ task :clean_doc do
146
+ # normally rm_rf, but mimic rake/clean
147
+ rm_r(DOC_DIR) rescue nil
148
+ end
149
+
150
+ desc "run rdoc then open browser"
151
+ task :show_doc => :doc do
152
+ open_browser(DOC_DIR + "/index.html")
153
+ end
154
+
155
+ task :rdoc => :doc
156
+ task :clean => :clean_doc
157
+
158
+ ######################################################################
159
+ # publisher
160
+
161
+ desc "upload docs"
162
+ task :publish => [:clean_doc, :doc] do
163
+ Rake::SshDirPublisher.new(
164
+ "#{RUBYFORGE_USER}@rubyforge.org",
165
+ "/var/www/gforge-projects/#{GEMSPEC.rubyforge_project}",
166
+ DOC_DIR
167
+ ).upload
168
+ end
169
+
170
+ ######################################################################
171
+ # install/uninstall
172
+
173
+ desc "direct install (no gem)"
174
+ task :install do
175
+ Jumpstart::SimpleInstaller.new.run([])
176
+ end
177
+
178
+ desc "direct uninstall (no gem)"
179
+ task :uninstall do
180
+ Jumpstart::SimpleInstaller.new.run(["--uninstall"])
181
+ end
182
+
183
+ ######################################################################
184
+ # debug
185
+
186
+ def comment_src_dst(on)
187
+ on ? ["", "#"] : ["#", ""]
188
+ end
189
+
190
+ def comment_regions(on, contents, start)
191
+ src, dst = comment_src_dst(on)
192
+ contents.gsub(%r!^(\s+)#{src}#{start}.*?^\1#{src}(\}|end)!m) { |chunk|
193
+ indent = $1
194
+ chunk.gsub(%r!^#{indent}#{src}!, "#{indent}#{dst}")
195
+ }
196
+ end
197
+
198
+ def comment_lines(on, contents, start)
199
+ src, dst = comment_src_dst(on)
200
+ contents.gsub(%r!^(\s*)#{src}#{start}!) {
201
+ $1 + dst + start
202
+ }
203
+ end
204
+
205
+ def debug_info(enable)
206
+ Find.find("lib", "test") { |path|
207
+ if path =~ %r!\.rb\Z!
208
+ replace_file(path) { |contents|
209
+ result1 = comment_regions(!enable, contents, "def trace_")
210
+ result2 = comment_regions(!enable, result1, "debug")
211
+ comment_lines(!enable, result2, "trace")
212
+ }
213
+ end
214
+ }
215
+ end
216
+
217
+ desc "enable debug and trace calls"
218
+ task :debug_on do
219
+ debug_info(true)
220
+ end
221
+
222
+ desc "disable debug and trace calls"
223
+ task :debug_off do
224
+ debug_info(false)
225
+ end
226
+
227
+ ######################################################################
228
+ # check columns
229
+
230
+ desc "check for columns > 80"
231
+ task :check_columns do
232
+ Dir["**/*.rb"].each { |file|
233
+ File.read(file).scan(%r!^.{81}!) { |match|
234
+ unless match =~ %r!http://!
235
+ raise "#{file} greater than 80 columns"
236
+ end
237
+ }
238
+ }
239
+ end
240
+
241
+ task :prerelease => :check_columns
242
+
243
+ ######################################################################
244
+ # comments
245
+
246
+ task :comments do
247
+ write_file("comments") {
248
+ Array.new.tap { |result|
249
+ (["Rakefile"] + Dir["**/*.{rb,rake}"]).each { |file|
250
+ File.read(file).scan(%r!\#[^\{].*$!) { |match|
251
+ result << match
252
+ }
253
+ }
254
+ }.join("\n")
255
+ }
256
+ end
257
+
258
+ ######################################################################
259
+ # release
260
+
261
+ def git(*args)
262
+ sh("git", *args)
263
+ end
264
+
265
+ task :prerelease => :clean do
266
+ unless `git status` =~ %r!nothing to commit \(working directory clean\)!
267
+ raise "Directory not clean"
268
+ end
269
+ %w[github.com rubyforge.org].each { |server|
270
+ cmd = "ping " + (
271
+ if Config::CONFIG["host"] =~ %r!darwin!
272
+ "-c2 #{server}"
273
+ else
274
+ "#{server} 2 2"
275
+ end
276
+ )
277
+ unless `#{cmd}` =~ %r!0% packet loss!
278
+ raise "No ping for #{server}"
279
+ end
280
+ }
281
+ end
282
+
283
+ def rubyforge(command, file)
284
+ sh(
285
+ "rubyforge",
286
+ command,
287
+ GEMSPEC.rubyforge_project,
288
+ GEMSPEC.rubyforge_project,
289
+ GEMSPEC.version.to_s,
290
+ file
291
+ )
292
+ end
293
+
294
+ task :finish_release do
295
+ gem, tgz = %w(gem tgz).map { |ext|
296
+ "pkg/#{GEMSPEC.name}-#{GEMSPEC.version}.#{ext}"
297
+ }
298
+
299
+ gem_md5, tgz_md5 = [gem, tgz].map { |file|
300
+ "#{file}.md5".tap { |md5|
301
+ sh("md5sum #{file} > #{md5}")
302
+ }
303
+ }
304
+
305
+ rubyforge("add_release", gem)
306
+ [gem_md5, tgz, tgz_md5].each { |file|
307
+ rubyforge("add_file", file)
308
+ }
309
+
310
+ git("tag", "#{GEMSPEC.name}-" + GEMSPEC.version.to_s)
311
+ git(*%w(push --tags origin master))
312
+ end
313
+
314
+ task :release =>
315
+ [
316
+ :prerelease,
317
+ :package,
318
+ :publish,
319
+ :finish_release,
320
+ ]
321
+
322
+ ######################################################################
323
+ # util
324
+
325
+ def open_browser(*files)
326
+ if Config::CONFIG["host"] =~ %r!darwin!
327
+ sh("open", "/Applications/Firefox.app", *files)
328
+ else
329
+ sh("firefox", *files)
330
+ end
331
+ end
332
+
333
+ unless respond_to? :tap
334
+ class Object
335
+ def tap
336
+ yield self
337
+ self
338
+ end
339
+ end
340
+ end
341
+
342
+ def replace_file(file)
343
+ old_contents = File.read(file)
344
+ yield(old_contents).tap { |new_contents|
345
+ if old_contents != new_contents
346
+ File.open(file, "wb") { |output|
347
+ output.print(new_contents)
348
+ }
349
+ end
350
+ }
351
+ end
352
+
353
+ def write_file(file)
354
+ yield.tap { |contents|
355
+ File.open(file, "wb") { |out|
356
+ out.print(contents)
357
+ }
358
+ }
359
+ end
360
+
361
+ def run_ruby_on_each(*files)
362
+ files.each { |file|
363
+ Jumpstart::Ruby.run_or_raise("-w", file)
364
+ }
365
+ end
data/test/test_basic.rb CHANGED
@@ -51,7 +51,7 @@ class TestBasic < Test::Unit::TestCase
51
51
 
52
52
  def test_malformed
53
53
  CompTree.build { |driver|
54
- assert_raise(CompTree::ArgumentError) {
54
+ assert_raise(ArgumentError) {
55
55
  driver.define {
56
56
  }
57
57
  }
@@ -61,16 +61,6 @@ class TestBasic < Test::Unit::TestCase
61
61
  driver.define(:a) {
62
62
  }
63
63
  }
64
- assert_raise(CompTree::ArgumentError) {
65
- driver.define(:b) {
66
- }
67
- driver.compute(:b, 0)
68
- }
69
- assert_raise(CompTree::ArgumentError) {
70
- driver.define(:c) {
71
- }
72
- driver.compute(:c, -1)
73
- }
74
64
  }
75
65
  end
76
66
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: comp_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - James M. Lawrence
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-09 00:00:00 -04:00
12
+ date: 2009-04-12 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -20,10 +20,10 @@ executables: []
20
20
  extensions: []
21
21
 
22
22
  extra_rdoc_files:
23
- - README
23
+ - README.rdoc
24
24
  files:
25
25
  - CHANGES
26
- - README
26
+ - README.rdoc
27
27
  - Rakefile
28
28
  - comp_tree.gemspec
29
29
  - install.rb
@@ -32,6 +32,7 @@ files:
32
32
  - lib/comp_tree/error.rb
33
33
  - lib/comp_tree/node.rb
34
34
  - lib/comp_tree.rb
35
+ - rakelib/jumpstart.rake
35
36
  - rakelib/jumpstart/ruby.rb
36
37
  - rakelib/jumpstart/simple_installer.rb
37
38
  - test/common.rb
@@ -47,7 +48,7 @@ homepage: comptree.rubyforge.org
47
48
  post_install_message:
48
49
  rdoc_options:
49
50
  - --main
50
- - README
51
+ - README.rdoc
51
52
  - --title
52
53
  - "comp_tree: Parallel Computation Tree"
53
54
  - --exclude
@@ -61,7 +62,7 @@ rdoc_options:
61
62
  - --exclude
62
63
  - lib/comp_tree/algorithm.rb
63
64
  - --exclude
64
- - lib/comp_tree/node.rb
65
+ - rakelib/jumpstart.rake
65
66
  - --exclude
66
67
  - rakelib/jumpstart/ruby.rb
67
68
  - --exclude