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 +13 -3
- data/Rakefile +3 -3
- data/ext/extconf.rb +1 -1
- data/ext/ruby_internals-1.9.h +28 -5
- data/ext/utilrb_ext.cc +8 -18
- data/ext/value_set.cc +19 -16
- data/ext/weakref.cc +30 -29
- data/lib/utilrb/column_formatter.rb +59 -14
- data/lib/utilrb/common.rb +1 -1
- data/lib/utilrb/enumerable/sequence.rb +8 -2
- data/lib/utilrb/enumerable/uniq.rb +7 -1
- data/lib/utilrb/pkgconfig.rb +72 -4
- data/lib/utilrb/weakref.rb +3 -3
- data/test/test_pkgconfig.rb +14 -0
- data/test/test_weakref.rb +28 -2
- metadata +24 -8
data/History.txt
CHANGED
@@ -1,12 +1,22 @@
|
|
1
|
-
=== Version 1.3.
|
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
|
-
|
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("
|
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
data/ext/ruby_internals-1.9.h
CHANGED
@@ -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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
317
|
+
VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
|
325
318
|
ValueSet& result = get_wrapped_set(vresult);
|
326
319
|
|
327
|
-
|
328
|
-
long size = RARRAY(self)->len;
|
320
|
+
long size = RARRAY_LEN(self);
|
329
321
|
for (int i = 0; i < size; ++i)
|
330
|
-
result.insert(
|
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 =
|
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*
|
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
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
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 =
|
4
|
-
SCREEN_WIDTH =
|
3
|
+
MARGIN = 1
|
4
|
+
SCREEN_WIDTH = 80
|
5
5
|
|
6
|
-
#
|
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
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
|
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
|
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 = ["
|
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 << "
|
98
|
+
format << "%-#{col_w}s"
|
61
99
|
end
|
62
100
|
|
63
|
-
format = format.join(" " * margin)
|
64
|
-
|
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
@@ -20,11 +20,17 @@ class SequenceEnumerator
|
|
20
20
|
include Enumerable
|
21
21
|
end
|
22
22
|
|
23
|
-
|
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
|
-
|
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 <
|
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
|
#
|
data/lib/utilrb/pkgconfig.rb
CHANGED
@@ -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
|
|
data/lib/utilrb/weakref.rb
CHANGED
@@ -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
|
-
|
12
|
-
|
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
|
data/test/test_pkgconfig.rb
CHANGED
@@ -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
|
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.
|
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:
|
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: :
|
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.
|
43
|
+
version: 1.12.2
|
44
44
|
version:
|
45
|
-
description:
|
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:
|
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.
|
187
|
+
rubygems_version: 1.3.4
|
172
188
|
signing_key:
|
173
|
-
specification_version:
|
189
|
+
specification_version: 3
|
174
190
|
summary: Yet another Ruby toolkit
|
175
191
|
test_files:
|
176
192
|
- test/test_time.rb
|