utilrb 1.3.3 → 1.4.0
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 +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
|