ruby-nuggets 0.2.5.256 → 0.2.6.257
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.
- data/README +1 -1
- data/lib/nuggets/util/added_methods.rb +248 -241
- data/lib/nuggets/util/added_methods/init.rb +2 -2
- data/lib/nuggets/version.rb +1 -1
- metadata +2 -2
data/README
CHANGED
@@ -1,323 +1,330 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
# - multi-line statements in irb (extract_source)
|
6
|
-
# - polishing!
|
7
|
-
|
8
|
-
require 'ruby2ruby'
|
9
|
-
|
10
|
-
module AddedMethods
|
1
|
+
begin
|
2
|
+
require 'ruby2ruby'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
11
5
|
|
12
|
-
|
6
|
+
module Util
|
13
7
|
|
14
|
-
|
8
|
+
# Watch for added methods and record them. Inspired by unroller,
|
9
|
+
# <http://unroller.rubyforge.org/classes/Unroller.html#M000034>.
|
10
|
+
#
|
11
|
+
# TODO:
|
12
|
+
# - multi-line statements in irb w/o ruby2ruby? (=> extract_source)
|
13
|
+
# - polishing!
|
15
14
|
|
16
|
-
|
15
|
+
module AddedMethods
|
17
16
|
|
18
|
-
|
19
|
-
update(*args) unless args.empty?
|
20
|
-
end
|
17
|
+
extend self
|
21
18
|
|
22
|
-
|
23
|
-
return unless Object.const_defined?(:SCRIPT_LINES__)
|
24
|
-
return unless script_lines = SCRIPT_LINES__[file]
|
19
|
+
HISTFILENAME = '(Readline::HISTORY)'.freeze
|
25
20
|
|
26
|
-
|
21
|
+
class AddedMethod < Hash
|
27
22
|
|
28
|
-
|
29
|
-
|
23
|
+
def initialize(*args)
|
24
|
+
update(*args) unless args.empty?
|
25
|
+
end
|
30
26
|
|
31
|
-
num_lines
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
def extract_source(num_lines = nil)
|
28
|
+
return unless Object.const_defined?(:SCRIPT_LINES__)
|
29
|
+
return unless script_lines = SCRIPT_LINES__[file]
|
30
|
+
|
31
|
+
start, from, to = line - 1, line, script_lines.size - 1
|
32
|
+
|
33
|
+
# suppose we're already in a block
|
34
|
+
in_block = 1
|
35
|
+
|
36
|
+
num_lines ||= case definition = script_lines[start]
|
37
|
+
# def ... end, or do ... end style block
|
38
|
+
when /\b(?:def|do)\b/
|
39
|
+
definition =~ /\bend\b/ ? 1 : begin
|
40
|
+
from.upto(to) { |i|
|
41
|
+
case line = script_lines[i]
|
42
|
+
when /[^;\s]\s+(?:if|unless)\b/
|
43
|
+
# probably postfix conditional, ignore
|
44
|
+
when /\b(?:if|unless|while|until|def|do)\b/
|
45
|
+
in_block += 1
|
46
|
+
when /\bend\b/
|
47
|
+
in_block -= 1
|
48
|
+
end
|
49
|
+
|
50
|
+
break i - start + 1 if in_block.zero?
|
51
|
+
}
|
52
|
+
end
|
53
|
+
# { ... } style block
|
54
|
+
when /\bdefine_method\b/
|
35
55
|
from.upto(to) { |i|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
in_block += 1
|
41
|
-
when /\bend\b/
|
42
|
-
in_block -= 1
|
43
|
-
end
|
56
|
+
line = script_lines[i]
|
57
|
+
|
58
|
+
in_block += line.count('{')
|
59
|
+
in_block -= line.count('}')
|
44
60
|
|
45
61
|
break i - start + 1 if in_block.zero?
|
46
62
|
}
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
from.upto(to) { |i|
|
51
|
-
line = script_lines[i]
|
63
|
+
else
|
64
|
+
1
|
65
|
+
end
|
52
66
|
|
53
|
-
|
54
|
-
in_block -= line.count('}')
|
67
|
+
lines = script_lines[start, num_lines]
|
55
68
|
|
56
|
-
|
57
|
-
|
69
|
+
# try to make sure we correctly extracted the method definition
|
70
|
+
if lines.first =~ /\b#{name}\b/ || !Object.const_defined?(:Ruby2Ruby)
|
71
|
+
lines
|
58
72
|
else
|
59
|
-
|
73
|
+
# use Ruby2Ruby as a last resort. but note that it only
|
74
|
+
# ever finds the *latest*, i.e. currently active, method
|
75
|
+
# definition, not necessarily the one we're looking for.
|
76
|
+
"#### [R2R] ####\n#{Ruby2Ruby.translate(klass, name)}"
|
77
|
+
end
|
60
78
|
end
|
61
79
|
|
62
|
-
|
63
|
-
|
64
|
-
# try to make sure we correctly extracted the method definition
|
65
|
-
if lines.first =~ /\b#{name}\b/
|
66
|
-
lines
|
67
|
-
else
|
68
|
-
# use Ruby2Ruby as a last resort. but note that it only
|
69
|
-
# ever finds the *latest*, i.e. currently active, method
|
70
|
-
# definition, not necessarily the one we're looking for.
|
71
|
-
"#### [R2R] ####\n#{Ruby2Ruby.translate(klass, name)}"
|
80
|
+
def to_s(num_lines = nil)
|
81
|
+
"# File #{file}, line #{line}\n#{extract_source(num_lines).map { |l| " #{l}" }}"
|
72
82
|
end
|
73
|
-
end
|
74
83
|
|
75
|
-
|
76
|
-
|
77
|
-
|
84
|
+
def klass
|
85
|
+
self[:class]
|
86
|
+
end
|
78
87
|
|
79
|
-
|
80
|
-
|
81
|
-
|
88
|
+
def method_missing(method, *args)
|
89
|
+
has_key?(method) ? self[method] : super
|
90
|
+
end
|
82
91
|
|
83
|
-
def method_missing(method, *args)
|
84
|
-
has_key?(method) ? self[method] : super
|
85
92
|
end
|
86
93
|
|
87
|
-
|
94
|
+
def init(regexp = nil, klasses = [], &block)
|
95
|
+
init_script_lines
|
96
|
+
patch_readline_history
|
88
97
|
|
89
|
-
|
90
|
-
|
91
|
-
|
98
|
+
define_callback(:__init, regexp, klasses, &block) if regexp
|
99
|
+
install_callbacks
|
100
|
+
end
|
92
101
|
|
93
|
-
|
94
|
-
|
95
|
-
|
102
|
+
def callbacks
|
103
|
+
init_callbacks
|
104
|
+
CALLBACKS
|
105
|
+
end
|
96
106
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
107
|
+
def callback(*args, &inner_block)
|
108
|
+
callback_args = [identify_added_method(*args << caller), caller, inner_block]
|
109
|
+
callbacks.each { |name, callback| callback[*callback_args] }
|
110
|
+
end
|
101
111
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
112
|
+
def define_callback(name, regexp = //, klasses = [], &outer_block)
|
113
|
+
raise TypeError, "wrong argument type #{name.class} (expected Symbol)" unless name.is_a?(Symbol)
|
114
|
+
raise "callback with name #{name} already exists" if callbacks.any? { |n, _| n == name }
|
106
115
|
|
107
|
-
|
108
|
-
|
109
|
-
raise "callback with name #{name} already exists" if callbacks.any? { |n, _| n == name }
|
116
|
+
raise TypeError, "wrong argument type #{regexp.class} (expected Regexp)" unless regexp.is_a?(Regexp)
|
117
|
+
raise TypeError, "wrong argument type #{klasses.class} (expected container object)" unless klasses.respond_to?(:empty?) && klasses.respond_to?(:include?)
|
110
118
|
|
111
|
-
|
112
|
-
|
119
|
+
callbacks << [name, lambda { |am, callstack, inner_block|
|
120
|
+
method, klass = am.values_at(:name, :class)
|
113
121
|
|
114
|
-
|
115
|
-
method, klass = am.values_at(:name, :class)
|
122
|
+
return if %w[method_added singleton_method_added].include?(method)
|
116
123
|
|
117
|
-
|
124
|
+
return unless klasses.empty? || klasses.include?(klass.to_s)
|
125
|
+
return unless method =~ regexp
|
118
126
|
|
119
|
-
|
120
|
-
|
127
|
+
if outer_block || inner_block
|
128
|
+
outer_block[am] if outer_block
|
129
|
+
inner_block[am] if inner_block
|
130
|
+
else
|
131
|
+
msg = "[#{am.base}] Adding #{'singleton ' if am.singleton}method #{klass}##{method}"
|
121
132
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
133
|
+
msg << if irb?(callstack)
|
134
|
+
" in (irb:#{IRB.conf[:MAIN_CONTEXT].instance_variable_get(:@line_no)})"
|
135
|
+
else
|
136
|
+
" at #{where(callstack)}"
|
137
|
+
end
|
127
138
|
|
128
|
-
|
129
|
-
" in (irb:#{IRB.conf[:MAIN_CONTEXT].instance_variable_get(:@line_no)})"
|
130
|
-
else
|
131
|
-
" at #{where(callstack)}"
|
139
|
+
puts msg
|
132
140
|
end
|
141
|
+
}]
|
142
|
+
end
|
133
143
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
def remove_callback(name)
|
140
|
-
callbacks.delete_if { |n, _| n == name }
|
141
|
-
end
|
144
|
+
def remove_callback(name)
|
145
|
+
callbacks.delete_if { |n, _| n == name }
|
146
|
+
end
|
142
147
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
148
|
+
def replace_callback(name, regexp = nil, klasses = [], &outer_block)
|
149
|
+
remove_callback(name)
|
150
|
+
define_callback(name, regexp, klasses, &outer_block)
|
151
|
+
end
|
147
152
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
+
def install_callbacks(bases = [Object, Class, Module, Kernel])
|
154
|
+
bases.each { |base|
|
155
|
+
[base, singleton_class(base)].each { |b|
|
156
|
+
b.send(:define_method, :method_added) { |id| AddedMethods.callback(b, self, id, false) }
|
157
|
+
b.send(:define_method, :singleton_method_added) { |id| AddedMethods.callback(b, self, id, true) }
|
158
|
+
}
|
153
159
|
}
|
154
|
-
|
155
|
-
end
|
160
|
+
end
|
156
161
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
162
|
+
def all_methods
|
163
|
+
init_all_methods
|
164
|
+
ALL_METHODS
|
165
|
+
end
|
161
166
|
|
162
|
-
|
163
|
-
|
167
|
+
def find(conditions = {})
|
168
|
+
conditions = conditions.dup
|
164
169
|
|
165
|
-
|
166
|
-
|
170
|
+
class_condition = conditions.delete(:class)
|
171
|
+
file_condition = conditions.delete(:file)
|
167
172
|
|
168
|
-
|
173
|
+
results = []
|
169
174
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
end
|
174
|
-
|
175
|
-
files.each { |file, entries|
|
176
|
-
if file_condition
|
177
|
-
next unless file_condition.is_a?(Regexp) ? file =~ file_condition : file == file_condition
|
175
|
+
all_methods.each { |klass, files|
|
176
|
+
if class_condition
|
177
|
+
next unless class_condition.is_a?(Array) ? class_condition.include?(klass) : klass == class_condition
|
178
178
|
end
|
179
179
|
|
180
|
-
|
181
|
-
|
182
|
-
:
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
180
|
+
files.each { |file, entries|
|
181
|
+
if file_condition
|
182
|
+
next unless file_condition.is_a?(Regexp) ? file =~ file_condition : file == file_condition
|
183
|
+
end
|
184
|
+
|
185
|
+
entries.each { |entry|
|
186
|
+
results << entry.merge(
|
187
|
+
:class => klass,
|
188
|
+
:file => file
|
189
|
+
) if conditions.all? { |key, value|
|
190
|
+
case value
|
191
|
+
when Array: value.include?(entry[key])
|
192
|
+
when Regexp: entry[key].to_s =~ value
|
193
|
+
else entry[key] == value
|
194
|
+
end
|
195
|
+
}
|
190
196
|
}
|
191
197
|
}
|
192
198
|
}
|
193
|
-
}
|
194
199
|
|
195
|
-
|
196
|
-
|
200
|
+
results
|
201
|
+
end
|
197
202
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
203
|
+
def find_by_class(*classes)
|
204
|
+
conditions = classes.last.is_a?(Hash) ? classes.pop : {}
|
205
|
+
find(conditions.merge(:class => classes))
|
206
|
+
end
|
202
207
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
208
|
+
def find_by_name(*names)
|
209
|
+
conditions = names.last.is_a?(Hash) ? names.pop : {}
|
210
|
+
names.inject([]) { |memo, name|
|
211
|
+
memo += find(conditions.merge(:name => name.to_s))
|
212
|
+
}
|
213
|
+
end
|
209
214
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
215
|
+
def find_one_by_name_or_class(name_or_class, conditions = {})
|
216
|
+
(name_or_class.is_a?(Class) ?
|
217
|
+
find_by_class(name_or_class) :
|
218
|
+
find_by_name(name_or_class)
|
219
|
+
).last
|
220
|
+
end
|
216
221
|
|
217
|
-
|
222
|
+
alias_method :[], :find_one_by_name_or_class
|
218
223
|
|
219
|
-
|
224
|
+
private
|
220
225
|
|
221
|
-
|
222
|
-
|
223
|
-
|
226
|
+
def singleton_class(klass = self)
|
227
|
+
class << klass; self; end
|
228
|
+
end
|
224
229
|
|
225
|
-
|
226
|
-
|
227
|
-
|
230
|
+
def init_script_lines
|
231
|
+
unless Object.const_defined?(:SCRIPT_LINES__)
|
232
|
+
Object.const_set(:SCRIPT_LINES__, {})
|
233
|
+
end
|
228
234
|
end
|
229
|
-
end
|
230
235
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
236
|
+
def init_callbacks
|
237
|
+
unless const_defined?(:CALLBACKS)
|
238
|
+
const_set(:CALLBACKS, [])
|
239
|
+
define_callback(:__default, //, [], &added_method_callback)
|
240
|
+
end
|
235
241
|
end
|
236
|
-
end
|
237
242
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
243
|
+
def init_all_methods
|
244
|
+
unless const_defined?(:ALL_METHODS)
|
245
|
+
const_set(:ALL_METHODS, Hash.new { |h, k|
|
246
|
+
h[k] = Hash.new { |i, j|
|
247
|
+
i[j] = []
|
248
|
+
}
|
249
|
+
})
|
250
|
+
end
|
245
251
|
end
|
246
|
-
end
|
247
252
|
|
248
|
-
|
249
|
-
|
250
|
-
|
253
|
+
def patch_readline_history
|
254
|
+
return unless have_readline_history?
|
255
|
+
return if Readline::HISTORY.respond_to?(:_added_methods_original_push)
|
251
256
|
|
252
|
-
|
253
|
-
|
257
|
+
class << Readline::HISTORY
|
258
|
+
alias_method :_added_methods_original_push, :push
|
254
259
|
|
255
|
-
|
256
|
-
|
257
|
-
|
260
|
+
def push(l)
|
261
|
+
(SCRIPT_LINES__[HISTFILENAME] ||= Readline::HISTORY.to_a) << l
|
262
|
+
_added_methods_original_push(l)
|
263
|
+
end
|
264
|
+
|
265
|
+
alias_method :<<, :push
|
258
266
|
end
|
267
|
+
end
|
259
268
|
|
260
|
-
|
269
|
+
def have_readline_history?
|
270
|
+
Object.const_defined?(:Readline) && Readline.const_defined?(:HISTORY)
|
261
271
|
end
|
262
|
-
end
|
263
272
|
|
264
|
-
|
265
|
-
|
266
|
-
end
|
273
|
+
def defined_in_irb?(callstack)
|
274
|
+
callstack = callstack.dup
|
267
275
|
|
268
|
-
|
269
|
-
|
276
|
+
callstack.shift # ignore immediate caller
|
277
|
+
callstack.reject! { |c| c =~ /\(irb\):|:in `irb_binding'/ }
|
278
|
+
callstack.pop if callstack.last =~ %r{/irb/workspace\.rb:}
|
270
279
|
|
271
|
-
|
272
|
-
|
273
|
-
callstack.pop if callstack.last =~ %r{/irb/workspace\.rb:}
|
280
|
+
callstack.empty?
|
281
|
+
end
|
274
282
|
|
275
|
-
callstack
|
276
|
-
|
283
|
+
def irb?(callstack)
|
284
|
+
have_readline_history? && defined_in_irb?(callstack)
|
285
|
+
end
|
277
286
|
|
278
|
-
|
279
|
-
|
280
|
-
|
287
|
+
def where(callstack, default = '(none):0')
|
288
|
+
callstack.find { |i| i !~ /:in `.*'/ } || callstack[1] || default
|
289
|
+
end
|
281
290
|
|
282
|
-
|
283
|
-
|
284
|
-
|
291
|
+
def added_method_callback
|
292
|
+
lambda { |am| add_method(am) }
|
293
|
+
end
|
285
294
|
|
286
|
-
|
287
|
-
|
288
|
-
|
295
|
+
def add_method(am)
|
296
|
+
am = AddedMethod.new(am) unless am.is_a?(AddedMethod)
|
297
|
+
all_methods[am.klass][am.file] << am
|
298
|
+
end
|
289
299
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
300
|
+
def identify_added_method(base, klass, id, singleton, callstack)
|
301
|
+
am = {
|
302
|
+
:base => base,
|
303
|
+
:class => klass,
|
304
|
+
:name => id.id2name,
|
305
|
+
:singleton => singleton
|
306
|
+
}
|
307
|
+
|
308
|
+
if irb?(callstack)
|
309
|
+
am.update(
|
310
|
+
:file => HISTFILENAME,
|
311
|
+
:line => Readline::HISTORY.size,
|
312
|
+
:source => begin Readline::HISTORY[-1] rescue IndexError end
|
313
|
+
)
|
314
|
+
else
|
315
|
+
file, line, _ = where(callstack).split(':')
|
316
|
+
line = line.to_i
|
317
|
+
|
318
|
+
am.update(
|
319
|
+
:file => file,
|
320
|
+
:line => line,
|
321
|
+
:source => (SCRIPT_LINES__[file] || [])[line - 1]
|
322
|
+
)
|
323
|
+
end
|
294
324
|
|
295
|
-
|
296
|
-
am = {
|
297
|
-
:base => base,
|
298
|
-
:class => klass,
|
299
|
-
:name => id.id2name,
|
300
|
-
:singleton => singleton
|
301
|
-
}
|
302
|
-
|
303
|
-
if irb?(callstack)
|
304
|
-
am.update(
|
305
|
-
:file => HISTFILENAME,
|
306
|
-
:line => Readline::HISTORY.size,
|
307
|
-
:source => begin Readline::HISTORY[-1] rescue IndexError end
|
308
|
-
)
|
309
|
-
else
|
310
|
-
file, line, _ = where(callstack).split(':')
|
311
|
-
line = line.to_i
|
312
|
-
|
313
|
-
am.update(
|
314
|
-
:file => file,
|
315
|
-
:line => line,
|
316
|
-
:source => (SCRIPT_LINES__[file] || [])[line - 1]
|
317
|
-
)
|
325
|
+
AddedMethod.new(am)
|
318
326
|
end
|
319
327
|
|
320
|
-
AddedMethod.new(am)
|
321
328
|
end
|
322
329
|
|
323
330
|
end
|
@@ -1,3 +1,3 @@
|
|
1
1
|
# just a short-cut
|
2
|
-
require
|
3
|
-
AddedMethods.init
|
2
|
+
require File.dirname(__FILE__)
|
3
|
+
Util::AddedMethods.init
|
data/lib/nuggets/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-nuggets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6.257
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jens Wille
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-07-
|
12
|
+
date: 2008-07-23 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|