ruby_ex 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +693 -0
- data/NEWS +74 -0
- data/SPEC.dyn.yml +6 -6
- data/SPEC.gemspec +14 -0
- data/SPEC.yml +4 -4
- data/lib/abstract.rb +2 -4
- data/lib/abstract_node.rb +1 -2
- data/lib/algorithms/simulated_annealing.rb +50 -29
- data/lib/attributed_class.rb +50 -21
- data/lib/auto_object.rb +102 -0
- data/lib/blank_slate.rb +102 -0
- data/lib/cache.rb +1 -2
- data/lib/choose.rb +165 -163
- data/lib/commands.rb +2 -3
- data/lib/commands/command.rb +47 -20
- data/lib/commands/datas.rb +1 -1
- data/lib/commands/datas/composite.rb +5 -1
- data/lib/commands/datas/data.rb +102 -5
- data/lib/commands/datas/factory.rb +13 -6
- data/lib/commands/datas/temp.rb +3 -5
- data/lib/commands/factory.rb +1 -1
- data/lib/commands/helpers.rb +1 -1
- data/lib/commands/pipe.rb +10 -1
- data/lib/commands/runners.rb +1 -1
- data/lib/commands/runners/exec.rb +1 -1
- data/lib/commands/runners/fork.rb +3 -16
- data/lib/commands/runners/mock.rb +67 -0
- data/lib/commands/runners/runner.rb +5 -3
- data/lib/commands/runners/system.rb +1 -1
- data/lib/commands/seq.rb +2 -1
- data/lib/config_file.rb +10 -2
- data/lib/const_regexp.rb +1 -2
- data/lib/{dlogger.rb → d_logger.rb} +1 -2
- data/lib/daemon.rb +1 -2
- data/lib/diff.rb +1 -2
- data/lib/drb/drb_observable.rb +1 -2
- data/lib/drb/drb_observable_pool.rb +2 -2
- data/lib/drb/drb_service.rb +1 -2
- data/lib/drb/drb_undumped_attributes.rb +1 -2
- data/lib/drb/drb_undumped_indexed_object.rb +1 -2
- data/lib/drb/insecure_protected_methods.rb +1 -2
- data/lib/drb_ex.rb +2 -2
- data/lib/file_type.rb +466 -0
- data/lib/generate_id.rb +12 -6
- data/lib/genpasswd.rb +22 -0
- data/lib/hash_eval.rb +83 -0
- data/lib/histogram.rb +1 -2
- data/lib/hookable.rb +3 -4
- data/lib/hooker.rb +1 -3
- data/lib/html_encode.rb +191 -0
- data/lib/indexed_node.rb +0 -1
- data/lib/io_marshal.rb +4 -2
- data/lib/ioo.rb +3 -2
- data/lib/kill_all.rb +46 -0
- data/lib/labeled_node.rb +0 -1
- data/lib/logger_observer.rb +8 -4
- data/lib/md5sum.rb +3 -3
- data/lib/meta_factory.rb +99 -0
- data/lib/method_call.rb +87 -0
- data/lib/mocks.rb +12 -0
- data/lib/mocks/assertions.rb +50 -0
- data/lib/mocks/method_logger.rb +40 -0
- data/lib/mocks/mock.rb +64 -0
- data/lib/mocks/object.rb +47 -0
- data/lib/mocks/observer.rb +38 -0
- data/lib/module/autoload_tree.rb +30 -29
- data/lib/module/hierarchy.rb +176 -171
- data/lib/module/instance_method_visibility.rb +39 -38
- data/lib/node.rb +0 -1
- data/lib/object_monitor.rb +1 -2
- data/lib/object_monitor_activity.rb +1 -2
- data/lib/observable.rb +1 -2
- data/lib/observable_pool.rb +1 -2
- data/lib/{orderedhash.rb → ordered_hash.rb} +41 -5
- data/lib/pp_hierarchy.rb +7 -2
- data/lib/r_path.rb +307 -0
- data/lib/random_generators.rb +7 -20
- data/lib/random_generators/random_generator.rb +2 -4
- data/lib/random_generators/ruby.rb +4 -2
- data/lib/regex_path.rb +124 -0
- data/lib/ruby_ex.rb +28 -98
- data/lib/safe_eval.rb +1 -2
- data/lib/sendmail.rb +14 -17
- data/lib/service_manager.rb +1 -2
- data/lib/shuffle.rb +6 -2
- data/lib/spring.rb +1 -2
- data/lib/spring_set.rb +1 -2
- data/lib/{symtbl.rb → sym_tbl.rb} +90 -5
- data/lib/sym_tbl_gsub.rb +227 -0
- data/lib/{synflow.rb → syn_flow.rb} +1 -2
- data/lib/text.rb +218 -0
- data/lib/timeout_ex.rb +1 -2
- data/lib/trace.rb +9 -8
- data/lib/uri/druby.rb +1 -2
- data/lib/uri/file.rb +1 -1
- data/lib/uri/ftp_ex.rb +1 -1
- data/lib/uri/http_ex.rb +1 -1
- data/lib/uri/mysql.rb +121 -0
- data/lib/uri/pgsql.rb +19 -38
- data/lib/uri/svn.rb +1 -2
- data/lib/uri_ex.rb +45 -3
- data/lib/verbose_object.rb +181 -38
- data/lib/yaml/chop_header.rb +19 -11
- data/lib/yaml/transform.rb +17 -11
- data/lib/yaml/yregexpath.rb +11 -5
- data/test/algorithms/simulated_annealing_test.rb +2 -2
- data/test/resources/foo.tar.gz +0 -0
- data/test/resources/tar.gz.log +49 -0
- data/test/sanity-suite.yml +5 -7
- data/test/sanity/multiple-requires.yml +17 -7
- data/test/sanity/single-requires.yml +38 -20
- data/test/stress-tests/threads_and_exceptions.yml +13 -0
- data/test/test-unit-setup.rb +3 -1
- data/test/unit-suite.yml +7 -8
- metadata +42 -31
- data/lib/algorithms.rb +0 -12
- data/lib/ask.rb +0 -100
- data/lib/checkout.rb +0 -12
- data/lib/dumpable_proc.rb +0 -57
- data/lib/filetype.rb +0 -229
- data/lib/thread_mutex.rb +0 -11
- data/lib/yaml/basenode_ext.rb +0 -63
data/lib/shuffle.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
2
|
# Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
|
3
3
|
# License:: GNU General Public License (GPL).
|
4
|
-
# Revision:: $Id: shuffle.rb
|
4
|
+
# Revision:: $Id: shuffle.rb 339 2005-09-06 23:27:27Z ertai $
|
5
5
|
|
6
|
-
|
6
|
+
module Shuffle
|
7
7
|
|
8
8
|
def shuffle! ( generator=nil )
|
9
9
|
n = size
|
@@ -25,6 +25,10 @@ class Array
|
|
25
25
|
dup.swap!(i, j)
|
26
26
|
end
|
27
27
|
|
28
|
+
end # module Shuffle
|
29
|
+
|
30
|
+
class Array
|
31
|
+
include Shuffle
|
28
32
|
end # class Array
|
29
33
|
|
30
34
|
|
data/lib/spring.rb
CHANGED
data/lib/spring_set.rb
CHANGED
@@ -3,9 +3,8 @@
|
|
3
3
|
# License: Ruby license.
|
4
4
|
|
5
5
|
# $LastChangedBy: ertai $
|
6
|
-
# $Id:
|
6
|
+
# $Id: sym_tbl.rb 339 2005-09-06 23:27:27Z ertai $
|
7
7
|
|
8
|
-
require 'ruby_ex'
|
9
8
|
require 'set'
|
10
9
|
|
11
10
|
class SymTbl
|
@@ -15,12 +14,23 @@ class SymTbl
|
|
15
14
|
attr_reader :sid, :local, :father
|
16
15
|
|
17
16
|
def initialize ( father_env=nil, default=nil )
|
18
|
-
@father = father_env
|
19
17
|
@sid = (@@sid += 1)
|
20
18
|
@local = Hash.new(default)
|
19
|
+
if father_env.is_a? Hash
|
20
|
+
@father = nil
|
21
|
+
merge!(father_env)
|
22
|
+
else
|
23
|
+
@father = father_env
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def key_convert ( aKey )
|
28
|
+
(aKey.is_a? Symbol)? aKey : aKey.to_s.to_sym
|
21
29
|
end
|
22
30
|
|
23
31
|
def [] ( aKey )
|
32
|
+
return nil if aKey == ''
|
33
|
+
aKey = key_convert(aKey)
|
24
34
|
if @local.has_key? aKey
|
25
35
|
@local[aKey]
|
26
36
|
elsif @father.nil?
|
@@ -31,6 +41,7 @@ class SymTbl
|
|
31
41
|
end
|
32
42
|
|
33
43
|
def []= ( aKey, aValue )
|
44
|
+
aKey = key_convert(aKey)
|
34
45
|
@local[aKey] = aValue
|
35
46
|
end
|
36
47
|
|
@@ -62,15 +73,60 @@ class SymTbl
|
|
62
73
|
ancestors.map{ |s| s.desc_one }.to_yaml
|
63
74
|
end
|
64
75
|
|
76
|
+
def merge(other)
|
77
|
+
symtbl = self.class.new(self)
|
78
|
+
symtbl.merge!(other)
|
79
|
+
end
|
80
|
+
|
81
|
+
def merge!(other)
|
82
|
+
other.each { |k, v| @local[key_convert(k)] = v }
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
alias update merge!
|
87
|
+
|
88
|
+
def has_key?(key)
|
89
|
+
key = key_convert(key)
|
90
|
+
if @local.has_key?(key)
|
91
|
+
true
|
92
|
+
else
|
93
|
+
if @father.nil?
|
94
|
+
false
|
95
|
+
else
|
96
|
+
@father.has_key?(key)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
alias key? has_key?
|
102
|
+
alias include? has_key?
|
103
|
+
alias member? has_key?
|
104
|
+
|
105
|
+
def has_local_key?(key)
|
106
|
+
@local.has_key?(key_convert(key))
|
107
|
+
end
|
108
|
+
|
109
|
+
def new_child
|
110
|
+
self.class.new(self)
|
111
|
+
end
|
112
|
+
|
65
113
|
end # class SymTbl
|
66
114
|
|
67
115
|
|
68
116
|
|
69
117
|
test_section __FILE__ do
|
70
118
|
|
71
|
-
require 'ruby_ex'
|
72
119
|
class SymTblTest < Test::Unit::TestCase
|
73
120
|
|
121
|
+
def setup
|
122
|
+
@father = SymTbl.new
|
123
|
+
@father[:a] = 0
|
124
|
+
@father[:b] = 1
|
125
|
+
@son = SymTbl.new(@father)
|
126
|
+
@son[:a] = 10
|
127
|
+
@son[:c] = 2
|
128
|
+
end
|
129
|
+
|
74
130
|
def test1
|
75
131
|
root = SymTbl.new
|
76
132
|
|
@@ -99,10 +155,39 @@ test_section __FILE__ do
|
|
99
155
|
|
100
156
|
assert_equal(42, sub2[:a], 't8')
|
101
157
|
|
102
|
-
assert_equal([{
|
158
|
+
assert_equal([{4=>{:a=>42}}, {3=>{:a=>2, :c=>3}}, {2=>{:b=>1, :a=>0}}],
|
103
159
|
YAML::load(sub2.desc))
|
104
160
|
end
|
105
161
|
|
162
|
+
def test_has_key?
|
163
|
+
assert(@son.has_key?(:a))
|
164
|
+
assert(@son.has_key?(:b))
|
165
|
+
assert(@son.has_key?(:c))
|
166
|
+
assert(! @son.has_key?(:not_a_key))
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_merge!
|
170
|
+
s = SymTbl.new
|
171
|
+
s[:a] = 40
|
172
|
+
s[:c] = 42
|
173
|
+
@son.merge!(s)
|
174
|
+
assert_equal(40, @son[:a])
|
175
|
+
assert_equal(42, @son[:c])
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_merge
|
179
|
+
s = SymTbl.new
|
180
|
+
s[:a] = 40
|
181
|
+
s[:c] = 42
|
182
|
+
r = @son.merge(s)
|
183
|
+
assert_equal(10, @son[:a])
|
184
|
+
assert_equal(2, @son[:c])
|
185
|
+
assert_equal(40, r[:a])
|
186
|
+
assert_equal(1, r[:b])
|
187
|
+
assert_equal(42, r[:c])
|
188
|
+
assert_equal(@son, r.father)
|
189
|
+
end
|
190
|
+
|
106
191
|
end # class SymTblTest
|
107
192
|
|
108
193
|
end
|
data/lib/sym_tbl_gsub.rb
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
|
3
|
+
# License:: Ruby License
|
4
|
+
# Revision:: $Id: sym_tbl_gsub.rb 339 2005-09-06 23:27:27Z ertai $
|
5
|
+
|
6
|
+
require 'sym_tbl'
|
7
|
+
|
8
|
+
class Object
|
9
|
+
|
10
|
+
def symtbl_gsub ( symtbl )
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def do_symtbl_gsub ( symtbl )
|
15
|
+
result = symtbl_gsub(symtbl)
|
16
|
+
return (result.nil?)? self : result
|
17
|
+
end
|
18
|
+
|
19
|
+
def symtbl_to_s
|
20
|
+
to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
end # class Object
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
module PrettyInspect
|
28
|
+
def symtbl_to_s
|
29
|
+
inspect
|
30
|
+
end
|
31
|
+
end # module PrettyInspect
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
class Hash
|
36
|
+
have PrettyInspect
|
37
|
+
|
38
|
+
def symtbl_gsub ( symtbl )
|
39
|
+
changed = false
|
40
|
+
res = self.class.new
|
41
|
+
each do |k,v|
|
42
|
+
new_k = k.symtbl_gsub(symtbl)
|
43
|
+
new_v = v.symtbl_gsub(symtbl)
|
44
|
+
changed = true if new_k or new_v
|
45
|
+
res[new_k || k] = (new_v || v)
|
46
|
+
end
|
47
|
+
changed ? res : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
end # class Hash
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
class Array
|
55
|
+
have PrettyInspect
|
56
|
+
|
57
|
+
def symtbl_gsub ( symtbl )
|
58
|
+
changed = false
|
59
|
+
res = self.class.new
|
60
|
+
each do |e|
|
61
|
+
changed = true if new_e = e.symtbl_gsub(symtbl)
|
62
|
+
res << (new_e || e)
|
63
|
+
end
|
64
|
+
changed ? res : nil
|
65
|
+
end
|
66
|
+
|
67
|
+
end # class Array
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
class SymTbl
|
72
|
+
|
73
|
+
def symtbl_gsub! ( symtbl )
|
74
|
+
new_local = @local.symtbl_gsub(symtbl)
|
75
|
+
return nil if new_local.nil?
|
76
|
+
@local = new_local
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def symtbl_gsub ( symtbl )
|
81
|
+
dup.symtbl_gsub!(symtbl)
|
82
|
+
end
|
83
|
+
|
84
|
+
end # class SymTbl
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
class Pathname
|
89
|
+
|
90
|
+
def symtbl_gsub ( symtbl )
|
91
|
+
res = to_s.symtbl_gsub(symtbl)
|
92
|
+
return self.class.new(res) unless res.nil?
|
93
|
+
end
|
94
|
+
|
95
|
+
end # class Pathname
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
class Regexp
|
100
|
+
have PrettyInspect
|
101
|
+
|
102
|
+
def symtbl_gsub ( symtbl )
|
103
|
+
res = source.symtbl_gsub(symtbl)
|
104
|
+
return self.class.new(res) unless res.nil?
|
105
|
+
end
|
106
|
+
|
107
|
+
end # class Regexp
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
class Symbol
|
112
|
+
|
113
|
+
def symtbl_gsub ( symtbl )
|
114
|
+
res = to_s.symtbl_gsub(symtbl)
|
115
|
+
return res.to_sym unless res.nil?
|
116
|
+
end
|
117
|
+
|
118
|
+
end # class Symbol
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
class String
|
123
|
+
|
124
|
+
def symtbl_gsub ( symtbl )
|
125
|
+
return nil unless self =~ /<<(.*)>>/
|
126
|
+
cur, last = self, nil
|
127
|
+
while cur != last
|
128
|
+
last = cur
|
129
|
+
cur = cur.gsub(/<<([^<>]*)>>/) do
|
130
|
+
s = symtbl[$1]
|
131
|
+
(s.nil?)? $& : s.symtbl_to_s
|
132
|
+
end
|
133
|
+
end
|
134
|
+
(cur == self)? nil : cur
|
135
|
+
end
|
136
|
+
|
137
|
+
end # class String
|
138
|
+
|
139
|
+
|
140
|
+
PathList.import!
|
141
|
+
class PathList
|
142
|
+
|
143
|
+
alias add_matching_without_expand add_matching
|
144
|
+
def add_matching(pattern)
|
145
|
+
pattern = @expand[pattern] if defined? @expand and @expand
|
146
|
+
add_matching_without_expand pattern
|
147
|
+
end
|
148
|
+
protected :add_matching
|
149
|
+
|
150
|
+
def symtbl_gsub! ( symtbl )
|
151
|
+
@expand = lambda { |pattern| pattern.do_symtbl_gsub(symtbl) }
|
152
|
+
map! { |path| path.do_symtbl_gsub(symtbl) }
|
153
|
+
@expand = nil
|
154
|
+
self
|
155
|
+
end
|
156
|
+
|
157
|
+
def symtbl_gsub ( symtbl )
|
158
|
+
dup.symtbl_gsub!(symtbl)
|
159
|
+
end
|
160
|
+
|
161
|
+
end # class PathList
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
module SymTblGsub
|
166
|
+
|
167
|
+
test_section __FILE__ do
|
168
|
+
class SymTblGsubTest < Test::Unit::TestCase
|
169
|
+
def setup
|
170
|
+
@s = SymTbl.new(
|
171
|
+
:foo => :bar,
|
172
|
+
:bar => [1, 2],
|
173
|
+
3 => 'foo',
|
174
|
+
:i => '<<j>>',
|
175
|
+
:j => '<<3>>',
|
176
|
+
:pwd => __FILE__.to_path.dirname.to_s
|
177
|
+
)
|
178
|
+
end
|
179
|
+
def assert_symtbl ( my, ref=nil )
|
180
|
+
assert_equal ref, my.symtbl_gsub(@s)
|
181
|
+
end
|
182
|
+
def test_string
|
183
|
+
assert_symtbl '<<foo>>', 'bar'
|
184
|
+
assert_symtbl '<<foo>><<3>> >> <<', 'barfoo >> <<'
|
185
|
+
assert_symtbl '<<<<>>>>%%><<>>^#^#'
|
186
|
+
assert_symtbl '<<<<bar>>>>', '<<[1, 2]>>'
|
187
|
+
assert_symtbl '%<<<<foo>>>>#', '%[1, 2]#'
|
188
|
+
assert_symtbl "_\n\t\000_<<i>>__", "_\n\t\000_foo__"
|
189
|
+
assert_symtbl '<<<<i>>>>', 'bar'
|
190
|
+
assert_symtbl '<<dne>> <<foo>>', '<<dne>> bar'
|
191
|
+
end
|
192
|
+
class Foo
|
193
|
+
end
|
194
|
+
def test_object
|
195
|
+
assert_symtbl Foo.new
|
196
|
+
end
|
197
|
+
def test_hash
|
198
|
+
assert_symtbl({'<<foo>>' => '<<i>>', 'barbar' => '<<3>>' },
|
199
|
+
{'barbar'=>'foo', 'bar'=>'foo'})
|
200
|
+
end
|
201
|
+
def test_array
|
202
|
+
assert_symtbl(['<<foo>>', '<<i>>', 'barbar <<3>>' ],
|
203
|
+
['bar', 'foo', 'barbar foo'])
|
204
|
+
end
|
205
|
+
def test_pathname
|
206
|
+
assert_symtbl('foo/<<foo>>/<<i>>'.to_path, 'foo/bar/foo'.to_path)
|
207
|
+
end
|
208
|
+
def test_regexp
|
209
|
+
assert_symtbl(/<<foo>>(<<i>>)*/, /bar(foo)*/)
|
210
|
+
end
|
211
|
+
def test_symbol
|
212
|
+
assert_symtbl(:'<<foo>> <<i>>', :'bar foo')
|
213
|
+
end
|
214
|
+
def test_pathlist
|
215
|
+
pathlist = ['<<foo>>', '<<i>>'.to_path]
|
216
|
+
ls1 = '<<bing>>/../test'.to_path + 'resources/autoload_tree/*.rb'
|
217
|
+
ls2 = '<<pwd>>/../test'.to_path + 'resources/autoload_tree/*.rb'
|
218
|
+
pathlist << ls2 << ls1
|
219
|
+
my = PathList[pathlist].symtbl_gsub(@s).map! { |x| x.basename }
|
220
|
+
my.all? { |x| assert_kind_of(Pathname, x) }
|
221
|
+
ref = %w[ bar foo A.rb B.rb ]
|
222
|
+
assert_equal ref.to_set, my.map!{ |x| x.to_s }.to_set
|
223
|
+
end
|
224
|
+
end # class SymTblGsubTest
|
225
|
+
end
|
226
|
+
|
227
|
+
end # module SymTblGsub
|
@@ -10,7 +10,6 @@
|
|
10
10
|
# parallel systems.
|
11
11
|
#
|
12
12
|
|
13
|
-
require 'ruby_ex'
|
14
13
|
require 'thread'
|
15
14
|
require 'set'
|
16
15
|
|
@@ -146,7 +145,7 @@ class SynFlowFactory
|
|
146
145
|
@transitions.include?(*transition)
|
147
146
|
end
|
148
147
|
|
149
|
-
|
148
|
+
|
150
149
|
def delta ( src, label )
|
151
150
|
@transitions.delta(src, label)
|
152
151
|
end
|
data/lib/text.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
# Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
|
2
|
+
# Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
3
|
+
# License:: Gnu General Public License.
|
4
|
+
# Revision:: $Id: text.rb 359 2005-09-16 10:05:22Z ertai $
|
5
|
+
|
6
|
+
class Text
|
7
|
+
|
8
|
+
attr_accessor :text, :width, :cut_if_needed
|
9
|
+
|
10
|
+
@@default_options = { :width => 78, :cut_if_needed => false }.freeze
|
11
|
+
|
12
|
+
# options:
|
13
|
+
# width: the maximal line width (default 78)
|
14
|
+
# cut_if_needed: see cropping
|
15
|
+
def initialize ( text, options={} )
|
16
|
+
options = @@default_options.merge options
|
17
|
+
@text = text
|
18
|
+
@width = options[:width]
|
19
|
+
@cut_if_needed = options[:cut_if_needed]
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
def justify! ( &block )
|
25
|
+
input = @text.to_a
|
26
|
+
@text, block = '', method(:adder) if block.nil?
|
27
|
+
last_line = input.size - 1
|
28
|
+
input.each_with_index do |line, i|
|
29
|
+
line =~ /^(\s*)(.*)\s*?(\n?)$/
|
30
|
+
indent, base, eol = $1, $2, $3
|
31
|
+
words = base.split(/\s+/)
|
32
|
+
base = words.join(' ')
|
33
|
+
width = indent.width + base.width
|
34
|
+
unless width > @width or base.empty? or i == last_line
|
35
|
+
spaces = words.size - 1
|
36
|
+
padding_size = @width - width
|
37
|
+
if spaces > 0
|
38
|
+
nb = ' ' * (padding_size / spaces + 1)
|
39
|
+
nb2 = nb + ' '
|
40
|
+
rest = padding_size % spaces + 1
|
41
|
+
base.gsub!(/ /) do
|
42
|
+
rest -= 1
|
43
|
+
(rest >= 0) ? nb2 : nb
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
block[indent, base, eol]
|
48
|
+
end
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
def split! ( &block )
|
55
|
+
last_new_line = (@text[-1] == ?\n)? "\n" : ''
|
56
|
+
indent = @text[/\A([ \t]*)/, 1]
|
57
|
+
words = @text.split(/\s+/)
|
58
|
+
@text, block = '', method(:adder) if block.nil?
|
59
|
+
|
60
|
+
line = ''
|
61
|
+
while not words.empty?
|
62
|
+
words.shift if words.first.empty?
|
63
|
+
word = words.first
|
64
|
+
if indent.width + line.width + word.width + 1 <= @width
|
65
|
+
line += ' ' unless line.empty?
|
66
|
+
line += word
|
67
|
+
words.shift
|
68
|
+
elsif line.empty?
|
69
|
+
if @cut_if_needed
|
70
|
+
line = word[0..width-1]
|
71
|
+
words[0] = word[width..-1]
|
72
|
+
block[indent, line, "\n"]
|
73
|
+
line = ''
|
74
|
+
else
|
75
|
+
block[indent, word, "\n"]
|
76
|
+
words.shift
|
77
|
+
end
|
78
|
+
else
|
79
|
+
block[indent, line, "\n"]
|
80
|
+
line = ''
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
block[indent, line, last_new_line] unless line.empty?
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
def split_and_justify! ( &block )
|
91
|
+
split!.justify!(&block)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def crop! ( width=@width, message=" ...\n", &block )
|
96
|
+
input = @text
|
97
|
+
@text, block = '', method(:adder) if block.nil?
|
98
|
+
message = message.to_s
|
99
|
+
width2 = width - 1 - message.chomp.width
|
100
|
+
raise ArgumentError, "Bad width: too low" if width2 < 0
|
101
|
+
input.each do |line|
|
102
|
+
if line.width > width
|
103
|
+
block[line[0..width2], message]
|
104
|
+
else
|
105
|
+
block[line]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
self
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def clip! ( head_size=100, tail_size=30, message="\n[...clipped...]\n\n", &block )
|
113
|
+
input = @text.to_a
|
114
|
+
size = input.size
|
115
|
+
return identity!(&block) if head_size + tail_size >= size
|
116
|
+
head = (head_size - 1 < 0)? [] : input[0 .. head_size - 1]
|
117
|
+
tail = input[[0, size - tail_size, head_size].max .. -1]
|
118
|
+
@text, block = '', method(:adder) if block.nil?
|
119
|
+
head.each(&block)
|
120
|
+
message.each(&block)
|
121
|
+
tail.each(&block)
|
122
|
+
self
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
def adder ( *args )
|
127
|
+
@text += args.join
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def identity! ( &block )
|
132
|
+
@text.each(&block) unless block.nil?
|
133
|
+
self
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
def clear
|
138
|
+
@text.clear
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
def mask!
|
143
|
+
@text = '*****'.to_text
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def to_s
|
148
|
+
@text.dup
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
# Redirect calls like `justify' to `dup.justify!'
|
153
|
+
def method_missing ( meth, *args, &block )
|
154
|
+
in_place_meth = :"#{meth}!"
|
155
|
+
return super unless respond_to? in_place_meth
|
156
|
+
dup.send(in_place_meth, *args, &block)
|
157
|
+
end
|
158
|
+
|
159
|
+
end # class Text
|
160
|
+
|
161
|
+
|
162
|
+
class String
|
163
|
+
def to_text ( *args, &block )
|
164
|
+
Text.new(self, *args, &block)
|
165
|
+
end
|
166
|
+
end # class String
|
167
|
+
|
168
|
+
|
169
|
+
test_section __FILE__ do
|
170
|
+
|
171
|
+
class TestText < ::Test::Unit::TestCase
|
172
|
+
|
173
|
+
def setup
|
174
|
+
@o = { :width => 10 }
|
175
|
+
@text = " foofoof barbarfoo foo f bar for na goo baz buz g"
|
176
|
+
@cropped = " foofo ...\n"
|
177
|
+
@splitted = " foofoof\n barbarfoo\n foo f bar\n for na\n goo baz\n buz g"
|
178
|
+
@splitted_justified = " foofoof\n barbarfoo\n foo f bar\n for na\n goo baz\n buz g"
|
179
|
+
@splitted_justified_cropped = " foofoof\n barba ...\n foo ...\n for ...\n goo ...\n buz g"
|
180
|
+
@clipped = " foofoof\n barbarfoo\n\n[...clipped...]\n\n buz g"
|
181
|
+
end
|
182
|
+
|
183
|
+
def teardown
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_justify
|
187
|
+
assert_equal @splitted_justified, @splitted.to_text(@o).justify.text
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_split
|
191
|
+
assert_equal @splitted, @text.to_text(@o).split.text
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_split_and_justify
|
195
|
+
assert_equal @splitted_justified, @text.to_text(@o).split_and_justify.text
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_crop
|
199
|
+
assert_equal @cropped, @text.to_text(@o).crop.text
|
200
|
+
assert_equal @splitted_justified_cropped, @splitted_justified.to_text(@o).crop.text
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_clip
|
204
|
+
assert_equal @clipped, @splitted_justified.to_text(@o).clip(2, 1).text
|
205
|
+
assert_equal 'yo', @splitted_justified.to_text(@o).clip(0, 0, 'yo').text
|
206
|
+
assert_equal " foofoof\nyo", @splitted_justified.to_text(@o).clip(1, 0, 'yo').text
|
207
|
+
assert_equal 'yo buz g', @splitted_justified.to_text(@o).clip(0, 1, 'yo').text
|
208
|
+
assert_equal @splitted_justified, @splitted_justified.to_text(@o).clip(100, 0, 'yo').text
|
209
|
+
assert_equal @splitted_justified, @splitted_justified.to_text(@o).clip(6, 0, 'yo').text
|
210
|
+
assert_equal @splitted_justified, @splitted_justified.to_text(@o).clip(0, 6, 'yo').text
|
211
|
+
assert_equal @splitted_justified, @splitted_justified.to_text(@o).clip(3, 3, 'yo').text
|
212
|
+
assert_equal " foofoof\n barbarfoo\nyo for na\n goo baz\n buz g",
|
213
|
+
@splitted_justified.to_text(@o).clip(2, 3, 'yo').text
|
214
|
+
end
|
215
|
+
|
216
|
+
end # class TestText
|
217
|
+
|
218
|
+
end
|