utilrb 1.3.2 → 1.3.3

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