pry 0.1.0
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/CHANGELOG +3 -0
- data/README.markdown +133 -0
- data/Rakefile +58 -0
- data/lib/pry.rb +101 -0
- data/lib/pry/version.rb +3 -0
- metadata +82 -0
data/CHANGELOG
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
Pry
|
2
|
+
=============
|
3
|
+
|
4
|
+
(C) John Mair (banisterfiend) 2010
|
5
|
+
|
6
|
+
_attach an irb-like session to any object_
|
7
|
+
|
8
|
+
Pry is a simple Ruby REPL that specializes in the interactive
|
9
|
+
manipulation of objects during the running of a program.
|
10
|
+
|
11
|
+
* Install the [gem](https://rubygems.org/gems/pry): `gem install pry`
|
12
|
+
* Read the [documentation](http://rdoc.info/github/banister/pry/master/file/README.markdown)
|
13
|
+
* See the [source code](http://github.com/banister/pry)
|
14
|
+
|
15
|
+
example: prying on an object at runtime
|
16
|
+
---------------------------------------
|
17
|
+
|
18
|
+
With the `Pry.into()` method we can pry (open an irb-like session) on
|
19
|
+
an object. In the example below we open a Pry session for the `Test` class and execute a method and add
|
20
|
+
an instance variable. The program is halted for the duration of the session.
|
21
|
+
|
22
|
+
require 'pry'
|
23
|
+
|
24
|
+
class Test
|
25
|
+
def self.hello() "hello world" end
|
26
|
+
end
|
27
|
+
|
28
|
+
Pry.into(Test)
|
29
|
+
|
30
|
+
# Pry session begins on stdin
|
31
|
+
Beginning Pry session for Test
|
32
|
+
pry(Test)> self
|
33
|
+
=> Test
|
34
|
+
pry(Test)> hello
|
35
|
+
=> "hello world"
|
36
|
+
pry(Test)> @y = 20
|
37
|
+
=> 20
|
38
|
+
pry(Test)> exit
|
39
|
+
Ending Pry session for Test
|
40
|
+
|
41
|
+
# program resumes here
|
42
|
+
|
43
|
+
If we now inspect the `Test` object we can see our changes have had
|
44
|
+
effect:
|
45
|
+
|
46
|
+
Test.instance_variable_get(:@y) #=> 20
|
47
|
+
|
48
|
+
|
49
|
+
example: Pry sessions can nest arbitrarily deep so we can pry on objects inside objects:
|
50
|
+
----------------------------------------------------------------------------------------
|
51
|
+
|
52
|
+
Here we will begin Pry at top-level, then pry on a class and then on
|
53
|
+
an instance variable inside that class:
|
54
|
+
|
55
|
+
# Pry.into() without parameters begins a Pry session on top-level (main)
|
56
|
+
Pry.into
|
57
|
+
Beginning Pry session for main
|
58
|
+
pry(main)> class Hello
|
59
|
+
pry(main)* @x = 20
|
60
|
+
pry(main)* end
|
61
|
+
=> 20
|
62
|
+
pry(main)> Pry.into Hello
|
63
|
+
Beginning Pry session for Hello
|
64
|
+
pry(Hello)> instance_variables
|
65
|
+
=> [:@x]
|
66
|
+
pry(Hello)> Pry.into @x
|
67
|
+
Beginning Pry session for 20
|
68
|
+
pry(20)> self + 10
|
69
|
+
=> 30
|
70
|
+
pry(20)> exit
|
71
|
+
Ending Pry session for 20
|
72
|
+
pry(Hello)> exit
|
73
|
+
Ending Pry session for Hello
|
74
|
+
pry(main)> exit
|
75
|
+
Ending Pry session for main
|
76
|
+
|
77
|
+
# program resumes here
|
78
|
+
|
79
|
+
|
80
|
+
example: Spawn a separate thread so you can use `Pry` to manipulate an
|
81
|
+
object without halting the program.
|
82
|
+
---------------------------------------------------------------------------------------------------
|
83
|
+
|
84
|
+
If we embed our `Pry.into` method inside its own thread we can examine
|
85
|
+
and manipulate objects without halting the program.
|
86
|
+
|
87
|
+
# Pry.into() without parameters opens up the top-level (main)
|
88
|
+
Thread.new { Pry.into }
|
89
|
+
|
90
|
+
|
91
|
+
Features and limitations
|
92
|
+
------------------------
|
93
|
+
|
94
|
+
Pry is an irb-like clone with an emphasis on interactively examining
|
95
|
+
and manipulating objects during the running of a program.
|
96
|
+
|
97
|
+
Its primary utility is probably in debugging, though it may have other
|
98
|
+
uses (such as implementing a quake-like console for games, for example). Here is a
|
99
|
+
list of Pry's features along with some of its limitations given at the
|
100
|
+
end.
|
101
|
+
|
102
|
+
Features:
|
103
|
+
|
104
|
+
* Pry can be invoked at any time and on any object in the running program.
|
105
|
+
* Pry sessions can nest arbitrarily deeply -- to go back one level of nesting type 'exit' or 'quit'
|
106
|
+
* Pry has multi-line support built in.
|
107
|
+
* Pry implements all the methods in the REPL chain separately: `Pry.r`
|
108
|
+
for reading; `Pry.re` for eval; `Pry.rep` for printing; and `Pry.repl`
|
109
|
+
for the loop (`Pry.into` is simply an alias for `Pry.repl`). You can
|
110
|
+
invoke any of these methods directly depending on exactly what aspect of the functionality you need.
|
111
|
+
|
112
|
+
Limitations:
|
113
|
+
|
114
|
+
* Pry does not pretend to be a replacement for `irb`,
|
115
|
+
and so does not have an executable. It is designed to be used by
|
116
|
+
other programs, not on its own. For a full-featured `irb` replacement
|
117
|
+
see [ripl](https://github.com/cldwalker/ripl)
|
118
|
+
* Although Pry works fine in Ruby 1.9, only Ruby 1.8 syntax is
|
119
|
+
supported. This is because Pry uses the
|
120
|
+
[RubyParser](https://github.com/seattlerb/ruby_parser)
|
121
|
+
gem internally to validate expressions, and RubyParser, as yet, only parses Ruby 1.8
|
122
|
+
code. In practice this usually just means you cannot use the new
|
123
|
+
hash literal syntax (this: syntax) or the 'stabby lambda' syntax
|
124
|
+
(->).
|
125
|
+
|
126
|
+
|
127
|
+
Contact
|
128
|
+
-------
|
129
|
+
|
130
|
+
Problems or questions contact me at [github](http://github.com/banister)
|
131
|
+
|
132
|
+
|
133
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
dlext = Config::CONFIG['DLEXT']
|
2
|
+
direc = File.dirname(__FILE__)
|
3
|
+
|
4
|
+
require 'rake/clean'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require "#{direc}/lib/pry/version"
|
7
|
+
|
8
|
+
CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o")
|
9
|
+
CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o",
|
10
|
+
"ext/**/*~", "ext/**/*#*", "ext/**/*.obj",
|
11
|
+
"ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake")
|
12
|
+
|
13
|
+
def apply_spec_defaults(s)
|
14
|
+
s.name = "pry"
|
15
|
+
s.summary = "attach an irb-like session to any object"
|
16
|
+
s.version = Pry::VERSION
|
17
|
+
s.date = Time.now.strftime '%Y-%m-%d'
|
18
|
+
s.author = "John Mair (banisterfiend)"
|
19
|
+
s.email = 'jrmair@gmail.com'
|
20
|
+
s.description = s.summary
|
21
|
+
s.require_path = 'lib'
|
22
|
+
s.add_dependency("ruby_parser",">=2.0.5")
|
23
|
+
s.homepage = "http://banisterfiend.wordpress.com"
|
24
|
+
s.has_rdoc = 'yard'
|
25
|
+
s.files = Dir["ext/**/extconf.rb", "ext/**/*.h", "ext/**/*.c", "lib/**/*.rb",
|
26
|
+
"test/*.rb", "CHANGELOG", "README.markdown", "Rakefile"]
|
27
|
+
end
|
28
|
+
|
29
|
+
task :test do
|
30
|
+
sh "bacon -k #{direc}/test/test.rb"
|
31
|
+
end
|
32
|
+
|
33
|
+
namespace :ruby do
|
34
|
+
spec = Gem::Specification.new do |s|
|
35
|
+
apply_spec_defaults(s)
|
36
|
+
s.platform = Gem::Platform::RUBY
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
40
|
+
pkg.need_zip = false
|
41
|
+
pkg.need_tar = false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "build all platform gems at once"
|
46
|
+
task :gems => [:rmgems, "ruby:gem"]
|
47
|
+
|
48
|
+
desc "remove all platform gems"
|
49
|
+
task :rmgems => ["ruby:clobber_package"]
|
50
|
+
|
51
|
+
desc "build and push latest gems"
|
52
|
+
task :pushgems => :gems do
|
53
|
+
chdir("#{direc}/pkg") do
|
54
|
+
Dir["*.gem"].each do |gemfile|
|
55
|
+
sh "gem push #{gemfile}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/pry.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'readline'
|
3
|
+
require 'ruby_parser'
|
4
|
+
|
5
|
+
module Pry
|
6
|
+
class << self
|
7
|
+
attr_accessor :default_prompt, :wait_prompt,
|
8
|
+
:session_start_msg, :session_end_msg
|
9
|
+
end
|
10
|
+
|
11
|
+
@default_prompt = proc { |v| "pry(#{v})> " }
|
12
|
+
@wait_prompt = proc { |v| "pry(#{v})* " }
|
13
|
+
@session_start_msg = proc { |v| "Beginning Pry session for #{v}" }
|
14
|
+
@session_end_msg = proc { |v| "Ending Pry session for #{v}" }
|
15
|
+
|
16
|
+
# loop
|
17
|
+
def self.repl(target=TOPLEVEL_BINDING)
|
18
|
+
if !target.is_a?(Binding)
|
19
|
+
target = target.instance_eval { binding }
|
20
|
+
end
|
21
|
+
|
22
|
+
puts session_start_msg.call(target.eval('self'))
|
23
|
+
|
24
|
+
loop do
|
25
|
+
if catch(:pop) { rep(target) } == :return
|
26
|
+
break target.eval('self')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
puts session_end_msg.call(target.eval('self'))
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
alias_method :into, :repl
|
35
|
+
alias_method :start, :repl
|
36
|
+
end
|
37
|
+
|
38
|
+
# print
|
39
|
+
def self.rep(target=TOPLEVEL_BINDING)
|
40
|
+
if !target.is_a?(Binding)
|
41
|
+
target = target.instance_eval { binding }
|
42
|
+
end
|
43
|
+
|
44
|
+
value = re(target)
|
45
|
+
case value
|
46
|
+
when Exception
|
47
|
+
puts "#{value.class}: #{value.message}"
|
48
|
+
else
|
49
|
+
puts "=> #{value.inspect}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# eval
|
54
|
+
def self.re(target=TOPLEVEL_BINDING)
|
55
|
+
target.eval r(target)
|
56
|
+
rescue StandardError => e
|
57
|
+
e
|
58
|
+
end
|
59
|
+
|
60
|
+
# read
|
61
|
+
def self.r(target=TOPLEVEL_BINDING)
|
62
|
+
eval_string = ""
|
63
|
+
loop do
|
64
|
+
val = Readline.readline(prompt(eval_string, target), true)
|
65
|
+
eval_string += "#{val}\n"
|
66
|
+
process_commands(val, eval_string, target)
|
67
|
+
|
68
|
+
break eval_string if valid_expression?(eval_string)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.process_commands(val, eval_string, target)
|
73
|
+
case val
|
74
|
+
when "#exit", "#quit"
|
75
|
+
exit
|
76
|
+
when "!"
|
77
|
+
eval_string.replace("")
|
78
|
+
puts "Refreshed REPL."
|
79
|
+
when "exit", "quit"
|
80
|
+
throw(:pop, :return)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.prompt(eval_string, target)
|
85
|
+
context = target.eval('self')
|
86
|
+
|
87
|
+
if eval_string.empty?
|
88
|
+
default_prompt.call(context)
|
89
|
+
else
|
90
|
+
wait_prompt.call(context)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.valid_expression?(code)
|
95
|
+
RubyParser.new.parse(code)
|
96
|
+
rescue Racc::ParseError
|
97
|
+
false
|
98
|
+
else
|
99
|
+
true
|
100
|
+
end
|
101
|
+
end
|
data/lib/pry/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pry
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- John Mair (banisterfiend)
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-09 00:00:00 +13:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: ruby_parser
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 2
|
30
|
+
- 0
|
31
|
+
- 5
|
32
|
+
version: 2.0.5
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: attach an irb-like session to any object
|
36
|
+
email: jrmair@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- lib/pry/version.rb
|
45
|
+
- lib/pry.rb
|
46
|
+
- CHANGELOG
|
47
|
+
- README.markdown
|
48
|
+
- Rakefile
|
49
|
+
has_rdoc: yard
|
50
|
+
homepage: http://banisterfiend.wordpress.com
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.3.7
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: attach an irb-like session to any object
|
81
|
+
test_files: []
|
82
|
+
|