utilrb 1.3.2 → 1.3.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/History.txt CHANGED
@@ -1,12 +1,22 @@
1
- === Version 1.3.1
1
+ === Version 1.3.3
2
+
3
+ * fixed a problem with WeakRef crashing on 1.8.7p172. This version of weakref
4
+ should now work on every versions of 1.8.6 and 1.8.7
5
+ * made ColumnFormatter more configurable
6
+ * made the Rakefile callable with ruby's binaries that are not called 'ruby'
7
+
8
+ === Version 1.3.2
2
9
 
3
10
  * make utilrb depend only on standard C++, no boost
4
- * make the Rakefile not depend on the availability of Hoe
11
+
12
+ === Version 1.3.1
13
+
14
+ * quickfix release: update the Manifest file for Hoe
5
15
 
6
16
  === Version 1.3
7
17
 
8
18
  * added Utilrb::WeakRef, a much leaner version of the standard WeakRef:
9
- implemented in C++, not a subclass of Delegate (delegate is very costly)
19
+ implemented in C++, not a subclass of Delegate (delegate is very costly).
10
20
 
11
21
  === Version 1.2
12
22
 
data/Rakefile CHANGED
@@ -20,11 +20,10 @@ begin
20
20
 
21
21
  p.summary = 'Yet another Ruby toolkit'
22
22
  p.description = p.paragraphs_of('README.txt', 3..6).join("\n\n")
23
- p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
23
+ p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1].map { |l| l.strip }
24
24
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
25
25
 
26
26
  p.extra_deps << ['facets', '>= 2.4.0'] << 'rake'
27
- p.rdoc_pattern = /(ext\/.*cc$|lib)|txt/
28
27
  end
29
28
  config.spec.extensions << 'ext/extconf.rb'
30
29
  rescue LoadError
@@ -34,10 +33,11 @@ rescue Exception => e
34
33
  STDERR.puts "error message is: #{e.message}"
35
34
  end
36
35
 
36
+ RUBY = RbConfig::CONFIG['RUBY_INSTALL_NAME']
37
37
  desc "builds Utilrb's C extension"
38
38
  task :setup do
39
39
  Dir.chdir("ext") do
40
- if !system("ruby extconf.rb") || !system("make")
40
+ if !system("#{RUBY} extconf.rb") || !system("make")
41
41
  raise "cannot build the C extension"
42
42
  end
43
43
  end
data/ext/extconf.rb CHANGED
@@ -2,7 +2,7 @@ require 'mkmf'
2
2
 
3
3
  CONFIG['CC'] = "g++"
4
4
  if RUBY_VERSION >= "1.9"
5
- $CFLAGS += "-DRUBY_IS_19"
5
+ $CFLAGS += " -DRUBY_IS_19"
6
6
  end
7
7
 
8
8
  $LDFLAGS += "-module"
@@ -12,9 +12,34 @@
12
12
 
13
13
  #include <ruby.h>
14
14
  #include <ruby/intern.h>
15
- #include <ruby/node.h>
16
15
  #include <ruby/re.h>
17
16
 
17
+ typedef struct RNode {
18
+ unsigned long flags;
19
+ char *nd_file;
20
+ union {
21
+ struct RNode *node;
22
+ ID id;
23
+ VALUE value;
24
+ VALUE (*cfunc)(ANYARGS);
25
+ ID *tbl;
26
+ } u1;
27
+ union {
28
+ struct RNode *node;
29
+ ID id;
30
+ long argc;
31
+ VALUE value;
32
+ } u2;
33
+ union {
34
+ struct RNode *node;
35
+ ID id;
36
+ long state;
37
+ struct global_entry *entry;
38
+ long cnt;
39
+ VALUE value;
40
+ } u3;
41
+ } NODE;
42
+
18
43
  typedef struct RVALUE {
19
44
  union {
20
45
  struct {
@@ -35,11 +60,9 @@ typedef struct RVALUE {
35
60
  struct RFile file;
36
61
  struct RNode node;
37
62
  struct RMatch match;
63
+ struct RRational rational;
64
+ struct RComplex complex;
38
65
  } as;
39
- #ifdef GC_DEBUG
40
- char *file;
41
- int line;
42
- #endif
43
66
  } RVALUE;
44
67
 
45
68
  static const size_t SLOT_SIZE = sizeof(RVALUE);
data/ext/utilrb_ext.cc CHANGED
@@ -1,17 +1,19 @@
1
1
  #include <ruby.h>
2
2
  #include <set>
3
3
 
4
+ #ifndef RUBINIUS
4
5
  #ifdef RUBY_IS_19
5
6
  #include "ruby_internals-1.9.h"
6
7
  #else
7
- #include <rubyio.h>
8
8
  #include "ruby_internals-1.8.h"
9
9
  #endif
10
+ #endif
10
11
 
11
12
  static VALUE mUtilrb;
12
13
 
13
14
  using namespace std;
14
15
 
16
+ #ifndef RUBINIUS
15
17
  static VALUE enumerable_each_uniq_i(VALUE i, VALUE* memo)
16
18
  {
17
19
  set<VALUE>& seen = *reinterpret_cast< set<VALUE>* >(memo);
@@ -34,21 +36,6 @@ static VALUE enumerable_each_uniq(VALUE self)
34
36
  return self;
35
37
  }
36
38
 
37
- #ifndef RUBY_IS_19
38
- /* call-seq:
39
- * io.clearerr => nil
40
- *
41
- * Clear all error flags on the IO
42
- */
43
- static VALUE io_clearerr(VALUE self)
44
- {
45
- OpenFile* file;
46
- file = RFILE(self)->fptr;
47
- clearerr(file->f);
48
- return Qnil;
49
- }
50
- #endif
51
-
52
39
  /* call-seq:
53
40
  * Kernel.is_singleton?(object)
54
41
  *
@@ -120,6 +107,7 @@ static VALUE proc_line(VALUE self)
120
107
 
121
108
  static VALUE kernel_is_immediate(VALUE klass, VALUE object)
122
109
  { return IMMEDIATE_P(object) ? Qtrue : Qfalse; }
110
+ #endif
123
111
 
124
112
  extern "C" void Init_value_set();
125
113
  extern "C" void Init_swap();
@@ -129,19 +117,21 @@ extern "C" void Init_utilrb_ext()
129
117
  {
130
118
  mUtilrb = rb_define_module("Utilrb");
131
119
 
120
+ #ifndef RUBINIUS
132
121
  rb_define_method(rb_mEnumerable, "each_uniq", RUBY_METHOD_FUNC(enumerable_each_uniq), 0);
133
122
  rb_define_method(rb_mKernel, "is_singleton?", RUBY_METHOD_FUNC(kernel_is_singleton_p), 0);
134
123
  #ifndef RUBY_IS_19
135
124
  rb_define_method(rb_cProc, "same_body?", RUBY_METHOD_FUNC(proc_same_body_p), 1);
136
125
  rb_define_method(rb_cProc, "file", RUBY_METHOD_FUNC(proc_file), 0);
137
126
  rb_define_method(rb_cProc, "line", RUBY_METHOD_FUNC(proc_line), 0);
138
- rb_define_method(rb_cIO, "clearerr", RUBY_METHOD_FUNC(io_clearerr), 0);
139
127
  #endif
140
128
 
141
129
  rb_define_singleton_method(rb_mKernel, "immediate?", RUBY_METHOD_FUNC(kernel_is_immediate), 1);
142
130
 
143
- Init_value_set();
144
131
  Init_swap();
145
132
  Init_weakref(mUtilrb);
133
+ #endif
134
+
135
+ Init_value_set();
146
136
  }
147
137
 
data/ext/value_set.cc CHANGED
@@ -106,7 +106,7 @@ static VALUE value_set_to_value_set(VALUE self) { return self; }
106
106
  static VALUE value_set_dup(VALUE vself, VALUE vother)
107
107
  {
108
108
  ValueSet const& self = get_wrapped_set(vself);
109
- VALUE vresult = rb_funcall(cValueSet, id_new, 0);
109
+ VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
110
110
  ValueSet& result = get_wrapped_set(vresult);
111
111
  for (ValueSet::const_iterator it = self.begin(); it != self.end(); ++it)
112
112
  result.insert(result.end(), *it);
@@ -142,7 +142,7 @@ static VALUE value_set_union(VALUE vself, VALUE vother)
142
142
  rb_raise(rb_eArgError, "expected a ValueSet");
143
143
  ValueSet const& other = get_wrapped_set(vother);
144
144
 
145
- VALUE vresult = rb_funcall(cValueSet, id_new, 0);
145
+ VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
146
146
  ValueSet& result = get_wrapped_set(vresult);
147
147
  std::set_union(self.begin(), self.end(), other.begin(), other.end(),
148
148
  std::inserter(result, result.end()));
@@ -179,7 +179,7 @@ static VALUE value_set_intersection(VALUE vself, VALUE vother)
179
179
  rb_raise(rb_eArgError, "expected a ValueSet");
180
180
  ValueSet const& other = get_wrapped_set(vother);
181
181
 
182
- VALUE vresult = rb_funcall(cValueSet, id_new, 0);
182
+ VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
183
183
  ValueSet& result = get_wrapped_set(vresult);
184
184
  std::set_intersection(self.begin(), self.end(), other.begin(), other.end(),
185
185
  std::inserter(result, result.end()));
@@ -230,7 +230,7 @@ static VALUE value_set_difference(VALUE vself, VALUE vother)
230
230
  rb_raise(rb_eArgError, "expected a ValueSet");
231
231
  ValueSet const& other = get_wrapped_set(vother);
232
232
 
233
- VALUE vresult = rb_funcall(cValueSet, id_new, 0);
233
+ VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
234
234
  ValueSet& result = get_wrapped_set(vresult);
235
235
  std::set_difference(self.begin(), self.end(), other.begin(), other.end(),
236
236
  std::inserter(result, result.end()));
@@ -307,13 +307,6 @@ static VALUE value_set_initialize_copy(VALUE vself, VALUE vother)
307
307
 
308
308
 
309
309
 
310
- static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
311
- {
312
- ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
313
- result.insert(i);
314
- return Qnil;
315
- }
316
-
317
310
  /* call-seq:
318
311
  * to_value_set => value_set
319
312
  *
@@ -321,17 +314,24 @@ static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
321
314
  */
322
315
  static VALUE array_to_value_set(VALUE self)
323
316
  {
324
- VALUE vresult = rb_funcall(cValueSet, id_new, 0);
317
+ VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
325
318
  ValueSet& result = get_wrapped_set(vresult);
326
319
 
327
- VALUE* ptr = RARRAY(self)->ptr;
328
- long size = RARRAY(self)->len;
320
+ long size = RARRAY_LEN(self);
329
321
  for (int i = 0; i < size; ++i)
330
- result.insert(ptr[i]);
322
+ result.insert(rb_ary_entry(self, i));
331
323
 
332
324
  return vresult;
333
325
  }
334
326
 
327
+ #ifndef RUBINIUS
328
+ static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
329
+ {
330
+ ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
331
+ result.insert(i);
332
+ return Qnil;
333
+ }
334
+
335
335
  /* call-seq:
336
336
  * enum.to_value_set => value_set
337
337
  *
@@ -339,12 +339,13 @@ static VALUE array_to_value_set(VALUE self)
339
339
  */
340
340
  static VALUE enumerable_to_value_set(VALUE self)
341
341
  {
342
- VALUE vresult = rb_funcall(cValueSet, id_new, 0);
342
+ VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
343
343
  ValueSet& result = get_wrapped_set(vresult);
344
344
 
345
345
  rb_iterate(rb_each, self, RUBY_METHOD_FUNC(enumerable_to_value_set_i), reinterpret_cast<VALUE>(&result));
346
346
  return vresult;
347
347
  }
348
+ #endif
348
349
 
349
350
  /*
350
351
  * Document-class: ValueSet
@@ -357,7 +358,9 @@ static VALUE enumerable_to_value_set(VALUE self)
357
358
 
358
359
  extern "C" void Init_value_set()
359
360
  {
361
+ #ifndef RUBINIUS
360
362
  rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);
363
+ #endif
361
364
  rb_define_method(rb_cArray, "to_value_set", RUBY_METHOD_FUNC(array_to_value_set), 0);
362
365
 
363
366
  cValueSet = rb_define_class("ValueSet", rb_cObject);
data/ext/weakref.cc CHANGED
@@ -1,7 +1,11 @@
1
1
  #include <set>
2
2
  #include <map>
3
3
  #include <ruby.h>
4
+ #ifdef RUBY_IS_19
5
+ #include <ruby/intern.h>
6
+ #else
4
7
  #include <intern.h>
8
+ #endif
5
9
 
6
10
  using std::set;
7
11
  using std::map;
@@ -12,6 +16,7 @@ static VALUE cRefError;
12
16
  /* Weakref internal structure. +obj+ is Qnil before initialization and Qundef
13
17
  * after finalization */
14
18
  struct WeakRef {
19
+ VALUE ruby_ref;
15
20
  VALUE obj;
16
21
  };
17
22
 
@@ -22,12 +27,25 @@ typedef map< VALUE, VALUE > ObjFromRefID;
22
27
  RefFromObjID from_obj_id;
23
28
  ObjFromRefID from_ref_id;
24
29
 
25
- static void weakref_free(WeakRef const* set) { delete set; }
30
+ static void weakref_free(WeakRef const* ref)
31
+ {
32
+ VALUE ref_id = rb_obj_id(ref->ruby_ref);
33
+ ObjFromRefID::iterator obj_it = from_ref_id.find(ref_id);
34
+ if (obj_it != from_ref_id.end())
35
+ {
36
+ VALUE obj_id = rb_obj_id(obj_it->second);
37
+ RefFromObjID::iterator ref_set = from_obj_id.find(obj_id);
38
+ ref_set->second.erase(ref->ruby_ref);
39
+ from_ref_id.erase(obj_it);
40
+ }
41
+ delete ref;
42
+ }
26
43
  static VALUE weakref_alloc(VALUE klass)
27
44
  {
28
45
  WeakRef* ref = new WeakRef;
29
46
  ref->obj = Qnil;
30
- return Data_Wrap_Struct(klass, NULL, weakref_free, ref);
47
+ ref->ruby_ref = Data_Wrap_Struct(klass, NULL, weakref_free, ref);
48
+ return ref->ruby_ref;
31
49
  }
32
50
 
33
51
  static WeakRef& get_weakref(VALUE self)
@@ -46,40 +64,24 @@ static VALUE do_object_finalize(VALUE mod, VALUE obj_id)
46
64
  ObjSet::iterator const end = ref_set->second.end();
47
65
  for (; it != end; ++it)
48
66
  {
49
- /* During GC, objects are garbage collected and *then* the finalizers are called. It means that, even though *it is referenced in from_obj_id, it may be invalid.
50
- *
51
- * When an object is marked for deferred finalization, its flags
52
- * are reset to a special value (flags = FL_MARK). FL_FINALIZE
53
- * should therefore not be set on it anymore.
54
- */
55
- if (FL_TEST(*it, FL_FINALIZE))
56
- {
57
- WeakRef& ref = get_weakref(*it);
58
- ref.obj = Qundef;
59
- }
67
+ // Do NOT use Data_Wrap_Struct here, it would break on recent Ruby
68
+ // interpreters. The reason is that the object type is reset during
69
+ // GC -- and the call to free functions is deferred.
70
+ //
71
+ // So, at this point, we're sure we have a RDATA in *it (otherwise
72
+ // weakref_free would have been called), but we can't use
73
+ // Data_Wrap_Struct because that would crash.
74
+ WeakRef& ref = *reinterpret_cast<WeakRef*>(RDATA(*it)->data);;
75
+ ref.obj = Qundef;
60
76
  from_ref_id.erase(rb_obj_id(*it));
61
77
  }
62
-
63
78
  from_obj_id.erase(obj_id);
64
79
  }
65
80
  return Qnil;
66
81
  }
67
82
 
68
- static VALUE do_weakref_finalize(VALUE mod, VALUE ref_id)
69
- {
70
- ObjFromRefID::iterator obj_it = from_ref_id.find(ref_id);
71
- if (obj_it != from_ref_id.end())
72
- {
73
- VALUE obj_id = rb_obj_id(obj_it->second);
74
- RefFromObjID::iterator ref_set = from_obj_id.find(obj_id);
75
- ref_set->second.erase(ref_id & ~FIXNUM_FLAG);
76
- from_ref_id.erase(obj_it);
77
- }
78
- return Qnil;
79
- }
80
-
81
83
  // Note: the Ruby code has already registered +do_object_finalize+ as the
82
- // finalizer for +obj+, and +do_weakref_finalize+ for +self+.
84
+ // finalizer for +obj+.
83
85
  //
84
86
  // It is forbidden to make a weakref-of-weakref or a weakref of an immediate
85
87
  // object
@@ -134,7 +136,6 @@ extern "C" void Init_weakref(VALUE mUtilrb)
134
136
  rb_define_alloc_func(cWeakRef, weakref_alloc);
135
137
 
136
138
  rb_define_singleton_method(cWeakRef, "do_object_finalize", RUBY_METHOD_FUNC(do_object_finalize), 1);
137
- rb_define_singleton_method(cWeakRef, "do_weakref_finalize", RUBY_METHOD_FUNC(do_weakref_finalize), 1);
138
139
  rb_define_singleton_method(cWeakRef, "refcount", RUBY_METHOD_FUNC(refcount), 1);
139
140
  rb_define_method(cWeakRef, "do_initialize", RUBY_METHOD_FUNC(weakref_do_initialize), 1);
140
141
  rb_define_method(cWeakRef, "get", RUBY_METHOD_FUNC(weakref_get), 0);
@@ -1,16 +1,53 @@
1
1
  # Displays a set of data into a column-formatted table
2
2
  class ColumnFormatter
3
- MARGIN = 3
4
- SCREEN_WIDTH = 90
3
+ MARGIN = 1
4
+ SCREEN_WIDTH = 80
5
5
 
6
- # data is an array of hashes. Each line of the array is a line to display,
7
- # a hash being a column_name => value data set. The special 'label' column
8
- # name is used to give a name to each line.
6
+ # Formats the given array of hash column-wise.
9
7
  #
10
- # If a block is given, the method yields the column names and the block must
11
- # return the array of columns to be displayed, sorted into the order of
12
- # the columns.
13
- def self.from_hashes(data, io = STDOUT, margin = MARGIN, screen_width = SCREEN_WIDTH)
8
+ # +data+ is an array of hash. In this array, each element is a sample. The
9
+ # column names are defined from the hash keys. If one hash does not have a
10
+ # value for a column, "-" is displayed instead.
11
+ #
12
+ # In the output, the columns are ordered alphabetically by default.
13
+ # Alternatively, they can be ordered by giving an :order option which is an
14
+ # array of string:
15
+ #
16
+ # from_hashes(data, STDOUT, :order => %w{Col0 Col1 Col2})
17
+ #
18
+ # Finally, the method can yield the set of available columns to a block (if
19
+ # given), and this block should return an ordered array of string.
20
+ #
21
+ # In both cases, columns not listed in the ordering array are not displayed.
22
+ #
23
+ # The formatting can be controlled by the following options:
24
+ # header_delimiter::
25
+ # if true, displays a line of dashes between the header
26
+ # and the rest of the table
27
+ # column_delimiter::
28
+ # a string that is inserted between columns
29
+ # left_padding::
30
+ # a string that is inserted in front of each line
31
+ # order::
32
+ # an array of column names, defining which columns should be displayed,
33
+ # and in which order they should be displayed. See above for more
34
+ # explanations.
35
+ # screen_width::
36
+ # if the table is wider than this count of characters, it is split into
37
+ # multiple tables.
38
+ # margin::
39
+ # defines how many spaces are inserted between two columns.
40
+ def self.from_hashes(data, io = STDOUT, options = Hash.new)
41
+ options = validate_options options, :margin => MARGIN,
42
+ :screen_width => SCREEN_WIDTH,
43
+ :header_delimiter => false,
44
+ :column_delimiter => "",
45
+ :left_padding => "",
46
+ :order => nil
47
+
48
+ margin = options[:margin]
49
+ screen_width = options[:screen_width]
50
+
14
51
  width = Hash.new
15
52
 
16
53
  # First, determine the columns width and height, and
@@ -35,7 +72,8 @@ class ColumnFormatter
35
72
  # Then ask the user to sort the keys for us
36
73
  names = width.keys.dup
37
74
  names.delete('label')
38
- names = if block_given? then yield(names)
75
+ names = if options[:order] then options[:order]
76
+ elsif block_given? then yield(names)
39
77
  else names.sort
40
78
  end
41
79
 
@@ -45,7 +83,7 @@ class ColumnFormatter
45
83
  if width.has_key?('label')
46
84
  line_n = ['label']
47
85
  line_w = width['label']
48
- format = ["% #{line_w}s"]
86
+ format = ["%-#{line_w}s"]
49
87
  else
50
88
  line_n = []
51
89
  line_w = 0
@@ -57,11 +95,18 @@ class ColumnFormatter
57
95
  col_w = width[col_n] || 0
58
96
  line_n << col_n
59
97
  line_w += col_w
60
- format << "% #{col_w}s"
98
+ format << "%-#{col_w}s"
61
99
  end
62
100
 
63
- format = format.join(" " * margin)
64
- io.puts format % line_n
101
+ format = format.join(" " * margin + options[:column_delimiter] + " " * margin)
102
+ header_line = format % line_n
103
+ io.puts options[:left_padding] + header_line
104
+ if options[:header_delimiter]
105
+ io.puts options[:left_padding] + "-" * header_line.length
106
+ end
107
+
108
+ format = options[:left_padding] + format
109
+
65
110
  data.each do |line_data|
66
111
  line_data = line_data.values_at(*line_n)
67
112
  line_data.map! { |v| v || '-' }
data/lib/utilrb/common.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Utilrb
2
2
  unless defined? Utilrb::VERSION
3
- VERSION = "1.3.2"
3
+ VERSION = "1.3.3"
4
4
  RUBY_IS_19 = (RUBY_VERSION >= "1.9")
5
5
  end
6
6
 
@@ -20,11 +20,17 @@ class SequenceEnumerator
20
20
  include Enumerable
21
21
  end
22
22
 
23
- class Enumerable::Enumerator # :nodoc
23
+ enumerator = if defined?(Enumerable::Enumerator)
24
+ Enumerable::Enumerator
25
+ else
26
+ Enumerator
27
+ end
28
+
29
+ enumerator.class_eval do # :nodoc
24
30
  # Builds a sequence of enumeration object.
25
31
  # ([1, 2].enum_for + [2, 3].enum_for).to_a # => [1, 2, 2, 3]
26
32
  def +(other_enumerator) # :nodoc
27
- SequenceEnumerator.new << self << other_enumerator
33
+ SequenceEnumerator.new << self << other_enumerator
28
34
  end
29
35
  end
30
36
 
@@ -2,9 +2,15 @@ require 'utilrb/common'
2
2
  require 'enumerator'
3
3
  require 'set'
4
4
 
5
+ enumerator = if defined?(Enumerable::Enumerator)
6
+ Enumerable::Enumerator
7
+ else
8
+ Enumerator
9
+ end
10
+
5
11
  # Enumerator object which removes duplicate entries.
6
12
  # See also Object#enum_uniq and Enumerable#each_uniq
7
- class UniqEnumerator < Enumerable::Enumerator
13
+ class UniqEnumerator < enumerator
8
14
  # Creates the enumerator on +obj+ using the method +enum_with+ to
9
15
  # enumerate. The method will be called with the arguments in +args+.
10
16
  #
@@ -1,10 +1,44 @@
1
+ require 'shellwords'
2
+
1
3
  module Utilrb
2
4
  # Access to information from pkg-config(1)
5
+ #
6
+ # This class allows to enumerate the pkg-config packages available, and
7
+ # create a PkgConfig object that allows to get access to the pkgconfig
8
+ # information.
9
+ #
10
+ # Create a new pkgconfig object with
11
+ #
12
+ # pkg = PkgConfig.new(name)
13
+ #
14
+ # It raises PkgConfig::NotFound if the package is not available.
15
+ #
16
+ # Then, the classical include directory and library directory flags can be
17
+ # listed with
18
+ #
19
+ # pkg.include_dirs
20
+ # pkg.library_dirs
21
+ #
22
+ # Standard fields are available with
23
+ #
24
+ # pkg.cflags
25
+ # pkg.cflags_only_I
26
+ # pkg.cflags_only_other
27
+ # pkg.libs
28
+ # pkg.libs_only_L
29
+ # pkg.libs_only_l
30
+ # pkg.libs_only_other
31
+ # pkg.static
32
+ #
33
+ # Arbitrary variables defined in the .pc file can be accessed with
34
+ #
35
+ # pkg.prefix
36
+ # pkg.libdir
37
+ #
3
38
  class PkgConfig
4
39
  class NotFound < RuntimeError
5
40
  attr_reader :name
6
41
  def initialize(name); @name = name end
7
- def to_s; "#{name} is not available to pkg-config" end
8
42
  end
9
43
 
10
44
  # The module name
@@ -16,7 +50,7 @@ module Utilrb
16
50
  # Raises PkgConfig::NotFound if the module does not exist
17
51
  def initialize(name)
18
52
  if !system("pkg-config --exists #{name}")
19
- raise NotFound.new(name)
53
+ raise NotFound.new(name), "#{name} is not available to pkg-config"
20
54
  end
21
55
 
22
56
  @name = name
@@ -25,24 +59,58 @@ module Utilrb
25
59
  @variables = Hash.new
26
60
  end
27
61
 
28
- def self.define_action(action)
62
+ def self.define_action(action) # :nodoc:
29
63
  define_method(action.gsub(/-/, '_')) do
30
64
  @actions[action] ||= `pkg-config --#{action} #{name}`.chomp.strip
31
65
  end
32
66
  nil
33
67
  end
34
68
 
69
+ # Returns the list of include directories listed in the Cflags: section
70
+ # of the pkgconfig file
71
+ def include_dirs
72
+ Shellwords.shellsplit(cflags_only_I).map { |v| v[2..-1] }
73
+ end
74
+
75
+ # Returns the list of library directories listed in the Libs: section
76
+ # of the pkgconfig file
77
+ def library_dirs
78
+ Shellwords.shellsplit(libs_only_L).map { |v| v[2..-1] }
79
+ end
80
+
35
81
  ACTIONS = %w{cflags cflags-only-I cflags-only-other
36
82
  libs libs-only-L libs-only-l libs-only-other static}
37
83
  ACTIONS.each { |action| define_action(action) }
38
84
 
39
- def method_missing(varname, *args, &proc)
85
+ def method_missing(varname, *args, &proc) # :nodoc:
40
86
  if args.empty?
41
87
  @variables[varname] ||= `pkg-config --variable=#{varname} #{name}`.chomp.strip
42
88
  else
43
89
  super(varname, *args, &proc)
44
90
  end
45
91
  end
92
+
93
+ # Returns true if there is a package with this name
94
+ def self.has_package?(name)
95
+ enum_for(:each_package, name).find { true }
96
+ end
97
+
98
+ # Yields the package names of available packages. If +regex+ is given,
99
+ # lists only the names that match the regular expression.
100
+ def self.each_package(regex = nil)
101
+ `pkg-config --list-all`.chomp.split.
102
+ each do |line|
103
+ line =~ /^([^\s]+)/
104
+ name = $1
105
+ if regex
106
+ if regex === name
107
+ yield(name)
108
+ end
109
+ else
110
+ yield(name)
111
+ end
112
+ end
113
+ end
46
114
  end
47
115
  end
48
116
 
@@ -7,9 +7,9 @@ Utilrb.require_ext("Utilrb::WeakRef") do
7
7
  if obj.kind_of?(WeakRef)
8
8
  raise ArgumentError, "cannot create a weakref of a weakref"
9
9
  end
10
-
11
- ObjectSpace.define_finalizer(obj, self.class.method(:do_object_finalize))
12
- ObjectSpace.define_finalizer(self, self.class.method(:do_weakref_finalize))
10
+ unless WeakRef.refcount(obj)
11
+ ObjectSpace.define_finalizer(obj, self.class.method(:do_object_finalize))
12
+ end
13
13
  do_initialize(obj)
14
14
  end
15
15
  end
@@ -26,9 +26,23 @@ class TC_PkgConfig < Test::Unit::TestCase
26
26
  assert_equal(%w{-Ia_prefix/include -O3}.to_set, pkg.cflags.split.to_set)
27
27
  assert_equal('-Ia_prefix/include', pkg.cflags_only_I)
28
28
  assert_equal('-O3', pkg.cflags_only_other)
29
+ assert_equal(['a_prefix/include'], pkg.include_dirs)
29
30
 
30
31
  assert_equal(%w{-ltest -lother -La_prefix/lib}.to_set, pkg.libs.split.to_set)
31
32
  assert_equal('-La_prefix/lib', pkg.libs_only_L)
32
33
  assert_equal(%w{-ltest -lother}.to_set, pkg.libs_only_l.split.to_set)
34
+ assert_equal(['a_prefix/lib'], pkg.library_dirs)
35
+
36
+ pkg = PkgConfig.new('test_pkgconfig_empty')
37
+ assert_equal('a_prefix', pkg.prefix)
38
+ assert_equal("", pkg.cflags)
39
+ assert_equal('', pkg.cflags_only_I)
40
+ assert_equal('', pkg.cflags_only_other)
41
+ assert_equal([], pkg.include_dirs)
42
+
43
+ assert_equal('', pkg.libs)
44
+ assert_equal('', pkg.libs_only_L)
45
+ assert_equal('', pkg.libs_only_l)
46
+ assert_equal([], pkg.library_dirs)
33
47
  end
34
48
  end
data/test/test_weakref.rb CHANGED
@@ -19,6 +19,18 @@ Utilrb.require_ext('TC_WeakRef') do
19
19
  assert_raises(ArgumentError) { Utilrb::WeakRef.new(ref) }
20
20
  end
21
21
 
22
+ def create_deep_pair(lvl)
23
+ if lvl == 0
24
+ 100.times do
25
+ obj = Object.new
26
+ WeakRef.new(obj)
27
+ obj = nil
28
+ end
29
+ else
30
+ create_deep_pair(lvl - 1)
31
+ end
32
+ end
33
+
22
34
  def create_deep_ref(lvl)
23
35
  if lvl == 0
24
36
  obj = Object.new
@@ -38,17 +50,31 @@ Utilrb.require_ext('TC_WeakRef') do
38
50
  end
39
51
  end
40
52
 
41
- def test_finalization
53
+ def test_finalized_objects
42
54
  refs, obj_id = create_deep_ref(100)
55
+ create_deep_ref(200) # erase the stack ...
43
56
  GC.start
44
57
  for ref in refs
45
58
  assert_raises(WeakRef::RefError) { ref.get }
46
59
  end
47
60
  assert_equal(nil, WeakRef.refcount(obj_id))
61
+ end
48
62
 
63
+ def test_finalized_refs
49
64
  obj, ref_id = create_deep_obj(100)
65
+ create_deep_ref(100) # erase the stack ...
66
+ GC.start
67
+ assert_raises(RangeError) do
68
+ ref = ObjectSpace._id2ref(ref_id)
69
+ if !ref.kind_of?(WeakRef)
70
+ raise RangeError
71
+ end
72
+ end
73
+ end
74
+
75
+ def test_finalization_ordering_crash
76
+ create_deep_pair(100)
50
77
  GC.start
51
- assert_raises(RangeError) { ObjectSpace._id2ref(ref_id) }
52
78
  end
53
79
  end
54
80
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: utilrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Joyeux
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-07-17 00:00:00 +02:00
12
+ date: 2009-06-22 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -34,15 +34,29 @@ dependencies:
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: hoe
37
- type: :runtime
37
+ type: :development
38
38
  version_requirement:
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 1.6.0
43
+ version: 1.12.2
44
44
  version:
45
- description: == What is Utilrb ? Utilrb is yet another Ruby toolkit, in the spirit of facets. It includes all the standard class extensions I use in my own projects like Genom.rb. == Installation The only dependency Utilrb has is flexmock if you want to run tests. It is available as a gem, so you can run gem install flexmock == Utilrb's C extension Utilrb includes a C extension in ext/. It is optional, but some of the functionalities will be disabled if it is not present. Trying to require a file in which there is a C-only feature will yield a warning on STDOUT.
45
+ description: |-
46
+ == What is Utilrb ?
47
+ Utilrb is yet another Ruby toolkit, in the spirit of facets. It includes all
48
+ the standard class extensions I use in my own projects like Genom.rb.
49
+
50
+ == Installation
51
+ The only dependency Utilrb has is flexmock if you want to run tests. It is
52
+ available as a gem, so you can run
53
+
54
+ gem install flexmock
55
+
56
+ == Utilrb's C extension
57
+ Utilrb includes a C extension in ext/. It is optional, but some of the
58
+ functionalities will be disabled if it is not present. Trying to require
59
+ a file in which there is a C-only feature will yield a warning on STDOUT.
46
60
  email:
47
61
  - sylvain.joyeux@m4x.org
48
62
  executables: []
@@ -145,7 +159,9 @@ files:
145
159
  - test/test_unbound_method.rb
146
160
  - test/test_weakref.rb
147
161
  has_rdoc: true
148
- homepage: " http://utilrb.rubyforge.org"
162
+ homepage: http://utilrb.rubyforge.org
163
+ licenses: []
164
+
149
165
  post_install_message:
150
166
  rdoc_options:
151
167
  - --main
@@ -168,9 +184,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
184
  requirements: []
169
185
 
170
186
  rubyforge_project: utilrb
171
- rubygems_version: 1.2.0
187
+ rubygems_version: 1.3.4
172
188
  signing_key:
173
- specification_version: 2
189
+ specification_version: 3
174
190
  summary: Yet another Ruby toolkit
175
191
  test_files:
176
192
  - test/test_time.rb