utilrb 0.2.3 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
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"));