extlib 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of extlib might be problematic. Click here for more details.
- data/.autotest +21 -0
- data/History.txt +1 -0
- data/Manifest.txt +29 -0
- data/README.txt +3 -0
- data/Rakefile +145 -0
- data/lib/extlib/hook.rb +80 -27
- data/lib/extlib/lazy_array.rb +4 -2
- data/lib/extlib/module.rb +31 -13
- data/lib/extlib/object.rb +1 -1
- data/lib/extlib/pooling.rb +47 -41
- data/lib/extlib/version.rb +3 -0
- data/spec/hook_spec.rb +332 -31
- data/spec/lazy_array_spec.rb +22 -8
- data/spec/module_spec.rb +33 -11
- data/spec/object_spec.rb +1 -1
- data/spec/pooling_spec.rb +3 -7
- data/tasks/hoe.rb +39 -0
- metadata +28 -16
- data/README +0 -0
data/.autotest
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Autotest.add_hook :initialize do |at|
|
2
|
+
ignore = %w[ .git log plugins script tasks bin CHANGELOG FAQ MIT-LICENSE QUICKLINKS README ]
|
3
|
+
|
4
|
+
ignore.each do |exception|
|
5
|
+
at.add_exception(exception)
|
6
|
+
end
|
7
|
+
|
8
|
+
at.clear_mappings
|
9
|
+
|
10
|
+
at.add_mapping(%r{^spec/.+_spec\.rb$}) do |filename,_|
|
11
|
+
filename
|
12
|
+
end
|
13
|
+
|
14
|
+
at.add_mapping(%r{^lib/extlib/(.+)\.rb$}) do |_,match|
|
15
|
+
[ "spec/#{match[1]}_spec.rb" ]
|
16
|
+
end
|
17
|
+
|
18
|
+
at.add_mapping(%r{^spec/spec_helper\.rb$}) do
|
19
|
+
at.files_matching(%r{^spec/.+_spec\.rb$})
|
20
|
+
end
|
21
|
+
end
|
data/History.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
|
data/Manifest.txt
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
.autotest
|
2
|
+
History.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
lib/extlib.rb
|
7
|
+
lib/extlib/assertions.rb
|
8
|
+
lib/extlib/blank.rb
|
9
|
+
lib/extlib/hook.rb
|
10
|
+
lib/extlib/inflection.rb
|
11
|
+
lib/extlib/lazy_array.rb
|
12
|
+
lib/extlib/module.rb
|
13
|
+
lib/extlib/object.rb
|
14
|
+
lib/extlib/pathname.rb
|
15
|
+
lib/extlib/pooling.rb
|
16
|
+
lib/extlib/string.rb
|
17
|
+
lib/extlib/struct.rb
|
18
|
+
lib/extlib/version.rb
|
19
|
+
spec/blank_spec.rb
|
20
|
+
spec/hook_spec.rb
|
21
|
+
spec/inflection_spec.rb
|
22
|
+
spec/lazy_array_spec.rb
|
23
|
+
spec/module_spec.rb
|
24
|
+
spec/object_spec.rb
|
25
|
+
spec/pooling_spec.rb
|
26
|
+
spec/spec_helper.rb
|
27
|
+
spec/string_spec.rb
|
28
|
+
spec/struct_spec.rb
|
29
|
+
tasks/hoe.rb
|
data/README.txt
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'pathname'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
require Pathname('spec/rake/spectask')
|
6
|
+
require Pathname('lib/extlib/version')
|
7
|
+
|
8
|
+
ROOT = Pathname(__FILE__).dirname.expand_path
|
9
|
+
|
10
|
+
AUTHOR = "Sam Smoot"
|
11
|
+
EMAIL = "ssmoot@gmail.com"
|
12
|
+
GEM_NAME = "extlib"
|
13
|
+
GEM_VERSION = Extlib::VERSION
|
14
|
+
GEM_DEPENDENCIES = [["english", ">=0.2.0"]]
|
15
|
+
GEM_CLEAN = "*.gem", "**/.DS_Store"
|
16
|
+
GEM_EXTRAS = { :has_rdoc => false }
|
17
|
+
|
18
|
+
PROJECT_NAME = "extlib"
|
19
|
+
PROJECT_URL = "http://extlib.rubyforge.org"
|
20
|
+
PROJECT_DESCRIPTION = PROJECT_SUMMARY = "Support Library for DataMapper and DataObjects"
|
21
|
+
|
22
|
+
require ROOT + 'tasks/hoe'
|
23
|
+
|
24
|
+
task :default => 'extlib:spec'
|
25
|
+
task :spec => 'extlib:spec'
|
26
|
+
|
27
|
+
desc 'Remove all package, docs and spec products'
|
28
|
+
task :clobber_all => %w[ clobber_package clobber_doc extlib:clobber_spec ]
|
29
|
+
|
30
|
+
namespace :extlib do
|
31
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
32
|
+
t.spec_opts << '--format' << 'specdoc' << '--colour'
|
33
|
+
t.spec_opts << '--loadby' << 'random'
|
34
|
+
t.spec_files = Pathname.glob(ENV['FILES'] || 'spec/**/*_spec.rb')
|
35
|
+
|
36
|
+
begin
|
37
|
+
t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
|
38
|
+
t.rcov_opts << '--exclude' << 'spec'
|
39
|
+
t.rcov_opts << '--text-summary'
|
40
|
+
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
41
|
+
rescue Exception
|
42
|
+
# rcov not installed
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "Generate documentation"
|
48
|
+
task :doc do
|
49
|
+
begin
|
50
|
+
require 'yard'
|
51
|
+
exec 'yardoc'
|
52
|
+
rescue LoadError
|
53
|
+
puts 'You will need to install the latest version of Yard to generate the
|
54
|
+
documentation for extlib.'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
WINDOWS = (RUBY_PLATFORM =~ /win32|mingw|bccwin|cygwin/) rescue nil
|
59
|
+
SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
|
60
|
+
|
61
|
+
desc "Install #{GEM_NAME}"
|
62
|
+
task :install => :package do
|
63
|
+
sh %{#{SUDO} gem install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources}
|
64
|
+
end
|
65
|
+
|
66
|
+
if WINDOWS
|
67
|
+
namespace :dev do
|
68
|
+
desc 'Install for development (for windows)'
|
69
|
+
task :winstall => :gem do
|
70
|
+
system %{gem install --no-rdoc --no-ri -l pkg/#{GEM_NAME}-#{GEM_VERSION}.gem}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
namespace :ci do
|
76
|
+
|
77
|
+
task :prepare do
|
78
|
+
rm_rf ROOT + "ci"
|
79
|
+
mkdir_p ROOT + "ci"
|
80
|
+
mkdir_p ROOT + "ci/doc"
|
81
|
+
mkdir_p ROOT + "ci/cyclomatic"
|
82
|
+
mkdir_p ROOT + "ci/token"
|
83
|
+
end
|
84
|
+
|
85
|
+
task :publish do
|
86
|
+
out = ENV['CC_BUILD_ARTIFACTS'] || "out"
|
87
|
+
mkdir_p out unless File.directory? out
|
88
|
+
|
89
|
+
mv "ci/unit_rspec_report.html", "#{out}/unit_rspec_report.html"
|
90
|
+
mv "ci/unit_coverage", "#{out}/unit_coverage"
|
91
|
+
mv "ci/integration_rspec_report.html", "#{out}/integration_rspec_report.html"
|
92
|
+
mv "ci/integration_coverage", "#{out}/integration_coverage"
|
93
|
+
mv "ci/doc", "#{out}/doc"
|
94
|
+
mv "ci/cyclomatic", "#{out}/cyclomatic_complexity"
|
95
|
+
mv "ci/token", "#{out}/token_complexity"
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
Spec::Rake::SpecTask.new("spec:unit" => :prepare) do |t|
|
100
|
+
t.spec_opts = ["--format", "specdoc", "--format", "html:#{ROOT}/ci/unit_rspec_report.html", "--diff"]
|
101
|
+
t.spec_files = Pathname.glob(ROOT + "spec/unit/**/*_spec.rb")
|
102
|
+
unless ENV['NO_RCOV']
|
103
|
+
t.rcov = true
|
104
|
+
t.rcov_opts << '--exclude' << "spec,gems"
|
105
|
+
t.rcov_opts << '--text-summary'
|
106
|
+
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
107
|
+
t.rcov_opts << '--only-uncovered'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
Spec::Rake::SpecTask.new("spec:integration" => :prepare) do |t|
|
112
|
+
t.spec_opts = ["--format", "specdoc", "--format", "html:#{ROOT}/ci/integration_rspec_report.html", "--diff"]
|
113
|
+
t.spec_files = Pathname.glob(ROOT + "spec/integration/**/*_spec.rb")
|
114
|
+
unless ENV['NO_RCOV']
|
115
|
+
t.rcov = true
|
116
|
+
t.rcov_opts << '--exclude' << "spec,gems"
|
117
|
+
t.rcov_opts << '--text-summary'
|
118
|
+
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
119
|
+
t.rcov_opts << '--only-uncovered'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
task :spec do
|
124
|
+
Rake::Task["ci:spec:unit"].invoke
|
125
|
+
mv ROOT + "coverage", ROOT + "ci/unit_coverage"
|
126
|
+
|
127
|
+
Rake::Task["ci:spec:integration"].invoke
|
128
|
+
mv ROOT + "coverage", ROOT + "ci/integration_coverage"
|
129
|
+
end
|
130
|
+
|
131
|
+
task :doc do
|
132
|
+
require 'yardoc'
|
133
|
+
sh 'yardoc'
|
134
|
+
end
|
135
|
+
|
136
|
+
task :saikuro => :prepare do
|
137
|
+
system "saikuro -c -i lib -y 0 -w 10 -e 15 -o ci/cyclomatic"
|
138
|
+
mv 'ci/cyclomatic/index_cyclo.html', 'ci/cyclomatic/index.html'
|
139
|
+
|
140
|
+
system "saikuro -t -i lib -y 0 -w 20 -e 30 -o ci/token"
|
141
|
+
mv 'ci/token/index_token.html', 'ci/token/index.html'
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
task :ci => ["ci:spec", "ci:doc", "ci:saikuro", :install, :publish]
|
data/lib/extlib/hook.rb
CHANGED
@@ -2,18 +2,21 @@ module Extlib
|
|
2
2
|
#
|
3
3
|
# TODO: Write more documentation!
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# stack is not created.
|
5
|
+
# Overview
|
6
|
+
# ========
|
8
7
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
8
|
+
# The Hook module is a very simple set of AOP helpers. Basically, it
|
9
|
+
# allows the developer to specify a method or block that should run
|
10
|
+
# before or after another method.
|
12
11
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
12
|
+
# Usage
|
13
|
+
# =====
|
14
|
+
#
|
15
|
+
# Halting The Hook Stack
|
16
|
+
#
|
17
|
+
# Inheritance
|
18
|
+
#
|
19
|
+
# Other Goodies
|
17
20
|
#
|
18
21
|
# Please bring up any issues regarding Hooks with carllerche on IRC
|
19
22
|
#
|
@@ -23,6 +26,17 @@ module Extlib
|
|
23
26
|
base.extend(ClassMethods)
|
24
27
|
base.const_set("CLASS_HOOKS", {}) unless base.const_defined?("CLASS_HOOKS")
|
25
28
|
base.const_set("INSTANCE_HOOKS", {}) unless base.const_defined?("INSTANCE_HOOKS")
|
29
|
+
base.class_eval do
|
30
|
+
class << self
|
31
|
+
def method_added(name)
|
32
|
+
process_method_added(name, :instance)
|
33
|
+
end
|
34
|
+
|
35
|
+
def singleton_method_added(name)
|
36
|
+
process_method_added(name, :class)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
26
40
|
end
|
27
41
|
|
28
42
|
module ClassMethods
|
@@ -120,6 +134,8 @@ module Extlib
|
|
120
134
|
|
121
135
|
# --- Alright kids... the rest is internal stuff ---
|
122
136
|
|
137
|
+
# Returns the correct HOOKS Hash depending on whether we are
|
138
|
+
# working with class methods or instance methods
|
123
139
|
def hooks_with_scope(scope)
|
124
140
|
case scope
|
125
141
|
when :class then class_hooks
|
@@ -136,6 +152,15 @@ module Extlib
|
|
136
152
|
self.const_get("INSTANCE_HOOKS")
|
137
153
|
end
|
138
154
|
|
155
|
+
# Registers a method as hookable. Registering hooks involves the following
|
156
|
+
# process
|
157
|
+
#
|
158
|
+
# * Create a blank entry in the HOOK Hash for the method.
|
159
|
+
# * Define the methods that execute the before and after hook stack.
|
160
|
+
# These methods will be no-ops at first, but everytime a new hook is
|
161
|
+
# defined, the methods will be redefined to incorporate the new hook.
|
162
|
+
# * Redefine the method that is to be hookable so that the hook stacks
|
163
|
+
# are invoked approprietly.
|
139
164
|
def register_hook(target_method, scope)
|
140
165
|
if scope == :instance && !method_defined?(target_method)
|
141
166
|
raise ArgumentError, "#{target_method} instance method does not exist"
|
@@ -147,6 +172,10 @@ module Extlib
|
|
147
172
|
|
148
173
|
if hooks[target_method].nil?
|
149
174
|
hooks[target_method] = {
|
175
|
+
# We need to keep track of which class in the Inheritance chain the
|
176
|
+
# method was declared hookable in. Every time a child declares a new
|
177
|
+
# hook for the method, the hook stack invocations need to be redefined
|
178
|
+
# in the original Class. See #define_hook_stack_execution_methods
|
150
179
|
:before => [], :after => [], :in => self
|
151
180
|
}
|
152
181
|
|
@@ -155,10 +184,14 @@ module Extlib
|
|
155
184
|
end
|
156
185
|
end
|
157
186
|
|
187
|
+
# Is the method registered as a hookable in the given scope.
|
158
188
|
def registered_as_hook?(target_method, scope)
|
159
189
|
! hooks_with_scope(scope)[target_method].nil?
|
160
190
|
end
|
161
191
|
|
192
|
+
# Generates names for the various utility methods. We need to do this because
|
193
|
+
# the various utility methods should not end in = so, while we're at it, we
|
194
|
+
# might as well get rid of all punctuation.
|
162
195
|
def hook_method_name(target_method, prefix, suffix)
|
163
196
|
target_method = target_method.to_s
|
164
197
|
|
@@ -166,10 +199,29 @@ module Extlib
|
|
166
199
|
when '?' then "#{prefix}_#{target_method[0..-2]}_ques_#{suffix}"
|
167
200
|
when '!' then "#{prefix}_#{target_method[0..-2]}_bang_#{suffix}"
|
168
201
|
when '=' then "#{prefix}_#{target_method[0..-2]}_eq_#{suffix}"
|
169
|
-
|
202
|
+
# I add a _nan_ suffix here so that we don't ever encounter
|
203
|
+
# any naming conflicts.
|
204
|
+
else "#{prefix}_#{target_method[0..-1]}_nan_#{suffix}"
|
170
205
|
end
|
171
206
|
end
|
172
207
|
|
208
|
+
# This will need to be refactored
|
209
|
+
def process_method_added(method_name, scope)
|
210
|
+
hooks_with_scope(scope).each do |target_method, hooks|
|
211
|
+
if hooks[:before].any? { |hook| hook[:name] == method_name }
|
212
|
+
define_hook_stack_execution_methods(target_method, scope)
|
213
|
+
end
|
214
|
+
|
215
|
+
if hooks[:after].any? { |hook| hook[:name] == method_name }
|
216
|
+
define_hook_stack_execution_methods(target_method, scope)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Defines two methods. One method executes the before hook stack. The other executes
|
222
|
+
# the after hook stack. This method will be called many times during the Class definition
|
223
|
+
# process. It should be called for each hook that is defined. It will also be called
|
224
|
+
# when a hook is redefined (to make sure that the arity hasn't changed).
|
173
225
|
def define_hook_stack_execution_methods(target_method, scope)
|
174
226
|
unless registered_as_hook?(target_method, scope)
|
175
227
|
raise ArgumentError, "#{target_method} has not be registered as a hookable #{scope} method"
|
@@ -177,9 +229,6 @@ module Extlib
|
|
177
229
|
|
178
230
|
hooks = hooks_with_scope(scope)
|
179
231
|
|
180
|
-
# before_hook_stack = "execute_before_" + "#{target_method}".sub(/([?!=]?$)/, '_hook_stack\1')
|
181
|
-
# after_hook_stack = "execute_after_" + "#{target_method}".sub(/([?!=]?$)/, '_hook_stack\1')
|
182
|
-
|
183
232
|
before_hooks = hooks[target_method][:before]
|
184
233
|
before_hooks = before_hooks.map{ |info| inline_call(info, scope) }.join("\n")
|
185
234
|
|
@@ -200,14 +249,20 @@ module Extlib
|
|
200
249
|
|
201
250
|
source = %{class << self\n#{source}\nend} if scope == :class
|
202
251
|
|
203
|
-
hooks[target_method][:in].class_eval(source)
|
252
|
+
hooks[target_method][:in].class_eval(source, __FILE__, __LINE__)
|
204
253
|
end
|
205
254
|
|
255
|
+
# Returns ruby code that will invoke the hook. It checks the arity of the hook method
|
256
|
+
# and passes arguments accordingly.
|
206
257
|
def inline_call(method_info, scope)
|
258
|
+
name = method_info[:name]
|
259
|
+
|
207
260
|
if scope == :instance
|
208
|
-
|
261
|
+
args = method_defined?(name) && instance_method(name).arity != 0 ? '*args' : ''
|
262
|
+
%(#{name}(#{args}) if self.class <= ObjectSpace._id2ref(#{method_info[:from].object_id}))
|
209
263
|
else
|
210
|
-
|
264
|
+
args = respond_to?(name) && method(name).arity != 0 ? '*args' : ''
|
265
|
+
%(#{name}(#{args}) if self <= ObjectSpace._id2ref(#{method_info[:from].object_id}))
|
211
266
|
end
|
212
267
|
end
|
213
268
|
|
@@ -215,8 +270,6 @@ module Extlib
|
|
215
270
|
args = args_for(method_with_scope(target_method, scope))
|
216
271
|
|
217
272
|
renamed_target = hook_method_name(target_method, 'hookable_', 'before_advised')
|
218
|
-
# before_hook_stack = "execute_before_" + "#{target_method}".sub(/([?!=]?$)/, '_hook_stack\1')
|
219
|
-
# after_hook_stack = "execute_after_" + "#{target_method}".sub(/([?!=]?$)/, '_hook_stack\1')
|
220
273
|
|
221
274
|
source = <<-EOD
|
222
275
|
def #{target_method}(#{args})
|
@@ -224,9 +277,9 @@ module Extlib
|
|
224
277
|
catch(:halt) do
|
225
278
|
#{hook_method_name(target_method, 'execute_before', 'hook_stack')}(#{args})
|
226
279
|
retval = #{renamed_target}(#{args})
|
227
|
-
#{hook_method_name(target_method, 'execute_after', 'hook_stack')}(#{args})
|
280
|
+
#{hook_method_name(target_method, 'execute_after', 'hook_stack')}(retval, #{args})
|
281
|
+
retval
|
228
282
|
end
|
229
|
-
retval
|
230
283
|
end
|
231
284
|
EOD
|
232
285
|
|
@@ -234,12 +287,12 @@ module Extlib
|
|
234
287
|
send(:alias_method, renamed_target, target_method)
|
235
288
|
|
236
289
|
proxy_module = Module.new
|
237
|
-
proxy_module.class_eval(source)
|
290
|
+
proxy_module.class_eval(source, __FILE__, __LINE__)
|
238
291
|
self.send(:include, proxy_module)
|
239
292
|
else
|
240
293
|
source = %{alias_method :#{renamed_target}, :#{target_method}\n#{source}}
|
241
294
|
source = %{class << self\n#{source}\nend} if scope == :class
|
242
|
-
class_eval(source)
|
295
|
+
class_eval(source, __FILE__, __LINE__)
|
243
296
|
end
|
244
297
|
end
|
245
298
|
|
@@ -286,13 +339,13 @@ module Extlib
|
|
286
339
|
|
287
340
|
def args_for(method)
|
288
341
|
if method.arity == 0
|
289
|
-
""
|
342
|
+
"&block"
|
290
343
|
elsif method.arity > 0
|
291
|
-
"_" << (1 .. method.arity).to_a.join(", _")
|
344
|
+
"_" << (1 .. method.arity).to_a.join(", _") << ", &block"
|
292
345
|
elsif (method.arity + 1) < 0
|
293
|
-
"_" << (1 .. (method.arity).abs - 1).to_a.join(", _") << ", *args"
|
346
|
+
"_" << (1 .. (method.arity).abs - 1).to_a.join(", _") << ", *args, &block"
|
294
347
|
else
|
295
|
-
"*args"
|
348
|
+
"*args, &block"
|
296
349
|
end
|
297
350
|
end
|
298
351
|
|
data/lib/extlib/lazy_array.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
class LazyArray # borrowed partially from StrokeDB
|
2
|
+
instance_methods.each { |m| undef_method m unless %w[ __id__ __send__ send dup class object_id kind_of? respond_to? assert_kind_of should should_not instance_variable_set instance_variable_get ].include?(m) }
|
3
|
+
|
2
4
|
include Enumerable
|
3
5
|
|
4
6
|
# these methods should return self or nil
|
5
7
|
RETURN_SELF = [ :<<, :clear, :concat, :collect!, :each, :each_index,
|
6
|
-
:each_with_index, :insert, :map!, :push, :replace,
|
7
|
-
:reverse!, :reverse_each, :sort!, :unshift ]
|
8
|
+
:each_with_index, :freeze, :insert, :map!, :push, :replace,
|
9
|
+
:reject!, :reverse!, :reverse_each, :sort!, :unshift ]
|
8
10
|
|
9
11
|
RETURN_SELF.each do |method|
|
10
12
|
class_eval <<-EOS, __FILE__, __LINE__
|
data/lib/extlib/module.rb
CHANGED
@@ -1,19 +1,37 @@
|
|
1
1
|
class Module
|
2
|
-
def find_const(
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
def find_const(const_name)
|
3
|
+
if const_name[0..1] == '::'
|
4
|
+
Object.find_const(const_name[2..-1])
|
5
|
+
else
|
6
|
+
nested_const_lookup(const_name)
|
7
|
+
end
|
6
8
|
end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
private
|
11
|
+
|
12
|
+
# Doesn't do any caching since constants can change with remove_const
|
13
|
+
def nested_const_lookup(const_name)
|
14
|
+
constants = [ Object ]
|
15
|
+
|
16
|
+
unless self == Object
|
17
|
+
self.name.split('::').each do |part|
|
18
|
+
constants.unshift(constants.first.const_get(part))
|
14
19
|
end
|
15
|
-
h[k] = klass
|
16
20
|
end
|
21
|
+
|
22
|
+
parts = const_name.split('::')
|
23
|
+
|
24
|
+
# from most to least specific constant, use each as a base and try
|
25
|
+
# to find a constant with the name const_name within them
|
26
|
+
constants.each do |const|
|
27
|
+
# return the nested constant if available
|
28
|
+
return const if parts.all? do |part|
|
29
|
+
const = const.const_defined?(part) ? const.const_get(part) : nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# if we get this far then the nested constant was not found
|
34
|
+
raise NameError, "uninitialized constant #{const_name}"
|
17
35
|
end
|
18
|
-
|
19
|
-
end # class Module
|
36
|
+
|
37
|
+
end # class Module
|