namebox 0.1.9 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/namebox.rb +77 -140
- metadata +8 -7
data/lib/namebox.rb
CHANGED
@@ -8,11 +8,8 @@
|
|
8
8
|
# This software is released "AS IS", without any warranty.
|
9
9
|
# The author is not responsible for the consequences of use of this software.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# when in class methods changed by extending modules in subclasses
|
14
|
-
# (self will be the class instead of subclass when namebox is closed).
|
15
|
-
# Next versions will be only compatible with Ruby 1.9.2 or greater.
|
11
|
+
# This version is only compatible with Ruby 1.9.2 or greater.
|
12
|
+
# For use with Ruby 1.8.7 or 1.9.1, get the version 0.1.8 or 0.1.9.
|
16
13
|
|
17
14
|
class Namebox
|
18
15
|
|
@@ -21,9 +18,6 @@ class Namebox
|
|
21
18
|
map { |c| Object.const_get(c) }.
|
22
19
|
select { |m| m.is_a? Module }.uniq
|
23
20
|
|
24
|
-
### FOR RUBY 1.8.7 USE ###
|
25
|
-
CLASS_EIGENCLASS = class << Class; self; end
|
26
|
-
|
27
21
|
class << self
|
28
22
|
|
29
23
|
# Wrapper to create a namebox only to protect modules when requiring.
|
@@ -150,16 +144,12 @@ class Namebox
|
|
150
144
|
# select classes to protect against included modules
|
151
145
|
@classes = @modules.select { |m| m.is_a? Class }
|
152
146
|
|
153
|
-
#
|
154
|
-
|
155
|
-
|
156
|
-
# include eigenclasses in @classes
|
157
|
-
@classes |= @eigen_instances.keys
|
147
|
+
# get eigenclasses
|
148
|
+
eigenclasses = @classes.map { |c| class << c; self; end }
|
158
149
|
|
159
|
-
#
|
160
|
-
|
161
|
-
|
162
|
-
eigen_instances = @eigen_instances
|
150
|
+
# include eigenclasses into @classes and @modules
|
151
|
+
@classes |= eigenclasses
|
152
|
+
@modules |= eigenclasses
|
163
153
|
|
164
154
|
# save preexisting methods and included modules
|
165
155
|
inc_mods_before = get_included_modules
|
@@ -191,98 +181,14 @@ class Namebox
|
|
191
181
|
|
192
182
|
new_modules.each do |new_module|
|
193
183
|
|
194
|
-
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
protector = Module.new
|
198
|
-
|
199
|
-
# Create a module to enable a tunnel to bypass the new_module
|
200
|
-
# in super method lookup when namebox is closed to new_module.
|
184
|
+
# Get a protector module for new_module; don't recreate it
|
185
|
+
# if a protector was already created for new_module.
|
201
186
|
#
|
202
|
-
|
187
|
+
protector = protector_module(new_module)
|
203
188
|
|
204
|
-
#
|
189
|
+
# reincludes the new_module with super_tunnel
|
190
|
+
# to allow bind(self) inside protector code.
|
205
191
|
#
|
206
|
-
class << protector; self; end.send(:define_method, :to_s) do
|
207
|
-
"Protector:#{new_module}/#{klass}"
|
208
|
-
end
|
209
|
-
|
210
|
-
new_module.instance_methods.each do |method_name|
|
211
|
-
|
212
|
-
new_method = new_module.instance_method(method_name)
|
213
|
-
|
214
|
-
protector.send :define_method, method_name do |*args, &blk|
|
215
|
-
if this_nb.open?
|
216
|
-
new_method.bind(self).call(*args, &blk)
|
217
|
-
else
|
218
|
-
begin
|
219
|
-
super_tunnel.instance_method(method_name).bind(self).call(*args, &blk)
|
220
|
-
rescue NoMethodError
|
221
|
-
|
222
|
-
# Can throw error in two cases:
|
223
|
-
# 1. There's really no super method (Ruby >= 1.9)
|
224
|
-
# 2. 1.8.7 does not find super when in a module after binding.
|
225
|
-
#
|
226
|
-
raise if RUBY_VERSION >= '1.9.0'
|
227
|
-
|
228
|
-
# future method
|
229
|
-
m = nil
|
230
|
-
|
231
|
-
# search the method in old modules
|
232
|
-
old_modules.each do |old_module|
|
233
|
-
begin
|
234
|
-
m = old_module.instance_method(method_name).bind(self)
|
235
|
-
break
|
236
|
-
rescue NameError
|
237
|
-
# try next
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
unless m
|
242
|
-
|
243
|
-
# last try: superklass
|
244
|
-
begin
|
245
|
-
superklass = klass.superclass
|
246
|
-
|
247
|
-
# superklass exist?
|
248
|
-
raise NameError unless superklass
|
249
|
-
|
250
|
-
# Ruby 1.8.7 get wrong superclass for eigenclasses
|
251
|
-
if superklass == CLASS_EIGENCLASS
|
252
|
-
|
253
|
-
# Get a bound method for superclass (although self
|
254
|
-
# won't be the same: superclass instead of klass).
|
255
|
-
# Can raise NameError if method does not exist.
|
256
|
-
#
|
257
|
-
m = eigen_instances[klass].superclass.method(method_name)
|
258
|
-
|
259
|
-
else
|
260
|
-
|
261
|
-
# Try to get method; raises NameError if it doesn't exist.
|
262
|
-
m = superklass.instance_method(method_name).bind(self)
|
263
|
-
|
264
|
-
end
|
265
|
-
|
266
|
-
rescue NameError
|
267
|
-
Namebox.no_method_error(self, method_name)
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
m.call(*args, &blk)
|
272
|
-
end
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
super_tunnel.send :define_method, method_name do |*args, &blk|
|
277
|
-
super(*args, &blk)
|
278
|
-
end
|
279
|
-
|
280
|
-
end
|
281
|
-
|
282
|
-
# include super_tunnel in new_module
|
283
|
-
new_module.send :include, super_tunnel
|
284
|
-
|
285
|
-
# reincludes the new_module with super_tunnel to allow bind(self)
|
286
192
|
klass.send :include, new_module
|
287
193
|
|
288
194
|
# finally, include the protector in the class
|
@@ -299,38 +205,32 @@ class Namebox
|
|
299
205
|
|
300
206
|
# get old method
|
301
207
|
info_old = methods_before[fullname] || {}
|
302
|
-
|
303
|
-
|
208
|
+
new_method = info[:method]
|
209
|
+
old_method = info_old[:method]
|
304
210
|
|
305
211
|
# don't touch unmodified methods
|
306
|
-
next if
|
212
|
+
next if new_method == old_method
|
307
213
|
|
308
214
|
# method was modified! take some info
|
309
|
-
|
215
|
+
method_name = info[:name]
|
310
216
|
klass = info[:class]
|
311
|
-
new_bound_m = info[:bound]
|
312
|
-
old_bound_m = info_old[:bound]
|
313
217
|
|
314
218
|
# redefine the method, which will check namebox visibility dinamically
|
315
|
-
klass.send :define_method,
|
219
|
+
klass.send :define_method, method_name do |*args, &blk|
|
316
220
|
|
317
221
|
# check namebox visibility
|
318
222
|
if this_nb.open?
|
319
223
|
|
320
|
-
#
|
321
|
-
|
224
|
+
# namebox method; bind instance method to self.
|
225
|
+
new_method.bind(self).call(*args, &blk)
|
322
226
|
|
323
227
|
else
|
324
228
|
|
325
229
|
# old method or super
|
326
|
-
if
|
327
|
-
|
230
|
+
if old_method
|
231
|
+
old_method.bind(self).call(*args, &blk)
|
328
232
|
else
|
329
|
-
|
330
|
-
super(*args, &blk)
|
331
|
-
rescue NoMethodError
|
332
|
-
Namebox.no_method_error(self, m_name)
|
333
|
-
end
|
233
|
+
super(*args, &blk)
|
334
234
|
end
|
335
235
|
|
336
236
|
end
|
@@ -433,18 +333,9 @@ class Namebox
|
|
433
333
|
|
434
334
|
@modules.each do |c|
|
435
335
|
|
436
|
-
# get eigenclass
|
437
|
-
ec = class << c; self; end
|
438
|
-
|
439
336
|
c.instance_methods(false).each do |m|
|
440
337
|
fullname = "#{c}##{m}"
|
441
|
-
gm[fullname] = {:class => c, :name => m, :method => c.instance_method(m)
|
442
|
-
end
|
443
|
-
|
444
|
-
c.methods(false).each do |m|
|
445
|
-
fullname = "#{c}.#{m}"
|
446
|
-
gm[fullname] = {:class => ec, :name => m, :method => ec.instance_method(m),
|
447
|
-
:bound => c.method(m) }
|
338
|
+
gm[fullname] = {:class => c, :name => m, :method => c.instance_method(m)}
|
448
339
|
end
|
449
340
|
|
450
341
|
end
|
@@ -457,7 +348,7 @@ class Namebox
|
|
457
348
|
inc_mods = {}
|
458
349
|
|
459
350
|
@classes.each do |c|
|
460
|
-
super_c =
|
351
|
+
super_c = c.superclass
|
461
352
|
|
462
353
|
# superclass included modules must be [] even when superclass is nil
|
463
354
|
super_inc_mods = super_c && super_c.included_modules || []
|
@@ -469,14 +360,60 @@ class Namebox
|
|
469
360
|
inc_mods
|
470
361
|
end
|
471
362
|
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
363
|
+
def protector_module(new_module)
|
364
|
+
@protector_modules ||= {}
|
365
|
+
if @protector_modules[new_module]
|
366
|
+
@protector_modules[new_module]
|
367
|
+
else
|
368
|
+
|
369
|
+
this_nb = self
|
370
|
+
|
371
|
+
# Create a protector module to protect the changed methods.
|
372
|
+
protector = Module.new
|
373
|
+
|
374
|
+
# Create a module to enable a tunnel to bypass the new_module
|
375
|
+
# in super method lookup when namebox is closed to new_module.
|
376
|
+
#
|
377
|
+
super_tunnel = Module.new
|
378
|
+
|
379
|
+
# Give a name to protector module; useful when using Method#owner.
|
380
|
+
#
|
381
|
+
class << protector; self; end.send(:define_method, :to_s) do
|
382
|
+
"Protector:#{new_module}"
|
383
|
+
end
|
384
|
+
|
385
|
+
new_module.instance_methods.each do |method_name|
|
386
|
+
|
387
|
+
new_method = new_module.instance_method(method_name)
|
388
|
+
|
389
|
+
protector.send :define_method, method_name do |*args, &blk|
|
390
|
+
|
391
|
+
# check namebox visibility
|
392
|
+
if this_nb.open?
|
393
|
+
|
394
|
+
# namebox method; bind instance method to self.
|
395
|
+
new_method.bind(self).call(*args, &blk)
|
396
|
+
|
397
|
+
else
|
398
|
+
|
399
|
+
# super (above module thru super_tunnel); can raise NoMethodError.
|
400
|
+
super_tunnel.instance_method(method_name).bind(self).call(*args, &blk)
|
401
|
+
|
402
|
+
end
|
403
|
+
|
404
|
+
end
|
405
|
+
|
406
|
+
super_tunnel.send :define_method, method_name do |*args, &blk|
|
407
|
+
super(*args, &blk)
|
408
|
+
end
|
409
|
+
|
410
|
+
end
|
411
|
+
|
412
|
+
# include super_tunnel in new_module
|
413
|
+
new_module.send :include, super_tunnel
|
414
|
+
|
415
|
+
@protector_modules[new_module] = protector
|
478
416
|
end
|
479
|
-
s
|
480
417
|
end
|
481
418
|
|
482
419
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: namebox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -15,11 +15,12 @@ description: ! 'Create namespace boxes to protect the core classes'' methods fro
|
|
15
15
|
changes, like refinements.
|
16
16
|
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
This version is only compatible with Ruby 1.9.2 or greater. For use with Ruby 1.8.7
|
19
|
+
or 1.9.1, get the version 0.1.8 or 0.1.9.
|
20
|
+
|
21
|
+
|
22
|
+
Note: this version is under tests, and can be considered a pre-release for 1.0.0.
|
23
|
+
Please, came back soon to check for that version. ;-)'
|
23
24
|
email: sony.fermino@gmail.com
|
24
25
|
executables: []
|
25
26
|
extensions: []
|
@@ -38,7 +39,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
38
39
|
requirements:
|
39
40
|
- - ! '>='
|
40
41
|
- !ruby/object:Gem::Version
|
41
|
-
version: 1.
|
42
|
+
version: 1.9.2
|
42
43
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
44
|
none: false
|
44
45
|
requirements:
|