namebox 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: