utilrb 1.3.3 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +17 -0
- data/Manifest.txt +11 -0
- data/README.txt +9 -5
- data/Rakefile +30 -50
- data/ext/extconf.rb +14 -1
- data/ext/value_set.cc +43 -1
- data/lib/utilrb/array/to_s.rb +1 -0
- data/lib/utilrb/common.rb +3 -2
- data/lib/utilrb/configsearch/configuration_finder.rb +78 -0
- data/lib/utilrb/configsearch.rb +2 -0
- data/lib/utilrb/hash/recursive_merge.rb +26 -0
- data/lib/utilrb/hash/to_s.rb +1 -0
- data/lib/utilrb/kernel/load_dsl_file.rb +187 -0
- data/lib/utilrb/kernel/options.rb +10 -1
- data/lib/utilrb/kernel/with_module.rb +53 -0
- data/lib/utilrb/logger/hierarchy.rb +21 -5
- data/lib/utilrb/logger/io.rb +25 -0
- data/lib/utilrb/marshal/load_with_missing_constants.rb +63 -0
- data/lib/utilrb/module/ancestor_p.rb +12 -18
- data/lib/utilrb/module/cached_enum.rb +15 -0
- data/lib/utilrb/module/const_defined_here_p.rb +11 -0
- data/lib/utilrb/module/define_or_reuse.rb +15 -22
- data/lib/utilrb/module/include.rb +12 -0
- data/lib/utilrb/module/inherited_enumerable.rb +15 -0
- data/lib/utilrb/object/scoped_eval.rb +17 -0
- data/lib/utilrb/object/singleton_class.rb +3 -44
- data/lib/utilrb/pkgconfig.rb +311 -27
- data/lib/utilrb/symbol/to_str.rb +5 -0
- data/lib/utilrb/value_set.rb +12 -0
- data/test/data/test_pkgconfig_empty.pc +10 -0
- data/test/test_kernel.rb +158 -0
- data/test/test_module.rb +11 -10
- data/test/test_object.rb +0 -28
- data/test/test_pkgconfig.rb +35 -1
- metadata +88 -44
data/History.txt
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
=== Version 1.4.0
|
2
|
+
|
3
|
+
* release the latest git version. utilrb has not seen any release for a very
|
4
|
+
long time, and did not move so much anyway. The reason for this release is
|
5
|
+
mainly to fix rubygem installation between older rubygem version and newest
|
6
|
+
ruby version
|
7
|
+
|
8
|
+
=== Version 1.3.4
|
9
|
+
|
10
|
+
* fixes a minor problem with PkgConfig handling on broken installations.
|
11
|
+
pkg-config is picky about all dependencies being installed on the system.
|
12
|
+
The issue is that pkg-config --list-all will stop in the middle of the
|
13
|
+
enumeration if one of the packages misses some dependencies.
|
14
|
+
PkgConfig.has_package? was using --list-all through PkgConfig.each_package,
|
15
|
+
and therefore was wrongly returning false sometimes.
|
16
|
+
Moved it to pkg-config --exists, which works.
|
17
|
+
|
1
18
|
=== Version 1.3.3
|
2
19
|
|
3
20
|
* fixed a problem with WeakRef crashing on 1.8.7p172. This version of weakref
|
data/Manifest.txt
CHANGED
@@ -17,6 +17,8 @@ lib/utilrb/array.rb
|
|
17
17
|
lib/utilrb/array/to_s.rb
|
18
18
|
lib/utilrb/column_formatter.rb
|
19
19
|
lib/utilrb/common.rb
|
20
|
+
lib/utilrb/configsearch.rb
|
21
|
+
lib/utilrb/configsearch/configuration_finder.rb
|
20
22
|
lib/utilrb/dir.rb
|
21
23
|
lib/utilrb/dir/empty.rb
|
22
24
|
lib/utilrb/enumerable.rb
|
@@ -30,23 +32,29 @@ lib/utilrb/exception/full_message.rb
|
|
30
32
|
lib/utilrb/gc.rb
|
31
33
|
lib/utilrb/gc/force.rb
|
32
34
|
lib/utilrb/hash.rb
|
35
|
+
lib/utilrb/hash/recursive_merge.rb
|
33
36
|
lib/utilrb/hash/slice.rb
|
34
37
|
lib/utilrb/hash/to_s.rb
|
35
38
|
lib/utilrb/hash/to_sym_keys.rb
|
36
39
|
lib/utilrb/kernel.rb
|
37
40
|
lib/utilrb/kernel/arity.rb
|
41
|
+
lib/utilrb/kernel/load_dsl_file.rb
|
38
42
|
lib/utilrb/kernel/options.rb
|
39
43
|
lib/utilrb/kernel/poll.rb
|
40
44
|
lib/utilrb/kernel/require.rb
|
41
45
|
lib/utilrb/kernel/swap.rb
|
46
|
+
lib/utilrb/kernel/with_module.rb
|
42
47
|
lib/utilrb/logger.rb
|
43
48
|
lib/utilrb/logger/forward.rb
|
44
49
|
lib/utilrb/logger/hierarchy.rb
|
50
|
+
lib/utilrb/logger/io.rb
|
51
|
+
lib/utilrb/marshal/load_with_missing_constants.rb
|
45
52
|
lib/utilrb/module.rb
|
46
53
|
lib/utilrb/module/ancestor_p.rb
|
47
54
|
lib/utilrb/module/attr_enumerable.rb
|
48
55
|
lib/utilrb/module/attr_predicate.rb
|
49
56
|
lib/utilrb/module/cached_enum.rb
|
57
|
+
lib/utilrb/module/const_defined_here_p.rb
|
50
58
|
lib/utilrb/module/define_method.rb
|
51
59
|
lib/utilrb/module/define_or_reuse.rb
|
52
60
|
lib/utilrb/module/include.rb
|
@@ -54,6 +62,7 @@ lib/utilrb/module/inherited_enumerable.rb
|
|
54
62
|
lib/utilrb/object.rb
|
55
63
|
lib/utilrb/object/address.rb
|
56
64
|
lib/utilrb/object/attribute.rb
|
65
|
+
lib/utilrb/object/scoped_eval.rb
|
57
66
|
lib/utilrb/object/singleton_class.rb
|
58
67
|
lib/utilrb/objectstats.rb
|
59
68
|
lib/utilrb/pkgconfig.rb
|
@@ -61,6 +70,7 @@ lib/utilrb/set.rb
|
|
61
70
|
lib/utilrb/set/to_s.rb
|
62
71
|
lib/utilrb/socket/tcp_server.rb
|
63
72
|
lib/utilrb/socket/tcp_socket.rb
|
73
|
+
lib/utilrb/symbol/to_str.rb
|
64
74
|
lib/utilrb/time.rb
|
65
75
|
lib/utilrb/time/to_hms.rb
|
66
76
|
lib/utilrb/unbound_method.rb
|
@@ -69,6 +79,7 @@ lib/utilrb/value_set.rb
|
|
69
79
|
lib/utilrb/weakref.rb
|
70
80
|
patches/gc_live_objects.patch
|
71
81
|
test/data/test_pkgconfig.pc
|
82
|
+
test/data/test_pkgconfig_empty.pc
|
72
83
|
test/test_array.rb
|
73
84
|
test/test_config.rb
|
74
85
|
test/test_dir.rb
|
data/README.txt
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
Utilrb
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
= Utilrb
|
2
|
+
http://utilrb.rubyforge.org
|
3
|
+
http://www.rubyforge.org/projects/utilrb
|
4
|
+
http://github.com/doudou/util-rb (git repository)
|
5
|
+
|
6
|
+
== License
|
5
7
|
|
6
8
|
Copyright (c) 2006-2008
|
7
9
|
Sylvain Joyeux <sylvain.joyeux@m4x.org>
|
@@ -10,10 +12,12 @@ Copyright (c) 2006-2008
|
|
10
12
|
This work is licensed under the BSD license. See License.txt for details
|
11
13
|
|
12
14
|
== What is Utilrb ?
|
15
|
+
|
13
16
|
Utilrb is yet another Ruby toolkit, in the spirit of facets. It includes all
|
14
|
-
the standard class extensions I use in
|
17
|
+
the standard class extensions I use in other projects.
|
15
18
|
|
16
19
|
== Installation
|
20
|
+
|
17
21
|
The only dependency Utilrb has is flexmock if you want to run tests. It is
|
18
22
|
available as a gem, so you can run
|
19
23
|
|
data/Rakefile
CHANGED
@@ -1,49 +1,53 @@
|
|
1
1
|
require 'rake'
|
2
|
-
require 'rake/rdoctask'
|
3
|
-
|
4
|
-
# FIX: Hoe always calls rdoc with -d, and diagram generation fails here
|
5
|
-
class Rake::RDocTask
|
6
|
-
alias __option_list__ option_list
|
7
|
-
def option_list
|
8
|
-
options = __option_list__
|
9
|
-
options.delete("-d")
|
10
|
-
options
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
2
|
require './lib/utilrb/common'
|
15
3
|
|
16
4
|
begin
|
17
5
|
require 'hoe'
|
18
|
-
config = Hoe.new('utilrb', Utilrb::VERSION) do |p|
|
19
|
-
p.developer("Sylvain Joyeux", "sylvain.joyeux@m4x.org")
|
20
6
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
7
|
+
hoe_spec = Hoe.spec 'utilrb' do
|
8
|
+
developer "Sylvain Joyeux", "sylvain.joyeux@m4x.org"
|
9
|
+
extra_deps <<
|
10
|
+
['facets', '>= 2.4.0'] <<
|
11
|
+
['rake', '>= 0']
|
12
|
+
|
13
|
+
extra_dev_deps <<
|
14
|
+
['flexmock', '>= 0.8.6']
|
25
15
|
|
26
|
-
|
16
|
+
self.summary = 'Yet another Ruby toolkit'
|
17
|
+
self.description = paragraphs_of('README.txt', 3..5).join("\n\n")
|
27
18
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
19
|
+
hoe_spec.spec.extensions << 'ext/extconf.rb'
|
20
|
+
Rake.clear_tasks(/^default$/)
|
21
|
+
Rake.clear_tasks(/publish_docs/)
|
22
|
+
|
31
23
|
rescue Exception => e
|
32
|
-
|
33
|
-
|
24
|
+
if e.message !~ /\.rubyforge/
|
25
|
+
STDERR.puts "WARN: cannot load the Hoe gem, or Hoe fails. Publishing tasks are disabled"
|
26
|
+
STDERR.puts "WARN: error message is: #{e.message}"
|
27
|
+
end
|
34
28
|
end
|
35
29
|
|
36
|
-
|
30
|
+
task :default => :setup
|
31
|
+
|
37
32
|
desc "builds Utilrb's C extension"
|
38
33
|
task :setup do
|
39
34
|
Dir.chdir("ext") do
|
40
|
-
if !system("#{RUBY} extconf.rb") || !system("make")
|
35
|
+
if !system("#{FileUtils::RUBY} extconf.rb") || !system("make")
|
41
36
|
raise "cannot build the C extension"
|
42
37
|
end
|
43
38
|
end
|
44
39
|
FileUtils.ln_sf "../ext/utilrb_ext.so", "lib/utilrb_ext.so"
|
45
40
|
end
|
46
41
|
|
42
|
+
task 'publish_docs' => 'redocs' do
|
43
|
+
if !system('./update_github')
|
44
|
+
raise "cannot update the gh-pages branch for GitHub"
|
45
|
+
end
|
46
|
+
if !system('git', 'push', 'github', '+gh-pages')
|
47
|
+
raise "cannot push the documentation"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
47
51
|
task :clean do
|
48
52
|
puts "Cleaning extension in ext/"
|
49
53
|
FileUtils.rm_f "lib/utilrb_ext.so"
|
@@ -63,27 +67,3 @@ task :full_test do
|
|
63
67
|
system("testrb test/")
|
64
68
|
end
|
65
69
|
|
66
|
-
task :rcov_test do
|
67
|
-
Dir.chdir('test') do
|
68
|
-
if !File.directory?('../rcov')
|
69
|
-
File.mkdir('../rcov')
|
70
|
-
end
|
71
|
-
File.open("../rcov/index.html", "w") do |index|
|
72
|
-
index.puts <<-EOF
|
73
|
-
<!DOCTYPE html PUBLIC
|
74
|
-
"-//W3C//DTD XHTML 1.0 Transitional//EN"
|
75
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
76
|
-
<body>
|
77
|
-
EOF
|
78
|
-
|
79
|
-
Dir.glob('test_*.rb').each do |path|
|
80
|
-
puts "\n" * 4 + "=" * 5 + " #{path} " + "=" * 5 + "\n"
|
81
|
-
basename = File.basename(path, '.rb')
|
82
|
-
system("rcov --replace-progname -o ../rcov/#{basename} #{path}")
|
83
|
-
index.puts "<div class=\"test\"><a href=\"#{basename}/index.html\">#{basename}</a></div>"
|
84
|
-
end
|
85
|
-
index.puts "</body>"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
data/ext/extconf.rb
CHANGED
@@ -5,6 +5,19 @@ if RUBY_VERSION >= "1.9"
|
|
5
5
|
$CFLAGS += " -DRUBY_IS_19"
|
6
6
|
end
|
7
7
|
|
8
|
-
$LDFLAGS += "-module"
|
8
|
+
$LDFLAGS += " -module"
|
9
9
|
create_makefile("utilrb_ext")
|
10
10
|
|
11
|
+
## WORKAROUND a problem with mkmf.rb
|
12
|
+
# It seems that the newest version do define an 'install' target. However, that
|
13
|
+
# install target tries to install in the system directories
|
14
|
+
#
|
15
|
+
# The issue is that RubyGems *does* call make install. Ergo, gem install utilrb
|
16
|
+
# is broken right now
|
17
|
+
lines = File.readlines("Makefile")
|
18
|
+
lines.delete_if { |l| l =~ /^install:/ }
|
19
|
+
lines << "install:"
|
20
|
+
File.open("Makefile", 'w') do |io|
|
21
|
+
io.write lines.join("\n")
|
22
|
+
end
|
23
|
+
|
data/ext/value_set.cc
CHANGED
@@ -165,6 +165,26 @@ static VALUE value_set_merge(VALUE vself, VALUE vother)
|
|
165
165
|
return vself;
|
166
166
|
}
|
167
167
|
|
168
|
+
/* call-seq:
|
169
|
+
* set.intersection!(other) => set
|
170
|
+
*
|
171
|
+
* Computes the intersection of +set+ and +other+, and modifies +self+ to be
|
172
|
+
* that interesection. This operation is O(N + M) if +other+ is a ValueSet
|
173
|
+
*/
|
174
|
+
static VALUE value_set_intersection_bang(VALUE vself, VALUE vother)
|
175
|
+
{
|
176
|
+
ValueSet& self = get_wrapped_set(vself);
|
177
|
+
if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
|
178
|
+
rb_raise(rb_eArgError, "expected a ValueSet");
|
179
|
+
ValueSet const& other = get_wrapped_set(vother);
|
180
|
+
|
181
|
+
ValueSet result;
|
182
|
+
std::set_intersection(self.begin(), self.end(), other.begin(), other.end(),
|
183
|
+
std::inserter(result, result.end()));
|
184
|
+
self.swap(result);
|
185
|
+
return vself;
|
186
|
+
}
|
187
|
+
|
168
188
|
/* call-seq:
|
169
189
|
* set.intersection(other) => intersection_set
|
170
190
|
* set & other => intersection_set
|
@@ -216,12 +236,32 @@ static VALUE value_set_intersects(VALUE vself, VALUE vother)
|
|
216
236
|
return Qfalse;
|
217
237
|
}
|
218
238
|
|
239
|
+
/* call-seq:
|
240
|
+
* set.difference!(other) => set
|
241
|
+
*
|
242
|
+
* Modifies +set+ so that it is the set of all elements of +set+ not in +other+.
|
243
|
+
* This operation is O(N + M).
|
244
|
+
*/
|
245
|
+
static VALUE value_set_difference_bang(VALUE vself, VALUE vother)
|
246
|
+
{
|
247
|
+
ValueSet& self = get_wrapped_set(vself);
|
248
|
+
if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
|
249
|
+
rb_raise(rb_eArgError, "expected a ValueSet");
|
250
|
+
ValueSet const& other = get_wrapped_set(vother);
|
251
|
+
|
252
|
+
ValueSet result;
|
253
|
+
std::set_difference(self.begin(), self.end(), other.begin(), other.end(),
|
254
|
+
std::inserter(result, result.end()));
|
255
|
+
self.swap(result);
|
256
|
+
return vself;
|
257
|
+
}
|
258
|
+
|
219
259
|
/* call-seq:
|
220
260
|
* set.difference(other) => difference_set
|
221
261
|
* set - other => difference_set
|
222
262
|
*
|
223
263
|
* Computes the set of all elements of +set+ not in +other+. This operation
|
224
|
-
* is O(N + M)
|
264
|
+
* is O(N + M).
|
225
265
|
*/
|
226
266
|
static VALUE value_set_difference(VALUE vself, VALUE vother)
|
227
267
|
{
|
@@ -371,8 +411,10 @@ extern "C" void Init_value_set()
|
|
371
411
|
rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
|
372
412
|
rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
|
373
413
|
rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
|
414
|
+
rb_define_method(cValueSet, "intersection!", RUBY_METHOD_FUNC(value_set_intersection_bang), 1);
|
374
415
|
rb_define_method(cValueSet, "intersects?", RUBY_METHOD_FUNC(value_set_intersects), 1);
|
375
416
|
rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
|
417
|
+
rb_define_method(cValueSet, "difference!", RUBY_METHOD_FUNC(value_set_difference_bang), 1);
|
376
418
|
rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
|
377
419
|
rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
|
378
420
|
rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
|
data/lib/utilrb/array/to_s.rb
CHANGED
@@ -2,6 +2,7 @@ require 'utilrb/enumerable/to_s_helper'
|
|
2
2
|
class Array
|
3
3
|
# Displays arrays as [ a, b, [c, d], ... ] instead of the standard #join
|
4
4
|
# Unlike #inspect, it calls #to_s on the elements too
|
5
|
+
undef_method :to_s
|
5
6
|
def to_s
|
6
7
|
EnumerableToString.to_s_helper(self, '[', ']') do |obj|
|
7
8
|
obj.to_s
|
data/lib/utilrb/common.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
module Utilrb
|
2
2
|
unless defined? Utilrb::VERSION
|
3
|
-
VERSION = "1.
|
4
|
-
|
3
|
+
VERSION = "1.4.0"
|
4
|
+
RUBY_IS_19 = (RUBY_VERSION >= "1.9.2")
|
5
|
+
RUBY_IS_191 = (RUBY_VERSION >= "1.9") && (RUBY_VERSION < "1.9.2")
|
5
6
|
end
|
6
7
|
|
7
8
|
unless defined? UTILRB_EXT_MODE
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Utilrb
|
2
|
+
# Find configuration files within the pathes given
|
3
|
+
# by ROCK_CONFIG_PATH environment variable
|
4
|
+
#
|
5
|
+
class ConfigurationFinder
|
6
|
+
|
7
|
+
# Find a file by searching through paths defined by an environment variable
|
8
|
+
# and a given package directory. Package name is appended to all pathes found
|
9
|
+
# in the environment
|
10
|
+
#
|
11
|
+
# Returns the path to the file on success, otherwise nil
|
12
|
+
def self.findWithEnv(filename, pkg_name, environment_search_path)
|
13
|
+
if environment_search_path
|
14
|
+
env_var = ENV[environment_search_path]
|
15
|
+
# Extract search path from environment variable
|
16
|
+
configuration_path = Array.new
|
17
|
+
env_var.split(':').each do | path |
|
18
|
+
# Extract path and append package name folder
|
19
|
+
configuration_path << File.join(path.gsub(/:$/,''), pkg_name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
if configuration_path == nil
|
24
|
+
raise "ConfigurationFinder: Environment variable #{environment_search_path} is not set!\n"
|
25
|
+
else
|
26
|
+
configuration = search(filename, configuration_path)
|
27
|
+
end
|
28
|
+
|
29
|
+
configuration
|
30
|
+
end
|
31
|
+
|
32
|
+
# Search for a file within [ $ROCK_CONFIG_PATH ]/<packagename>/
|
33
|
+
# Will not perform a recursive search
|
34
|
+
#
|
35
|
+
# Returns the path to the file on success, otherwise nil
|
36
|
+
def self.find(filename, pkg_name)
|
37
|
+
findWithEnv(filename, pkg_name, 'ROCK_CONFIG_PATH')
|
38
|
+
end
|
39
|
+
|
40
|
+
# Search for a file only in the given search directories
|
41
|
+
#
|
42
|
+
# Returns the path to the file on success, otherwise nil
|
43
|
+
def self.search(filename, search_dirs)
|
44
|
+
search_dirs.each do |path|
|
45
|
+
file = File.join(path,filename)
|
46
|
+
if File.exist?(file)
|
47
|
+
return file
|
48
|
+
end
|
49
|
+
end
|
50
|
+
return
|
51
|
+
end
|
52
|
+
|
53
|
+
# Search for a file using the system id (<basename>_<id>)
|
54
|
+
#
|
55
|
+
# returns the configuration found in [ $ROCK_CONFIG_PATH ]/<basename>/<id>/, performs
|
56
|
+
# a fallback search in <basename> and returns nil if no config could
|
57
|
+
# be found
|
58
|
+
def self.findSystemConfig(filename, system_id)
|
59
|
+
id_components = system_id.split('_')
|
60
|
+
|
61
|
+
if(id_components.size != 2)
|
62
|
+
raise "ConfigurationFinder: Invalid system identifier #{system_id} provided. " +
|
63
|
+
"Use <basename>_<id>"
|
64
|
+
end
|
65
|
+
|
66
|
+
base_pkg_name = id_components[0]
|
67
|
+
id_pkg_name = File.join(base_pkg_name, id_components[1])
|
68
|
+
system_config = find(filename, id_pkg_name)
|
69
|
+
|
70
|
+
if !system_config
|
71
|
+
system_config = find(filename, base_pkg_name)
|
72
|
+
end
|
73
|
+
|
74
|
+
system_config
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Hash
|
2
|
+
def recursive_merge(hash, &block)
|
3
|
+
merge(hash) do |k, v1, v2|
|
4
|
+
if v1.kind_of?(Hash) && v2.kind_of?(Hash)
|
5
|
+
v1.recursive_merge(v2, &block)
|
6
|
+
elsif block_given?
|
7
|
+
yield(k, v1, v2)
|
8
|
+
else
|
9
|
+
v2
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def recursive_merge!(hash, &block)
|
15
|
+
merge!(hash) do |k, v1, v2|
|
16
|
+
if v1.kind_of?(Hash) && v2.kind_of?(Hash)
|
17
|
+
v1.recursive_merge!(v2, &block)
|
18
|
+
elsif block_given?
|
19
|
+
yield(k, v1, v2)
|
20
|
+
else
|
21
|
+
v2
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
data/lib/utilrb/hash/to_s.rb
CHANGED
@@ -2,6 +2,7 @@ require 'utilrb/enumerable/to_s_helper'
|
|
2
2
|
class Hash
|
3
3
|
# Displays hashes as { a => A, b => B, ... } instead of the standard #join
|
4
4
|
# Unlike #inspect, it calls #to_s on the elements too
|
5
|
+
undef_method :to_s
|
5
6
|
def to_s
|
6
7
|
EnumerableToString.to_s_helper(self, '{', '}') do |k, v|
|
7
8
|
"#{k} => #{v}"
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'utilrb/common'
|
2
|
+
require 'utilrb/object/singleton_class'
|
3
|
+
require 'utilrb/kernel/with_module'
|
4
|
+
|
5
|
+
module Kernel
|
6
|
+
def self.backtrace_remove_first_occurence_of(e, rx)
|
7
|
+
# Remove the first occurence of eval_dsl_file_content in the backtrace
|
8
|
+
backtrace = e.backtrace.dup
|
9
|
+
found = false
|
10
|
+
backtrace.delete_if do |line|
|
11
|
+
break if found
|
12
|
+
line =~ rx
|
13
|
+
found = true
|
14
|
+
end
|
15
|
+
raise e, e.message, e.backtrace
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_dsl_filter_backtrace(file, full_backtrace = false, *exceptions)
|
19
|
+
# Compute the position of the dsl-loading method that called us, so that
|
20
|
+
# we don't touch anything below that while we are filtering the
|
21
|
+
# backtrace
|
22
|
+
if !full_backtrace
|
23
|
+
callers = caller
|
24
|
+
our_frame_pos = caller.size
|
25
|
+
callers.each do |line|
|
26
|
+
if line != /load_dsl_file\.rb/
|
27
|
+
our_frame_pos -= 1
|
28
|
+
else
|
29
|
+
break
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
yield
|
35
|
+
|
36
|
+
rescue Exception => e
|
37
|
+
raise e if full_backtrace
|
38
|
+
if exceptions.any? { |e_class| e.kind_of?(e_class) }
|
39
|
+
raise e
|
40
|
+
end
|
41
|
+
|
42
|
+
backtrace = e.backtrace.dup
|
43
|
+
message = e.message.dup
|
44
|
+
|
45
|
+
# Filter out the message ... it can contain backtrace information as
|
46
|
+
# well (!)
|
47
|
+
message = message.split("\n").map do |line|
|
48
|
+
if line =~ /^.*:\d+(:.*)$/
|
49
|
+
backtrace.unshift line
|
50
|
+
nil
|
51
|
+
else
|
52
|
+
line
|
53
|
+
end
|
54
|
+
end.compact.join("\n")
|
55
|
+
|
56
|
+
|
57
|
+
if message.empty?
|
58
|
+
message = backtrace.shift
|
59
|
+
if message =~ /^(\s*[^\s]+:\d+:)\s*(.*)/
|
60
|
+
location = $1
|
61
|
+
message = $2
|
62
|
+
backtrace.unshift location
|
63
|
+
else
|
64
|
+
backtrace.unshift message
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
filtered_backtrace = backtrace[0, backtrace.size - our_frame_pos].
|
69
|
+
map do |line|
|
70
|
+
line.gsub! /:in `.*dsl.*'/, ''
|
71
|
+
if line =~ /load_dsl_file.*(method_missing|send)/
|
72
|
+
next
|
73
|
+
end
|
74
|
+
|
75
|
+
if line =~ /(load_dsl_file\.rb|with_module\.rb):\d+/
|
76
|
+
next
|
77
|
+
else
|
78
|
+
line
|
79
|
+
end
|
80
|
+
end.compact
|
81
|
+
|
82
|
+
|
83
|
+
backtrace = (filtered_backtrace[0, 1] + filtered_backtrace + backtrace[(backtrace.size - our_frame_pos)..-1])
|
84
|
+
raise e, message, backtrace
|
85
|
+
end
|
86
|
+
|
87
|
+
def eval_dsl_block(block, proxied_object, context, full_backtrace, *exceptions)
|
88
|
+
load_dsl_filter_backtrace(nil, full_backtrace, *exceptions) do
|
89
|
+
proxied_object.with_module(*context, &block)
|
90
|
+
true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def eval_dsl_file_content(file, file_content, proxied_object, context, full_backtrace, *exceptions, &block)
|
95
|
+
code = with_module(*context) do
|
96
|
+
code = <<-EOD
|
97
|
+
Proc.new { #{file_content} }
|
98
|
+
EOD
|
99
|
+
eval code, binding, file, 1
|
100
|
+
end
|
101
|
+
|
102
|
+
dsl_exec_common(file, proxied_object, context, full_backtrace, *exceptions, &code)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Load the given file by eval-ing it in the provided binding. The
|
106
|
+
# originality of this method is to translate errors that are detected in the
|
107
|
+
# eval'ed code into errors that refer to the provided file
|
108
|
+
#
|
109
|
+
# The caller of this method should call it at the end of its definition
|
110
|
+
# file, or the translation method may not be robust at all
|
111
|
+
def eval_dsl_file(file, proxied_object, context, full_backtrace, *exceptions, &block)
|
112
|
+
if !File.readable?(file)
|
113
|
+
raise ArgumentError, "#{file} does not exist"
|
114
|
+
end
|
115
|
+
|
116
|
+
loaded_file = file.gsub(/^#{Regexp.quote(Dir.pwd)}\//, '')
|
117
|
+
file_content = File.read(file)
|
118
|
+
eval_dsl_file_content(loaded_file, file_content, proxied_object, context, full_backtrace, *exceptions, &block)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Same than eval_dsl_file, but will not load the same file twice
|
122
|
+
def load_dsl_file(file, *args, &block)
|
123
|
+
file = File.expand_path(file)
|
124
|
+
if $LOADED_FEATURES.include?(file)
|
125
|
+
return false
|
126
|
+
end
|
127
|
+
|
128
|
+
eval_dsl_file(file, *args, &block)
|
129
|
+
$LOADED_FEATURES << file
|
130
|
+
true
|
131
|
+
end
|
132
|
+
|
133
|
+
def dsl_exec(proxied_object, context, full_backtrace, *exceptions, &code)
|
134
|
+
dsl_exec_common(nil, proxied_object, context, full_backtrace, *exceptions, &code)
|
135
|
+
end
|
136
|
+
|
137
|
+
def dsl_exec_common(file, proxied_object, context, full_backtrace, *exceptions, &code)
|
138
|
+
load_dsl_filter_backtrace(file, full_backtrace, *exceptions) do
|
139
|
+
sandbox = with_module(*context) do
|
140
|
+
Class.new do
|
141
|
+
attr_accessor :main_object
|
142
|
+
def initialize(obj); @main_object = obj end
|
143
|
+
def method_missing(*m, &block)
|
144
|
+
main_object.send(*m, &block)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
old_constants, new_constants = nil
|
150
|
+
if !Utilrb::RUBY_IS_191
|
151
|
+
old_constants = Kernel.constants
|
152
|
+
end
|
153
|
+
|
154
|
+
sandbox = sandbox.new(proxied_object)
|
155
|
+
sandbox.with_module(*context) do
|
156
|
+
old_constants =
|
157
|
+
if respond_to?(:constants)
|
158
|
+
constants
|
159
|
+
else self.class.constants
|
160
|
+
end
|
161
|
+
|
162
|
+
instance_eval(&code)
|
163
|
+
|
164
|
+
new_constants =
|
165
|
+
if respond_to?(:constants)
|
166
|
+
constants
|
167
|
+
else self.class.constants
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Check if the user defined new constants by using class K and/or
|
172
|
+
# mod Mod
|
173
|
+
if !Utilrb::RUBY_IS_191
|
174
|
+
new_constants = Kernel.constants
|
175
|
+
end
|
176
|
+
|
177
|
+
new_constants -= old_constants
|
178
|
+
new_constants.delete_if { |n| n.to_s == 'WithModuleConstResolutionExtension' }
|
179
|
+
if !new_constants.empty?
|
180
|
+
msg = "#{new_constants.first} does not exist. You cannot define new constants in this context"
|
181
|
+
raise NameError.new(msg, new_constants.first)
|
182
|
+
end
|
183
|
+
true
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
@@ -17,11 +17,20 @@ module Kernel
|
|
17
17
|
# filter_options(nil, known_options) -> default_options, {}
|
18
18
|
#
|
19
19
|
def filter_options(options, option_spec)
|
20
|
+
unknown_options = Hash.new
|
21
|
+
options = options.dup
|
22
|
+
options.delete_if do |key, value|
|
23
|
+
if !key.respond_to?(:to_sym)
|
24
|
+
unknown_options[key] = value
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
20
29
|
options = (options.to_hash || Hash.new).to_sym_keys
|
21
30
|
# cannot use #to_sym_keys as option_spec can be an array
|
22
31
|
option_spec = option_spec.inject({}) { |h, (k, v)| h[k.to_sym] = v; h }
|
23
32
|
|
24
|
-
unknown_options
|
33
|
+
unknown_options.merge!(options.slice(*(options.keys - option_spec.keys)))
|
25
34
|
known_options = options.slice(*option_spec.keys)
|
26
35
|
|
27
36
|
# Set default values defined in the spec
|