utilrb 0.2.3 → 1.0

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,27 @@
1
+ === Version 1.0
2
+ Bumped version number because of incompatible changes. Make it 1.0 since
3
+ having 0. version numbers for this kind of library is completely meaningless
4
+
5
+ * incompatible changes:
6
+ - Enumerable#+ acts on too many objects. Define it only on Enumerable::Enumerator
7
+ - remove automatic convertion into ValueSet for methods which were doing it
8
+ - removed Queue#get: fastthread is now the preferred threading library in
9
+ Ruby 1.8.6, so Queue#get cannot be implemented anymore
10
+
11
+ * new features:
12
+ - PkgConfig class
13
+ - define Proc#same_body?, Proc#file and Proc#line
14
+ - Module#attr_predicate
15
+ - 'since', 'until' and block parameters for Exception#full_message
16
+ - ValueSet#intersects? (more efficient than checking that the intersection
17
+ is empty)
18
+
19
+ * changes and fixes:
20
+ - properly handle singleton classes in has_ancestor?
21
+ - properly handle recursion in ValueSet#to_s and Array#to_s
22
+ - add the 'setup' task on the Rakefile to build the C extension
23
+ - make Module#has_ancestor? work event if the C extension is not built
24
+
1
25
  === Version 0.2.3
2
26
 
3
27
  * new features:
data/Manifest.txt CHANGED
@@ -7,6 +7,7 @@ bm/allocation.rb
7
7
  bm/speed.rb
8
8
  ext/extconf.rb
9
9
  ext/faster.cc
10
+ ext/ruby_internals.h
10
11
  ext/swap.cc
11
12
  ext/value_set.cc
12
13
  lib/utilrb.rb
@@ -38,6 +39,7 @@ lib/utilrb/logger/hierarchy.rb
38
39
  lib/utilrb/module.rb
39
40
  lib/utilrb/module/ancestor_p.rb
40
41
  lib/utilrb/module/attr_enumerable.rb
42
+ lib/utilrb/module/attr_predicate.rb
41
43
  lib/utilrb/module/define_method.rb
42
44
  lib/utilrb/module/include.rb
43
45
  lib/utilrb/module/inherited_enumerable.rb
@@ -46,8 +48,7 @@ lib/utilrb/object/address.rb
46
48
  lib/utilrb/object/attribute.rb
47
49
  lib/utilrb/object/singleton_class.rb
48
50
  lib/utilrb/objectstats.rb
49
- lib/utilrb/queue.rb
50
- lib/utilrb/queue/get.rb
51
+ lib/utilrb/pkgconfig.rb
51
52
  lib/utilrb/set.rb
52
53
  lib/utilrb/set/to_s.rb
53
54
  lib/utilrb/time.rb
@@ -55,10 +56,11 @@ lib/utilrb/time/to_hms.rb
55
56
  lib/utilrb/unbound_method.rb
56
57
  lib/utilrb/unbound_method/call.rb
57
58
  lib/utilrb/value_set.rb
58
- patches/fastthread-queue-get.patch
59
+ test/data/test_pkgconfig.pc
59
60
  test/test_array.rb
60
61
  test/test_config.rb
61
62
  test/test_enumerable.rb
63
+ test/test_exception.rb
62
64
  test/test_gc.rb
63
65
  test/test_hash.rb
64
66
  test/test_kernel.rb
@@ -66,5 +68,7 @@ test/test_misc.rb
66
68
  test/test_module.rb
67
69
  test/test_object.rb
68
70
  test/test_objectstats.rb
71
+ test/test_pkgconfig.rb
72
+ test/test_proc.rb
69
73
  test/test_time.rb
70
74
  test/test_unbound_method.rb
data/Rakefile CHANGED
@@ -1,3 +1,15 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+ # FIX: Hoe always calls rdoc with -d, and diagram generation fails here
4
+ class Rake::RDocTask
5
+ alias __option_list__ option_list
6
+ def option_list
7
+ options = __option_list__
8
+ options.delete("-d")
9
+ options
10
+ end
11
+ end
12
+
1
13
  require 'hoe'
2
14
  require './lib/utilrb/common'
3
15
 
@@ -8,9 +20,20 @@ Hoe.new('utilrb', Utilrb::VERSION) do |p|
8
20
  p.summary = 'Yet another Ruby toolkit'
9
21
  p.description = p.paragraphs_of('README.txt', 3..6).join("\n\n")
10
22
  p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
11
- p.changes = p.paragraphs_of('Changes.txt', 0..2).join("\n\n")
23
+ p.changes = p.paragraphs_of('Changes.txt', 0..3).join("\n\n")
12
24
 
13
25
  p.extra_deps << 'facets'
26
+ p.rdoc_pattern = /(ext\/.*cc$|lib)|txt/
27
+ end
28
+
29
+ desc "builds Utilrb's C extension"
30
+ task :setup do
31
+ Dir.chdir("ext") do
32
+ if !system("ruby extconf.rb") || !system("make")
33
+ raise "cannot build the C extension"
34
+ end
35
+ end
36
+ FileUtils.ln_sf "../../ext/faster.so", "lib/utilrb/faster.so"
14
37
  end
15
38
 
16
39
  task :full_test do
data/ext/faster.cc CHANGED
@@ -1,5 +1,6 @@
1
1
  #include <ruby.h>
2
2
  #include <set>
3
+ #include "ruby_internals.h"
3
4
 
4
5
  using namespace std;
5
6
 
@@ -38,6 +39,59 @@ static VALUE kernel_is_singleton_p(VALUE self)
38
39
  return Qfalse;
39
40
  }
40
41
 
42
+
43
+ /* call-seq:
44
+ * proc.same_body?(other) => true or false
45
+ *
46
+ * Returns true if +self+ and +other+ have the same body
47
+ */
48
+ static VALUE proc_same_body_p(VALUE self, VALUE other)
49
+ {
50
+ if (self == other) return Qtrue;
51
+ if (TYPE(other) != T_DATA) return Qfalse;
52
+ if (RDATA(other)->dmark != RDATA(self)->dmark) return Qfalse;
53
+ if (CLASS_OF(self) != CLASS_OF(other)) return Qfalse;
54
+
55
+ struct BLOCK* data, *data2;
56
+ Data_Get_Struct(self, struct BLOCK, data);
57
+ Data_Get_Struct(other, struct BLOCK, data2);
58
+ return (data->body == data2->body) ? Qtrue : Qfalse;
59
+ }
60
+
61
+ /* call-seq:
62
+ * proc.file
63
+ *
64
+ * Returns the file in which the proc body is defined, or nil
65
+ */
66
+ static VALUE proc_file(VALUE self)
67
+ {
68
+ struct BLOCK *data;
69
+ NODE *node;
70
+
71
+ Data_Get_Struct(self, struct BLOCK, data);
72
+ if ((node = data->frame.node) || (node = data->body))
73
+ return rb_str_new2(node->nd_file);
74
+ else
75
+ return Qnil;
76
+ }
77
+
78
+ /* call-seq:
79
+ * proc.file
80
+ *
81
+ * Returns the line at which the proc body is defined, or nil
82
+ */
83
+ static VALUE proc_line(VALUE self)
84
+ {
85
+ struct BLOCK *data;
86
+ NODE *node;
87
+
88
+ Data_Get_Struct(self, struct BLOCK, data);
89
+ if ((node = data->frame.node) || (node = data->body))
90
+ return INT2FIX(nd_line(node));
91
+ else
92
+ return Qnil;
93
+ }
94
+
41
95
  extern "C" void Init_value_set();
42
96
  extern "C" void Init_swap();
43
97
 
@@ -45,6 +99,9 @@ extern "C" void Init_faster()
45
99
  {
46
100
  rb_define_method(rb_mEnumerable, "each_uniq", RUBY_METHOD_FUNC(enumerable_each_uniq), 0);
47
101
  rb_define_method(rb_mKernel, "is_singleton?", RUBY_METHOD_FUNC(kernel_is_singleton_p), 0);
102
+ rb_define_method(rb_cProc, "same_body?", RUBY_METHOD_FUNC(proc_same_body_p), 1);
103
+ rb_define_method(rb_cProc, "file", RUBY_METHOD_FUNC(proc_file), 0);
104
+ rb_define_method(rb_cProc, "line", RUBY_METHOD_FUNC(proc_line), 0);
48
105
 
49
106
  Init_value_set();
50
107
  Init_swap();
@@ -0,0 +1,72 @@
1
+ #ifndef __RUBY_INTERNALS_HH__
2
+ #define __RUBY_INTERNALS_HH__
3
+
4
+ /* WARNING: this file contains copies of internal Ruby structures. They are not supposed to be copied (I think ;-)), but I had to nonetheless.
5
+ * The following methods depend on these:
6
+ *
7
+ * Kernel.swap!
8
+ * Proc#same_body?
9
+ * Proc#file
10
+ * Proc#line
11
+ */
12
+
13
+ #include <ruby.h>
14
+ #include <intern.h>
15
+ #include <node.h>
16
+ #include <re.h>
17
+ #include <env.h>
18
+
19
+ typedef struct RVALUE {
20
+ union {
21
+ struct {
22
+ unsigned long flags; /* always 0 for freed obj */
23
+ struct RVALUE *next;
24
+ } free;
25
+ struct RBasic basic;
26
+ struct RObject object;
27
+ struct RClass klass;
28
+ struct RFloat flonum;
29
+ struct RString string;
30
+ struct RArray array;
31
+ struct RRegexp regexp;
32
+ struct RHash hash;
33
+ struct RData data;
34
+ struct RStruct rstruct;
35
+ struct RBignum bignum;
36
+ struct RFile file;
37
+ struct RNode node;
38
+ struct RMatch match;
39
+ struct RVarmap varmap;
40
+ struct SCOPE scope;
41
+ } as;
42
+ #ifdef GC_DEBUG
43
+ char *file;
44
+ int line;
45
+ #endif
46
+ } RVALUE;
47
+ static const size_t SLOT_SIZE = sizeof(RVALUE);
48
+
49
+ /* This is a copy of Ruby 1.8.5 BLOCK structure. It sucks to copy it here,
50
+ * but it is not public in Ruby and it is needed to define same_body? */
51
+ struct BLOCK {
52
+ NODE *var;
53
+ NODE *body;
54
+ VALUE self;
55
+ struct FRAME frame;
56
+ struct SCOPE *scope;
57
+ VALUE klass;
58
+ NODE *cref;
59
+ int iter;
60
+ int vmode;
61
+ int flags;
62
+ int uniq;
63
+ struct RVarmap *dyna_vars;
64
+ VALUE orig_thread;
65
+ VALUE wrapper;
66
+ VALUE block_obj;
67
+ struct BLOCK *outer;
68
+ struct BLOCK *prev;
69
+ };
70
+
71
+ #endif
72
+
data/ext/swap.cc CHANGED
@@ -1,38 +1,4 @@
1
- #include <ruby.h>
2
- #include <intern.h>
3
- #include <node.h>
4
- #include <re.h>
5
- #include <env.h>
6
-
7
- typedef struct RVALUE {
8
- union {
9
- struct {
10
- unsigned long flags; /* always 0 for freed obj */
11
- struct RVALUE *next;
12
- } free;
13
- struct RBasic basic;
14
- struct RObject object;
15
- struct RClass klass;
16
- struct RFloat flonum;
17
- struct RString string;
18
- struct RArray array;
19
- struct RRegexp regexp;
20
- struct RHash hash;
21
- struct RData data;
22
- struct RStruct rstruct;
23
- struct RBignum bignum;
24
- struct RFile file;
25
- struct RNode node;
26
- struct RMatch match;
27
- struct RVarmap varmap;
28
- struct SCOPE scope;
29
- } as;
30
- #ifdef GC_DEBUG
31
- char *file;
32
- int line;
33
- #endif
34
- } RVALUE;
35
- static const size_t SLOT_SIZE = sizeof(RVALUE);
1
+ #include "ruby_internals.h"
36
2
 
37
3
  /*
38
4
  * Kernel.swap!(obj1, obj2, *args)
data/ext/value_set.cc CHANGED
@@ -9,7 +9,6 @@ using namespace std;
9
9
 
10
10
  static VALUE cValueSet;
11
11
  static ID id_new;
12
- static ID id_to_value_set;
13
12
 
14
13
  typedef std::set<VALUE> ValueSet;
15
14
  static ValueSet& get_wrapped_set(VALUE self)
@@ -110,7 +109,9 @@ static VALUE value_set_to_value_set(VALUE self) { return self; }
110
109
  static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
111
110
  {
112
111
  ValueSet const& self = get_wrapped_set(vself);
113
- ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
112
+ if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
113
+ rb_raise(rb_eArgError, "expected a ValueSet");
114
+ ValueSet const& other = get_wrapped_set(vother);
114
115
  return std::includes(self.begin(), self.end(), other.begin(), other.end()) ? Qtrue : Qfalse;
115
116
  }
116
117
 
@@ -124,7 +125,9 @@ static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
124
125
  static VALUE value_set_union(VALUE vself, VALUE vother)
125
126
  {
126
127
  ValueSet const& self = get_wrapped_set(vself);
127
- ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
128
+ if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
129
+ rb_raise(rb_eArgError, "expected a ValueSet");
130
+ ValueSet const& other = get_wrapped_set(vother);
128
131
 
129
132
  VALUE vresult = rb_funcall(cValueSet, id_new, 0);
130
133
  ValueSet& result = get_wrapped_set(vresult);
@@ -141,7 +144,9 @@ static VALUE value_set_union(VALUE vself, VALUE vother)
141
144
  static VALUE value_set_merge(VALUE vself, VALUE vother)
142
145
  {
143
146
  ValueSet& self = get_wrapped_set(vself);
144
- ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
147
+ if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
148
+ rb_raise(rb_eArgError, "expected a ValueSet");
149
+ ValueSet const& other = get_wrapped_set(vother);
145
150
 
146
151
  self.insert(other.begin(), other.end());
147
152
  return vself;
@@ -157,7 +162,9 @@ static VALUE value_set_merge(VALUE vself, VALUE vother)
157
162
  static VALUE value_set_intersection(VALUE vself, VALUE vother)
158
163
  {
159
164
  ValueSet const& self = get_wrapped_set(vself);
160
- ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
165
+ if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
166
+ rb_raise(rb_eArgError, "expected a ValueSet");
167
+ ValueSet const& other = get_wrapped_set(vother);
161
168
 
162
169
  VALUE vresult = rb_funcall(cValueSet, id_new, 0);
163
170
  ValueSet& result = get_wrapped_set(vresult);
@@ -165,6 +172,37 @@ static VALUE value_set_intersection(VALUE vself, VALUE vother)
165
172
  std::inserter(result, result.end()));
166
173
  return vresult;
167
174
  }
175
+
176
+ /* call-seq:
177
+ * set.intersects?(other) => true or false
178
+ *
179
+ * Returns true if there is elements in +set+ that are also in +other
180
+ */
181
+ static VALUE value_set_intersects(VALUE vself, VALUE vother)
182
+ {
183
+ ValueSet const& self = get_wrapped_set(vself);
184
+ if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
185
+ rb_raise(rb_eArgError, "expected a ValueSet");
186
+ ValueSet const& other = get_wrapped_set(vother);
187
+
188
+ ValueSet::const_iterator
189
+ self_it = self.begin(),
190
+ self_end = self.end(),
191
+ other_it = other.begin(),
192
+ other_end = other.end();
193
+
194
+ while(self_it != self_end && other_it != other_end)
195
+ {
196
+ if (*self_it < *other_it)
197
+ ++self_it;
198
+ else if (*other_it < *self_it)
199
+ ++other_it;
200
+ else
201
+ return Qtrue;
202
+ }
203
+ return Qfalse;
204
+ }
205
+
168
206
  /* call-seq:
169
207
  * set.difference(other) => difference_set
170
208
  * set - other => difference_set
@@ -175,7 +213,9 @@ static VALUE value_set_intersection(VALUE vself, VALUE vother)
175
213
  static VALUE value_set_difference(VALUE vself, VALUE vother)
176
214
  {
177
215
  ValueSet const& self = get_wrapped_set(vself);
178
- ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
216
+ if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
217
+ rb_raise(rb_eArgError, "expected a ValueSet");
218
+ ValueSet const& other = get_wrapped_set(vother);
179
219
 
180
220
  VALUE vresult = rb_funcall(cValueSet, id_new, 0);
181
221
  ValueSet& result = get_wrapped_set(vresult);
@@ -219,10 +259,9 @@ static VALUE value_set_delete(VALUE vself, VALUE v)
219
259
  static VALUE value_set_equal(VALUE vself, VALUE vother)
220
260
  {
221
261
  ValueSet const& self = get_wrapped_set(vself);
222
- if (!rb_respond_to(vother, id_to_value_set))
262
+ if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
223
263
  return Qfalse;
224
-
225
- ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
264
+ ValueSet const& other = get_wrapped_set(vother);
226
265
  return (self == other) ? Qtrue : Qfalse;
227
266
  }
228
267
 
@@ -244,7 +283,7 @@ static VALUE value_set_clear(VALUE self)
244
283
  */
245
284
  static VALUE value_set_initialize_copy(VALUE vself, VALUE vother)
246
285
  {
247
- ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
286
+ ValueSet const& other = get_wrapped_set(vother);
248
287
  set<VALUE> new_set(other.begin(), other.end());
249
288
  get_wrapped_set(vself).swap(new_set);
250
289
  return vself;
@@ -292,13 +331,13 @@ extern "C" void Init_value_set()
292
331
 
293
332
  cValueSet = rb_define_class("ValueSet", rb_cObject);
294
333
  id_new = rb_intern("new");
295
- id_to_value_set = rb_intern("to_value_set");
296
334
  rb_define_alloc_func(cValueSet, value_set_alloc);
297
335
  rb_define_method(cValueSet, "each", RUBY_METHOD_FUNC(value_set_each), 0);
298
336
  rb_define_method(cValueSet, "include?", RUBY_METHOD_FUNC(value_set_include_p), 1);
299
337
  rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
300
338
  rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
301
339
  rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
340
+ rb_define_method(cValueSet, "intersects?", RUBY_METHOD_FUNC(value_set_intersects), 1);
302
341
  rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
303
342
  rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
304
343
  rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
@@ -3,11 +3,11 @@ class Array
3
3
  # Unlike #inspect, it calls #to_s on the elements too
4
4
  def to_s
5
5
  stack = (Thread.current[:array_to_s] ||= [])
6
- if stack.include?(self)
6
+ if stack.include?(object_id)
7
7
  "..."
8
8
  else
9
9
  begin
10
- stack.push self
10
+ stack.push object_id
11
11
  "[" << map { |obj| obj.to_s }.join(", ") << "]"
12
12
  ensure
13
13
  stack.pop
data/lib/utilrb/common.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Utilrb
2
- VERSION = "0.2.3" unless defined? Utilrb::VERSION
2
+ VERSION = "1.0" unless defined? Utilrb::VERSION
3
3
 
4
4
  unless defined? UTILRB_FASTER_MODE
5
5
  if ENV['UTILRB_FASTER_MODE'] == 'no'
@@ -1,8 +1,16 @@
1
- # An enumerator which iterates on a sequence of enumerator
1
+ require 'enumerator'
2
+
3
+ # An enumerator which iterates on multiple iterators in sequence
4
+ #
5
+ # ([1, 2].enum_for + [2, 3].enum_for).each => 1, 2, 2, 3
6
+ #
7
+ # See also Enumerator#+
2
8
  class SequenceEnumerator
3
9
  def initialize; @sequence = Array.new end
10
+
11
+ def +(other); SequenceEnumerator.new << self << other end
4
12
  # Adds +object+ at the back of the sequence
5
- def <<(object); @sequence << object; self end
13
+ def <<(other); @sequence << other; self end
6
14
 
7
15
  def each
8
16
  @sequence.each { |enum| enum.each { |o| yield(o) } } if block_given?
@@ -12,7 +20,7 @@ class SequenceEnumerator
12
20
  include Enumerable
13
21
  end
14
22
 
15
- module Enumerable # :nodoc
23
+ class Enumerable::Enumerator # :nodoc
16
24
  # Builds a sequence of enumeration object.
17
25
  # ([1, 2].enum_for + [2, 3]).each => 1, 2, 2, 3
18
26
  def +(other_enumerator) # :nodoc
@@ -1,3 +1,4 @@
1
+ require 'utilrb/kernel/options'
1
2
 
2
3
  class Exception
3
4
  # Returns the full exception message, with backtrace, like the one we get from
@@ -16,9 +17,40 @@ class Exception
16
17
  # test.rb:3:in `test': this is a test (RuntimeError)
17
18
  # from test.rb:7
18
19
  #
19
- def full_message
20
- first, *remaining = backtrace
21
- "#{first}: #{message} (#{self.class})\n\tfrom " + remaining.join("\n\tfrom ")
20
+ # Two regular expressions can be given through the +options+ hash to filter the backtrace:
21
+ # since::
22
+ # Only the methods *below* the first matching line will be displayed. The matching
23
+ # line is included.
24
+ # until::
25
+ # Only the methods *above* the first matching line will be displayed. The matching
26
+ # line is *not* included
27
+ #
28
+ # If a block is given, each line of the backtrace are yield and only the lines for which
29
+ # the block returns true are displayed
30
+ #
31
+ def full_message(options = {}, &block)
32
+ options = validate_options options, [:since, :until]
33
+ since_matches, until_matches = options[:since], options[:until]
34
+
35
+ trace = backtrace
36
+ if since_matches || until_matches
37
+ found_beginning, found_end = !since_matches, false
38
+ trace = trace.find_all do |line|
39
+ found_beginning ||= (line =~ since_matches)
40
+ found_end ||= (line =~ until_matches) if until_matches
41
+ found_beginning && !found_end
42
+ end
43
+ end
44
+
45
+ first, *remaining = if block_given? then trace.find_all(&block)
46
+ else trace
47
+ end
48
+
49
+ msg = "#{first}: #{message} (#{self.class})"
50
+ unless remaining.empty?
51
+ msg << "\n\tfrom " + remaining.join("\n\tfrom ")
52
+ end
53
+ msg
22
54
  end
23
55
  end
24
56
 
@@ -1,6 +1,25 @@
1
+ require 'utilrb/common'
1
2
  class Module
2
- # Check if +klass+ is an ancestor of this class/module
3
- def has_ancestor?(klass); self == klass || self < klass end
3
+ Utilrb.if_faster do
4
+ # Check if +klass+ is an ancestor of this class/module
5
+ #
6
+ # It works for singleton classes as well:
7
+ #
8
+ # class MyClass; end
9
+ # obj = MyClass.new
10
+ # singleton = class << obj; obj end
11
+ #
12
+ # singleton.has_ancestor?(MyClass) # => true
13
+ #
14
+ def has_ancestor?(klass)
15
+ self == klass || self < klass || (is_singleton? && superclass.has_ancestor?(klass))
16
+ end
17
+ end
18
+ Utilrb.unless_faster do
19
+ def has_ancestor?(klass) # :nodoc:
20
+ self == klass || self < klass || superclass == klass || superclass < klass
21
+ end
22
+ end
4
23
  end
5
24
 
6
25
 
@@ -0,0 +1,17 @@
1
+ class Module
2
+ # Defines a +name+ predicate (name should end with '?'), and if writable is true
3
+ # a writer method which is +name+ without '?'
4
+ #
5
+ # The predicate reads the instance variable which is +name+ without the '?'
6
+ def attr_predicate(name, writable = false)
7
+ attr_name = name.to_s.gsub(/\?$/, '')
8
+ attr_reader attr_name
9
+ alias_method "#{attr_name}?", attr_name
10
+ remove_method attr_name
11
+
12
+ if writable
13
+ class_eval "def #{attr_name}=(value); @#{attr_name} = !!value end"
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,48 @@
1
+ module Utilrb
2
+ # Access to information from pkg-config(1)
3
+ class PkgConfig
4
+ class NotFound < RuntimeError
5
+ attr_reader :name
6
+ def initialize(name); @name = name end
7
+ def to_s; "#{name} is not available to pkg-config" end
8
+ end
9
+
10
+ # The module name
11
+ attr_reader :name
12
+ # The module version
13
+ attr_reader :version
14
+
15
+ # Create a PkgConfig object for the package +name+
16
+ # Raises PkgConfig::NotFound if the module does not exist
17
+ def initialize(name)
18
+ if !system("pkg-config --exists #{name}")
19
+ raise NotFound.new(name)
20
+ end
21
+
22
+ @name = name
23
+ @version = `pkg-config --modversion #{name}`.chomp.strip
24
+ @actions = Hash.new
25
+ @variables = Hash.new
26
+ end
27
+
28
+ def self.define_action(action)
29
+ define_method(action.gsub(/-/, '_')) do
30
+ @actions[action] ||= `pkg-config --#{action} #{name}`.chomp.strip
31
+ end
32
+ nil
33
+ end
34
+
35
+ ACTIONS = %w{cflags cflags-only-I cflags-only-other
36
+ libs libs-only-L libs-only-l libs-only-other static}
37
+ ACTIONS.each { |action| define_action(action) }
38
+
39
+ def method_missing(varname, *args, &proc)
40
+ if args.empty?
41
+ @variables[varname] ||= `pkg-config --variable=#{varname} #{name}`.chomp.strip
42
+ else
43
+ super(varname, *args, &proc)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
@@ -9,13 +9,13 @@ class Time
9
9
  # s, s.ms, m:s, m:s.ms, h:m:s, h:m:s.ms
10
10
  def self.from_hms(string)
11
11
  unless string =~ /(?:^|:)(\d+)(?:$|\.)/
12
- raise "invalid format #{string}"
12
+ raise ArgumentError, "#{string} found, expected [[h:]m:]s[.ms]"
13
13
  end
14
14
  hm, ms = $`, $'
15
15
 
16
16
  s = Integer($1)
17
17
  unless hm =~ /^(?:(\d*):)?(?:(\d*))?$/
18
- raise "invalid format #{string}. found #{hm}, expected nothing, m: or h:m:"
18
+ raise ArgumentError, "found #{hm}, expected nothing, m: or h:m:"
19
19
  end
20
20
  h, m = if $2.empty? then
21
21
  if $1 then [0, Integer($1)]
@@ -27,7 +27,7 @@ class Time
27
27
  ms = if ms.empty? then 0
28
28
  else
29
29
  unless ms =~ /^\d*$/
30
- raise "invalid format "#{string}"
30
+ raise ArgumentError, "found #{string}, expected a number"
31
31
  end
32
32
  ms += "0" * (3 - ms.size)
33
33
  Integer(ms)
@@ -9,9 +9,25 @@ Utilrb.require_faster("ValueSet") do
9
9
  include Enumerable
10
10
 
11
11
  def to_s
12
- base = super[0..-2]
13
- "#{base} { #{to_a.map { |o| o.to_s }.join(", ")} }"
12
+ stack = (Thread.current[:__value_set_stack__] ||= ValueSet.new)
13
+ if stack.include?(self)
14
+ "..."
15
+ else
16
+ stack << self
17
+
18
+ base = super[0..-2]
19
+ "#{base} { #{to_a.map { |o| o.to_s }.join(", ")} }"
20
+ end
21
+ ensure
22
+ stack.delete(self)
14
23
  end
15
24
  alias :inspect :to_s
25
+
26
+ def _dump(lvl = -1)
27
+ Marshal.dump(to_a)
28
+ end
29
+ def self._load(str)
30
+ Marshal.load(str).to_value_set
31
+ end
16
32
  end
17
33
  end
@@ -0,0 +1,9 @@
1
+ prefix=a_prefix
2
+
3
+ Name: test_pkgconfig
4
+ Description:
5
+ Version: 4.2
6
+
7
+ Cflags: -I${prefix}/include -O3
8
+ Libs: -ltest -lother -L${prefix}/lib
9
+
@@ -43,6 +43,7 @@ class TC_Enumerable < Test::Unit::TestCase
43
43
  c2 = [:d, :e, :f]
44
44
  assert_equal([:a, :b, :c, :d, :e, :f], (c1.to_enum + c2.to_enum).to_a)
45
45
  assert_equal([:a, :b, :c, :d, :e, :f], [c1, c2].inject(null_enum) { |a, b| a + b }.to_a)
46
+ assert_equal([:a, :b, :c, :d, :e, :f], [c1, c2].inject(SequenceEnumerator.new) { |a, b| a << b }.to_a)
46
47
  end
47
48
 
48
49
  def test_random_element
@@ -66,9 +67,13 @@ class TC_Enumerable < Test::Unit::TestCase
66
67
  assert_equal(5, a.size)
67
68
  assert_equal([1, 3, 4, 6, 8], a.to_a)
68
69
  assert(a.include?(1))
69
- assert(a.include_all?([4, 1, 8]))
70
+ assert(a.include_all?([4, 1, 8].to_value_set))
70
71
  assert(!a.include_all?(b))
71
72
 
73
+ assert(a.intersects?(b))
74
+ assert(b.intersects?(a))
75
+ assert(!a.intersects?([2, 9, 12].to_value_set))
76
+
72
77
  assert(a.object_id == a.to_value_set.object_id)
73
78
 
74
79
  assert_equal([1, 2, 3, 4, 6, 8, 11], (a.union(b)).to_a)
@@ -87,6 +92,12 @@ class TC_Enumerable < Test::Unit::TestCase
87
92
 
88
93
  assert_equal([1,3,5].to_value_set, [1, 2, 3, 4, 5, 6].to_value_set.delete_if { |v| v % 2 == 0 })
89
94
  end
95
+
96
+ def test_value_set_recursive_to_s
97
+ v = [1, 2].to_value_set
98
+ v << v
99
+ assert_nothing_raised { v.to_s }
100
+ end
90
101
  end
91
102
  end
92
103
 
@@ -0,0 +1,38 @@
1
+ require 'test_config'
2
+ require 'utilrb/exception'
3
+ require 'flexmock'
4
+
5
+ class TC_Exception < Test::Unit::TestCase
6
+ def test_full_message
7
+ FlexMock.use do |mock|
8
+ error = Exception.new
9
+ def error.message; "this is an error" end
10
+ def error.backtrace
11
+ (0..10).map { |i| i.to_s }
12
+ end
13
+
14
+ full = error.full_message.split("\n")
15
+ assert_equal(11, full.size)
16
+
17
+ filtered = error.full_message { |line| Integer(line) % 2 == 0 }.split("\n")
18
+ assert_equal(6, filtered.size)
19
+ assert_equal(full.values_at(0, 2, 4, 6, 8, 10), filtered)
20
+
21
+ since_matches = error.full_message(:since => /4/).split("\n")
22
+ assert_equal(7, since_matches.size)
23
+ assert_equal(full.values_at(*(5..10)), since_matches[1..-1])
24
+
25
+ until_matches = error.full_message(:until => /3/).split("\n")
26
+ assert_equal(3, until_matches.size)
27
+ assert_equal(full.values_at(1, 2), until_matches[1..-1])
28
+
29
+ since_and_until = error.full_message(:since => /3/, :until => /6/).split("\n")
30
+ assert_equal(3, since_and_until.size)
31
+ assert_equal(full.values_at(4, 5), since_and_until[1..-1])
32
+
33
+ all = error.full_message(:since => /3/, :until => /6/) { |line| Integer(line) % 2 == 0 }.split("\n")
34
+ assert_equal(1, all.size)
35
+ end
36
+ end
37
+ end
38
+
data/test/test_module.rb CHANGED
@@ -123,5 +123,25 @@ class TC_Module < Test::Unit::TestCase
123
123
  assert_equal([[:base, 10], [:overriden, 20], [:overriden, 15], [:derived, 25]].to_set, derived.enum_for(:each_mapped, nil, false).to_set)
124
124
  assert_equal([[:base, 10], [:overriden, 15], [:derived, 25]].to_set, derived.enum_for(:each_mapped, nil, true).to_set)
125
125
  end
126
+
127
+ def test_has_ancestor
128
+ mod = Module.new
129
+ parent = Class.new do
130
+ include mod
131
+ end
132
+ child = Class.new(parent)
133
+ singleton = child.new.singleton_class
134
+
135
+ assert(child.has_ancestor?(parent))
136
+ assert(child.has_ancestor?(mod))
137
+ assert(parent.has_ancestor?(mod))
138
+
139
+ assert(singleton.has_ancestor?(parent), singleton.superclass)
140
+ assert(singleton.has_ancestor?(mod))
141
+ assert(singleton.has_ancestor?(child))
142
+
143
+ assert(!parent.has_ancestor?(child))
144
+ assert(!parent.has_ancestor?(singleton))
145
+ end
126
146
  end
127
147
 
data/test/test_object.rb CHANGED
@@ -61,5 +61,24 @@ class TC_Object < Test::Unit::TestCase
61
61
  assert_equal(klass, object.singleton_class.superclass)
62
62
  assert_equal([object.singleton_class, klass, Object], object.singleton_class.ancestors[0, 3])
63
63
  end
64
+
65
+ def test_attr_predicate
66
+ klass = Class.new do
67
+ attr_predicate :working
68
+ attr_predicate :not_working, true
69
+ end
70
+ assert(klass.method_defined?(:working?))
71
+ assert(!klass.method_defined?(:working))
72
+ assert(!klass.method_defined?(:working=))
73
+ assert(klass.method_defined?(:not_working?))
74
+ assert(!klass.method_defined?(:not_working))
75
+ assert(klass.method_defined?(:not_working=))
76
+
77
+ object = klass.new
78
+ object.instance_eval { @working = true }
79
+ assert(object.working?)
80
+ object.not_working = 5
81
+ assert_equal(true, object.not_working?)
82
+ end
64
83
  end
65
84
 
@@ -0,0 +1,35 @@
1
+ require 'test/unit'
2
+ require 'set'
3
+ require 'utilrb/pkgconfig'
4
+
5
+ class TC_PkgConfig < Test::Unit::TestCase
6
+ def setup
7
+ @old_pkg_config_path = ENV['PKG_CONFIG_PATH']
8
+ ENV['PKG_CONFIG_PATH'] = File.join(File.expand_path(File.dirname(__FILE__)), 'data')
9
+ end
10
+ def teardown
11
+ ENV['PKG_CONFIG_PATH'] = @old_pkg_config_path
12
+ end
13
+
14
+ PkgConfig = Utilrb::PkgConfig
15
+ def test_find_package
16
+ STDERR.puts ENV['PKG_CONFIG_PATH']
17
+ assert_raises(PkgConfig::NotFound) { PkgConfig.new('does_not_exist') }
18
+ assert_nothing_raised { PkgConfig.new('test_pkgconfig') }
19
+ end
20
+
21
+ def test_load
22
+ pkg = PkgConfig.new('test_pkgconfig')
23
+ assert_equal('test_pkgconfig', pkg.name)
24
+ assert_equal('4.2', pkg.version)
25
+
26
+ assert_equal('a_prefix', pkg.prefix)
27
+ assert_equal(%w{-Ia_prefix/include -O3}.to_set, pkg.cflags.split.to_set)
28
+ assert_equal('-Ia_prefix/include', pkg.cflags_only_I)
29
+ assert_equal('-O3', pkg.cflags_only_other)
30
+
31
+ assert_equal(%w{-ltest -lother -La_prefix/lib}.to_set, pkg.libs.split.to_set)
32
+ assert_equal('-La_prefix/lib', pkg.libs_only_L)
33
+ assert_equal(%w{-ltest -lother}.to_set, pkg.libs_only_l.split.to_set)
34
+ end
35
+ end
data/test/test_proc.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'test/unit'
2
+ require 'utilrb'
3
+
4
+ Utilrb.require_faster('TC_Proc') do
5
+ class TC_Proc < Test::Unit::TestCase
6
+ def block_to_proc_helper(&block); block end
7
+ def block_to_proc
8
+ [block_to_proc_helper { blo }, block_to_proc_helper { bla }]
9
+ end
10
+ def test_same_body
11
+ a1, a2 = block_to_proc
12
+ b1, b2 = block_to_proc
13
+ assert(a1.same_body?(b1))
14
+ assert(a2.same_body?(b2))
15
+ assert(!a1.same_body?(b2))
16
+ assert(!a2.same_body?(b1))
17
+ end
18
+
19
+ def test_line
20
+ assert_equal(8, block_to_proc.first.line)
21
+ end
22
+
23
+ def test_file
24
+ assert_equal(File.expand_path(__FILE__), File.expand_path(block_to_proc.first.file))
25
+ end
26
+ end
27
+ end
28
+
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.1
2
+ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: utilrb
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.3
7
- date: 2007-01-30 00:00:00 +01:00
6
+ version: "1.0"
7
+ date: 2007-03-31 00:00:00 +02:00
8
8
  summary: Yet another Ruby toolkit
9
9
  require_paths:
10
10
  - lib
@@ -39,6 +39,7 @@ files:
39
39
  - bm/speed.rb
40
40
  - ext/extconf.rb
41
41
  - ext/faster.cc
42
+ - ext/ruby_internals.h
42
43
  - ext/swap.cc
43
44
  - ext/value_set.cc
44
45
  - lib/utilrb.rb
@@ -70,6 +71,7 @@ files:
70
71
  - lib/utilrb/module.rb
71
72
  - lib/utilrb/module/ancestor_p.rb
72
73
  - lib/utilrb/module/attr_enumerable.rb
74
+ - lib/utilrb/module/attr_predicate.rb
73
75
  - lib/utilrb/module/define_method.rb
74
76
  - lib/utilrb/module/include.rb
75
77
  - lib/utilrb/module/inherited_enumerable.rb
@@ -78,8 +80,7 @@ files:
78
80
  - lib/utilrb/object/attribute.rb
79
81
  - lib/utilrb/object/singleton_class.rb
80
82
  - lib/utilrb/objectstats.rb
81
- - lib/utilrb/queue.rb
82
- - lib/utilrb/queue/get.rb
83
+ - lib/utilrb/pkgconfig.rb
83
84
  - lib/utilrb/set.rb
84
85
  - lib/utilrb/set/to_s.rb
85
86
  - lib/utilrb/time.rb
@@ -87,10 +88,11 @@ files:
87
88
  - lib/utilrb/unbound_method.rb
88
89
  - lib/utilrb/unbound_method/call.rb
89
90
  - lib/utilrb/value_set.rb
90
- - patches/fastthread-queue-get.patch
91
+ - test/data/test_pkgconfig.pc
91
92
  - test/test_array.rb
92
93
  - test/test_config.rb
93
94
  - test/test_enumerable.rb
95
+ - test/test_exception.rb
94
96
  - test/test_gc.rb
95
97
  - test/test_hash.rb
96
98
  - test/test_kernel.rb
@@ -98,9 +100,13 @@ files:
98
100
  - test/test_module.rb
99
101
  - test/test_object.rb
100
102
  - test/test_objectstats.rb
103
+ - test/test_pkgconfig.rb
104
+ - test/test_proc.rb
101
105
  - test/test_time.rb
102
106
  - test/test_unbound_method.rb
103
107
  test_files:
108
+ - test/test_proc.rb
109
+ - test/test_exception.rb
104
110
  - test/test_time.rb
105
111
  - test/test_misc.rb
106
112
  - test/test_module.rb
@@ -113,6 +119,7 @@ test_files:
113
119
  - test/test_enumerable.rb
114
120
  - test/test_hash.rb
115
121
  - test/test_objectstats.rb
122
+ - test/test_pkgconfig.rb
116
123
  rdoc_options: []
117
124
 
118
125
  extra_rdoc_files: []
@@ -140,5 +147,5 @@ dependencies:
140
147
  requirements:
141
148
  - - ">="
142
149
  - !ruby/object:Gem::Version
143
- version: 1.1.7
150
+ version: 1.2.0
144
151
  version:
@@ -1,22 +0,0 @@
1
- class Queue
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
20
- end
21
- end
22
- end
data/lib/utilrb/queue.rb DELETED
@@ -1,2 +0,0 @@
1
- require 'utilrb/kernel/require'
2
- require_dir(__FILE__)
@@ -1,72 +0,0 @@
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"));