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 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
@@ -1,4 +1,5 @@
1
- Copyright (c) The Regents of the University of California.
1
+ Copyright (c) 2006-2007 LAAS/CNRS <openrobots@laas.fr>
2
+ 2006-2007 Sylvain Joyeux <sylvain.joyeux@laas.fr>
2
3
  All rights reserved.
3
4
 
4
5
  Redistribution and use in source and binary forms, with or without
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/gc/force.rb
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/logger.rb
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/module.rb
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
- License.txt
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..1).join("\n\n")
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
- /* Returns true if +self+ is a singleton class */
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
 
@@ -1,4 +1,6 @@
1
1
  class Array
2
+ # Displays arrays as [ a, b, [c, d], ... ] instead of the standard #join
3
+ # Unlike #inspect, it calls #to_s on the elements too
2
4
  def to_s
3
5
  stack = (Thread.current[:array_to_s] ||= [])
4
6
  if stack.include?(self)
data/lib/utilrb/common.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Utilrb
2
- VERSION = "0.2.2" unless defined? Utilrb::VERSION
2
+ VERSION = "0.2.3" unless defined? Utilrb::VERSION
3
3
 
4
4
  unless defined? UTILRB_FASTER_MODE
5
5
  if ENV['UTILRB_FASTER_MODE'] == 'no'
@@ -2,6 +2,8 @@
2
2
  # Kernel#null_enum
3
3
  class NullEnumerator
4
4
  def each; self end
5
+ def +(other); other end
6
+
5
7
  include Enumerable
6
8
  end
7
9
 
@@ -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 Array === self
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
- nil
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
@@ -3,7 +3,6 @@ class SequenceEnumerator
3
3
  def initialize; @sequence = Array.new end
4
4
  # Adds +object+ at the back of the sequence
5
5
  def <<(object); @sequence << object; self end
6
- alias :+ :<<
7
6
 
8
7
  def each
9
8
  @sequence.each { |enum| enum.each { |o| yield(o) } } if block_given?
@@ -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 ")
@@ -1,4 +1,6 @@
1
1
  class Hash
2
+ # Displays hashes as { a => A, b => B, ... } instead of the standard #join
3
+ # Unlike #inspect, it calls #to_s on the elements too
2
4
  def to_s
3
5
  "{" << map { |k, v| "#{k} => #{v}" }.join(", ") << "}"
4
6
  end
@@ -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)
@@ -3,7 +3,7 @@ require 'utilrb/object/singleton_class'
3
3
 
4
4
  Utilrb.unless_faster do
5
5
  class Object
6
- # :call-seq
6
+ # call-seq:
7
7
  # attribute :name => default_value
8
8
  # attribute(:name) { default_value }
9
9
  #
@@ -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
- def has_singleton?; defined? @singleton_class end
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
- def has_singleton?
25
- defined? @singleton_class
26
- end
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
@@ -1,15 +1,23 @@
1
1
  require 'utilrb/gc/force'
2
+ require 'utilrb/object/attribute'
2
3
 
3
4
  module ObjectStats
4
- # Allocates no object
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
- # Allocates 1 Hash, which is included in the count
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 the memory allocation in the block
23
- # If alive is true, then only non-gcable objects
24
- # are returned.
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
- def self.stats(filter = nil)
39
- total_count = 0
40
- output = ""
41
- count_by_class.each do |klass, obj_count|
42
- total_count += obj_count
43
- if !filter || klass.name =~ filter
44
- output << klass.name << " " << obj_count.to_s << "\n"
45
- end
46
- end
47
-
48
- (output << "Total object count: #{total_count}")
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
- end
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
 
@@ -1,17 +1,22 @@
1
1
  class Queue
2
- # Returns all elements currently in the queue.
3
- # If +non_block+ is true, returns an empty array
4
- # if the queue is empty
5
- def get(non_block = false)
6
- while (Thread.critical = true; @que.empty?)
7
- return [] if non_block
8
- @waiting.push Thread.current
9
- Thread.stop
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
@@ -0,0 +1,2 @@
1
+ require 'utilrb/kernel/require'
2
+ require_dir(__FILE__)
@@ -0,0 +1,7 @@
1
+ require 'set'
2
+ class Set
3
+ def to_s
4
+ "{ #{map { |o| o.to_s }.join(", ")} }"
5
+ end
6
+ end
7
+
@@ -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"));
@@ -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
@@ -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.0
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.2
7
- date: 2006-12-01 00:00:00 +01:00
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/gc/force.rb
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/logger.rb
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/module.rb
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
- - License.txt
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: hoe
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: 1.1.4
134
+ version: 0.0.0
130
135
  version:
131
136
  - !ruby/object:Gem::Dependency
132
- name: facets
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: 0.0.0
143
+ version: 1.1.7
139
144
  version: