comp_tree 0.5.0

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.
Files changed (48) hide show
  1. data/README +153 -0
  2. data/Rakefile +152 -0
  3. data/comp_tree.gemspec +38 -0
  4. data/contrib/quix/Rakefile +16 -0
  5. data/contrib/quix/install.rb +3 -0
  6. data/contrib/quix/lib/quix/builtin/dir/casefold_brackets.rb +7 -0
  7. data/contrib/quix/lib/quix/builtin/kernel/tap.rb +9 -0
  8. data/contrib/quix/lib/quix/builtin/module/include.rb +21 -0
  9. data/contrib/quix/lib/quix/builtin/module/private.rb +41 -0
  10. data/contrib/quix/lib/quix/config.rb +37 -0
  11. data/contrib/quix/lib/quix/cygwin.rb +60 -0
  12. data/contrib/quix/lib/quix/diagnostic.rb +44 -0
  13. data/contrib/quix/lib/quix/enumerable.rb +33 -0
  14. data/contrib/quix/lib/quix/fileutils.rb +37 -0
  15. data/contrib/quix/lib/quix/hash_struct.rb +27 -0
  16. data/contrib/quix/lib/quix/kernel.rb +61 -0
  17. data/contrib/quix/lib/quix/lazy_struct.rb +55 -0
  18. data/contrib/quix/lib/quix/simple_installer.rb +87 -0
  19. data/contrib/quix/lib/quix/string.rb +38 -0
  20. data/contrib/quix/lib/quix/subpackager.rb +52 -0
  21. data/contrib/quix/lib/quix/thread_local.rb +32 -0
  22. data/contrib/quix/lib/quix/vars.rb +138 -0
  23. data/contrib/quix/lib/quix.rb +32 -0
  24. data/contrib/quix/test/all.rb +12 -0
  25. data/contrib/quix/test/test_deps.rb +25 -0
  26. data/contrib/quix/test/test_include.rb +47 -0
  27. data/contrib/quix/test/test_private.rb +86 -0
  28. data/contrib/quix/test/test_root.rb +19 -0
  29. data/contrib/quix/test/test_struct.rb +48 -0
  30. data/contrib/quix/test/test_vars.rb +187 -0
  31. data/install.rb +3 -0
  32. data/lib/comp_tree/algorithm.rb +210 -0
  33. data/lib/comp_tree/bucket_ipc.rb +151 -0
  34. data/lib/comp_tree/driver.rb +267 -0
  35. data/lib/comp_tree/error.rb +27 -0
  36. data/lib/comp_tree/node.rb +165 -0
  37. data/lib/comp_tree/quix/builtin/kernel/tap.rb +33 -0
  38. data/lib/comp_tree/quix/diagnostic.rb +68 -0
  39. data/lib/comp_tree/quix/kernel.rb +85 -0
  40. data/lib/comp_tree/retriable_fork.rb +42 -0
  41. data/lib/comp_tree/task_node.rb +22 -0
  42. data/lib/comp_tree.rb +23 -0
  43. data/test/all.rb +12 -0
  44. data/test/test_bucketipc.rb +72 -0
  45. data/test/test_circular.rb +36 -0
  46. data/test/test_comp_tree.rb +364 -0
  47. data/test/test_exception.rb +97 -0
  48. metadata +120 -0
@@ -0,0 +1,61 @@
1
+
2
+ require 'thread'
3
+
4
+ module Quix
5
+ module Kernel
6
+ def let
7
+ yield self
8
+ end
9
+
10
+ def singleton_class
11
+ class << self
12
+ self
13
+ end
14
+ end
15
+
16
+ module Gensym
17
+ @mutex = Mutex.new
18
+ @count = 0
19
+
20
+ def gensym(prefix = nil)
21
+ count = Gensym.module_eval {
22
+ @mutex.synchronize {
23
+ @count += 1
24
+ }
25
+ }
26
+ "#{prefix || :G}_#{count}_#{rand}".to_sym
27
+ end
28
+ end
29
+ include Gensym
30
+
31
+ def call_private(method, *args, &block)
32
+ instance_eval { send(method, *args, &block) }
33
+ end
34
+
35
+ def with_warnings(value = true)
36
+ previous = $VERBOSE
37
+ $VERBOSE = value
38
+ begin
39
+ yield
40
+ ensure
41
+ $VERBOSE = previous
42
+ end
43
+ end
44
+
45
+ def no_warnings(&block)
46
+ with_warnings(false, &block)
47
+ end
48
+
49
+ def abort_on_exception(value = true)
50
+ previous = Thread.abort_on_exception
51
+ Thread.abort_on_exception = value
52
+ begin
53
+ yield
54
+ ensure
55
+ Thread.abort_on_exception = previous
56
+ end
57
+ end
58
+
59
+ extend self
60
+ end
61
+ end
@@ -0,0 +1,55 @@
1
+
2
+ require 'ostruct'
3
+ require 'quix/builtin/kernel/tap'
4
+
5
+ module Quix
6
+ #
7
+ # An OpenStruct with the ability to define lazily-evaluated fields.
8
+ #
9
+ class LazyStruct < OpenStruct
10
+ #
11
+ # For mixing into an existing OpenStruct instance singleton class.
12
+ #
13
+ module Mixin
14
+ #
15
+ # &block is evaluated when this attribute is requested. The
16
+ # same result is returned for subsquent calls, until the field
17
+ # is assigned a different value.
18
+ #
19
+ def attribute(reader, &block)
20
+ singleton = (class << self ; self ; end)
21
+ singleton.instance_eval {
22
+ #
23
+ # Define a special reader method in the singleton class.
24
+ #
25
+ define_method(reader) {
26
+ block.call.tap { |value|
27
+ #
28
+ # The value has been computed. Replace this method with a
29
+ # one-liner giving the value.
30
+ #
31
+ singleton.instance_eval {
32
+ remove_method(reader)
33
+ define_method(reader) { value }
34
+ }
35
+ }
36
+ }
37
+
38
+ #
39
+ # Revert to the old OpenStruct behavior when the writer is called.
40
+ #
41
+ writer = "#{reader}=".to_sym
42
+ define_method(writer) { |value|
43
+ singleton.instance_eval {
44
+ remove_method(reader)
45
+ remove_method(writer)
46
+ }
47
+ method_missing(writer, value)
48
+ }
49
+ }
50
+ end
51
+ end
52
+
53
+ include Mixin
54
+ end
55
+ end
@@ -0,0 +1,87 @@
1
+
2
+ require 'rbconfig'
3
+ require 'fileutils'
4
+ require 'find'
5
+ require 'fileutils'
6
+ require 'quix/vars'
7
+
8
+ module Quix
9
+ class SimpleInstaller
10
+ include Quix::Vars
11
+
12
+ def initialize
13
+ dest_root = Config::CONFIG["sitelibdir"]
14
+ sources = []
15
+ Find.find("./lib") { |source|
16
+ if install_file?(source)
17
+ sources << source
18
+ end
19
+ }
20
+ @spec = sources.inject(Array.new) { |acc, source|
21
+ if source == "./lib"
22
+ acc
23
+ else
24
+ dest = File.join(dest_root, source.sub(%r!\A\./lib!, ""))
25
+
26
+ install = lambda {
27
+ if File.directory?(source)
28
+ unless File.directory?(dest)
29
+ puts "mkdir #{dest}"
30
+ FileUtils.mkdir(dest)
31
+ end
32
+ else
33
+ puts "install #{source} --> #{dest}"
34
+ FileUtils.install(source, dest)
35
+ end
36
+ }
37
+
38
+ uninstall = lambda {
39
+ if File.directory?(source)
40
+ if File.directory?(dest)
41
+ puts "rmdir #{dest}"
42
+ FileUtils.rmdir(dest)
43
+ end
44
+ else
45
+ if File.file?(dest)
46
+ puts "rm #{dest}"
47
+ FileUtils.rm(dest)
48
+ end
49
+ end
50
+ }
51
+
52
+ acc << locals_to_hash {%{source, dest, install, uninstall}}
53
+ end
54
+ }
55
+ end
56
+
57
+ def install_file?(source)
58
+ !File.symlink?(source) and
59
+ (File.directory?(source) or
60
+ (File.file?(source) and File.extname(source) == ".rb"))
61
+ end
62
+
63
+ attr_accessor :spec
64
+
65
+ def install
66
+ @spec.each { |entry|
67
+ entry[:install].call
68
+ }
69
+ end
70
+
71
+ def uninstall
72
+ @spec.reverse.each { |entry|
73
+ entry[:uninstall].call
74
+ }
75
+ end
76
+
77
+ def run(args = ARGV)
78
+ if args.empty? or (args.size == 1 and args.first == "install")
79
+ install
80
+ elsif args.size == 1 and args.first == "--uninstall"
81
+ uninstall
82
+ else
83
+ raise "unrecognized arguments: #{args.inspect}"
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,38 @@
1
+
2
+ require 'quix/builtin/kernel/tap'
3
+
4
+ module Quix
5
+ module String
6
+ def trim_left!
7
+ sub!(%r!\A\s+!, "")
8
+ end
9
+
10
+ def trim_right!
11
+ sub!(%r!\s+\Z!, "")
12
+ end
13
+
14
+ def trim!
15
+ result_left = trim_left!
16
+ result_right = trim_right!
17
+ result_left || result_right
18
+ end
19
+
20
+ def trim_left
21
+ clone.tap { |result|
22
+ result.trim_left!
23
+ }
24
+ end
25
+
26
+ def trim_right
27
+ clone.tap { |result|
28
+ result.trim_right!
29
+ }
30
+ end
31
+
32
+ def trim
33
+ clone.tap { |result|
34
+ result.trim!
35
+ }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,52 @@
1
+
2
+ require 'quix/hash_struct'
3
+
4
+ module Quix
5
+ module Subpackager
6
+ WARNING = %q{
7
+
8
+
9
+ ######################################################
10
+ #
11
+ # **** DO NOT EDIT ****
12
+ #
13
+ # **** THIS IS A GENERATED FILE *****
14
+ #
15
+ ######################################################
16
+
17
+
18
+ }.gsub(%r!^ +!, "")
19
+
20
+ def self.run(packages)
21
+ HashStruct.recursive_new(packages).each_pair { |pkg, pkg_spec|
22
+ pkg_spec.subpackages.each_pair { |subpkg, subpkg_spec|
23
+ process_path = lambda { |path|
24
+ source = "#{subpkg_spec.lib_dir}/#{path}.rb"
25
+ dest = "#{pkg_spec.lib_dir}/#{pkg}/#{path}.rb"
26
+
27
+ contents =
28
+ WARNING +
29
+ File.read(source).gsub(%r!require [\'\"]#{subpkg}!) {
30
+ |match|
31
+ match.sub(%r!#{subpkg}\Z!, "#{pkg}/#{subpkg}")
32
+ }.gsub(subpkg_spec.name_in_ruby) {
33
+ "#{pkg_spec.name_in_ruby}::#{subpkg_spec.name_in_ruby}"
34
+ } +
35
+ WARNING
36
+
37
+ mkdir_p(File.dirname(dest))
38
+ puts "#{source} --> #{dest}"
39
+ File.open(dest, "w") { |t| t.print(contents) }
40
+ }
41
+
42
+ unless subpkg_spec.ignore_root_rb
43
+ process_path.call(subpkg)
44
+ end
45
+ subpkg_spec.sources.each { |path|
46
+ process_path.call("#{subpkg}/#{path}")
47
+ }
48
+ }
49
+ }
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,32 @@
1
+
2
+ require 'thread'
3
+ require 'quix/kernel'
4
+
5
+ module Quix
6
+ class ThreadLocal
7
+ include Quix::Kernel
8
+
9
+ def initialize(prefix = nil, &default)
10
+ @name = gensym(prefix)
11
+ @accessed = gensym(prefix)
12
+ @default = default
13
+ end
14
+
15
+ def value
16
+ t = Thread.current
17
+ unless t[@accessed]
18
+ if @default
19
+ t[@name] = @default.call
20
+ end
21
+ t[@accessed] = true
22
+ end
23
+ t[@name]
24
+ end
25
+
26
+ def value=(value)
27
+ t = Thread.current
28
+ t[@accessed] = true
29
+ t[@name] = value
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,138 @@
1
+
2
+ require 'quix/kernel'
3
+ require 'quix/thread_local'
4
+ require 'quix/builtin/kernel/tap'
5
+ require 'ostruct'
6
+
7
+ module Quix
8
+ module Vars
9
+ include Quix::Kernel
10
+
11
+ def eval_locals(code_with_locals, &block)
12
+ code_with_locals.call.split(",").map { |name|
13
+ # trim
14
+ name.sub(%r!\A\s+!, "").sub(%r!\s+\Z!, "")
15
+ }.each { |name|
16
+ block.call(name, eval(name, code_with_locals.binding))
17
+ }
18
+ end
19
+
20
+ def hash_to_locals(&block)
21
+ if hash = block.call
22
+ hash.each_pair { |name, value|
23
+ Vars.argument_cache.value = value
24
+ eval("#{name} = #{Vars.name}.argument_cache.value", block.binding)
25
+ }
26
+ end
27
+ end
28
+
29
+ def locals_to_hash(&block)
30
+ Hash.new.tap { |hash|
31
+ eval_locals(block) { |name, value|
32
+ hash[name.to_sym] = value
33
+ }
34
+ }
35
+ end
36
+
37
+ def config_to_hash(code)
38
+ Hash.new.tap { |hash|
39
+ each_config_pair(code) { |name, value|
40
+ hash[name] = value
41
+ }
42
+ }
43
+ end
44
+
45
+ def each_config_pair(code, &block)
46
+ Vars.argument_cache.value = code
47
+ vars, bind = private__eval_config_code
48
+ vars.each { |var|
49
+ yield(var.to_sym, eval(var, bind))
50
+ }
51
+ end
52
+
53
+ def hash_to_ivs(opts = nil, &block)
54
+ if hash = block.call
55
+ private__hash_to_ivs(
56
+ hash,
57
+ eval("self", block.binding),
58
+ opts && opts[:force])
59
+ end
60
+ end
61
+
62
+ def locals_to_ivs(opts = nil, &block)
63
+ hash = Hash.new
64
+ eval_locals(block) { |name, value|
65
+ hash[name] = value
66
+ }
67
+ private__hash_to_ivs(
68
+ hash,
69
+ eval("self", block.binding),
70
+ opts && opts[:force])
71
+ end
72
+
73
+ def with_readers(hash, *args, &block)
74
+ caller_self = eval("self", block.binding)
75
+ readers =
76
+ if args.empty?
77
+ hash.keys
78
+ else
79
+ args
80
+ end
81
+ singleton_class.instance_eval {
82
+ added = Array.new
83
+ begin
84
+ readers.each { |reader|
85
+ if caller_self.respond_to?(reader)
86
+ raise(
87
+ "Reader '#{reader}' already exists in #{caller_self.inspect}")
88
+ end
89
+ define_method(reader) {
90
+ hash[reader]
91
+ }
92
+ added << reader
93
+ }
94
+ block.call
95
+ ensure
96
+ added.each { |reader|
97
+ remove_method(reader)
98
+ }
99
+ end
100
+ }
101
+ end
102
+
103
+ private
104
+
105
+ class << self
106
+ attr_accessor :argument_cache
107
+ end
108
+ @argument_cache = ThreadLocal.new
109
+
110
+ def private__eval_config_code
111
+ eval %Q{
112
+ #{Vars.argument_cache.value}
113
+
114
+ [local_variables, binding]
115
+ }
116
+ end
117
+
118
+ def private__hash_to_ivs(hash, target, force)
119
+ target.instance_eval {
120
+ hash.each_pair { |name, value|
121
+ ivar = "@#{name}"
122
+ unless force
123
+ existing_value = no_warnings {
124
+ instance_variable_get(ivar)
125
+ }
126
+ unless existing_value.nil?
127
+ raise "instance variable already set: #{name}"
128
+ end
129
+ end
130
+ instance_variable_set(ivar, value)
131
+ }
132
+ }
133
+ end
134
+
135
+ extend self
136
+ end
137
+ end
138
+
@@ -0,0 +1,32 @@
1
+ #
2
+ # Convience only -- include most everything
3
+ #
4
+
5
+ root = File.dirname(__FILE__)
6
+ pkgname = File.basename(__FILE__).sub(%r!\.rb\Z!, "")
7
+
8
+ Dir["#{root}/#{pkgname}/**/*.rb"].map { |file|
9
+ # change to relative paths
10
+ file.sub(%r!\A#{root}/!, "").sub(%r!\.rb\Z!, "")
11
+ }.reject { |file|
12
+ (file =~ %r!cygwin! and RUBY_PLATFORM !~ %r!cygwin!) or
13
+ file =~ %r!builtin!
14
+ }.each { |file|
15
+ require file
16
+ }
17
+
18
+ require 'quix/builtin/kernel/tap'
19
+
20
+ %w(Config Enumerable FileUtils String).each { |name|
21
+ Kernel.const_get(name).module_eval {
22
+ include Quix.const_get(name)
23
+ }
24
+ }
25
+
26
+ Config.extend(Quix::Config)
27
+
28
+ class Object
29
+ include Quix::Kernel
30
+ end
31
+
32
+ include Quix
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
2
+
3
+ require 'quix/config'
4
+
5
+ #
6
+ # Run in separate exec to check for missing dependencies.
7
+ #
8
+ Dir["#{File.dirname(__FILE__)}/test_*.rb"].each { |test|
9
+ unless system(Quix::Config.ruby_executable, test)
10
+ raise "test failed: #{test}"
11
+ end
12
+ }
@@ -0,0 +1,25 @@
1
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
2
+
3
+ require 'test/unit'
4
+ require 'quix/config'
5
+
6
+ class TestDeps < Test::Unit::TestCase
7
+ include Quix::Config
8
+ def test_deps
9
+ ruby = ruby_executable
10
+ root = File.expand_path("#{File.dirname(__FILE__)}/../lib")
11
+ Dir["#{root}/**/*.rb"].map { |file|
12
+ file.
13
+ sub(%r!\A#{root}/!, "").
14
+ sub(%r!\.rb\Z!, "")
15
+ }.each { |file|
16
+ unless file =~ %r!cygwin! and RUBY_PLATFORM !~ %r!cygwin!
17
+ Dir.chdir(root) {
18
+ assert(
19
+ system(ruby, "-r", file, "-e", ""),
20
+ "error requiring: '#{file}'")
21
+ }
22
+ end
23
+ }
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
2
+
3
+ require 'test/unit'
4
+ require 'open3'
5
+ require 'quix/config'
6
+
7
+ class TestInclude < Test::Unit::TestCase
8
+ include Quix::Config
9
+
10
+ def test_include
11
+ Dir.chdir(File.dirname(__FILE__)) {
12
+ code = %q{
13
+ $LOAD_PATH.unshift "../lib"
14
+ require 'quix/builtin/module/include'
15
+
16
+ module A
17
+ def f ; end
18
+ end
19
+
20
+ module B
21
+ def f ; end
22
+ end
23
+
24
+ module C
25
+ include A
26
+ include B
27
+ end
28
+
29
+ class D
30
+ include B
31
+ include A
32
+ end
33
+ }
34
+ ruby = ruby_executable
35
+ begin
36
+ stdin, stdout, stderr = Open3.popen3("#{ruby} -d -")
37
+ stdin.puts(code)
38
+ stdin.close_write
39
+ assert_equal(stderr.readlines,
40
+ ["Note: replacing C#f with B#f\n",
41
+ "Note: replacing D#f with A#f\n"])
42
+ rescue NotImplementedError
43
+ puts "Skipping #{File.basename(__FILE__)}."
44
+ end
45
+ }
46
+ end
47
+ end
@@ -0,0 +1,86 @@
1
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
2
+
3
+ require 'test/unit'
4
+ require 'quix/config'
5
+ require 'quix/kernel'
6
+
7
+ if Quix::Config.version_ge("1.8.7")
8
+ require 'test/unit'
9
+ require 'quix/builtin/module/private'
10
+
11
+ class TestPrivate < Test::Unit::TestCase
12
+ BODY = %{
13
+ def f ; end
14
+
15
+ private {
16
+ def g ; end
17
+ def h ; end
18
+ }
19
+
20
+ def i ; end
21
+
22
+ private {
23
+ def j ; end
24
+ }
25
+
26
+ def k ; end
27
+
28
+ private {
29
+ }
30
+
31
+ def l ; end
32
+
33
+ def m ; end
34
+ def n ; end
35
+ private :m, :n
36
+
37
+ def o ; end
38
+ }
39
+
40
+ class A
41
+ eval(BODY)
42
+ end
43
+
44
+ module B
45
+ eval(BODY)
46
+ end
47
+
48
+ class C
49
+ include B
50
+ end
51
+
52
+ def test_1
53
+ [A, C].map { |klass| klass.new }.each { |t|
54
+ assert_nothing_raised { t.f }
55
+ assert_raises(NoMethodError) { t.g }
56
+ assert_raises(NoMethodError) { t.h }
57
+ assert_nothing_raised { t.i }
58
+ assert_raises(NoMethodError) { t.j }
59
+ assert_nothing_raised { t.k }
60
+ assert_nothing_raised { t.l }
61
+ assert_raises(NoMethodError) { t.m }
62
+ assert_raises(NoMethodError) { t.n }
63
+ assert_nothing_raised { t.o }
64
+ }
65
+ end
66
+
67
+ def test_2
68
+ added = []
69
+ Class.new {
70
+ extend(Quix::Kernel).singleton_class.instance_eval {
71
+ define_method(:method_added) { |name|
72
+ added << name
73
+ }
74
+ }
75
+
76
+ private {
77
+ def f ; end
78
+ }
79
+
80
+ def g ; end
81
+ }
82
+ assert_equal([:f, :g], added)
83
+ end
84
+ end
85
+ end
86
+
@@ -0,0 +1,19 @@
1
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
2
+
3
+ require 'quix'
4
+ require 'test/unit'
5
+
6
+ class TestRoot < Test::Unit::TestCase
7
+ def test_1
8
+ assert_equal(class << self ; self ; end, singleton_class)
9
+ assert_equal("moo", "moo".tap { |t| t*2 })
10
+ assert_equal("moomoo", "moo".let { |t| t*2 })
11
+ assert_equal("zzz", " zzz ".trim)
12
+ assert_nothing_raised {
13
+ ThreadLocal.new
14
+ LazyStruct.new
15
+ HashStruct.new
16
+ Config.ruby_executable
17
+ }
18
+ end
19
+ end