utilrb 1.0 → 1.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.txt +72 -56
- data/Manifest.txt +4 -0
- data/Rakefile +1 -1
- data/ext/faster.cc +1 -1
- data/ext/value_set.cc +36 -0
- data/lib/utilrb/array/to_s.rb +3 -10
- data/lib/utilrb/column_formatter.rb +73 -0
- data/lib/utilrb/common.rb +1 -1
- data/lib/utilrb/enumerable/sequence.rb +3 -3
- data/lib/utilrb/enumerable/to_s_helper.rb +17 -0
- data/lib/utilrb/enumerable/uniq.rb +16 -9
- data/lib/utilrb/hash/to_s.rb +4 -1
- data/lib/utilrb/kernel/options.rb +3 -3
- data/lib/utilrb/logger/forward.rb +4 -0
- data/lib/utilrb/module/ancestor_p.rb +2 -2
- data/lib/utilrb/module/attr_enumerable.rb +21 -7
- data/lib/utilrb/module/attr_predicate.rb +4 -3
- data/lib/utilrb/module/cached_enum.rb +26 -0
- data/lib/utilrb/module/define_method.rb +1 -1
- data/lib/utilrb/module/include.rb +5 -5
- data/lib/utilrb/module/inherited_enumerable.rb +106 -47
- data/lib/utilrb/object/attribute.rb +14 -28
- data/lib/utilrb/object/singleton_class.rb +9 -11
- data/lib/utilrb/objectstats.rb +20 -53
- data/lib/utilrb/set/to_s.rb +5 -1
- data/lib/utilrb/time/to_hms.rb +15 -12
- data/lib/utilrb/unbound_method/call.rb +2 -0
- data/lib/utilrb/value_set.rb +5 -10
- data/test/test_array.rb +6 -0
- data/test/test_enumerable.rb +14 -4
- data/test/test_hash.rb +9 -1
- data/test/test_objectstats.rb +11 -4
- data/test/test_set.rb +19 -0
- data/test/test_time.rb +4 -1
- metadata +17 -8
data/Changes.txt
CHANGED
@@ -1,74 +1,90 @@
|
|
1
|
+
=== Version 1.1
|
2
|
+
|
3
|
+
* changes and fixes:
|
4
|
+
- fix documentation here and there
|
5
|
+
- make sure all defined #to_s methods handle recursion
|
6
|
+
- defined Module#cached_enum: returns an Enumerator method for
|
7
|
+
a "each_" method, cachin the enumerator object. Works also
|
8
|
+
for iteration with one argument (caching one Enumerator by
|
9
|
+
argument)
|
10
|
+
- fix Time.from_hms when the millisecond field has leading zeroes
|
11
|
+
- optimizations here and there:
|
12
|
+
* Array#to_value_set does not rely on rb_iterate
|
13
|
+
* specific implementation of ValueSet#dup
|
14
|
+
* more generally, avoid object allocation where possible
|
15
|
+
- ColumnFormatter object: formats CSV output for display
|
16
|
+
|
1
17
|
=== Version 1.0
|
2
18
|
Bumped version number because of incompatible changes. Make it 1.0 since
|
3
19
|
having 0. version numbers for this kind of library is completely meaningless
|
4
20
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
* incompatible changes:
|
22
|
+
- Enumerable#+ acts on too many objects. Define it only on Enumerable::Enumerator
|
23
|
+
- remove automatic convertion into ValueSet for methods which were doing it
|
24
|
+
- removed Queue#get: fastthread is now the preferred threading library in
|
25
|
+
Ruby 1.8.6, so Queue#get cannot be implemented anymore
|
26
|
+
|
27
|
+
* new features:
|
28
|
+
- PkgConfig class
|
29
|
+
- define Proc#same_body?, Proc#file and Proc#line
|
30
|
+
- Module#attr_predicate
|
31
|
+
- 'since', 'until' and block parameters for Exception#full_message
|
32
|
+
- ValueSet#intersects? (more efficient than checking that the intersection
|
33
|
+
is empty)
|
34
|
+
|
35
|
+
* changes and fixes:
|
36
|
+
- properly handle singleton classes in has_ancestor?
|
37
|
+
- properly handle recursion in ValueSet#to_s and Array#to_s
|
38
|
+
- add the 'setup' task on the Rakefile to build the C extension
|
39
|
+
- make Module#has_ancestor? work event if the C extension is not built
|
24
40
|
|
25
41
|
=== Version 0.2.3
|
26
42
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
* new features:
|
44
|
+
- BenchmarkAllocation, a Benchmark-like interface to benchmark object
|
45
|
+
allocation
|
46
|
+
- ValueSet#delete_if
|
47
|
+
- Time#from_hms takes a time as "h:m:s.ms" and builds the corresponding
|
48
|
+
Time object. Note that "s", "s.ms", "m:s", "m:s.ms", ... are accepted
|
49
|
+
formats
|
50
|
+
|
51
|
+
* changes and fixes:
|
52
|
+
- define Queue#get only if we are using Ruby's core Queue. The current
|
53
|
+
implementation is incompatible with fastthread for instance (and
|
54
|
+
fastthhread's maintainer does not want #get on its Queue). Included
|
55
|
+
a patch to define Queue#get on fastthread
|
56
|
+
- fix ValueSet#== raising if the argument is not a ValueSet
|
57
|
+
- fix brain-dead SequenceEnumerator#+, which was changing its receiver
|
42
58
|
|
43
59
|
=== Version 0.2.2
|
44
60
|
The "don't forget to bump version number" release. 0.2 was supposed to be 0.2.1
|
45
61
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
62
|
+
* new features:
|
63
|
+
- Queue#get: waits for the queue to be not empty and returns all elements at
|
64
|
+
once. A non_block parameter is given which makes get() return [] if the
|
65
|
+
queue is empty
|
50
66
|
|
51
|
-
|
52
|
-
|
53
|
-
|
67
|
+
* changes:
|
68
|
+
- Array#to_s and Hash#to_s now enclose the result in [] and {}. The difference
|
69
|
+
with #inspect is that we call #to_s on the elements.
|
54
70
|
|
55
71
|
=== Version 0.2.1
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
72
|
+
* new features:
|
73
|
+
- Kernel#is_singleton?
|
74
|
+
- Module#inherited_enumerable (class_inherited_enumerable on steroids)
|
75
|
+
- Module#attribute() can be used in singleton classes (previously we had to
|
76
|
+
call class_attribute() in the class itself)
|
77
|
+
- UnboundMethod#call(obj, *args, &block) calls the method on obj with
|
78
|
+
the provided arguments (does m.bind(obj).call(*args, &block))
|
79
|
+
|
80
|
+
* changes:
|
81
|
+
- changed semantics of Module::include for inclusion of modules in modules:
|
82
|
+
the source_module::ClassExtension gets included in
|
83
|
+
target_module::ClassExtension. Previously, it was extending the target's
|
84
|
+
singleton class. This way, Module really acts as a mixin for both class
|
85
|
+
methods and instance methods
|
70
86
|
|
71
87
|
=== Version 0.1
|
72
|
-
|
88
|
+
* Initial release
|
73
89
|
|
74
90
|
|
data/Manifest.txt
CHANGED
@@ -13,11 +13,13 @@ ext/value_set.cc
|
|
13
13
|
lib/utilrb.rb
|
14
14
|
lib/utilrb/array.rb
|
15
15
|
lib/utilrb/array/to_s.rb
|
16
|
+
lib/utilrb/column_formatter.rb
|
16
17
|
lib/utilrb/common.rb
|
17
18
|
lib/utilrb/enumerable.rb
|
18
19
|
lib/utilrb/enumerable/null.rb
|
19
20
|
lib/utilrb/enumerable/random_element.rb
|
20
21
|
lib/utilrb/enumerable/sequence.rb
|
22
|
+
lib/utilrb/enumerable/to_s_helper.rb
|
21
23
|
lib/utilrb/enumerable/uniq.rb
|
22
24
|
lib/utilrb/exception.rb
|
23
25
|
lib/utilrb/exception/full_message.rb
|
@@ -40,6 +42,7 @@ lib/utilrb/module.rb
|
|
40
42
|
lib/utilrb/module/ancestor_p.rb
|
41
43
|
lib/utilrb/module/attr_enumerable.rb
|
42
44
|
lib/utilrb/module/attr_predicate.rb
|
45
|
+
lib/utilrb/module/cached_enum.rb
|
43
46
|
lib/utilrb/module/define_method.rb
|
44
47
|
lib/utilrb/module/include.rb
|
45
48
|
lib/utilrb/module/inherited_enumerable.rb
|
@@ -70,5 +73,6 @@ test/test_object.rb
|
|
70
73
|
test/test_objectstats.rb
|
71
74
|
test/test_pkgconfig.rb
|
72
75
|
test/test_proc.rb
|
76
|
+
test/test_set.rb
|
73
77
|
test/test_time.rb
|
74
78
|
test/test_unbound_method.rb
|
data/Rakefile
CHANGED
@@ -20,7 +20,7 @@ Hoe.new('utilrb', Utilrb::VERSION) do |p|
|
|
20
20
|
p.summary = 'Yet another Ruby toolkit'
|
21
21
|
p.description = p.paragraphs_of('README.txt', 3..6).join("\n\n")
|
22
22
|
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
23
|
-
p.changes = p.paragraphs_of('Changes.txt', 0..
|
23
|
+
p.changes = p.paragraphs_of('Changes.txt', 0..1).join("\n\n")
|
24
24
|
|
25
25
|
p.extra_deps << 'facets'
|
26
26
|
p.rdoc_pattern = /(ext\/.*cc$|lib)|txt/
|
data/ext/faster.cc
CHANGED
data/ext/value_set.cc
CHANGED
@@ -101,6 +101,22 @@ static VALUE value_set_include_p(VALUE vself, VALUE vother)
|
|
101
101
|
*/
|
102
102
|
static VALUE value_set_to_value_set(VALUE self) { return self; }
|
103
103
|
|
104
|
+
/* call-seq:
|
105
|
+
* set.dup => other_set
|
106
|
+
*
|
107
|
+
* Duplicates this set, without duplicating the pointed-to objects
|
108
|
+
*/
|
109
|
+
static VALUE value_set_dup(VALUE vself, VALUE vother)
|
110
|
+
{
|
111
|
+
ValueSet const& self = get_wrapped_set(vself);
|
112
|
+
VALUE vresult = rb_funcall(cValueSet, id_new, 0);
|
113
|
+
ValueSet& result = get_wrapped_set(vresult);
|
114
|
+
for (ValueSet::const_iterator it = self.begin(); it != self.end(); ++it)
|
115
|
+
result.insert(result.end(), *it);
|
116
|
+
|
117
|
+
return vresult;
|
118
|
+
}
|
119
|
+
|
104
120
|
/* call-seq:
|
105
121
|
* set.include_all?(other) => true or false
|
106
122
|
*
|
@@ -302,6 +318,24 @@ static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
|
|
302
318
|
return Qnil;
|
303
319
|
}
|
304
320
|
|
321
|
+
/* call-seq:
|
322
|
+
* to_value_set => value_set
|
323
|
+
*
|
324
|
+
* Converts this array into a ValueSet object
|
325
|
+
*/
|
326
|
+
static VALUE array_to_value_set(VALUE self)
|
327
|
+
{
|
328
|
+
VALUE vresult = rb_funcall(cValueSet, id_new, 0);
|
329
|
+
ValueSet& result = get_wrapped_set(vresult);
|
330
|
+
|
331
|
+
VALUE* ptr = RARRAY(self)->ptr;
|
332
|
+
long size = RARRAY(self)->len;
|
333
|
+
for (int i = 0; i < size; ++i)
|
334
|
+
result.insert(ptr[i]);
|
335
|
+
|
336
|
+
return vresult;
|
337
|
+
}
|
338
|
+
|
305
339
|
/* call-seq:
|
306
340
|
* enum.to_value_set => value_set
|
307
341
|
*
|
@@ -328,6 +362,7 @@ static VALUE enumerable_to_value_set(VALUE self)
|
|
328
362
|
extern "C" void Init_value_set()
|
329
363
|
{
|
330
364
|
rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);
|
365
|
+
rb_define_method(rb_cArray, "to_value_set", RUBY_METHOD_FUNC(array_to_value_set), 0);
|
331
366
|
|
332
367
|
cValueSet = rb_define_class("ValueSet", rb_cObject);
|
333
368
|
id_new = rb_intern("new");
|
@@ -344,6 +379,7 @@ extern "C" void Init_value_set()
|
|
344
379
|
rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
|
345
380
|
rb_define_method(cValueSet, "==", RUBY_METHOD_FUNC(value_set_equal), 1);
|
346
381
|
rb_define_method(cValueSet, "to_value_set", RUBY_METHOD_FUNC(value_set_to_value_set), 0);
|
382
|
+
rb_define_method(cValueSet, "dup", RUBY_METHOD_FUNC(value_set_dup), 0);
|
347
383
|
rb_define_method(cValueSet, "empty?", RUBY_METHOD_FUNC(value_set_empty_p), 0);
|
348
384
|
rb_define_method(cValueSet, "size", RUBY_METHOD_FUNC(value_set_size), 0);
|
349
385
|
rb_define_method(cValueSet, "clear", RUBY_METHOD_FUNC(value_set_clear), 0);
|
data/lib/utilrb/array/to_s.rb
CHANGED
@@ -1,17 +1,10 @@
|
|
1
|
+
require 'utilrb/enumerable/to_s_helper'
|
1
2
|
class Array
|
2
3
|
# Displays arrays as [ a, b, [c, d], ... ] instead of the standard #join
|
3
4
|
# Unlike #inspect, it calls #to_s on the elements too
|
4
5
|
def to_s
|
5
|
-
|
6
|
-
|
7
|
-
"..."
|
8
|
-
else
|
9
|
-
begin
|
10
|
-
stack.push object_id
|
11
|
-
"[" << map { |obj| obj.to_s }.join(", ") << "]"
|
12
|
-
ensure
|
13
|
-
stack.pop
|
14
|
-
end
|
6
|
+
EnumerableToString.to_s_helper(self, '[', ']') do |obj|
|
7
|
+
obj.to_s
|
15
8
|
end
|
16
9
|
end
|
17
10
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Displays a set of data into a column-formatted table
|
2
|
+
class ColumnFormatter
|
3
|
+
MARGIN = 3
|
4
|
+
SCREEN_WIDTH = 90
|
5
|
+
|
6
|
+
# data is an array of hashes. Each line of the array is a line to display,
|
7
|
+
# a hash being a column_name => value data set. The special 'label' column
|
8
|
+
# name is used to give a name to each line.
|
9
|
+
#
|
10
|
+
# If a block is given, the method yields the column names and the block must
|
11
|
+
# return the array of columns to be displayed, sorted into the order of
|
12
|
+
# the columns.
|
13
|
+
def self.from_hashes(data, io = STDOUT, margin = MARGIN, screen_width = SCREEN_WIDTH)
|
14
|
+
width = Hash.new
|
15
|
+
|
16
|
+
# First, determine the columns width and height, and
|
17
|
+
# convert data into strings
|
18
|
+
data = data.map do |line_data|
|
19
|
+
line_data = line_data.inject({}) do |h, (label, data)|
|
20
|
+
h[label.to_s] = data.to_s
|
21
|
+
h
|
22
|
+
end
|
23
|
+
|
24
|
+
line_data.each do |label, data|
|
25
|
+
unless width.has_key?(label)
|
26
|
+
width[label] = label.length
|
27
|
+
end
|
28
|
+
|
29
|
+
if width[label] < data.length
|
30
|
+
width[label] = data.length
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Then ask the user to sort the keys for us
|
36
|
+
names = width.keys.dup
|
37
|
+
names.delete('label')
|
38
|
+
names = if block_given? then yield(names)
|
39
|
+
else names.sort
|
40
|
+
end
|
41
|
+
|
42
|
+
# Finally, format and display
|
43
|
+
while !names.empty?
|
44
|
+
# we determine the set of columns to display
|
45
|
+
if width.has_key?('label')
|
46
|
+
line_n = ['label']
|
47
|
+
line_w = width['label']
|
48
|
+
format = ["% #{line_w}s"]
|
49
|
+
else
|
50
|
+
line_n = []
|
51
|
+
line_w = 0
|
52
|
+
format = []
|
53
|
+
end
|
54
|
+
|
55
|
+
while !names.empty? && (line_w < screen_width)
|
56
|
+
col_n = names.shift
|
57
|
+
col_w = width[col_n]
|
58
|
+
line_n << col_n
|
59
|
+
line_w += col_w
|
60
|
+
format << "% #{col_w}s"
|
61
|
+
end
|
62
|
+
|
63
|
+
format = format.join(" " * margin)
|
64
|
+
io.puts format % line_n
|
65
|
+
data.each do |line_data|
|
66
|
+
line_data = line_data.values_at(*line_n)
|
67
|
+
line_data.map! { |v| v || '-' }
|
68
|
+
io.puts format % line_data
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
data/lib/utilrb/common.rb
CHANGED
@@ -2,9 +2,9 @@ require 'enumerator'
|
|
2
2
|
|
3
3
|
# An enumerator which iterates on multiple iterators in sequence
|
4
4
|
#
|
5
|
-
# ([1, 2].enum_for + [2, 3].enum_for).
|
5
|
+
# ([1, 2].enum_for + [2, 3].enum_for).to_a # => [1, 2, 2, 3]
|
6
6
|
#
|
7
|
-
# See also Enumerator#+
|
7
|
+
# See also Enumerable::Enumerator#+
|
8
8
|
class SequenceEnumerator
|
9
9
|
def initialize; @sequence = Array.new end
|
10
10
|
|
@@ -22,7 +22,7 @@ end
|
|
22
22
|
|
23
23
|
class Enumerable::Enumerator # :nodoc
|
24
24
|
# Builds a sequence of enumeration object.
|
25
|
-
# ([1, 2].enum_for + [2, 3]).
|
25
|
+
# ([1, 2].enum_for + [2, 3].enum_for).to_a # => [1, 2, 2, 3]
|
26
26
|
def +(other_enumerator) # :nodoc
|
27
27
|
SequenceEnumerator.new << self << other_enumerator
|
28
28
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module EnumerableToString
|
2
|
+
# This method is a generic implementaion of #to_s on enumerables.
|
3
|
+
def self.to_s_helper(enumerable, start, stop)
|
4
|
+
stack = (Thread.current[:to_s_helper] ||= [])
|
5
|
+
if stack.include?(enumerable.object_id)
|
6
|
+
"..."
|
7
|
+
else
|
8
|
+
begin
|
9
|
+
stack.push enumerable.object_id
|
10
|
+
start.dup << enumerable.map { |el| yield(el) }.join(", ") << stop
|
11
|
+
ensure
|
12
|
+
stack.pop
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -2,11 +2,19 @@ require 'utilrb/common'
|
|
2
2
|
require 'enumerator'
|
3
3
|
require 'set'
|
4
4
|
|
5
|
-
# Enumerator object which removes duplicate entries.
|
6
|
-
#
|
5
|
+
# Enumerator object which removes duplicate entries.
|
6
|
+
# See also Object#enum_uniq and Enumerable#each_uniq
|
7
7
|
class UniqEnumerator < Enumerable::Enumerator
|
8
|
-
|
9
|
-
|
8
|
+
# Creates the enumerator on +obj+ using the method +enum_with+ to
|
9
|
+
# enumerate. The method will be called with the arguments in +args+.
|
10
|
+
#
|
11
|
+
# If +key+ is given, it is a proc object which should return the key on
|
12
|
+
# which we base ourselves to compare two objects. If it is not given,
|
13
|
+
# UniqEnumerator uses the object itself
|
14
|
+
#
|
15
|
+
# See also Object#enum_uniq and Enumerable#each_uniq
|
16
|
+
def initialize(obj, enum_with, args, key = nil)
|
17
|
+
super(obj, enum_with, *args)
|
10
18
|
@key = key
|
11
19
|
@result = Hash.new
|
12
20
|
end
|
@@ -29,12 +37,12 @@ class UniqEnumerator < Enumerable::Enumerator
|
|
29
37
|
self
|
30
38
|
end
|
31
39
|
end
|
32
|
-
|
33
|
-
include Enumerable
|
34
40
|
end
|
35
41
|
|
36
42
|
class Object
|
37
|
-
# Enumerate removing the duplicate
|
43
|
+
# Enumerate using the <tt>each(*args)</tt> method, removing the duplicate
|
44
|
+
# entries. If +filter+ is given, it should return an object the enumerator
|
45
|
+
# will compare for equality (instead of using the objects themselves)
|
38
46
|
def enum_uniq(enum_with = :each, *args, &filter)
|
39
47
|
UniqEnumerator.new(self, enum_with, args, filter)
|
40
48
|
end
|
@@ -43,10 +51,9 @@ end
|
|
43
51
|
Utilrb.unless_faster do
|
44
52
|
module Enumerable
|
45
53
|
# call-seq:
|
46
|
-
#
|
54
|
+
# each_uniq { |obj| ... }
|
47
55
|
#
|
48
56
|
# Yields all unique values found in +enum+
|
49
|
-
#
|
50
57
|
def each_uniq(&iterator)
|
51
58
|
seen = Set.new
|
52
59
|
each do |obj|
|