namebox 0.0.2 → 0.0.3

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 +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: []