comp_tree 0.5.2 → 0.7.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.
- data/CHANGES +24 -0
- data/README +19 -52
- data/Rakefile +1 -138
- data/comp_tree.gemspec +33 -30
- data/install.rb +3 -3
- data/lib/comp_tree/algorithm.rb +117 -156
- data/lib/comp_tree/driver.rb +39 -154
- data/lib/comp_tree/error.rb +18 -23
- data/lib/comp_tree/node.rb +46 -50
- data/lib/comp_tree.rb +56 -0
- data/rakelib/jumpstart/ruby.rb +51 -0
- data/{contrib/quix/lib/quix → rakelib/jumpstart}/simple_installer.rb +11 -13
- data/test/common.rb +29 -0
- data/test/test_basic.rb +189 -0
- data/test/test_circular.rb +34 -31
- data/test/test_drain.rb +38 -0
- data/test/test_exception.rb +37 -86
- data/test/test_flood.rb +14 -0
- data/test/test_grind.rb +77 -0
- data/test/test_sequential.rb +21 -0
- metadata +45 -58
- data/contrib/quix/Rakefile +0 -16
- data/contrib/quix/install.rb +0 -3
- data/contrib/quix/lib/quix/builtin/dir/casefold_brackets.rb +0 -7
- data/contrib/quix/lib/quix/builtin/kernel/tap.rb +0 -9
- data/contrib/quix/lib/quix/builtin/module/include.rb +0 -21
- data/contrib/quix/lib/quix/builtin/module/private.rb +0 -41
- data/contrib/quix/lib/quix/config.rb +0 -37
- data/contrib/quix/lib/quix/cygwin.rb +0 -60
- data/contrib/quix/lib/quix/diagnostic.rb +0 -44
- data/contrib/quix/lib/quix/enumerable.rb +0 -33
- data/contrib/quix/lib/quix/fileutils.rb +0 -37
- data/contrib/quix/lib/quix/hash_struct.rb +0 -27
- data/contrib/quix/lib/quix/kernel.rb +0 -61
- data/contrib/quix/lib/quix/lazy_struct.rb +0 -55
- data/contrib/quix/lib/quix/string.rb +0 -38
- data/contrib/quix/lib/quix/subpackager.rb +0 -52
- data/contrib/quix/lib/quix/thread_local.rb +0 -32
- data/contrib/quix/lib/quix/vars.rb +0 -138
- data/contrib/quix/lib/quix.rb +0 -32
- data/contrib/quix/test/all.rb +0 -12
- data/contrib/quix/test/test_deps.rb +0 -25
- data/contrib/quix/test/test_include.rb +0 -47
- data/contrib/quix/test/test_private.rb +0 -86
- data/contrib/quix/test/test_root.rb +0 -19
- data/contrib/quix/test/test_struct.rb +0 -48
- data/contrib/quix/test/test_vars.rb +0 -187
- data/lib/comp_tree/bucket_ipc.rb +0 -151
- data/lib/comp_tree/diagnostic.rb +0 -44
- data/lib/comp_tree/misc.rb +0 -61
- data/lib/comp_tree/retriable_fork.rb +0 -42
- data/lib/comp_tree/tap.rb +0 -9
- data/lib/comp_tree/task_node.rb +0 -22
- data/test/all.rb +0 -12
- data/test/test_bucketipc.rb +0 -72
- data/test/test_comp_tree.rb +0 -364
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.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James M. Lawrence
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-04-09 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description: Build a computation tree and execute it with N parallel threads.
|
16
|
+
description: Build a computation tree and execute it with N parallel threads.
|
17
17
|
email: quixoticsycophant@gmail.com
|
18
18
|
executables: []
|
19
19
|
|
@@ -22,53 +22,26 @@ extensions: []
|
|
22
22
|
extra_rdoc_files:
|
23
23
|
- README
|
24
24
|
files:
|
25
|
+
- CHANGES
|
25
26
|
- README
|
27
|
+
- Rakefile
|
26
28
|
- comp_tree.gemspec
|
27
|
-
-
|
28
|
-
-
|
29
|
-
-
|
30
|
-
-
|
31
|
-
-
|
32
|
-
-
|
33
|
-
-
|
34
|
-
-
|
35
|
-
-
|
36
|
-
-
|
37
|
-
-
|
38
|
-
-
|
39
|
-
-
|
40
|
-
-
|
41
|
-
-
|
42
|
-
-
|
43
|
-
- ./contrib/quix/lib/quix/thread_local.rb
|
44
|
-
- ./contrib/quix/lib/quix/vars.rb
|
45
|
-
- ./contrib/quix/lib/quix.rb
|
46
|
-
- ./contrib/quix/test/all.rb
|
47
|
-
- ./contrib/quix/test/test_deps.rb
|
48
|
-
- ./contrib/quix/test/test_include.rb
|
49
|
-
- ./contrib/quix/test/test_private.rb
|
50
|
-
- ./contrib/quix/test/test_root.rb
|
51
|
-
- ./contrib/quix/test/test_struct.rb
|
52
|
-
- ./contrib/quix/test/test_vars.rb
|
53
|
-
- ./install.rb
|
54
|
-
- ./lib/comp_tree/algorithm.rb
|
55
|
-
- ./lib/comp_tree/bucket_ipc.rb
|
56
|
-
- ./lib/comp_tree/diagnostic.rb
|
57
|
-
- ./lib/comp_tree/driver.rb
|
58
|
-
- ./lib/comp_tree/error.rb
|
59
|
-
- ./lib/comp_tree/misc.rb
|
60
|
-
- ./lib/comp_tree/node.rb
|
61
|
-
- ./lib/comp_tree/retriable_fork.rb
|
62
|
-
- ./lib/comp_tree/tap.rb
|
63
|
-
- ./lib/comp_tree/task_node.rb
|
64
|
-
- ./lib/comp_tree.rb
|
65
|
-
- ./test/all.rb
|
66
|
-
- ./test/test_bucketipc.rb
|
67
|
-
- ./test/test_circular.rb
|
68
|
-
- ./test/test_comp_tree.rb
|
69
|
-
- ./test/test_exception.rb
|
70
|
-
- ./Rakefile
|
71
|
-
- ./contrib/quix/Rakefile
|
29
|
+
- install.rb
|
30
|
+
- lib/comp_tree/algorithm.rb
|
31
|
+
- lib/comp_tree/driver.rb
|
32
|
+
- lib/comp_tree/error.rb
|
33
|
+
- lib/comp_tree/node.rb
|
34
|
+
- lib/comp_tree.rb
|
35
|
+
- rakelib/jumpstart/ruby.rb
|
36
|
+
- rakelib/jumpstart/simple_installer.rb
|
37
|
+
- test/common.rb
|
38
|
+
- test/test_basic.rb
|
39
|
+
- test/test_circular.rb
|
40
|
+
- test/test_drain.rb
|
41
|
+
- test/test_exception.rb
|
42
|
+
- test/test_flood.rb
|
43
|
+
- test/test_grind.rb
|
44
|
+
- test/test_sequential.rb
|
72
45
|
has_rdoc: true
|
73
46
|
homepage: comptree.rubyforge.org
|
74
47
|
post_install_message:
|
@@ -78,23 +51,37 @@ rdoc_options:
|
|
78
51
|
- --title
|
79
52
|
- "comp_tree: Parallel Computation Tree"
|
80
53
|
- --exclude
|
81
|
-
-
|
54
|
+
- CHANGES
|
82
55
|
- --exclude
|
83
|
-
-
|
56
|
+
- Rakefile
|
84
57
|
- --exclude
|
85
|
-
-
|
58
|
+
- comp_tree.gemspec
|
59
|
+
- --exclude
|
60
|
+
- install.rb
|
61
|
+
- --exclude
|
62
|
+
- lib/comp_tree/algorithm.rb
|
63
|
+
- --exclude
|
64
|
+
- lib/comp_tree/node.rb
|
65
|
+
- --exclude
|
66
|
+
- rakelib/jumpstart/ruby.rb
|
67
|
+
- --exclude
|
68
|
+
- rakelib/jumpstart/simple_installer.rb
|
69
|
+
- --exclude
|
70
|
+
- test/common.rb
|
71
|
+
- --exclude
|
72
|
+
- test/test_basic.rb
|
86
73
|
- --exclude
|
87
|
-
-
|
74
|
+
- test/test_circular.rb
|
88
75
|
- --exclude
|
89
|
-
-
|
76
|
+
- test/test_drain.rb
|
90
77
|
- --exclude
|
91
|
-
-
|
78
|
+
- test/test_exception.rb
|
92
79
|
- --exclude
|
93
|
-
-
|
80
|
+
- test/test_flood.rb
|
94
81
|
- --exclude
|
95
|
-
-
|
82
|
+
- test/test_grind.rb
|
96
83
|
- --exclude
|
97
|
-
-
|
84
|
+
- test/test_sequential.rb
|
98
85
|
require_paths:
|
99
86
|
- lib
|
100
87
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -112,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
99
|
requirements: []
|
113
100
|
|
114
101
|
rubyforge_project: comptree
|
115
|
-
rubygems_version: 1.
|
102
|
+
rubygems_version: 1.3.1
|
116
103
|
signing_key:
|
117
104
|
specification_version: 2
|
118
105
|
summary: Parallel Computation Tree
|
data/contrib/quix/Rakefile
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift "./lib"
|
2
|
-
|
3
|
-
require 'quix/simple_installer'
|
4
|
-
require 'quix/config'
|
5
|
-
|
6
|
-
task :test do
|
7
|
-
load './test/all.rb'
|
8
|
-
end
|
9
|
-
|
10
|
-
task :install do
|
11
|
-
Quix::SimpleInstaller.new.install
|
12
|
-
end
|
13
|
-
|
14
|
-
task :uninstall do
|
15
|
-
Quix::SimpleInstaller.new.uninstall
|
16
|
-
end
|
data/contrib/quix/install.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
|
2
|
-
if $DEBUG and !(defined?($NO_DEBUG_INCLUDE) and $NO_DEBUG_INCLUDE)
|
3
|
-
class Module
|
4
|
-
orig_include = instance_method(:include)
|
5
|
-
remove_method(:include)
|
6
|
-
define_method(:include) { |*mods|
|
7
|
-
mods.each { |mod|
|
8
|
-
if mod.class == Module
|
9
|
-
mod.instance_methods(true).each { |name|
|
10
|
-
if self.instance_methods(true).include?(name)
|
11
|
-
STDERR.puts("Note: replacing #{self.inspect}##{name} " +
|
12
|
-
"with #{mod.inspect}##{name}")
|
13
|
-
end
|
14
|
-
}
|
15
|
-
end
|
16
|
-
orig_include.bind(self).call(*mods)
|
17
|
-
}
|
18
|
-
}
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
@@ -1,41 +0,0 @@
|
|
1
|
-
|
2
|
-
class Module
|
3
|
-
alias_method :private__original, :private
|
4
|
-
def private(*args, &block)
|
5
|
-
private__original(*args)
|
6
|
-
if block
|
7
|
-
singleton_class = (class << self ; self ; end)
|
8
|
-
caller_self = block.binding.eval("self")
|
9
|
-
method_added__original =
|
10
|
-
if (t = method(:method_added)) and t.owner == singleton_class
|
11
|
-
t
|
12
|
-
else
|
13
|
-
nil
|
14
|
-
end
|
15
|
-
begin
|
16
|
-
singleton_class.instance_eval {
|
17
|
-
define_method(:method_added) { |name|
|
18
|
-
caller_self.instance_eval {
|
19
|
-
private__original(name.to_sym)
|
20
|
-
}
|
21
|
-
if t = method_added__original
|
22
|
-
t.call(name)
|
23
|
-
end
|
24
|
-
}
|
25
|
-
}
|
26
|
-
block.call
|
27
|
-
ensure
|
28
|
-
if t = method_added__original
|
29
|
-
t.owner.instance_eval {
|
30
|
-
define_method(:method_added, t)
|
31
|
-
}
|
32
|
-
else
|
33
|
-
singleton_class.instance_eval {
|
34
|
-
remove_method(:method_added)
|
35
|
-
}
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
@@ -1,37 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rbconfig'
|
3
|
-
|
4
|
-
module Quix
|
5
|
-
module Config
|
6
|
-
CONFIG = ::Config::CONFIG
|
7
|
-
|
8
|
-
def ruby_executable
|
9
|
-
File.join(CONFIG["bindir"], CONFIG["RUBY_INSTALL_NAME"])
|
10
|
-
end
|
11
|
-
|
12
|
-
def version_gt(version) ; version_compare( :>, version) ; end
|
13
|
-
def version_lt(version) ; version_compare( :<, version) ; end
|
14
|
-
def version_eq(version) ; version_compare(:==, version) ; end
|
15
|
-
def version_ge(version) ; version_compare(:>=, version) ; end
|
16
|
-
def version_le(version) ; version_compare(:<=, version) ; end
|
17
|
-
def version_ne(version) ; version_compare(:"!=", version) ; end
|
18
|
-
|
19
|
-
def version_compare(op, version)
|
20
|
-
major, minor, teeny =
|
21
|
-
version.split(".").map { |n| n.to_i }
|
22
|
-
|
23
|
-
this_major, this_minor, this_teeny =
|
24
|
-
%w(MAJOR MINOR TEENY).map { |v| CONFIG[v].to_i }
|
25
|
-
|
26
|
-
if this_major == major and this_minor == minor
|
27
|
-
this_teeny.send(op, teeny)
|
28
|
-
elsif this_major == major
|
29
|
-
this_minor.send(op, minor)
|
30
|
-
else
|
31
|
-
this_major.send(op, major)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
extend self
|
36
|
-
end
|
37
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
|
2
|
-
unless RUBY_PLATFORM =~ %r!cygwin!
|
3
|
-
raise NotImplementedError, "cygwin-only module"
|
4
|
-
end
|
5
|
-
|
6
|
-
require 'fileutils'
|
7
|
-
require 'thread'
|
8
|
-
|
9
|
-
module Quix
|
10
|
-
module Cygwin
|
11
|
-
def run_batchfile(file, *args)
|
12
|
-
dos_pwd_env {
|
13
|
-
sh("cmd", "/c", dos_path(file), *args)
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
def normalize_path(path)
|
18
|
-
path.sub(%r!/+\Z!, "")
|
19
|
-
end
|
20
|
-
|
21
|
-
def unix2dos(string)
|
22
|
-
string.
|
23
|
-
gsub("\n", "\r\n").
|
24
|
-
gsub(%r!\r+!, "\r")
|
25
|
-
end
|
26
|
-
|
27
|
-
def dos_path(unix_path)
|
28
|
-
`cygpath -w #{normalize_path(unix_path)}`.chomp
|
29
|
-
end
|
30
|
-
|
31
|
-
def unix_path(dos_path)
|
32
|
-
escaped_path = dos_path.sub(%r!\\+\Z!, "").gsub("\\", "\\\\\\\\")
|
33
|
-
`cygpath #{escaped_path}`.chomp
|
34
|
-
end
|
35
|
-
|
36
|
-
def dos_pwd_env
|
37
|
-
Thread.exclusive {
|
38
|
-
orig = ENV["PWD"]
|
39
|
-
ENV["PWD"] = dos_path(Dir.pwd)
|
40
|
-
begin
|
41
|
-
yield
|
42
|
-
ensure
|
43
|
-
ENV["PWD"] = orig
|
44
|
-
end
|
45
|
-
}
|
46
|
-
end
|
47
|
-
|
48
|
-
def avoid_dll(file)
|
49
|
-
temp_file = file + ".avoiding-link"
|
50
|
-
FileUtils.mv(file, temp_file)
|
51
|
-
begin
|
52
|
-
yield
|
53
|
-
ensure
|
54
|
-
FileUtils.mv(temp_file, file)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
extend self
|
59
|
-
end
|
60
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'comp_tree/tap'
|
3
|
-
|
4
|
-
module CompTree
|
5
|
-
module Diagnostic
|
6
|
-
def show(desc = nil, stream = STDOUT, &block)
|
7
|
-
if desc
|
8
|
-
stream.puts(desc)
|
9
|
-
end
|
10
|
-
if block
|
11
|
-
expression = block.call
|
12
|
-
eval(expression, block.binding).tap { |result|
|
13
|
-
stream.printf("%-16s => %s\n", expression, result.inspect)
|
14
|
-
}
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
if $DEBUG
|
19
|
-
def debug
|
20
|
-
yield
|
21
|
-
end
|
22
|
-
|
23
|
-
def debugging?
|
24
|
-
true
|
25
|
-
end
|
26
|
-
|
27
|
-
def trace(desc = nil, &block)
|
28
|
-
if desc
|
29
|
-
show("#{desc}.".sub(%r!\.\.+\Z!, ""), STDERR, &block)
|
30
|
-
else
|
31
|
-
show(nil, STDERR, &block)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
else
|
35
|
-
# non-$DEBUG
|
36
|
-
def debug ; end
|
37
|
-
def debugging? ; end
|
38
|
-
def trace(*args) ; end
|
39
|
-
end
|
40
|
-
|
41
|
-
extend self
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
@@ -1,33 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'quix/builtin/kernel/tap'
|
3
|
-
|
4
|
-
module Quix
|
5
|
-
module Enumerable
|
6
|
-
def inject_with_index(*args)
|
7
|
-
index = 0
|
8
|
-
inject(*args) { |acc, elem|
|
9
|
-
yield(acc, elem, index).tap {
|
10
|
-
index += 1
|
11
|
-
}
|
12
|
-
}
|
13
|
-
end
|
14
|
-
|
15
|
-
def map_with_index
|
16
|
-
Array.new.tap { |result|
|
17
|
-
each_with_index { |elem, index|
|
18
|
-
result << yield(elem, index)
|
19
|
-
}
|
20
|
-
}
|
21
|
-
end
|
22
|
-
|
23
|
-
def select_with_index
|
24
|
-
Array.new.tap { |result|
|
25
|
-
each_with_index { |elem, index|
|
26
|
-
if yield(elem, index)
|
27
|
-
result << elem
|
28
|
-
end
|
29
|
-
}
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'tmpdir'
|
3
|
-
require 'quix/builtin/kernel/tap'
|
4
|
-
|
5
|
-
module Quix
|
6
|
-
module FileUtils
|
7
|
-
def rename_file(file, new_name)
|
8
|
-
#
|
9
|
-
# For case-insensitive systems, we must move the file elsewhere
|
10
|
-
# before changing case.
|
11
|
-
#
|
12
|
-
temp = File.join(Dir.tmpdir, File.basename(file))
|
13
|
-
::FileUtils.mv(file, temp)
|
14
|
-
begin
|
15
|
-
::FileUtils.mv(temp, new_name)
|
16
|
-
rescue
|
17
|
-
::FileUtils.mv(temp, file)
|
18
|
-
raise
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def replace_file(file)
|
23
|
-
old_contents = File.read(file)
|
24
|
-
yield(old_contents).tap { |new_contents|
|
25
|
-
File.open(file, "w") { |output|
|
26
|
-
output.print(new_contents)
|
27
|
-
}
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
def stem(file)
|
32
|
-
file.sub(%r!#{File.extname(file)}\Z!, "")
|
33
|
-
end
|
34
|
-
|
35
|
-
extend self
|
36
|
-
end
|
37
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'quix/builtin/kernel/tap'
|
3
|
-
require 'ostruct'
|
4
|
-
|
5
|
-
module Quix
|
6
|
-
class HashStruct < OpenStruct
|
7
|
-
def method_missing(sym, *args, &block)
|
8
|
-
if table.respond_to? sym
|
9
|
-
table.send(sym, *args, &block)
|
10
|
-
else
|
11
|
-
super
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class << self
|
16
|
-
def recursive_new(hash)
|
17
|
-
new.tap { |s|
|
18
|
-
hash.each_pair { |key, value|
|
19
|
-
s.send(
|
20
|
-
:"#{key}=",
|
21
|
-
value.is_a?(Hash) ? recursive_new(value) : value)
|
22
|
-
}
|
23
|
-
}
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'thread'
|
3
|
-
|
4
|
-
module CompTree
|
5
|
-
module Misc
|
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}".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
|
@@ -1,55 +0,0 @@
|
|
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
|
@@ -1,38 +0,0 @@
|
|
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
|