pry 0.6.8.1 → 0.7.0pre4
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +3 -3
- data/lib/pry.rb +1 -0
- data/lib/pry/commands.rb +136 -64
- data/lib/pry/pry_class.rb +9 -0
- data/lib/pry/pry_instance.rb +23 -6
- data/lib/pry/version.rb +1 -1
- metadata +15 -14
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ require "#{direc}/lib/pry/version"
|
|
8
8
|
CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o")
|
9
9
|
CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o",
|
10
10
|
"ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "**/*#*", "**/*#*.*",
|
11
|
-
"ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake")
|
11
|
+
"ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake", "**/*.rbc")
|
12
12
|
|
13
13
|
def apply_spec_defaults(s)
|
14
14
|
s.name = "pry"
|
@@ -25,8 +25,8 @@ def apply_spec_defaults(s)
|
|
25
25
|
s.homepage = "http://banisterfiend.wordpress.com"
|
26
26
|
s.has_rdoc = 'yard'
|
27
27
|
s.executables = ["pry"]
|
28
|
-
s.files = Dir["ext/**/extconf.rb", "ext/**/*.h", "ext/**/*.c", "lib
|
29
|
-
|
28
|
+
s.files = Dir["ext/**/extconf.rb", "ext/**/*.h", "ext/**/*.c", "lib/**/*", "examples/**/*.rb",
|
29
|
+
"test/*.rb", "test/testrc", "CHANGELOG", "LICENSE", "README.markdown", "Rakefile", ".gemtest"]
|
30
30
|
end
|
31
31
|
|
32
32
|
task :test do
|
data/lib/pry.rb
CHANGED
data/lib/pry/commands.rb
CHANGED
@@ -3,6 +3,11 @@ require "method_source"
|
|
3
3
|
require "pry/command_base"
|
4
4
|
require "pry/pry_instance"
|
5
5
|
|
6
|
+
begin
|
7
|
+
require "pry-doc"
|
8
|
+
rescue LoadError
|
9
|
+
end
|
10
|
+
|
6
11
|
class Pry
|
7
12
|
|
8
13
|
# Default commands used by Pry.
|
@@ -30,44 +35,29 @@ class Pry
|
|
30
35
|
text.split.drop(1).join(' ')
|
31
36
|
end
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
meth_name = meth_name_from_binding.call(target)
|
39
|
-
if !meth_name
|
40
|
-
output.puts "Cannot find containing method. Did you remember to use \`binding.pry\` ?"
|
41
|
-
next
|
42
|
-
end
|
43
|
-
|
44
|
-
check_for_dynamically_defined_method.call(file)
|
45
|
-
|
46
|
-
output.puts "--\nFrom #{file} @ line #{line_num} in #{klass}##{meth_name}:\n--"
|
47
|
-
|
48
|
-
# This method inspired by http://rubygems.org/gems/ir_b
|
49
|
-
File.open(file).each_with_index do |line, index|
|
50
|
-
line_n = index + 1
|
51
|
-
next unless line_n > (line_num - 6)
|
52
|
-
break if line_n > (line_num + 5)
|
53
|
-
if line_n == line_num
|
54
|
-
code =" =>#{line_n.to_s.rjust(3)}: #{line.chomp}"
|
55
|
-
if Pry.color
|
56
|
-
code = CodeRay.scan(code, :ruby).term
|
57
|
-
end
|
58
|
-
output.puts code
|
59
|
-
code
|
38
|
+
get_method_object = lambda do |meth_name, target, options|
|
39
|
+
if options[:M]
|
40
|
+
target.eval("instance_method(:#{meth_name})")
|
41
|
+
elsif options[:m]
|
42
|
+
target.eval("method(:#{meth_name})")
|
60
43
|
else
|
61
|
-
|
62
|
-
|
63
|
-
|
44
|
+
begin
|
45
|
+
target.eval("method(:#{meth_name})")
|
46
|
+
rescue
|
47
|
+
target.eval("instance_method(:#{meth_name})")
|
64
48
|
end
|
65
|
-
output.puts code
|
66
|
-
code
|
67
49
|
end
|
68
|
-
end
|
69
50
|
end
|
70
|
-
|
51
|
+
|
52
|
+
make_header = lambda do |file, line, code_type|
|
53
|
+
header = case code_type
|
54
|
+
when :ruby
|
55
|
+
"--\nFrom #{file} @ line #{line}:\n--"
|
56
|
+
else
|
57
|
+
"--\nFrom Ruby Core (C Method):\n--"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
71
61
|
command "!", "Clear the input buffer. Useful if the parsing process goes wrong and you get stuck in the read loop." do
|
72
62
|
output.puts "Input buffer cleared!"
|
73
63
|
opts[:eval_string].clear
|
@@ -128,6 +118,44 @@ class Pry
|
|
128
118
|
output.puts "Last result: #{Pry.view(Pry.last_result)}"
|
129
119
|
end
|
130
120
|
|
121
|
+
command "whereami", "Show the code context for the session." do
|
122
|
+
file = target.eval('__FILE__')
|
123
|
+
line_num = target.eval('__LINE__')
|
124
|
+
klass = target.eval('self.class')
|
125
|
+
|
126
|
+
meth_name = meth_name_from_binding.call(target)
|
127
|
+
if !meth_name
|
128
|
+
output.puts "Cannot find containing method. Did you remember to use \`binding.pry\` ?"
|
129
|
+
next
|
130
|
+
end
|
131
|
+
|
132
|
+
check_for_dynamically_defined_method.call(file)
|
133
|
+
|
134
|
+
output.puts "--\nFrom #{file} @ line #{line_num} in #{klass}##{meth_name}:\n--"
|
135
|
+
|
136
|
+
# This method inspired by http://rubygems.org/gems/ir_b
|
137
|
+
File.open(file).each_with_index do |line, index|
|
138
|
+
line_n = index + 1
|
139
|
+
next unless line_n > (line_num - 6)
|
140
|
+
break if line_n > (line_num + 5)
|
141
|
+
if line_n == line_num
|
142
|
+
code =" =>#{line_n.to_s.rjust(3)}: #{line.chomp}"
|
143
|
+
if Pry.color
|
144
|
+
code = CodeRay.scan(code, :ruby).term
|
145
|
+
end
|
146
|
+
output.puts code
|
147
|
+
code
|
148
|
+
else
|
149
|
+
code = "#{line_n.to_s.rjust(6)}: #{line.chomp}"
|
150
|
+
if Pry.color
|
151
|
+
code = CodeRay.scan(code, :ruby).term
|
152
|
+
end
|
153
|
+
output.puts code
|
154
|
+
code
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
131
159
|
command "version", "Show Pry version." do
|
132
160
|
output.puts "Pry version: #{Pry::VERSION} on Ruby #{RUBY_VERSION}."
|
133
161
|
end
|
@@ -190,6 +218,10 @@ Shows local and instance variables by default.
|
|
190
218
|
|
191
219
|
opts.on("-p", "--private", "Display private methods (with -m).") do
|
192
220
|
options[:p] = true
|
221
|
+
end
|
222
|
+
|
223
|
+
opts.on("-j", "--just-singletons", "Display just the singleton methods (with -m).") do
|
224
|
+
options[:j] = true
|
193
225
|
end
|
194
226
|
|
195
227
|
opts.on("-s", "--super", "Include superclass entries (relevant to constant and methods options).") do
|
@@ -224,7 +256,7 @@ Shows local and instance variables by default.
|
|
224
256
|
}) if options.empty? || (options.size == 1 && options[:v])
|
225
257
|
|
226
258
|
# Display public methods by default if -m or -M switch is used.
|
227
|
-
options[:P] = true if (options[:m] || options[:M]) && !(options[:p] || options[:r])
|
259
|
+
options[:P] = true if (options[:m] || options[:M]) && !(options[:p] || options[:r] || options[:j])
|
228
260
|
|
229
261
|
info = {}
|
230
262
|
target_self = target.eval('self')
|
@@ -253,6 +285,8 @@ Shows local and instance variables by default.
|
|
253
285
|
info["protected methods"] = [Array(target.eval("protected_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:r]) || options[:a]
|
254
286
|
|
255
287
|
info["private methods"] = [Array(target.eval("private_methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:p]) || options[:a]
|
288
|
+
|
289
|
+
info["just singleton methods"] = [Array(target.eval("methods(#{options[:s]})")).sort, i += 1] if (options[:m] && options[:j]) || options[:a]
|
256
290
|
|
257
291
|
info["public instance methods"] = [Array(target.eval("public_instance_methods(#{options[:s]})")).uniq.sort, i += 1] if target_self.is_a?(Module) && ((options[:M] && options[:P]) || options[:a])
|
258
292
|
|
@@ -288,6 +322,7 @@ Shows local and instance variables by default.
|
|
288
322
|
# plain
|
289
323
|
else
|
290
324
|
list = info.values.sort_by { |v| v.last }.map { |v| v.first }.inject(&:+)
|
325
|
+
list.uniq! if list
|
291
326
|
if Pry.color
|
292
327
|
output.puts CodeRay.scan(Pry.view(list), :ruby).term
|
293
328
|
else
|
@@ -374,11 +409,24 @@ e.g: eval-file -c self "hello.rb"
|
|
374
409
|
if obj == "/"
|
375
410
|
throw(:breakout, 1) if opts[:nesting].level > 0
|
376
411
|
next
|
377
|
-
end
|
412
|
+
end
|
378
413
|
|
379
414
|
target.eval("#{obj}.pry")
|
380
415
|
end
|
381
416
|
|
417
|
+
# FIXME!!! the last matcher doesn't work on "+nil+ or +false+", it
|
418
|
+
# doesn't accurately strip the +
|
419
|
+
process_comment_markup = lambda do |comment, code_type|
|
420
|
+
comment.gsub(/<code>(?:\s*\n)?(.*?)\s*<\/code>/m) { Pry.color ? CodeRay.scan($1, code_type).term : $1 }.
|
421
|
+
gsub(/<em>(?:\s*\n)?(.*?)\s*<\/em>/m) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }.
|
422
|
+
gsub(/<i>(?:\s*\n)?(.*?)\s*<\/i>/m) { Pry.color ? "\e[34m#{$1}\e[0m" : $1 }.
|
423
|
+
gsub(/\B\+(.*)\+\B/) { Pry.color ? "\e[32m#{$1}\e[0m": $1 }
|
424
|
+
end
|
425
|
+
|
426
|
+
strip_leading_hash_from_ruby_comments = lambda do |comment|
|
427
|
+
comment.gsub /^\s*#\s*/, ''
|
428
|
+
end
|
429
|
+
|
382
430
|
command "show-doc", "Show the comments above METH. Type `show-doc --help` for more info." do |*args|
|
383
431
|
options = {}
|
384
432
|
target = target()
|
@@ -390,10 +438,14 @@ Show the comments above method METH. Shows _method_ comments (rather than instan
|
|
390
438
|
e.g show-doc hello_method
|
391
439
|
--
|
392
440
|
}
|
393
|
-
opts.on("-M", "--instance-methods", "Operate on instance methods
|
441
|
+
opts.on("-M", "--instance-methods", "Operate on instance methods.") do
|
394
442
|
options[:M] = true
|
395
443
|
end
|
396
444
|
|
445
|
+
opts.on("-m", "--methods", "Operate on methods.") do
|
446
|
+
options[:m] = true
|
447
|
+
end
|
448
|
+
|
397
449
|
opts.on("-c", "--context CONTEXT", "Select object context to run under.") do |context|
|
398
450
|
target = Pry.binding_for(target.eval(context))
|
399
451
|
end
|
@@ -414,30 +466,41 @@ e.g show-doc hello_method
|
|
414
466
|
end
|
415
467
|
|
416
468
|
begin
|
417
|
-
|
418
|
-
meth = target.eval("instance_method(:#{meth_name})")
|
419
|
-
else
|
420
|
-
meth = target.eval("method(:#{meth_name})")
|
421
|
-
end
|
469
|
+
meth = get_method_object.call(meth_name, target, options)
|
422
470
|
rescue
|
423
471
|
output.puts "Invalid method name: #{meth_name}. Type `show-doc --help` for help"
|
424
472
|
next
|
425
473
|
end
|
426
474
|
|
427
|
-
|
475
|
+
code_type = :ruby
|
476
|
+
|
477
|
+
if Pry.has_pry_doc && meth.source_location.nil?
|
478
|
+
info = Pry::MethodInfo.info_for(meth)
|
479
|
+
if !info
|
480
|
+
output.puts "Cannot find docs for C method: #{meth_name}"
|
481
|
+
next
|
482
|
+
end
|
483
|
+
doc = info.docstring
|
484
|
+
code_type = info.source_type
|
485
|
+
else
|
486
|
+
doc = strip_leading_hash_from_ruby_comments.call(meth.comment)
|
487
|
+
end
|
488
|
+
|
489
|
+
doc = process_comment_markup.call(doc, code_type)
|
490
|
+
|
428
491
|
file, line = meth.source_location
|
429
492
|
check_for_dynamically_defined_method.call(file)
|
430
493
|
|
431
|
-
output.puts
|
432
|
-
|
433
|
-
if Pry.color
|
434
|
-
doc = CodeRay.scan(doc, :ruby).term
|
435
|
-
end
|
436
|
-
|
494
|
+
output.puts make_header.call(file, line, code_type)
|
495
|
+
|
437
496
|
output.puts doc
|
438
497
|
doc
|
439
498
|
end
|
440
499
|
|
500
|
+
strip_comments_from_c_code = lambda do |code|
|
501
|
+
code.sub /\A\s*\/\*.*?\*\/\s*/m, ''
|
502
|
+
end
|
503
|
+
|
441
504
|
command "show-method", "Show the source for METH. Type `show-method --help` for more info." do |*args|
|
442
505
|
options = {}
|
443
506
|
target = target()
|
@@ -449,10 +512,14 @@ Show the source for method METH. Shows _method_ source (rather than instance met
|
|
449
512
|
e.g: show-method hello_method
|
450
513
|
--
|
451
514
|
}
|
452
|
-
opts.on("-M", "--instance-methods", "Operate on instance methods
|
515
|
+
opts.on("-M", "--instance-methods", "Operate on instance methods.") do
|
453
516
|
options[:M] = true
|
454
517
|
end
|
455
518
|
|
519
|
+
opts.on("-m", "--methods", "Operate on methods.") do
|
520
|
+
options[:m] = true
|
521
|
+
end
|
522
|
+
|
456
523
|
opts.on("-c", "--context CONTEXT", "Select object context to run under.") do |context|
|
457
524
|
target = Pry.binding_for(target.eval(context))
|
458
525
|
end
|
@@ -469,36 +536,41 @@ e.g: show-method hello_method
|
|
469
536
|
|
470
537
|
# If no method name is given then use current method, if it exists
|
471
538
|
meth_name = meth_name_from_binding.call(target) if !meth_name
|
472
|
-
|
473
539
|
if !meth_name
|
474
540
|
output.puts "You need to specify a method. Type `show-method --help` for help"
|
475
541
|
next
|
476
542
|
end
|
477
543
|
|
478
544
|
begin
|
479
|
-
|
480
|
-
meth = target.eval("instance_method(:#{meth_name})")
|
481
|
-
else
|
482
|
-
meth = target.eval("method(:#{meth_name})")
|
483
|
-
end
|
545
|
+
meth = get_method_object.call(meth_name, target, options)
|
484
546
|
rescue
|
485
|
-
target_self = target.eval('self')
|
486
|
-
if !options[:M]&& target_self.is_a?(Module) &&
|
487
|
-
target_self.method_defined?(meth_name)
|
488
|
-
output.puts "Did you mean: show-method -M #{meth_name} ?"
|
489
|
-
end
|
490
547
|
output.puts "Invalid method name: #{meth_name}. Type `show-method --help` for help"
|
491
548
|
next
|
492
549
|
end
|
493
550
|
|
494
|
-
|
551
|
+
code_type = :ruby
|
552
|
+
|
553
|
+
# Try to find source for C methods using MethodInfo (if possible)
|
554
|
+
if Pry.has_pry_doc && meth.source_location.nil?
|
555
|
+
info = Pry::MethodInfo.info_for(meth)
|
556
|
+
if !info
|
557
|
+
output.puts "Cannot find source for C method: #{meth_name}"
|
558
|
+
next
|
559
|
+
end
|
560
|
+
code = info.source
|
561
|
+
code = strip_comments_from_c_code.call(code)
|
562
|
+
code_type = info.source_type
|
563
|
+
else
|
564
|
+
code = meth.source
|
565
|
+
end
|
566
|
+
|
495
567
|
file, line = meth.source_location
|
496
568
|
check_for_dynamically_defined_method.call(file)
|
497
569
|
|
498
|
-
output.puts
|
570
|
+
output.puts make_header.call(file, line, code_type)
|
499
571
|
|
500
572
|
if Pry.color
|
501
|
-
code = CodeRay.scan(code,
|
573
|
+
code = CodeRay.scan(code, code_type).term
|
502
574
|
end
|
503
575
|
|
504
576
|
output.puts code
|
data/lib/pry/pry_class.rb
CHANGED
@@ -17,6 +17,11 @@ class Pry
|
|
17
17
|
# @return [Object] The last result.
|
18
18
|
attr_accessor :last_result
|
19
19
|
|
20
|
+
# Get last exception raised.
|
21
|
+
# This method should not need to be accessed directly.
|
22
|
+
# @return [Exception] The last exception.
|
23
|
+
attr_accessor :last_exception
|
24
|
+
|
20
25
|
# Get the active Pry instance that manages the active Pry session.
|
21
26
|
# This method should not need to be accessed directly.
|
22
27
|
# @return [Pry] The active Pry instance.
|
@@ -73,6 +78,10 @@ class Pry
|
|
73
78
|
# Set to true if Pry is invoked from command line using `pry` executable
|
74
79
|
# @return [Boolean]
|
75
80
|
attr_accessor :cli
|
81
|
+
|
82
|
+
# Set to true if the pry-doc extension is loaded.
|
83
|
+
# @return [Boolean]
|
84
|
+
attr_accessor :has_pry_doc
|
76
85
|
end
|
77
86
|
|
78
87
|
# Load the rc files given in the `Pry::RC_FILES` array.
|
data/lib/pry/pry_instance.rb
CHANGED
@@ -135,19 +135,20 @@ class Pry
|
|
135
135
|
Readline.completion_proc = Pry::InputCompleter.build_completion_proc(target, commands.commands.keys)
|
136
136
|
end
|
137
137
|
|
138
|
-
# eval the expression and save to last_result
|
139
|
-
Pry.last_result = target.eval r(target), __FILE__, __LINE__
|
140
138
|
|
141
139
|
# save the pry instance to active_instance
|
142
140
|
Pry.active_instance = self
|
143
|
-
|
144
|
-
# define locals _pry_ and _ (active instance and last expression)
|
145
141
|
target.eval("_pry_ = Pry.active_instance")
|
146
|
-
|
142
|
+
|
143
|
+
# eval the expression and save to last_result
|
144
|
+
# Do not want __FILE__, __LINE__ here because we need to distinguish
|
145
|
+
# (eval) methods for show-method and friends.
|
146
|
+
# This also sets the `_` local for the session.
|
147
|
+
set_last_result(target.eval(r(target)), target)
|
147
148
|
rescue SystemExit => e
|
148
149
|
exit
|
149
150
|
rescue Exception => e
|
150
|
-
e
|
151
|
+
set_last_exception(e, target)
|
151
152
|
end
|
152
153
|
|
153
154
|
# Perform a read.
|
@@ -188,6 +189,22 @@ class Pry
|
|
188
189
|
end
|
189
190
|
end
|
190
191
|
|
192
|
+
# Set the last result of an eval.
|
193
|
+
# @param [Object] result The result.
|
194
|
+
# @param [Binding] target The binding to set `_` on.
|
195
|
+
def set_last_result(result, target)
|
196
|
+
Pry.last_result = result
|
197
|
+
target.eval("_ = Pry.last_result")
|
198
|
+
end
|
199
|
+
|
200
|
+
# Set the last exception for a session.
|
201
|
+
# @param [Exception] ex The exception.
|
202
|
+
# @param [Binding] target The binding to set `_ex_` on.
|
203
|
+
def set_last_exception(ex, target)
|
204
|
+
Pry.last_exception = ex
|
205
|
+
target.eval("_ex_ = Pry.last_exception")
|
206
|
+
end
|
207
|
+
|
191
208
|
# Process Pry commands. Pry commands are not Ruby methods and are evaluated
|
192
209
|
# prior to Ruby expressions.
|
193
210
|
# Commands can be modified/configured by the user: see `Pry::Commands`
|
data/lib/pry/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: -766259871
|
5
|
+
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
|
11
|
-
version: 0.6.8.1
|
8
|
+
- 7
|
9
|
+
- 0pre4
|
10
|
+
version: 0.7.0pre4
|
12
11
|
platform: ruby
|
13
12
|
authors:
|
14
13
|
- John Mair (banisterfiend)
|
@@ -16,7 +15,7 @@ autorequire:
|
|
16
15
|
bindir: bin
|
17
16
|
cert_chain: []
|
18
17
|
|
19
|
-
date: 2011-03-
|
18
|
+
date: 2011-03-15 00:00:00 +13:00
|
20
19
|
default_executable:
|
21
20
|
dependencies:
|
22
21
|
- !ruby/object:Gem::Dependency
|
@@ -92,7 +91,6 @@ extensions: []
|
|
92
91
|
extra_rdoc_files: []
|
93
92
|
|
94
93
|
files:
|
95
|
-
- lib/pry.rb
|
96
94
|
- lib/pry/commands.rb
|
97
95
|
- lib/pry/version.rb
|
98
96
|
- lib/pry/command_base.rb
|
@@ -103,6 +101,7 @@ files:
|
|
103
101
|
- lib/pry/print.rb
|
104
102
|
- lib/pry/pry_class.rb
|
105
103
|
- lib/pry/pry_instance.rb
|
104
|
+
- lib/pry.rb
|
106
105
|
- examples/example_commands.rb
|
107
106
|
- examples/example_image_edit.rb
|
108
107
|
- examples/example_input2.rb
|
@@ -122,7 +121,7 @@ files:
|
|
122
121
|
- Rakefile
|
123
122
|
- .gemtest
|
124
123
|
- bin/pry
|
125
|
-
has_rdoc:
|
124
|
+
has_rdoc: yard
|
126
125
|
homepage: http://banisterfiend.wordpress.com
|
127
126
|
licenses: []
|
128
127
|
|
@@ -143,16 +142,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
143
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
143
|
none: false
|
145
144
|
requirements:
|
146
|
-
- - "
|
145
|
+
- - ">"
|
147
146
|
- !ruby/object:Gem::Version
|
148
|
-
hash:
|
147
|
+
hash: 25
|
149
148
|
segments:
|
150
|
-
-
|
151
|
-
|
149
|
+
- 1
|
150
|
+
- 3
|
151
|
+
- 1
|
152
|
+
version: 1.3.1
|
152
153
|
requirements: []
|
153
154
|
|
154
155
|
rubyforge_project:
|
155
|
-
rubygems_version: 1.
|
156
|
+
rubygems_version: 1.3.7
|
156
157
|
signing_key:
|
157
158
|
specification_version: 3
|
158
159
|
summary: attach an irb-like session to any object at runtime
|