namebox 0.0.2 → 0.0.3

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 +103 -116
  2. metadata +4 -3
data/lib/namebox.rb CHANGED
@@ -55,93 +55,88 @@ class Namebox
55
55
 
56
56
  end
57
57
 
58
- # get the superclass of ancestor in the base's ancestors list
59
- def super_ancestor(base, ancestor)
60
- ba = base.ancestors
61
- i = ba.index(ancestor)
62
- ba[i + 1] if i
63
- end
58
+ ###################################################
59
+ # INSTANCE METHODS HELPERS
60
+ ###################################################
64
61
 
65
- # get the instance method from superclass of ancestor
66
- # in the base_class' ancestors list
62
+ # Get the super methods from klass' ancestors list.
63
+ # +is_instance+: boolean for instance or class methods
64
+ # +limit_ancestor+: the last ancestor to check for methods
65
+ # +default_method+: the method to return case not found
66
+ # +first+: returns the first method found; else returns an array
67
67
  #
68
- def super_method(name, base_class, ancestor = base_class)
68
+ def super_methods(name, klass, is_instance, limit_ancestor, default_method,
69
+ first = false, &validator)
69
70
 
70
- super_class = super_ancestor(base_class, ancestor)
71
+ ancestors = is_instance ? klass.ancestors : class_ancestors(klass)
71
72
 
72
- # no super_class!
73
- raise NameError unless super_class
73
+ sm = []
74
+ limit_index = ancestors.index(limit_ancestor) || ancestors.length - 1
74
75
 
75
- # get the super method (can throw NameError if it doesn't exist)
76
- super_class.instance_method(name)
77
- end
76
+ # skip first ancestor (0) - the class itself
77
+ #
78
+ for i in 1..limit_index
79
+ super_ancestor = ancestors[i]
80
+ begin
81
+ m = super_ancestor.instance_method(name)
82
+ rescue NameError
83
+ m = nil
84
+ end
85
+
86
+ # only owners (and the last) are interesting
87
+ next unless m && m.owner == super_ancestor || i == limit_index
88
+
89
+ # check if it matches the requisites
90
+ next unless validator.call(m)
91
+
92
+ return m if first
93
+
94
+ sm << m
78
95
 
79
- def super_owner(name, base_class, ancestor)
80
- begin
81
- super_method(name, base_class, ancestor).owner
82
- rescue NameError
83
96
  end
97
+
98
+ # return found methods
99
+ return sm unless sm.empty?
100
+
101
+ # not found
102
+ first ? default_method : [default_method]
84
103
  end
85
104
 
86
105
  ###################################################
87
106
  # CLASS METHODS HELPERS
88
107
  ###################################################
89
108
 
90
- # build ancestors list for class methods
91
- def class_ancestors(klass)
92
- list = []
93
-
94
- # in reverse order is easier to add modules in the correct order
95
- # and to avoid redundancy thru Array#|
96
- #
97
- klass.ancestors.reverse.each do |a|
109
+ # build ancestors list for class methods lookup
110
+ def class_ancestors(c)
98
111
 
99
- # get eigenclass ancestors
100
- aa = class << a; self; end
101
-
102
- # add new modules to list
103
- list |= aa.ancestors.reverse
104
-
105
- # add current ancestor to list
106
- list << a
107
- end
112
+ # only classes have superclass
113
+ return c.ancestors if c.instance_of? Module
108
114
 
109
- # reverse to the correct order
110
- list.reverse
111
- end
115
+ list = []
116
+ eigenclass = class << c; self; end
117
+ mod_class = eigenclass.included_modules
112
118
 
113
- def class_owner(mtd)
114
- owner = mtd.owner
115
- return owner if owner.instance_of? Module
116
- ObjectSpace.each_object(owner).to_a.last
117
- end
119
+ while c
118
120
 
119
- # get the superclass of ancestor in the base's ancestors list
120
- def class_super_ancestor(base, ancestor)
121
- ca = class_ancestors(base)
122
- i = ca.index(ancestor)
123
- ca[i + 1] if i
124
- end
121
+ s = c.superclass
122
+ eigensuper = class << s; self; end
125
123
 
126
- # get the class method from superclass of ancestor
127
- # in the base_class' ancestors list
128
- #
129
- def class_super_method(name, base_class, ancestor = base_class)
124
+ # if there's no superclass, consider Kernel as included module;
125
+ # so it won't be added now, but later, in the correct order.
126
+ mod_super = s ? eigensuper.included_modules : [Kernel]
130
127
 
131
- super_class = class_super_ancestor(base_class, ancestor)
128
+ # add eigenclass and its included modules
129
+ # (discarding the ones inherited from superclasses)
130
+ list << eigenclass
131
+ list += mod_class - mod_super
132
132
 
133
- # no super_class!
134
- raise NameError unless super_class
133
+ # rotate values
134
+ c, eigenclass, mod_class = s, eigensuper, mod_super
135
135
 
136
- # get the super method (can throw NameError if it doesn't exist)
137
- super_class.method(name)
138
- end
139
-
140
- def class_super_owner(name, base_class, ancestor)
141
- begin
142
- class_owner(class_super_method(name, base_class, ancestor))
143
- rescue NameError
144
136
  end
137
+
138
+ # finally adds Class's ancestors (including Kernel)
139
+ list += Class.ancestors
145
140
  end
146
141
 
147
142
  end
@@ -200,6 +195,8 @@ class Namebox
200
195
 
201
196
  # save preexisting methods
202
197
  methods_before = get_methods
198
+ $msb = methods_before["Symbol#&"]
199
+ $mob = methods_before["Object#&"]
203
200
 
204
201
  # ###############################################################
205
202
  # RUN THE CODE, which can change the methods of protected modules
@@ -210,13 +207,14 @@ class Namebox
210
207
 
211
208
  # get methods after changes
212
209
  methods_after = get_methods
210
+ $msa = methods_after["Symbol#&"]
211
+ $moa = methods_after["Object#&"]
213
212
 
214
213
  # compare with preexisting data to discover affected methods
215
214
  unless methods_after == methods_before
216
215
 
217
216
  # thru closure, this namebox will be useful inside redefined methods
218
217
  this_nb = self
219
-
220
218
  methods_after.each do |fullname, info|
221
219
 
222
220
  # get old method
@@ -230,9 +228,11 @@ class Namebox
230
228
  # method was modified! take some info
231
229
  name = info[:name]
232
230
  klass = info[:class]
231
+ is_instance = info[:is_instance]
232
+ old_owner = old_m && old_m.owner
233
233
 
234
234
  # instance and class methods are managed differently
235
- if info[:instance]
235
+ if is_instance
236
236
 
237
237
  ##########################################################
238
238
  #
@@ -240,19 +240,12 @@ class Namebox
240
240
  #
241
241
  ##########################################################
242
242
 
243
- # use closure to avoid recalculations inside method
244
- old_owner = old_m && old_m.owner
245
-
246
- # owners to skip
247
- new_owners = []
248
- o = new_m.owner
249
- while o && o != old_owner
250
- new_owners << o
251
- o = Namebox.super_owner(name, klass, o)
243
+ # new methods to skip
244
+ new_methods = Namebox.super_methods(name, klass, is_instance,
245
+ old_owner, new_m) do |sm|
246
+ sm != old_m
252
247
  end
253
248
 
254
- ## print "#{klass}##{name}: "; p new_owners;
255
-
256
249
  # redefine the method, which will check namebox visibility dinamically
257
250
  klass.send :define_method, name do |*args, &blk|
258
251
 
@@ -269,18 +262,14 @@ class Namebox
269
262
  # must be dynamic because it can change anytime
270
263
  # (someone can attach a new definition to some ancestor)
271
264
 
272
- begin
273
- # try before owner (after klass - this method)
274
- m = Namebox.super_method(name, klass)
275
-
276
- # skip new owners
277
- while new_owners.include? m.owner
278
- m = Namebox.super_method(name, klass, m.owner)
279
- end
265
+ m = Namebox.super_methods(name, klass, is_instance,
266
+ old_owner, old_m, true) do |sm|
267
+ !new_methods.include?(sm)
268
+ end
280
269
 
281
- rescue NameError
270
+ unless m
282
271
 
283
- # didn't find a different method; raise NoMethodError
272
+ # didn't find a method; raise NoMethodError
284
273
 
285
274
  # if inspect is too big, shorten it
286
275
  obj = self.inspect.to_s
@@ -303,20 +292,13 @@ class Namebox
303
292
  #
304
293
  ##########################################################
305
294
 
306
- # use closure to avoid recalculations inside method
307
- old_owner = old_m && Namebox.class_owner(old_m)
308
-
309
- # owners to skip
310
- new_owners = []
311
- o = Namebox.class_owner(new_m)
312
- while o && o != old_owner
313
- new_owners << o
314
- o = Namebox.class_super_owner(name, klass, o)
295
+ # new methods to skip
296
+ new_methods = Namebox.super_methods(name, klass, is_instance,
297
+ old_owner, new_m) do |sm|
298
+ sm != old_m
315
299
  end
316
300
 
317
- ## print "#{klass.inspect}.#{name}: "; p new_owners;
318
-
319
- # redefine class method thru eigenclass
301
+ # redefine the method thru eigenclass
320
302
  class << klass; self; end.send :define_method, name do |*args, &blk|
321
303
 
322
304
  # check namebox visibility
@@ -330,38 +312,43 @@ class Namebox
330
312
 
331
313
  # search a different method to call
332
314
  # must be dynamic because it can change anytime
333
- # (someone can extend an ancestor with some module)
315
+ # (someone can attach a new definition to some ancestor)
334
316
 
335
- begin
336
- # try before owner (after klass - this method)
337
- m = Namebox.class_super_method(name, klass)
317
+ m = Namebox.super_methods(name, klass, is_instance,
318
+ old_owner, old_m, true) do |sm|
319
+ !new_methods.include?(sm)
320
+ end
338
321
 
339
- # skip new owners
340
- while new_owners.include?(m_owner = Namebox.class_owner(m))
341
- m = Namebox.class_super_method(name, klass, m_owner)
342
- end
322
+ unless m
343
323
 
344
- # bind to self (can throw TypeError in 1.8.7)
345
- m = m.unbind.bind(self)
324
+ # didn't find a method; raise NoMethodError
346
325
 
347
- rescue NameError
326
+ # if inspect is too big, shorten it
327
+ obj = self.inspect.to_s
328
+ obj = obj[0..45] + '...' + obj[-1] if obj.length > 50
348
329
 
349
- # didn't find a different method
350
330
  raise NoMethodError.new("Undefined class method `#{name}' " +
351
- "for #{self}:#{self.class}")
331
+ "for #{obj}:#{self.class}")
332
+ end
333
+
334
+ begin
335
+
336
+ # bind to self (raises TypeError in 1.8.7)
337
+ m = m.bind(self) if m.instance_of? UnboundMethod
352
338
 
353
339
  rescue TypeError
354
340
 
355
341
  # Ruby 1.8.7 does not bind singleton methods to descendant class;
356
- # use current m anyway
342
+ # try to use a pre-bound method
343
+ m = ObjectSpace.each_object(m.owner).to_a.last.method(name)
357
344
 
358
345
  end
359
346
 
360
347
  # run!
361
348
  m.call(*args, &blk)
362
-
363
349
  end
364
350
  end
351
+
365
352
  end
366
353
  end
367
354
  end
@@ -465,7 +452,7 @@ class Namebox
465
452
 
466
453
  c.instance_methods.each do |m|
467
454
  fullname = "#{c}##{m}"
468
- gm[fullname] = {:class => c, :instance => true, :name => m,
455
+ gm[fullname] = {:class => c, :is_instance => true, :name => m,
469
456
  :method => c.instance_method(m) }
470
457
  end
471
458
 
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.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,9 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-11 00:00:00.000000000 Z
12
+ date: 2013-01-15 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description:
14
+ description: ! 'Please, note: this version is very unstable and it''s under tests.
15
+ Came back soon to check new versions with bug fixes.'
15
16
  email: sony.fermino@gmail.com
16
17
  executables: []
17
18
  extensions: []