utilrb 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|