comp_tree 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.rdoc CHANGED
@@ -1,6 +1,11 @@
1
1
 
2
2
  = CompTree ChangeLog
3
3
 
4
+ == Version 0.7.6
5
+
6
+ * Driver#define returns created node
7
+ * Raise CompTree::ArgumentError for nonexistent node or threads < 1
8
+
4
9
  == Version 0.7.5
5
10
 
6
11
  * fix manual install
data/MANIFEST ADDED
@@ -0,0 +1,26 @@
1
+ CHANGES.rdoc
2
+ MANIFEST
3
+ README.rdoc
4
+ Rakefile
5
+ devel/jumpstart.rb
6
+ devel/jumpstart/lazy_attribute.rb
7
+ devel/jumpstart/ruby.rb
8
+ devel/jumpstart/simple_installer.rb
9
+ install.rb
10
+ lib/comp_tree.rb
11
+ lib/comp_tree/algorithm.rb
12
+ lib/comp_tree/driver.rb
13
+ lib/comp_tree/error.rb
14
+ lib/comp_tree/node.rb
15
+ lib/comp_tree/queue.rb
16
+ lib/comp_tree/queue_new.rb
17
+ lib/comp_tree/queue_old.rb
18
+ test/common.rb
19
+ test/test_basic.rb
20
+ test/test_circular.rb
21
+ test/test_drain.rb
22
+ test/test_exception.rb
23
+ test/test_flood.rb
24
+ test/test_grind.rb
25
+ test/test_sequential.rb
26
+ test/test_throw.rb
data/devel/jumpstart.rb CHANGED
@@ -1 +1,634 @@
1
- require 'jumpstart/jumpstart'
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ $LOAD_PATH.unshift File.dirname(__FILE__)
3
+
4
+ require 'rubygems'
5
+ require 'ostruct'
6
+ require 'rbconfig'
7
+
8
+ require 'rake/gempackagetask'
9
+ require 'rake/contrib/sshpublisher'
10
+ require 'rake/clean'
11
+
12
+ require 'rdoc/rdoc'
13
+
14
+ require 'jumpstart/ruby'
15
+ require 'jumpstart/lazy_attribute'
16
+ require 'jumpstart/simple_installer'
17
+
18
+ class Jumpstart
19
+ include LazyAttribute
20
+
21
+ def initialize(project_name)
22
+ attribute :name do
23
+ project_name
24
+ end
25
+
26
+ attribute :version do
27
+ const = "VERSION"
28
+ begin
29
+ require name
30
+ if mod = Object.const_get(to_camel_case(name))
31
+ candidates = mod.constants.grep(%r!#{const}!)
32
+ result = (
33
+ if candidates.size == 1
34
+ candidates.first
35
+ elsif candidates.include? const
36
+ const
37
+ else
38
+ raise
39
+ end
40
+ )
41
+ mod.const_get(result)
42
+ else
43
+ raise
44
+ end
45
+ rescue Exception
46
+ "0.0.0"
47
+ end
48
+ end
49
+
50
+ attribute :rubyforge_name do
51
+ name.gsub('_', '')
52
+ end
53
+
54
+ attribute :rubyforge_user do
55
+ email.first[%r!^.*(?=@)!]
56
+ end
57
+
58
+ attribute :readme_file do
59
+ "README.rdoc"
60
+ end
61
+
62
+ attribute :history_file do
63
+ "CHANGES.rdoc"
64
+ end
65
+
66
+ attribute :doc_dir do
67
+ "documentation"
68
+ end
69
+
70
+ attribute :spec_files do
71
+ Dir["spec/*_{spec,example}.rb"]
72
+ end
73
+
74
+ attribute :test_files do
75
+ Dir["test/test_*.rb"]
76
+ end
77
+
78
+ attribute :rcov_dir do
79
+ "coverage"
80
+ end
81
+
82
+ attribute :spec_output do
83
+ "spec.html"
84
+ end
85
+
86
+ %w[gem tgz].map { |ext|
87
+ attribute ext.to_sym do
88
+ "pkg/#{name}-#{version}.#{ext}"
89
+ end
90
+ }
91
+
92
+ attribute :rcov_options do
93
+ # workaround for the default rspec task
94
+ Dir["*"].select { |f| File.directory? f }.inject(Array.new) { |acc, dir|
95
+ if dir == "lib"
96
+ acc
97
+ else
98
+ acc + ["--exclude", dir + "/"]
99
+ end
100
+ } + ["--text-report"]
101
+ end
102
+
103
+ attribute :readme_file do
104
+ "README.rdoc"
105
+ end
106
+
107
+ attribute :manifest_file do
108
+ "MANIFEST"
109
+ end
110
+
111
+ attribute :files do
112
+ if File.exist?(manifest_file)
113
+ File.read(manifest_file).split("\n")
114
+ else
115
+ [manifest_file] + `git ls-files`.split("\n")
116
+ end
117
+ end
118
+
119
+ attribute :rdoc_files do
120
+ Dir["lib/**/*.rb"]
121
+ end
122
+
123
+ attribute :extra_rdoc_files do
124
+ if File.exist?(readme_file)
125
+ [readme_file]
126
+ else
127
+ []
128
+ end
129
+ end
130
+
131
+ attribute :rdoc_options do
132
+ if File.exist?(readme_file)
133
+ ["--main", readme_file]
134
+ else
135
+ []
136
+ end + [
137
+ "--title", "#{name}: #{summary}",
138
+ ] + (files - rdoc_files).inject(Array.new) { |acc, file|
139
+ acc + ["--exclude", file]
140
+ }
141
+ end
142
+
143
+ attribute :browser do
144
+ if Config::CONFIG["host"] =~ %r!darwin!
145
+ app = %w[Firefox Safari].map { |t|
146
+ "/Applications/#{t}.app"
147
+ }.select { |t|
148
+ File.exist? t
149
+ }.first
150
+ if app
151
+ ["open", app]
152
+ else
153
+ raise "need to set `browser'"
154
+ end
155
+ else
156
+ "firefox"
157
+ end
158
+ end
159
+
160
+ attribute :gemspec do
161
+ Gem::Specification.new { |g|
162
+ g.has_rdoc = true
163
+ %w[
164
+ name
165
+ authors
166
+ email
167
+ summary
168
+ version
169
+ description
170
+ files
171
+ extra_rdoc_files
172
+ rdoc_options
173
+ ].each { |param|
174
+ value = send(param) and (
175
+ g.send("#{param}=", value)
176
+ )
177
+ }
178
+
179
+ if rubyforge_name
180
+ g.rubyforge_project = rubyforge_name
181
+ end
182
+
183
+ if url
184
+ g.homepage = url
185
+ end
186
+
187
+ extra_deps.each { |dep|
188
+ g.add_dependency(*dep)
189
+ }
190
+
191
+ extra_dev_deps.each { |dep|
192
+ g.add_development_dependency(*dep)
193
+ }
194
+ }
195
+ end
196
+
197
+ attribute :readme_contents do
198
+ File.read(readme_file) rescue "FIXME: readme_file"
199
+ end
200
+
201
+ attribute :sections do
202
+ begin
203
+ pairs = Hash[*readme_contents.split(%r!^== (\w+).*?$!)[1..-1]].map {
204
+ |section, contents|
205
+ [section.downcase, contents.strip]
206
+ }
207
+ Hash[*pairs.flatten]
208
+ rescue
209
+ nil
210
+ end
211
+ end
212
+
213
+ attribute :description_section do
214
+ "description"
215
+ end
216
+
217
+ attribute :summary_section do
218
+ "summary"
219
+ end
220
+
221
+ attribute :description_sentences do
222
+ 1
223
+ end
224
+
225
+ attribute :summary_sentences do
226
+ 1
227
+ end
228
+
229
+ [:summary, :description].each { |section|
230
+ attribute section do
231
+ begin
232
+ sections[send("#{section}_section")].
233
+ gsub("\n", " ").
234
+ split(%r!\.\s*!m).
235
+ first(send("#{section}_sentences")).
236
+ join(". ") << "."
237
+ rescue
238
+ "FIXME: #{section}"
239
+ end
240
+ end
241
+ }
242
+
243
+ attribute :url do
244
+ begin
245
+ readme_contents.match(%r!^\*.*?(http://\S+)!)[1]
246
+ rescue
247
+ "http://#{rubyforge_name}.rubyforge.org"
248
+ end
249
+ end
250
+
251
+ attribute :extra_deps do
252
+ []
253
+ end
254
+
255
+ attribute :extra_dev_deps do
256
+ []
257
+ end
258
+
259
+ yield self
260
+
261
+ self.class.instance_methods(false).select { |t|
262
+ t.to_s =~ %r!\Adefine_!
263
+ }.each { |method_name|
264
+ send(method_name)
265
+ }
266
+ end
267
+
268
+ def developer(name, email)
269
+ authors << name
270
+ self.email << email
271
+ end
272
+
273
+ def authors
274
+ @authors ||= Array.new
275
+ end
276
+
277
+ def email
278
+ @email ||= Array.new
279
+ end
280
+
281
+ def dependency(name, version)
282
+ extra_deps << [name, version]
283
+ end
284
+
285
+ def define_clean
286
+ task :clean do
287
+ Rake::Task[:clobber].invoke
288
+ end
289
+ end
290
+
291
+ def define_package
292
+ task manifest_file do
293
+ create_manifest
294
+ end
295
+ CLEAN.include manifest_file
296
+ task :package => :clean
297
+ Rake::GemPackageTask.new(gemspec) { |t|
298
+ t.need_tar = true
299
+ }
300
+ end
301
+
302
+ def define_spec
303
+ unless spec_files.empty?
304
+ require 'spec/rake/spectask'
305
+
306
+ desc "run specs"
307
+ Spec::Rake::SpecTask.new('spec') do |t|
308
+ t.spec_files = spec_files
309
+ end
310
+
311
+ desc "run specs with text output"
312
+ Spec::Rake::SpecTask.new('text_spec') do |t|
313
+ t.spec_files = spec_files
314
+ t.spec_opts = ['-fs']
315
+ end
316
+
317
+ desc "run specs with html output"
318
+ Spec::Rake::SpecTask.new('full_spec') do |t|
319
+ t.spec_files = spec_files
320
+ t.rcov = true
321
+ t.rcov_opts = rcov_options
322
+ t.spec_opts = ["-fh:#{spec_output}"]
323
+ end
324
+
325
+ desc "run full_spec then open browser"
326
+ task :show_spec => :full_spec do
327
+ open_browser(spec_output, rcov_dir + "/index.html")
328
+ end
329
+
330
+ desc "run specs individually"
331
+ task :spec_deps do
332
+ run_ruby_on_each(*spec_files)
333
+ end
334
+
335
+ task :prerelease => [:spec, :spec_deps]
336
+ task :default => :spec
337
+
338
+ CLEAN.include spec_output
339
+ end
340
+ end
341
+
342
+ def define_test
343
+ unless test_files.empty?
344
+ desc "run tests"
345
+ task :test do
346
+ test_files.each { |file|
347
+ require file
348
+ }
349
+ end
350
+
351
+ desc "run tests with rcov"
352
+ task :full_test do
353
+ verbose(false) {
354
+ sh("rcov", "-o", rcov_dir, "--text-report",
355
+ *(test_files + rcov_options)
356
+ )
357
+ }
358
+ end
359
+
360
+ desc "run full_test then open browser"
361
+ task :show_test => :full_test do
362
+ open_browser(rcov_dir + "/index.html")
363
+ end
364
+
365
+ desc "run tests individually"
366
+ task :test_deps do
367
+ run_ruby_on_each(*test_files)
368
+ end
369
+
370
+ task :prerelease => [:test, :test_deps]
371
+ task :default => :test
372
+
373
+ CLEAN.include rcov_dir
374
+ end
375
+ end
376
+
377
+ def define_doc
378
+ desc "run rdoc"
379
+ task :doc => :clean_doc do
380
+ args = (
381
+ gemspec.rdoc_options +
382
+ gemspec.require_paths.clone +
383
+ gemspec.extra_rdoc_files +
384
+ ["-o", doc_dir]
385
+ ).flatten.map { |t| t.to_s }
386
+ RDoc::RDoc.new.document args
387
+ end
388
+
389
+ task :clean_doc do
390
+ # normally rm_rf, but mimic rake/clean output
391
+ rm_r(doc_dir) rescue nil
392
+ end
393
+
394
+ desc "run rdoc then open browser"
395
+ task :show_doc => :doc do
396
+ open_browser(doc_dir + "/index.html")
397
+ end
398
+
399
+ task :rdoc => :doc
400
+ task :clean => :clean_doc
401
+ end
402
+
403
+ def define_publish
404
+ desc "upload docs"
405
+ task :publish => [:clean_doc, :doc] do
406
+ Rake::SshDirPublisher.new(
407
+ "#{rubyforge_user}@rubyforge.org",
408
+ "/var/www/gforge-projects/#{rubyforge_name}",
409
+ doc_dir
410
+ ).upload
411
+ end
412
+ end
413
+
414
+ def define_install
415
+ desc "direct install (no gem)"
416
+ task :install do
417
+ SimpleInstaller.new.run([])
418
+ end
419
+
420
+ desc "direct uninstall (no gem)"
421
+ task :uninstall do
422
+ SimpleInstaller.new.run(["--uninstall"])
423
+ end
424
+ end
425
+
426
+ def define_debug
427
+ runner = Class.new do
428
+ def comment_src_dst(on)
429
+ on ? ["", "#"] : ["#", ""]
430
+ end
431
+
432
+ def comment_regions(on, contents, start)
433
+ src, dst = comment_src_dst(on)
434
+ contents.gsub(%r!^(\s+)#{src}#{start}.*?^\1#{src}(\}|end)!m) { |chunk|
435
+ indent = $1
436
+ chunk.gsub(%r!^#{indent}#{src}!, "#{indent}#{dst}")
437
+ }
438
+ end
439
+
440
+ def comment_lines(on, contents, start)
441
+ src, dst = comment_src_dst(on)
442
+ contents.gsub(%r!^(\s*)#{src}#{start}!) {
443
+ $1 + dst + start
444
+ }
445
+ end
446
+
447
+ def debug_info(enable)
448
+ Find.find("lib", "test") { |path|
449
+ if path =~ %r!\.rb\Z!
450
+ Jumpstart.replace_file(path) { |contents|
451
+ result = comment_regions(!enable, contents, "debug")
452
+ comment_lines(!enable, result, "trace")
453
+ }
454
+ end
455
+ }
456
+ end
457
+ end
458
+
459
+ desc "enable debug and trace calls"
460
+ task :debug_on do
461
+ runner.new.debug_info(true)
462
+ end
463
+
464
+ desc "disable debug and trace calls"
465
+ task :debug_off do
466
+ runner.new.debug_info(false)
467
+ end
468
+ end
469
+
470
+ def define_columns
471
+ desc "check for columns > 80"
472
+ task :check_columns do
473
+ Dir["**/*.rb"].each { |file|
474
+ File.read(file).scan(%r!^.{81}!) { |match|
475
+ unless match =~ %r!http://!
476
+ raise "#{file} greater than 80 columns: #{match}"
477
+ end
478
+ }
479
+ }
480
+ end
481
+ task :prerelease => :check_columns
482
+ end
483
+
484
+ def define_comments
485
+ task :comments do
486
+ file = "comments.txt"
487
+ write_file(file) {
488
+ Array.new.tap { |result|
489
+ (["Rakefile"] + Dir["**/*.{rb,rake}"]).each { |file|
490
+ File.read(file).scan(%r!\#[^\{].*$!) { |match|
491
+ result << match
492
+ }
493
+ }
494
+ }.join("\n")
495
+ }
496
+ CLEAN.include file
497
+ end
498
+ end
499
+
500
+ def define_check_directory
501
+ task :check_directory do
502
+ unless `git status` =~ %r!nothing to commit \(working directory clean\)!
503
+ raise "Directory not clean"
504
+ end
505
+ end
506
+ end
507
+
508
+ def define_ping
509
+ task :ping do
510
+ %w[github.com rubyforge.org].each { |server|
511
+ cmd = "ping " + (
512
+ if Config::CONFIG["host"] =~ %r!darwin!
513
+ "-c2 #{server}"
514
+ else
515
+ "#{server} 2 2"
516
+ end
517
+ )
518
+ unless `#{cmd}` =~ %r!0% packet loss!
519
+ raise "No ping for #{server}"
520
+ end
521
+ }
522
+ end
523
+ end
524
+
525
+ def define_update_jumpstart
526
+ url = ENV["RUBY_JUMPSTART"] || "git://github.com/quix/jumpstart.git"
527
+ task :update_jumpstart do
528
+ git "clone", url
529
+ rm_rf "devel/jumpstart"
530
+ Dir["jumpstart/**/*.rb"].each { |source|
531
+ dest = source.sub(%r!\Ajumpstart/!, "devel/")
532
+ dest_dir = File.dirname(dest)
533
+ mkdir_p(dest_dir) unless File.directory?(dest_dir)
534
+ cp source, dest
535
+ }
536
+ rm_r "jumpstart"
537
+ git "commit", "devel", "-m", "update jumpstart"
538
+ end
539
+ end
540
+
541
+ def git(*args)
542
+ sh("git", *args)
543
+ end
544
+
545
+ def create_manifest
546
+ write_file(manifest_file) {
547
+ files.sort.join("\n")
548
+ }
549
+ end
550
+
551
+ def rubyforge(command, file)
552
+ sh(
553
+ "rubyforge",
554
+ command,
555
+ rubyforge_name,
556
+ rubyforge_name,
557
+ version.to_s,
558
+ file
559
+ )
560
+ end
561
+
562
+ def define_release
563
+ task :prerelease => [:clean, :check_directory, :ping]
564
+
565
+ task :finish_release do
566
+ gem_md5, tgz_md5 = [gem, tgz].map { |file|
567
+ "#{file}.md5".tap { |md5|
568
+ sh("md5sum #{file} > #{md5}")
569
+ }
570
+ }
571
+
572
+ rubyforge("add_release", gem)
573
+ [gem_md5, tgz, tgz_md5].each { |file|
574
+ rubyforge("add_file", file)
575
+ }
576
+
577
+ git("tag", "#{name}-" + version.to_s)
578
+ git(*%w(push --tags origin master))
579
+ end
580
+
581
+ task :release => [:prerelease, :package, :publish, :finish_release]
582
+ end
583
+
584
+ def define_debug_gem
585
+ task :debug_gem do
586
+ puts gemspec.to_ruby
587
+ end
588
+ end
589
+
590
+ def open_browser(*files)
591
+ sh(*([browser].flatten + files))
592
+ end
593
+
594
+ def write_file(file)
595
+ yield.tap { |contents|
596
+ File.open(file, "wb") { |out|
597
+ out.print(contents)
598
+ }
599
+ }
600
+ end
601
+
602
+ def run_ruby_on_each(*files)
603
+ files.each { |file|
604
+ Ruby.run("-w", file)
605
+ }
606
+ end
607
+
608
+ def to_camel_case(str)
609
+ str.split('_').map { |t| t.capitalize }.join
610
+ end
611
+
612
+ class << self
613
+ def replace_file(file)
614
+ old_contents = File.read(file)
615
+ yield(old_contents).tap { |new_contents|
616
+ if old_contents != new_contents
617
+ File.open(file, "wb") { |output|
618
+ output.print(new_contents)
619
+ }
620
+ end
621
+ }
622
+ end
623
+ end
624
+ end
625
+
626
+ unless respond_to? :tap
627
+ class Object
628
+ def tap
629
+ yield self
630
+ self
631
+ end
632
+ end
633
+ end
634
+
@@ -52,16 +52,18 @@ module CompTree
52
52
  # retrieve or create parent and children
53
53
  #
54
54
 
55
- parent = @nodes[name] || (@nodes[name] = @node_class.new(name))
55
+ parent = @nodes.fetch(name) {
56
+ @nodes[name] = @node_class.new(name)
57
+ }
56
58
  if parent.function
57
- raise RedefinitionError, "Node `#{parent.name.inspect}' redefined."
59
+ raise RedefinitionError, "node `#{parent.name.inspect}' redefined"
58
60
  end
59
61
  parent.function = block
60
62
 
61
63
  children = child_names.map { |child_name|
62
- @nodes[child_name] || (
64
+ @nodes.fetch(child_name) {
63
65
  @nodes[child_name] = @node_class.new(child_name)
64
- )
66
+ }
65
67
  }
66
68
 
67
69
  #
@@ -71,6 +73,8 @@ module CompTree
71
73
  children.each { |child|
72
74
  child.parents << parent
73
75
  }
76
+
77
+ parent
74
78
  end
75
79
 
76
80
  #
@@ -118,9 +122,13 @@ module CompTree
118
122
  def compute(name, opts)
119
123
  threads = (opts.is_a?(Hash) ? opts[:threads] : opts).to_i
120
124
  unless threads > 0
121
- raise ArgumentError, "number of threads must be greater than zero"
125
+ raise CompTree::ArgumentError,
126
+ "number of threads must be greater than zero"
122
127
  end
123
- root = @nodes[name]
128
+ root = @nodes.fetch(name) {
129
+ raise CompTree::ArgumentError,
130
+ "no such node named `#{name.inspect}'"
131
+ }
124
132
  if root.computed
125
133
  root.result
126
134
  elsif threads == 1
@@ -13,4 +13,7 @@ module CompTree
13
13
 
14
14
  # Encountered a node without a function during a computation.
15
15
  class NoFunctionError < Error ; end
16
+
17
+ # Missing or malformed method arguments
18
+ class ArgumentError < Error ; end
16
19
  end