utilrb 0.2.2 → 0.2.3
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 +18 -0
- data/License.txt +2 -1
- data/Manifest.txt +19 -15
- data/Rakefile +1 -1
- data/ext/faster.cc +5 -1
- data/ext/value_set.cc +25 -0
- data/lib/utilrb/array/to_s.rb +2 -0
- data/lib/utilrb/common.rb +1 -1
- data/lib/utilrb/enumerable/null.rb +2 -0
- data/lib/utilrb/enumerable/random_element.rb +12 -4
- data/lib/utilrb/enumerable/sequence.rb +0 -1
- data/lib/utilrb/exception/full_message.rb +16 -0
- data/lib/utilrb/hash/to_s.rb +2 -0
- data/lib/utilrb/hash/to_sym_keys.rb +4 -0
- data/lib/utilrb/kernel/options.rb +7 -1
- data/lib/utilrb/object/attribute.rb +1 -1
- data/lib/utilrb/object/singleton_class.rb +21 -4
- data/lib/utilrb/objectstats.rb +189 -18
- data/lib/utilrb/queue/get.rb +18 -13
- data/lib/utilrb/set.rb +2 -0
- data/lib/utilrb/set/to_s.rb +7 -0
- data/lib/utilrb/time/to_hms.rb +32 -0
- data/patches/fastthread-queue-get.patch +72 -0
- data/test/test_enumerable.rb +3 -0
- data/test/test_objectstats.rb +6 -6
- data/test/test_time.rb +31 -0
- metadata +29 -24
data/Changes.txt
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
=== Version 0.2.3
|
2
|
+
|
3
|
+
* new features:
|
4
|
+
- BenchmarkAllocation, a Benchmark-like interface to benchmark object
|
5
|
+
allocation
|
6
|
+
- ValueSet#delete_if
|
7
|
+
- Time#from_hms takes a time as "h:m:s.ms" and builds the corresponding
|
8
|
+
Time object. Note that "s", "s.ms", "m:s", "m:s.ms", ... are accepted
|
9
|
+
formats
|
10
|
+
|
11
|
+
* changes and fixes:
|
12
|
+
- define Queue#get only if we are using Ruby's core Queue. The current
|
13
|
+
implementation is incompatible with fastthread for instance (and
|
14
|
+
fastthhread's maintainer does not want #get on its Queue). Included
|
15
|
+
a patch to define Queue#get on fastthread
|
16
|
+
- fix ValueSet#== raising if the argument is not a ValueSet
|
17
|
+
- fix brain-dead SequenceEnumerator#+, which was changing its receiver
|
18
|
+
|
1
19
|
=== Version 0.2.2
|
2
20
|
The "don't forget to bump version number" release. 0.2 was supposed to be 0.2.1
|
3
21
|
|
data/License.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -1,58 +1,61 @@
|
|
1
|
+
Changes.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
1
6
|
bm/allocation.rb
|
2
7
|
bm/speed.rb
|
3
|
-
Changes.txt
|
4
8
|
ext/extconf.rb
|
5
9
|
ext/faster.cc
|
6
10
|
ext/swap.cc
|
7
11
|
ext/value_set.cc
|
12
|
+
lib/utilrb.rb
|
8
13
|
lib/utilrb/array.rb
|
9
14
|
lib/utilrb/array/to_s.rb
|
10
15
|
lib/utilrb/common.rb
|
16
|
+
lib/utilrb/enumerable.rb
|
11
17
|
lib/utilrb/enumerable/null.rb
|
12
18
|
lib/utilrb/enumerable/random_element.rb
|
13
|
-
lib/utilrb/enumerable.rb
|
14
19
|
lib/utilrb/enumerable/sequence.rb
|
15
20
|
lib/utilrb/enumerable/uniq.rb
|
16
|
-
lib/utilrb/exception/full_message.rb
|
17
21
|
lib/utilrb/exception.rb
|
18
|
-
lib/utilrb/
|
22
|
+
lib/utilrb/exception/full_message.rb
|
19
23
|
lib/utilrb/gc.rb
|
24
|
+
lib/utilrb/gc/force.rb
|
20
25
|
lib/utilrb/hash.rb
|
21
26
|
lib/utilrb/hash/slice.rb
|
22
27
|
lib/utilrb/hash/to_s.rb
|
23
28
|
lib/utilrb/hash/to_sym_keys.rb
|
29
|
+
lib/utilrb/kernel.rb
|
24
30
|
lib/utilrb/kernel/arity.rb
|
25
31
|
lib/utilrb/kernel/options.rb
|
26
32
|
lib/utilrb/kernel/poll.rb
|
27
|
-
lib/utilrb/kernel.rb
|
28
33
|
lib/utilrb/kernel/require.rb
|
29
34
|
lib/utilrb/kernel/swap.rb
|
35
|
+
lib/utilrb/logger.rb
|
30
36
|
lib/utilrb/logger/forward.rb
|
31
37
|
lib/utilrb/logger/hierarchy.rb
|
32
|
-
lib/utilrb/
|
38
|
+
lib/utilrb/module.rb
|
33
39
|
lib/utilrb/module/ancestor_p.rb
|
34
40
|
lib/utilrb/module/attr_enumerable.rb
|
35
41
|
lib/utilrb/module/define_method.rb
|
36
42
|
lib/utilrb/module/include.rb
|
37
43
|
lib/utilrb/module/inherited_enumerable.rb
|
38
|
-
lib/utilrb/
|
44
|
+
lib/utilrb/object.rb
|
39
45
|
lib/utilrb/object/address.rb
|
40
46
|
lib/utilrb/object/attribute.rb
|
41
|
-
lib/utilrb/object.rb
|
42
47
|
lib/utilrb/object/singleton_class.rb
|
43
48
|
lib/utilrb/objectstats.rb
|
44
|
-
lib/utilrb/queue/get.rb
|
45
49
|
lib/utilrb/queue.rb
|
46
|
-
lib/utilrb.rb
|
50
|
+
lib/utilrb/queue/get.rb
|
51
|
+
lib/utilrb/set.rb
|
52
|
+
lib/utilrb/set/to_s.rb
|
47
53
|
lib/utilrb/time.rb
|
48
54
|
lib/utilrb/time/to_hms.rb
|
49
|
-
lib/utilrb/unbound_method/call.rb
|
50
55
|
lib/utilrb/unbound_method.rb
|
56
|
+
lib/utilrb/unbound_method/call.rb
|
51
57
|
lib/utilrb/value_set.rb
|
52
|
-
|
53
|
-
Manifest.txt
|
54
|
-
Rakefile
|
55
|
-
README.txt
|
58
|
+
patches/fastthread-queue-get.patch
|
56
59
|
test/test_array.rb
|
57
60
|
test/test_config.rb
|
58
61
|
test/test_enumerable.rb
|
@@ -63,4 +66,5 @@ test/test_misc.rb
|
|
63
66
|
test/test_module.rb
|
64
67
|
test/test_object.rb
|
65
68
|
test/test_objectstats.rb
|
69
|
+
test/test_time.rb
|
66
70
|
test/test_unbound_method.rb
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ Hoe.new('utilrb', Utilrb::VERSION) do |p|
|
|
8
8
|
p.summary = 'Yet another Ruby toolkit'
|
9
9
|
p.description = p.paragraphs_of('README.txt', 3..6).join("\n\n")
|
10
10
|
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
11
|
-
p.changes = p.paragraphs_of('Changes.txt', 0..
|
11
|
+
p.changes = p.paragraphs_of('Changes.txt', 0..2).join("\n\n")
|
12
12
|
|
13
13
|
p.extra_deps << 'facets'
|
14
14
|
end
|
data/ext/faster.cc
CHANGED
@@ -25,7 +25,11 @@ static VALUE enumerable_each_uniq(VALUE self)
|
|
25
25
|
return self;
|
26
26
|
}
|
27
27
|
|
28
|
-
/*
|
28
|
+
/* call-seq:
|
29
|
+
* Kernel.is_singleton?(object)
|
30
|
+
*
|
31
|
+
* Returns true if +self+ is a singleton class
|
32
|
+
*/
|
29
33
|
static VALUE kernel_is_singleton_p(VALUE self)
|
30
34
|
{
|
31
35
|
if (BUILTIN_TYPE(self) == T_CLASS && FL_TEST(self, FL_SINGLETON))
|
data/ext/value_set.cc
CHANGED
@@ -65,6 +65,27 @@ static VALUE value_set_each(VALUE self)
|
|
65
65
|
}
|
66
66
|
return self;
|
67
67
|
}
|
68
|
+
|
69
|
+
/* call-seq:
|
70
|
+
* set.delete_if { |obj| ... } => set
|
71
|
+
*
|
72
|
+
* Deletes all objects for which the block returns true
|
73
|
+
*/
|
74
|
+
static VALUE value_set_delete_if(VALUE self)
|
75
|
+
{
|
76
|
+
ValueSet& set = get_wrapped_set(self);
|
77
|
+
for (ValueSet::iterator it = set.begin(); it != set.end();)
|
78
|
+
{
|
79
|
+
// Increment before calling yield() so that
|
80
|
+
// the current element can be deleted safely
|
81
|
+
ValueSet::iterator this_it = it++;
|
82
|
+
bool do_delete = RTEST(rb_yield(*this_it));
|
83
|
+
if (do_delete)
|
84
|
+
set.erase(this_it);
|
85
|
+
}
|
86
|
+
return self;
|
87
|
+
}
|
88
|
+
|
68
89
|
/* call-seq:
|
69
90
|
* set.include?(value) => true or false
|
70
91
|
*
|
@@ -198,6 +219,9 @@ static VALUE value_set_delete(VALUE vself, VALUE v)
|
|
198
219
|
static VALUE value_set_equal(VALUE vself, VALUE vother)
|
199
220
|
{
|
200
221
|
ValueSet const& self = get_wrapped_set(vself);
|
222
|
+
if (!rb_respond_to(vother, id_to_value_set))
|
223
|
+
return Qfalse;
|
224
|
+
|
201
225
|
ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
|
202
226
|
return (self == other) ? Qtrue : Qfalse;
|
203
227
|
}
|
@@ -285,6 +309,7 @@ extern "C" void Init_value_set()
|
|
285
309
|
rb_define_method(cValueSet, "size", RUBY_METHOD_FUNC(value_set_size), 0);
|
286
310
|
rb_define_method(cValueSet, "clear", RUBY_METHOD_FUNC(value_set_clear), 0);
|
287
311
|
rb_define_method(cValueSet, "initialize_copy", RUBY_METHOD_FUNC(value_set_initialize_copy), 1);
|
312
|
+
rb_define_method(cValueSet, "delete_if", RUBY_METHOD_FUNC(value_set_delete_if), 0);
|
288
313
|
}
|
289
314
|
|
290
315
|
|
data/lib/utilrb/array/to_s.rb
CHANGED
data/lib/utilrb/common.rb
CHANGED
@@ -1,15 +1,23 @@
|
|
1
|
+
class Array
|
2
|
+
# Returns a random element of the array
|
3
|
+
def random_element; self[rand(size)] end
|
4
|
+
end
|
5
|
+
|
1
6
|
module Enumerable
|
7
|
+
# Returns a random element in the enumerable. In the worst case scenario,
|
8
|
+
# it converts the enumerable into an array
|
2
9
|
def random_element
|
3
|
-
if
|
4
|
-
self[rand(size)]
|
5
|
-
elsif respond_to?(:to_ary)
|
10
|
+
if respond_to?(:to_ary)
|
6
11
|
to_ary.random_element
|
7
12
|
elsif respond_to?(:size)
|
13
|
+
return if size == 0
|
8
14
|
element = rand(size)
|
9
15
|
each_with_index { |e, i| return e if i == element }
|
10
|
-
|
16
|
+
raise "something wrong here ..."
|
11
17
|
elsif respond_to?(:to_a)
|
12
18
|
to_a.random_element
|
19
|
+
else
|
20
|
+
raise ArgumentError, "cannot ue #random_element on this enumerable"
|
13
21
|
end
|
14
22
|
end
|
15
23
|
end
|
@@ -1,5 +1,21 @@
|
|
1
1
|
|
2
2
|
class Exception
|
3
|
+
# Returns the full exception message, with backtrace, like the one we get from
|
4
|
+
# the Ruby interpreter when the program is aborted (well, almost like that)
|
5
|
+
#
|
6
|
+
# For instance,
|
7
|
+
# def test
|
8
|
+
# raise RuntimeError, "this is a test"
|
9
|
+
# rescue
|
10
|
+
# puts $!.full_message
|
11
|
+
# end
|
12
|
+
# test
|
13
|
+
#
|
14
|
+
# displays
|
15
|
+
#
|
16
|
+
# test.rb:3:in `test': this is a test (RuntimeError)
|
17
|
+
# from test.rb:7
|
18
|
+
#
|
3
19
|
def full_message
|
4
20
|
first, *remaining = backtrace
|
5
21
|
"#{first}: #{message} (#{self.class})\n\tfrom " + remaining.join("\n\tfrom ")
|
data/lib/utilrb/hash/to_s.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
class Hash
|
2
|
+
# Returns a hash for which all keys have been converted to symbols (only
|
3
|
+
# valid for string/symbol keys of course)
|
4
|
+
#
|
5
|
+
# { 'a' => 1, :b => '2' }.to_sym_keys => { :a => 1, :b => '2' }
|
2
6
|
def to_sym_keys
|
3
7
|
inject({}) { |h, (k, v)| h[k.to_sym] = v; h }
|
4
8
|
end
|
@@ -5,6 +5,12 @@ module Kernel
|
|
5
5
|
# arguments, with default value support. All option keys are
|
6
6
|
# converted to symbols for consistency.
|
7
7
|
#
|
8
|
+
# The following rules apply:
|
9
|
+
# * if a hash is given, non-nil values are treated as default values.
|
10
|
+
# * an array is equivalent to a hash where all values are 'nil'
|
11
|
+
#
|
12
|
+
# See #validate_options and #filter_and_validate_options
|
13
|
+
#
|
8
14
|
# call-seq:
|
9
15
|
# filter_options(option, hash) -> known, unknown
|
10
16
|
# filter_options(option, array) -> known, unknown
|
@@ -38,7 +44,7 @@ module Kernel
|
|
38
44
|
# as an empty option hash, all keys are converted into symbols.
|
39
45
|
#
|
40
46
|
def validate_options(options, known_options)
|
41
|
-
opt, unknown = filter_options(options, known_options)
|
47
|
+
opt, unknown = Kernel.filter_options(options, known_options)
|
42
48
|
unless unknown.empty?
|
43
49
|
not_valid = unknown.keys.map { |m| "'#{m}'" }.join(" ")
|
44
50
|
raise ArgumentError, "unknown options #{not_valid}", caller(1)
|
@@ -1,7 +1,18 @@
|
|
1
1
|
require 'utilrb/object/address'
|
2
|
+
|
3
|
+
class Object
|
4
|
+
# Returns true if this object has its own singleton class
|
5
|
+
def has_singleton?; defined? @singleton_class end
|
6
|
+
end
|
7
|
+
|
2
8
|
if RUBY_VERSION >= "1.9"
|
3
9
|
class Object
|
4
|
-
|
10
|
+
# Returns the singleton class for this object
|
11
|
+
#
|
12
|
+
# The first element of #ancestors on the returned singleton class is
|
13
|
+
# the singleton class itself. A #singleton_instance accessor is also
|
14
|
+
# defined, which returns the object instance the class is the singleton
|
15
|
+
# of.
|
5
16
|
def singleton_class
|
6
17
|
if defined? @singleton_class
|
7
18
|
return @singleton_class
|
@@ -21,9 +32,15 @@ if RUBY_VERSION >= "1.9"
|
|
21
32
|
end
|
22
33
|
else
|
23
34
|
class Object
|
24
|
-
|
25
|
-
|
26
|
-
|
35
|
+
# Returns the singleton class for this object.
|
36
|
+
#
|
37
|
+
# In Ruby 1.8, makes sure that the #superclass method of the singleton class
|
38
|
+
# returns the object's class (instead of Class), as Ruby 1.9 does
|
39
|
+
#
|
40
|
+
# The first element of #ancestors on the returned singleton class is
|
41
|
+
# the singleton class itself. A #singleton_instance accessor is also
|
42
|
+
# defined, which returns the object instance the class is the singleton
|
43
|
+
# of.
|
27
44
|
def singleton_class
|
28
45
|
if defined? @singleton_class
|
29
46
|
return @singleton_class
|
data/lib/utilrb/objectstats.rb
CHANGED
@@ -1,15 +1,23 @@
|
|
1
1
|
require 'utilrb/gc/force'
|
2
|
+
require 'utilrb/object/attribute'
|
2
3
|
|
3
4
|
module ObjectStats
|
4
|
-
#
|
5
|
+
# The count of objects currently allocated
|
6
|
+
#
|
7
|
+
# It allocates no objects, which means that if
|
8
|
+
# a = ObjectStats.count
|
9
|
+
# b = ObjectStats.count
|
10
|
+
# then a == b
|
5
11
|
def self.count
|
6
12
|
count = 0
|
7
|
-
ObjectSpace.each_object { |obj| count += 1}
|
13
|
+
ObjectSpace.each_object { |obj| count += 1 }
|
8
14
|
|
9
15
|
count
|
10
16
|
end
|
11
17
|
|
12
|
-
#
|
18
|
+
# Returns a klass => count hash counting the currently allocated objects
|
19
|
+
#
|
20
|
+
# It allocates 1 Hash, which is included in the count
|
13
21
|
def self.count_by_class
|
14
22
|
by_class = Hash.new(0)
|
15
23
|
ObjectSpace.each_object { |obj|
|
@@ -19,10 +27,19 @@ module ObjectStats
|
|
19
27
|
by_class
|
20
28
|
end
|
21
29
|
|
22
|
-
# Profiles
|
23
|
-
#
|
24
|
-
#
|
30
|
+
# Profiles how much objects has been allocated by the block. Returns a
|
31
|
+
# klass => count hash like count_by_class
|
32
|
+
#
|
33
|
+
# If alive is true, then only live objects are returned.
|
25
34
|
def self.profile(alive = false)
|
35
|
+
if alive
|
36
|
+
GC.force
|
37
|
+
profile do
|
38
|
+
yield
|
39
|
+
GC.force
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
26
43
|
already_disabled = GC.disable
|
27
44
|
before = count_by_class
|
28
45
|
yield
|
@@ -34,19 +51,173 @@ module ObjectStats
|
|
34
51
|
merge(after) { |klass, old, new| new - old }.
|
35
52
|
delete_if { |klass, count| count == 0 }
|
36
53
|
end
|
54
|
+
end
|
37
55
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
56
|
+
# BenchmarkAllocation is a Benchmark-like interface to benchmark object allocation.
|
57
|
+
#
|
58
|
+
# == Formatting
|
59
|
+
# BenchmarkAllocation formats its output in two ways (see examples below)
|
60
|
+
# * first, each part of a class path is displayed in its own line, to reduce
|
61
|
+
# the output width
|
62
|
+
# * then, output is formatted so that it does not exceed
|
63
|
+
# BenchmarkAllocation::SCREEN_WIDTH width
|
64
|
+
#
|
65
|
+
#
|
66
|
+
# == Examples
|
67
|
+
#
|
68
|
+
# For instance,
|
69
|
+
#
|
70
|
+
# require 'utilrb/objectstats'
|
71
|
+
#
|
72
|
+
# module Namespace
|
73
|
+
# class MyClass
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# BenchmarkAllocation.bm do |x|
|
78
|
+
# x.report("array") { Array.new }
|
79
|
+
# x.report("hash") { Hash.new }
|
80
|
+
# x.report("myclass") { MyClass.new }
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# will produce the output
|
84
|
+
#
|
85
|
+
# Array Hash Namespace::
|
86
|
+
# MyClass
|
87
|
+
# array 1 - -
|
88
|
+
# hash - 1 -
|
89
|
+
# myclass - - 1
|
90
|
+
#
|
91
|
+
# Like Benchmark, a rehearsal benchmark method, BenchmarkAllocation.bmbm
|
92
|
+
# is provided:
|
93
|
+
#
|
94
|
+
# require 'utilrb/objectstats'
|
95
|
+
# require 'delegate'
|
96
|
+
#
|
97
|
+
# module Namespace
|
98
|
+
# class MyClass
|
99
|
+
# end
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# delegate_klass = nil
|
103
|
+
# BenchmarkAllocation.bmbm do |x|
|
104
|
+
# x.report("array") { Array.new }
|
105
|
+
# x.report("hash") { Hash.new }
|
106
|
+
# x.report("myclass") { Namespace::MyClass.new }
|
107
|
+
# x.report("delegate") do
|
108
|
+
# delegate_klass ||= Class.new(DelegateClass(Namespace::MyClass)) do
|
109
|
+
# def self.name; "Delegate(MyClass)" end
|
110
|
+
# end
|
111
|
+
# delegate_klass.new(Namespace::MyClass.new)
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# produces
|
116
|
+
#
|
117
|
+
# Rehearsal --------------------------------------------------------------------------------
|
118
|
+
#
|
119
|
+
# Array Class Delegate(MyClass) Hash Namespace:: String
|
120
|
+
# MyClass
|
121
|
+
# array 1 - - - - -
|
122
|
+
# hash - - - 1 - -
|
123
|
+
# myclass - - - - 1 -
|
124
|
+
# delegate 5 2 1 2 1 247
|
125
|
+
# ------------------------------------------------------------------------------------------
|
126
|
+
#
|
127
|
+
# Array Delegate(MyClass) Hash Namespace::
|
128
|
+
# MyClass
|
129
|
+
# array 1 - - -
|
130
|
+
# hash - - 1 -
|
131
|
+
# myclass - - - 1
|
132
|
+
# delegate - 1 - 1
|
133
|
+
#
|
134
|
+
class BenchmarkAllocation
|
135
|
+
MARGIN = 2
|
136
|
+
SCREEN_WIDTH = 90
|
137
|
+
|
138
|
+
def self.bm(label_width = nil)
|
139
|
+
yield(gather = new)
|
140
|
+
gather.format
|
49
141
|
end
|
50
|
-
|
142
|
+
def self.bmbm(label_width = nil)
|
143
|
+
yield(gather = new)
|
144
|
+
|
145
|
+
title = "Rehearsal"
|
146
|
+
puts title + " " + "-" * (SCREEN_WIDTH - title.length - 1)
|
147
|
+
gather.format
|
148
|
+
puts "-" * SCREEN_WIDTH
|
149
|
+
|
150
|
+
yield(gather = new)
|
151
|
+
gather.format
|
152
|
+
end
|
153
|
+
|
154
|
+
def format(screen_width = SCREEN_WIDTH, margin = MARGIN)
|
155
|
+
label_width ||= 0
|
156
|
+
column_names = profiles.inject([]) do |column_names, (label, profile)|
|
157
|
+
label_width = label_width < label.length ? label.length : label_width
|
158
|
+
column_names |= profile.keys
|
159
|
+
end.sort
|
51
160
|
|
161
|
+
# split at the :: to separate modules and klasses (reduce header sizes)
|
162
|
+
blocks = []
|
163
|
+
header, columns, current_width = nil
|
164
|
+
column_names.each_with_index do |name, col_index|
|
165
|
+
splitted = name.gsub(/::/, "::\n").split("\n")
|
166
|
+
width = splitted.map { |part| part.length }.max + MARGIN
|
167
|
+
|
168
|
+
if !current_width || (current_width + label_width + width > screen_width)
|
169
|
+
# start a new block
|
170
|
+
blocks << [[], []]
|
171
|
+
header, columns = blocks.last
|
172
|
+
current_width = 0
|
173
|
+
end
|
174
|
+
|
175
|
+
splitted.each_with_index do |part, line_index|
|
176
|
+
if !header[line_index]
|
177
|
+
header[line_index] = columns.map { |_, w| " " * w }
|
178
|
+
end
|
179
|
+
header[line_index] << "% #{width}s" % [part]
|
180
|
+
end
|
181
|
+
# Pad the remaining lines
|
182
|
+
header[splitted.size..-1].each_with_index do |line, index|
|
183
|
+
line << " " * width
|
184
|
+
end
|
185
|
+
|
186
|
+
columns << [name, width]
|
187
|
+
current_width += width
|
188
|
+
end
|
189
|
+
|
190
|
+
blocks.each do |header, columns|
|
191
|
+
puts
|
192
|
+
header.each { |line| puts " " * label_width + line.join("") }
|
193
|
+
|
194
|
+
profiles.each do |label, profile|
|
195
|
+
print "% #{label_width}s" % [label]
|
196
|
+
columns.each do |name, width|
|
197
|
+
|
198
|
+
if count = profile[name]
|
199
|
+
print "% #{width}i" % [profile[name] || 0]
|
200
|
+
else
|
201
|
+
print " " * (width - 1) + "-"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
puts
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
attribute(:profiles) { Array.new }
|
210
|
+
def report(label)
|
211
|
+
result = ObjectStats.profile do
|
212
|
+
yield
|
213
|
+
end
|
214
|
+
result.inject({}) do |result, (klass, count)|
|
215
|
+
klass = klass.name
|
216
|
+
klass = "unknown" if !klass || klass.empty?
|
217
|
+
result[klass] = count
|
218
|
+
result
|
219
|
+
end
|
220
|
+
profiles << [label, result]
|
221
|
+
end
|
222
|
+
end
|
52
223
|
|
data/lib/utilrb/queue/get.rb
CHANGED
@@ -1,17 +1,22 @@
|
|
1
1
|
class Queue
|
2
|
-
# Returns all elements currently in the queue.
|
3
|
-
#
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
# Returns all elements currently in the queue. If +non_block+ is true,
|
3
|
+
# returns an empty array if the queue is empty
|
4
|
+
#
|
5
|
+
# WARNING: this method is NOT compatible with fastthread's Queue implementation
|
6
|
+
# If you rely on Queue#get and want to use fastthread, you will have to patch
|
7
|
+
# fastthread with patches/fastthread-queue-get.patch
|
8
|
+
unless instance_methods.include?("get")
|
9
|
+
def get(non_block = false)
|
10
|
+
while (Thread.critical = true; @que.empty?)
|
11
|
+
return [] if non_block
|
12
|
+
@waiting.push Thread.current
|
13
|
+
Thread.stop
|
14
|
+
end
|
15
|
+
result = @que.dup
|
16
|
+
@que.clear
|
17
|
+
result
|
18
|
+
ensure
|
19
|
+
Thread.critical = false
|
10
20
|
end
|
11
|
-
result = @que.dup
|
12
|
-
@que.clear
|
13
|
-
result
|
14
|
-
ensure
|
15
|
-
Thread.critical = false
|
16
21
|
end
|
17
22
|
end
|
data/lib/utilrb/set.rb
ADDED
data/lib/utilrb/time/to_hms.rb
CHANGED
@@ -1,6 +1,38 @@
|
|
1
1
|
class Time
|
2
|
+
# Converts this time into a h:m:s.ms representation
|
2
3
|
def to_hms
|
3
4
|
sec, usec = tv_sec, tv_usec
|
4
5
|
"%i:%02i:%02i.%03i" % [sec / 3600, (sec % 3600) / 60, sec % 60, usec / 1000]
|
5
6
|
end
|
7
|
+
|
8
|
+
# Creates a Time object from a h:m:s.ms representation. The following formats are allowed:
|
9
|
+
# s, s.ms, m:s, m:s.ms, h:m:s, h:m:s.ms
|
10
|
+
def self.from_hms(string)
|
11
|
+
unless string =~ /(?:^|:)(\d+)(?:$|\.)/
|
12
|
+
raise "invalid format #{string}"
|
13
|
+
end
|
14
|
+
hm, ms = $`, $'
|
15
|
+
|
16
|
+
s = Integer($1)
|
17
|
+
unless hm =~ /^(?:(\d*):)?(?:(\d*))?$/
|
18
|
+
raise "invalid format #{string}. found #{hm}, expected nothing, m: or h:m:"
|
19
|
+
end
|
20
|
+
h, m = if $2.empty? then
|
21
|
+
if $1 then [0, Integer($1)]
|
22
|
+
else [0, 0]
|
23
|
+
end
|
24
|
+
else [Integer($1), Integer($2)]
|
25
|
+
end
|
26
|
+
|
27
|
+
ms = if ms.empty? then 0
|
28
|
+
else
|
29
|
+
unless ms =~ /^\d*$/
|
30
|
+
raise "invalid format "#{string}"
|
31
|
+
end
|
32
|
+
ms += "0" * (3 - ms.size)
|
33
|
+
Integer(ms)
|
34
|
+
end
|
35
|
+
|
36
|
+
Time.at(Float(h * 3600 + m * 60 + s) + ms * 1.0e-3)
|
37
|
+
end
|
6
38
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
--- fastthread-0.6.2/ext/fastthread/fastthread.c 2007-01-25 12:09:54.956708000 +0100
|
2
|
+
+++ fastthread-0.6.2.new/ext/fastthread/fastthread.c 2007-01-25 11:49:49.151455000 +0100
|
3
|
+
@@ -737,6 +737,61 @@ rb_queue_marshal_load(self, data)
|
4
|
+
|
5
|
+
static VALUE rb_queue_marshal_dump _((VALUE));
|
6
|
+
|
7
|
+
+
|
8
|
+
+/* call-seq:
|
9
|
+
+ * Queue#get(non_block = false) => array
|
10
|
+
+ *
|
11
|
+
+ * Returns an array containing all elements currently in the queue. After a call
|
12
|
+
+ * to #get, the queue is empty. If non_block is false, the call will block until
|
13
|
+
+ * there is something in it. Otherwise, if the queue is empty, it returns an empty
|
14
|
+
+ * array.
|
15
|
+
+ */
|
16
|
+
+static VALUE
|
17
|
+
+rb_queue_get(argc, argv, self)
|
18
|
+
+ int argc;
|
19
|
+
+ VALUE *argv;
|
20
|
+
+ VALUE self;
|
21
|
+
+{
|
22
|
+
+ Queue *queue;
|
23
|
+
+ int should_block;
|
24
|
+
+ VALUE result;
|
25
|
+
+ Data_Get_Struct(self, Queue, queue);
|
26
|
+
+
|
27
|
+
+ if ( argc == 0 ) {
|
28
|
+
+ should_block = 1;
|
29
|
+
+ } else if ( argc == 1 ) {
|
30
|
+
+ should_block = !RTEST(argv[0]);
|
31
|
+
+ } else {
|
32
|
+
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
|
33
|
+
+ }
|
34
|
+
+
|
35
|
+
+ lock_mutex(&queue->mutex);
|
36
|
+
+ if ( !queue->values.entries ) {
|
37
|
+
+ /* NOTE: locking is not needed to check if the queue is empty
|
38
|
+
+ since AFAIK C extensions are never preempted. I do as in #pop
|
39
|
+
+ where it is done.
|
40
|
+
+ */
|
41
|
+
+ if ( !should_block ) {
|
42
|
+
+ unlock_mutex(&queue->mutex);
|
43
|
+
+ return rb_ary_new();
|
44
|
+
+ }
|
45
|
+
+ while (!queue->values.entries) {
|
46
|
+
+ wait_condvar(&queue->value_available, &queue->mutex);
|
47
|
+
+ }
|
48
|
+
+ }
|
49
|
+
+
|
50
|
+
+ result = rb_ary_new();
|
51
|
+
+ while ( queue->values.entries ) {
|
52
|
+
+ rb_ary_push(result, shift_list(&queue->values));
|
53
|
+
+ }
|
54
|
+
+ if ( queue->capacity ) {
|
55
|
+
+ signal_condvar(&queue->space_available);
|
56
|
+
+ }
|
57
|
+
+ unlock_mutex(&queue->mutex);
|
58
|
+
+
|
59
|
+
+ return result;
|
60
|
+
+}
|
61
|
+
+
|
62
|
+
static VALUE
|
63
|
+
rb_queue_marshal_dump(self)
|
64
|
+
VALUE self;
|
65
|
+
@@ -991,6 +1046,7 @@ static VALUE setup_classes(unused)
|
66
|
+
rb_define_method(rb_cQueue, "num_waiting", rb_queue_num_waiting, 0);
|
67
|
+
rb_define_method(rb_cQueue, "pop", rb_queue_pop, -1);
|
68
|
+
rb_define_method(rb_cQueue, "push", rb_queue_push, 1);
|
69
|
+
+ rb_define_method(rb_cQueue, "get", rb_queue_get, -1);
|
70
|
+
rb_alias(rb_cQueue, rb_intern("<<"), rb_intern("push"));
|
71
|
+
rb_alias(rb_cQueue, rb_intern("deq"), rb_intern("pop"));
|
72
|
+
rb_alias(rb_cQueue, rb_intern("shift"), rb_intern("pop"));
|
data/test/test_enumerable.rb
CHANGED
@@ -74,6 +74,7 @@ class TC_Enumerable < Test::Unit::TestCase
|
|
74
74
|
assert_equal([1, 2, 3, 4, 6, 8, 11], (a.union(b)).to_a)
|
75
75
|
assert_equal([1, 3, 4], (a.intersection(b)).to_a)
|
76
76
|
assert_equal([6, 8], (a.difference(b)).to_a)
|
77
|
+
assert(! (a == :bla)) # check #== behaves correctly with a non-enumerable
|
77
78
|
|
78
79
|
a.delete(1)
|
79
80
|
assert(! a.include?(1))
|
@@ -83,6 +84,8 @@ class TC_Enumerable < Test::Unit::TestCase
|
|
83
84
|
assert([].to_value_set.empty?)
|
84
85
|
|
85
86
|
assert([1, 2, 4, 3].to_value_set.clear.empty?)
|
87
|
+
|
88
|
+
assert_equal([1,3,5].to_value_set, [1, 2, 3, 4, 5, 6].to_value_set.delete_if { |v| v % 2 == 0 })
|
86
89
|
end
|
87
90
|
end
|
88
91
|
end
|
data/test/test_objectstats.rb
CHANGED
@@ -3,17 +3,17 @@ require 'test_config'
|
|
3
3
|
require 'utilrb/objectstats'
|
4
4
|
|
5
5
|
class TC_ObjectStats < Test::Unit::TestCase
|
6
|
+
def teardown
|
7
|
+
GC.enable
|
8
|
+
end
|
9
|
+
|
10
|
+
def allocate_dead_hash; Hash.new; nil end
|
11
|
+
|
6
12
|
def test_object_stats
|
7
13
|
assert( ObjectStats.profile { ObjectStats.count }.empty?, "Object allocation profile changed" )
|
8
14
|
assert_equal({ Hash => 1 }, ObjectStats.profile { ObjectStats.count_by_class }, "Object allocation profile changed")
|
9
15
|
assert_equal({ Array => 1 }, ObjectStats.profile { test = [] })
|
10
16
|
assert_equal({ Array => 2, Hash => 1 }, ObjectStats.profile { a, b = [], {} })
|
11
|
-
|
12
|
-
GC.start
|
13
|
-
GC.disable
|
14
|
-
Hash.new
|
15
|
-
assert([Hash, 1], ObjectStats.profile { Hash.new }.collect { |klass, count| [klass, count] })
|
16
|
-
assert([Hash, -1], ObjectStats.profile { GC.start }.collect { |klass, count| [klass, count] })
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
data/test/test_time.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_config'
|
2
|
+
require 'utilrb/time'
|
3
|
+
|
4
|
+
class TC_Time < Test::Unit::TestCase
|
5
|
+
def test_to_hms
|
6
|
+
assert_equal("0:00:00.000", Time.at(0).to_hms)
|
7
|
+
assert_equal("0:00:00.100", Time.at(0.1).to_hms)
|
8
|
+
assert_equal("0:00:34.100", Time.at(34.1).to_hms)
|
9
|
+
assert_equal("0:21:34.100", Time.at(21 * 60 + 34.1).to_hms)
|
10
|
+
assert_equal("236:21:34.100", Time.at(236 * 3600 + 21 * 60 + 34.1).to_hms)
|
11
|
+
end
|
12
|
+
def test_from_hms
|
13
|
+
assert_equal(Time.at(0), Time.from_hms("0:00:00.000"))
|
14
|
+
assert_equal(Time.at(0.1), Time.from_hms("0:00:00.100"))
|
15
|
+
assert_equal(Time.at(34.1), Time.from_hms("0:00:34.100"))
|
16
|
+
assert_equal(Time.at(21 * 60 + 34.1), Time.from_hms("0:21:34.100"))
|
17
|
+
assert_equal(Time.at(236 * 3600 + 21 * 60 + 34.1), Time.from_hms("236:21:34.100"))
|
18
|
+
|
19
|
+
assert_equal(Time.at(0), Time.from_hms("0"))
|
20
|
+
assert_equal(Time.at(0), Time.from_hms(":0"))
|
21
|
+
assert_equal(Time.at(62), Time.from_hms("1:2"))
|
22
|
+
assert_equal(Time.at(3723), Time.from_hms("1:2:3"))
|
23
|
+
|
24
|
+
assert_equal(Time.at(0), Time.from_hms("0"))
|
25
|
+
assert_equal(Time.at(0), Time.from_hms("0."))
|
26
|
+
assert_in_delta(0, Time.at(1.2) - Time.from_hms("1.2"), 0.001)
|
27
|
+
assert_in_delta(0, Time.at(121.3) - Time.from_hms("2:1.3"), 0.001)
|
28
|
+
assert_in_delta(0, Time.at(3723.4) - Time.from_hms("1:2:3.4"), 0.001)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.
|
2
|
+
rubygems_version: 0.9.1
|
3
3
|
specification_version: 1
|
4
4
|
name: utilrb
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
7
|
-
date:
|
6
|
+
version: 0.2.3
|
7
|
+
date: 2007-01-30 00:00:00 +01:00
|
8
8
|
summary: Yet another Ruby toolkit
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -30,61 +30,64 @@ post_install_message:
|
|
30
30
|
authors:
|
31
31
|
- Sylvain Joyeux
|
32
32
|
files:
|
33
|
+
- Changes.txt
|
34
|
+
- License.txt
|
35
|
+
- Manifest.txt
|
36
|
+
- README.txt
|
37
|
+
- Rakefile
|
33
38
|
- bm/allocation.rb
|
34
39
|
- bm/speed.rb
|
35
|
-
- Changes.txt
|
36
40
|
- ext/extconf.rb
|
37
41
|
- ext/faster.cc
|
38
42
|
- ext/swap.cc
|
39
43
|
- ext/value_set.cc
|
44
|
+
- lib/utilrb.rb
|
40
45
|
- lib/utilrb/array.rb
|
41
46
|
- lib/utilrb/array/to_s.rb
|
42
47
|
- lib/utilrb/common.rb
|
48
|
+
- lib/utilrb/enumerable.rb
|
43
49
|
- lib/utilrb/enumerable/null.rb
|
44
50
|
- lib/utilrb/enumerable/random_element.rb
|
45
|
-
- lib/utilrb/enumerable.rb
|
46
51
|
- lib/utilrb/enumerable/sequence.rb
|
47
52
|
- lib/utilrb/enumerable/uniq.rb
|
48
|
-
- lib/utilrb/exception/full_message.rb
|
49
53
|
- lib/utilrb/exception.rb
|
50
|
-
- lib/utilrb/
|
54
|
+
- lib/utilrb/exception/full_message.rb
|
51
55
|
- lib/utilrb/gc.rb
|
56
|
+
- lib/utilrb/gc/force.rb
|
52
57
|
- lib/utilrb/hash.rb
|
53
58
|
- lib/utilrb/hash/slice.rb
|
54
59
|
- lib/utilrb/hash/to_s.rb
|
55
60
|
- lib/utilrb/hash/to_sym_keys.rb
|
61
|
+
- lib/utilrb/kernel.rb
|
56
62
|
- lib/utilrb/kernel/arity.rb
|
57
63
|
- lib/utilrb/kernel/options.rb
|
58
64
|
- lib/utilrb/kernel/poll.rb
|
59
|
-
- lib/utilrb/kernel.rb
|
60
65
|
- lib/utilrb/kernel/require.rb
|
61
66
|
- lib/utilrb/kernel/swap.rb
|
67
|
+
- lib/utilrb/logger.rb
|
62
68
|
- lib/utilrb/logger/forward.rb
|
63
69
|
- lib/utilrb/logger/hierarchy.rb
|
64
|
-
- lib/utilrb/
|
70
|
+
- lib/utilrb/module.rb
|
65
71
|
- lib/utilrb/module/ancestor_p.rb
|
66
72
|
- lib/utilrb/module/attr_enumerable.rb
|
67
73
|
- lib/utilrb/module/define_method.rb
|
68
74
|
- lib/utilrb/module/include.rb
|
69
75
|
- lib/utilrb/module/inherited_enumerable.rb
|
70
|
-
- lib/utilrb/
|
76
|
+
- lib/utilrb/object.rb
|
71
77
|
- lib/utilrb/object/address.rb
|
72
78
|
- lib/utilrb/object/attribute.rb
|
73
|
-
- lib/utilrb/object.rb
|
74
79
|
- lib/utilrb/object/singleton_class.rb
|
75
80
|
- lib/utilrb/objectstats.rb
|
76
|
-
- lib/utilrb/queue/get.rb
|
77
81
|
- lib/utilrb/queue.rb
|
78
|
-
- lib/utilrb.rb
|
82
|
+
- lib/utilrb/queue/get.rb
|
83
|
+
- lib/utilrb/set.rb
|
84
|
+
- lib/utilrb/set/to_s.rb
|
79
85
|
- lib/utilrb/time.rb
|
80
86
|
- lib/utilrb/time/to_hms.rb
|
81
|
-
- lib/utilrb/unbound_method/call.rb
|
82
87
|
- lib/utilrb/unbound_method.rb
|
88
|
+
- lib/utilrb/unbound_method/call.rb
|
83
89
|
- lib/utilrb/value_set.rb
|
84
|
-
-
|
85
|
-
- Manifest.txt
|
86
|
-
- Rakefile
|
87
|
-
- README.txt
|
90
|
+
- patches/fastthread-queue-get.patch
|
88
91
|
- test/test_array.rb
|
89
92
|
- test/test_config.rb
|
90
93
|
- test/test_enumerable.rb
|
@@ -95,8 +98,10 @@ files:
|
|
95
98
|
- test/test_module.rb
|
96
99
|
- test/test_object.rb
|
97
100
|
- test/test_objectstats.rb
|
101
|
+
- test/test_time.rb
|
98
102
|
- test/test_unbound_method.rb
|
99
103
|
test_files:
|
104
|
+
- test/test_time.rb
|
100
105
|
- test/test_misc.rb
|
101
106
|
- test/test_module.rb
|
102
107
|
- test/test_unbound_method.rb
|
@@ -120,20 +125,20 @@ requirements: []
|
|
120
125
|
|
121
126
|
dependencies:
|
122
127
|
- !ruby/object:Gem::Dependency
|
123
|
-
name:
|
128
|
+
name: facets
|
124
129
|
version_requirement:
|
125
130
|
version_requirements: !ruby/object:Gem::Version::Requirement
|
126
131
|
requirements:
|
127
|
-
- - "
|
132
|
+
- - ">"
|
128
133
|
- !ruby/object:Gem::Version
|
129
|
-
version:
|
134
|
+
version: 0.0.0
|
130
135
|
version:
|
131
136
|
- !ruby/object:Gem::Dependency
|
132
|
-
name:
|
137
|
+
name: hoe
|
133
138
|
version_requirement:
|
134
139
|
version_requirements: !ruby/object:Gem::Version::Requirement
|
135
140
|
requirements:
|
136
|
-
- - "
|
141
|
+
- - ">="
|
137
142
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
143
|
+
version: 1.1.7
|
139
144
|
version:
|