namebox 0.1.9 → 0.2.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.
Files changed (2) hide show
  1. data/lib/namebox.rb +77 -140
  2. metadata +8 -7
@@ -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
- # Version 0.1.9 - This is the last version compatible with Ruby 1.8.7 and 1.9.1.
12
- # It's slow, memory-consuming and it has some issues about loosing 'self'
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
- # hash for fast search for instances of eigenclasses
154
- @eigen_instances = Hash[*@classes.map { |c| [class << c; self; end, c] }.flatten]
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
- # eigen_instances will be useful as bound local variable in a closure
160
- # for another object; so we can't use instance var @eigen_instances
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
- # Create a protector module to protect the changed methods.
195
- # This protector module is specifc to new_module and klass.
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
- super_tunnel = Module.new
187
+ protector = protector_module(new_module)
203
188
 
204
- # Give name to protector module; useful when using Method#owner.
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
- new_m = info[:method]
303
- old_m = info_old[:method]
208
+ new_method = info[:method]
209
+ old_method = info_old[:method]
304
210
 
305
211
  # don't touch unmodified methods
306
- next if new_m == old_m
212
+ next if new_method == old_method
307
213
 
308
214
  # method was modified! take some info
309
- m_name = info[:name]
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, m_name do |*args, &blk|
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
- # Call the new method. Instance methods are unbound; bind to self.
321
- m = (new_bound_m || new_m.bind(self)).call(*args, &blk)
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 old_m
327
- (old_bound_m || old_m.bind(self)).call(*args, &blk)
230
+ if old_method
231
+ old_method.bind(self).call(*args, &blk)
328
232
  else
329
- begin
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 = get_superclass(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
- # Get superclass of a class; correct values for eigenclasses in 1.8.7.
473
- def get_superclass(c)
474
- s = c.superclass
475
- if s == CLASS_EIGENCLASS
476
- # Ruby 1.8.7 limitation
477
- s = class << @eigen_instances[c].superclass; self; end
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.1.9
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
- Note: this is the last version compatible with Ruby 1.8.7 and 1.9.1. It''s slow,
19
- memory-consuming and it has some issues about loosing ''self'' when in class methods
20
- changed by extending modules in subclasses (self will be the class instead of subclass
21
- when namebox is closed). Next versions will be only compatible with Ruby 1.9.2 or
22
- greater.'
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.8.7
42
+ version: 1.9.2
42
43
  required_rubygems_version: !ruby/object:Gem::Requirement
43
44
  none: false
44
45
  requirements: