pry 0.9.10pre1-i386-mingw32 → 0.9.11-i386-mingw32
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/.travis.yml +3 -1
- data/CHANGELOG +63 -2
- data/CONTRIBUTORS +43 -25
- data/Gemfile +7 -0
- data/Guardfile +62 -0
- data/README.markdown +4 -4
- data/Rakefile +34 -35
- data/lib/pry.rb +107 -54
- data/lib/pry/cli.rb +34 -11
- data/lib/pry/code.rb +165 -182
- data/lib/pry/code/code_range.rb +70 -0
- data/lib/pry/code/loc.rb +92 -0
- data/lib/pry/code_object.rb +153 -0
- data/lib/pry/command.rb +160 -22
- data/lib/pry/command_set.rb +37 -26
- data/lib/pry/commands.rb +4 -27
- data/lib/pry/commands/amend_line.rb +99 -0
- data/lib/pry/commands/bang.rb +20 -0
- data/lib/pry/commands/bang_pry.rb +17 -0
- data/lib/pry/commands/cat.rb +53 -0
- data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
- data/lib/pry/commands/cat/exception_formatter.rb +78 -0
- data/lib/pry/commands/cat/file_formatter.rb +84 -0
- data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
- data/lib/pry/commands/cd.rb +30 -0
- data/lib/pry/commands/code_collector.rb +165 -0
- data/lib/pry/commands/deprecated_commands.rb +2 -0
- data/lib/pry/commands/disable_pry.rb +27 -0
- data/lib/pry/commands/easter_eggs.rb +112 -0
- data/lib/pry/commands/edit.rb +206 -0
- data/lib/pry/commands/edit/exception_patcher.rb +25 -0
- data/lib/pry/commands/edit/file_and_line_locator.rb +38 -0
- data/lib/pry/commands/edit/method_patcher.rb +122 -0
- data/lib/pry/commands/exit.rb +42 -0
- data/lib/pry/commands/exit_all.rb +29 -0
- data/lib/pry/commands/exit_program.rb +24 -0
- data/lib/pry/commands/find_method.rb +199 -0
- data/lib/pry/commands/fix_indent.rb +19 -0
- data/lib/pry/commands/gem_cd.rb +26 -0
- data/lib/pry/commands/gem_install.rb +29 -0
- data/lib/pry/commands/gem_list.rb +33 -0
- data/lib/pry/commands/gem_open.rb +29 -0
- data/lib/pry/commands/gist.rb +95 -0
- data/lib/pry/commands/help.rb +164 -0
- data/lib/pry/commands/hist.rb +161 -0
- data/lib/pry/commands/import_set.rb +22 -0
- data/lib/pry/commands/install_command.rb +51 -0
- data/lib/pry/commands/jump_to.rb +29 -0
- data/lib/pry/commands/ls.rb +339 -0
- data/lib/pry/commands/nesting.rb +25 -0
- data/lib/pry/commands/play.rb +69 -0
- data/lib/pry/commands/pry_backtrace.rb +26 -0
- data/lib/pry/commands/pry_version.rb +17 -0
- data/lib/pry/commands/raise_up.rb +32 -0
- data/lib/pry/commands/reload_code.rb +39 -0
- data/lib/pry/commands/reset.rb +18 -0
- data/lib/pry/commands/ri.rb +56 -0
- data/lib/pry/commands/save_file.rb +61 -0
- data/lib/pry/commands/shell_command.rb +43 -0
- data/lib/pry/commands/shell_mode.rb +27 -0
- data/lib/pry/commands/show_doc.rb +78 -0
- data/lib/pry/commands/show_info.rb +139 -0
- data/lib/pry/commands/show_input.rb +17 -0
- data/lib/pry/commands/show_source.rb +37 -0
- data/lib/pry/commands/simple_prompt.rb +22 -0
- data/lib/pry/commands/stat.rb +40 -0
- data/lib/pry/commands/switch_to.rb +23 -0
- data/lib/pry/commands/toggle_color.rb +20 -0
- data/lib/pry/commands/whereami.rb +114 -0
- data/lib/pry/commands/wtf.rb +57 -0
- data/lib/pry/completion.rb +120 -46
- data/lib/pry/config.rb +11 -0
- data/lib/pry/core_extensions.rb +30 -19
- data/lib/pry/editor.rb +129 -0
- data/lib/pry/helpers.rb +1 -0
- data/lib/pry/helpers/base_helpers.rb +89 -119
- data/lib/pry/helpers/command_helpers.rb +7 -122
- data/lib/pry/helpers/table.rb +100 -0
- data/lib/pry/helpers/text.rb +4 -4
- data/lib/pry/history_array.rb +5 -0
- data/lib/pry/hooks.rb +1 -3
- data/lib/pry/indent.rb +104 -30
- data/lib/pry/method.rb +66 -22
- data/lib/pry/module_candidate.rb +26 -15
- data/lib/pry/pager.rb +70 -0
- data/lib/pry/plugins.rb +1 -2
- data/lib/pry/pry_class.rb +63 -22
- data/lib/pry/pry_instance.rb +58 -37
- data/lib/pry/rubygem.rb +74 -0
- data/lib/pry/terminal_info.rb +43 -0
- data/lib/pry/test/helper.rb +185 -0
- data/lib/pry/version.rb +1 -1
- data/lib/pry/wrapped_module.rb +58 -24
- data/pry.gemspec +21 -37
- data/{test/test_cli.rb → spec/cli_spec.rb} +0 -0
- data/spec/code_object_spec.rb +277 -0
- data/{test/test_code.rb → spec/code_spec.rb} +19 -1
- data/{test/test_command_helpers.rb → spec/command_helpers_spec.rb} +0 -0
- data/{test/test_command_integration.rb → spec/command_integration_spec.rb} +38 -46
- data/{test/test_command_set.rb → spec/command_set_spec.rb} +18 -1
- data/{test/test_command.rb → spec/command_spec.rb} +250 -149
- data/spec/commands/amend_line_spec.rb +247 -0
- data/spec/commands/bang_spec.rb +19 -0
- data/spec/commands/cat_spec.rb +164 -0
- data/spec/commands/cd_spec.rb +250 -0
- data/spec/commands/disable_pry_spec.rb +25 -0
- data/spec/commands/edit_spec.rb +727 -0
- data/spec/commands/exit_all_spec.rb +34 -0
- data/spec/commands/exit_program_spec.rb +19 -0
- data/spec/commands/exit_spec.rb +34 -0
- data/{test/test_default_commands/test_find_method.rb → spec/commands/find_method_spec.rb} +27 -7
- data/spec/commands/gem_list_spec.rb +26 -0
- data/spec/commands/gist_spec.rb +75 -0
- data/{test/test_default_commands/test_help.rb → spec/commands/help_spec.rb} +8 -9
- data/spec/commands/hist_spec.rb +181 -0
- data/spec/commands/jump_to_spec.rb +15 -0
- data/spec/commands/ls_spec.rb +177 -0
- data/spec/commands/play_spec.rb +140 -0
- data/spec/commands/raise_up_spec.rb +56 -0
- data/spec/commands/save_file_spec.rb +177 -0
- data/spec/commands/show_doc_spec.rb +378 -0
- data/spec/commands/show_input_spec.rb +17 -0
- data/spec/commands/show_source_spec.rb +597 -0
- data/spec/commands/whereami_spec.rb +154 -0
- data/spec/completion_spec.rb +233 -0
- data/spec/control_d_handler_spec.rb +58 -0
- data/spec/editor_spec.rb +79 -0
- data/{test/test_exception_whitelist.rb → spec/exception_whitelist_spec.rb} +0 -0
- data/{test → spec/fixtures}/candidate_helper1.rb +0 -0
- data/{test → spec/fixtures}/candidate_helper2.rb +0 -0
- data/{test/test_default_commands → spec/fixtures}/example.erb +0 -0
- data/spec/fixtures/example_nesting.rb +33 -0
- data/spec/fixtures/show_source_doc_examples.rb +15 -0
- data/{test → spec/fixtures}/testrc +0 -0
- data/{test → spec/fixtures}/testrcbad +0 -0
- data/spec/helper.rb +34 -0
- data/spec/helpers/bacon.rb +86 -0
- data/spec/helpers/mock_pry.rb +43 -0
- data/spec/helpers/table_spec.rb +83 -0
- data/{test/test_history_array.rb → spec/history_array_spec.rb} +21 -19
- data/{test/test_hooks.rb → spec/hooks_spec.rb} +0 -0
- data/{test/test_indent.rb → spec/indent_spec.rb} +24 -0
- data/{test/test_input_stack.rb → spec/input_stack_spec.rb} +4 -0
- data/{test/test_method.rb → spec/method_spec.rb} +65 -1
- data/{test/test_prompt.rb → spec/prompt_spec.rb} +0 -0
- data/{test/test_pry_defaults.rb → spec/pry_defaults_spec.rb} +14 -14
- data/{test/test_pry_history.rb → spec/pry_history_spec.rb} +15 -0
- data/spec/pry_output_spec.rb +95 -0
- data/{test/test_pry.rb → spec/pry_spec.rb} +74 -32
- data/{test/test_sticky_locals.rb → spec/sticky_locals_spec.rb} +27 -25
- data/{test/test_syntax_checking.rb → spec/syntax_checking_spec.rb} +17 -1
- data/{test/test_wrapped_module.rb → spec/wrapped_module_spec.rb} +92 -5
- metadata +239 -115
- data/examples/example_basic.rb +0 -15
- data/examples/example_command_override.rb +0 -32
- data/examples/example_commands.rb +0 -36
- data/examples/example_hooks.rb +0 -9
- data/examples/example_image_edit.rb +0 -67
- data/examples/example_input.rb +0 -7
- data/examples/example_input2.rb +0 -29
- data/examples/example_output.rb +0 -11
- data/examples/example_print.rb +0 -6
- data/examples/example_prompt.rb +0 -9
- data/examples/helper.rb +0 -6
- data/lib/pry/default_commands/cd.rb +0 -81
- data/lib/pry/default_commands/commands.rb +0 -62
- data/lib/pry/default_commands/context.rb +0 -98
- data/lib/pry/default_commands/easter_eggs.rb +0 -95
- data/lib/pry/default_commands/editing.rb +0 -420
- data/lib/pry/default_commands/find_method.rb +0 -169
- data/lib/pry/default_commands/gems.rb +0 -84
- data/lib/pry/default_commands/gist.rb +0 -187
- data/lib/pry/default_commands/help.rb +0 -127
- data/lib/pry/default_commands/hist.rb +0 -120
- data/lib/pry/default_commands/input_and_output.rb +0 -306
- data/lib/pry/default_commands/introspection.rb +0 -410
- data/lib/pry/default_commands/ls.rb +0 -272
- data/lib/pry/default_commands/misc.rb +0 -38
- data/lib/pry/default_commands/navigating_pry.rb +0 -110
- data/lib/pry/default_commands/whereami.rb +0 -92
- data/lib/pry/extended_commands/experimental.rb +0 -7
- data/test/helper.rb +0 -223
- data/test/test_completion.rb +0 -62
- data/test/test_control_d_handler.rb +0 -45
- data/test/test_default_commands/test_cd.rb +0 -321
- data/test/test_default_commands/test_context.rb +0 -288
- data/test/test_default_commands/test_documentation.rb +0 -315
- data/test/test_default_commands/test_gems.rb +0 -18
- data/test/test_default_commands/test_input.rb +0 -428
- data/test/test_default_commands/test_introspection.rb +0 -511
- data/test/test_default_commands/test_ls.rb +0 -151
- data/test/test_default_commands/test_shell.rb +0 -343
- data/test/test_default_commands/test_show_source.rb +0 -432
- data/test/test_pry_output.rb +0 -41
@@ -0,0 +1,206 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::Edit < Pry::ClassCommand
|
3
|
+
require 'pry/commands/edit/method_patcher'
|
4
|
+
require 'pry/commands/edit/exception_patcher'
|
5
|
+
require 'pry/commands/edit/file_and_line_locator'
|
6
|
+
|
7
|
+
match 'edit'
|
8
|
+
group 'Editing'
|
9
|
+
description 'Invoke the default editor on a file.'
|
10
|
+
|
11
|
+
banner <<-'BANNER'
|
12
|
+
Usage: edit [--no-reload|--reload|--patch] [--line LINE] [--temp|--ex|FILE[:LINE]|OBJECT|--in N]
|
13
|
+
|
14
|
+
Open a text editor. When no FILE is given, edits the pry input buffer. Ensure
|
15
|
+
`Pry.config.editor` is set to your editor of choice.
|
16
|
+
|
17
|
+
edit sample.rb edit -p MyClass#my_method
|
18
|
+
edit sample.rb --line 105 edit YourClass
|
19
|
+
edit MyClass#my_method edit --ex
|
20
|
+
edit --method edit --ex -p
|
21
|
+
|
22
|
+
https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_command
|
23
|
+
BANNER
|
24
|
+
|
25
|
+
def options(opt)
|
26
|
+
opt.on :e, :ex, "Open the file that raised the most recent exception (_ex_.file)",
|
27
|
+
:optional_argument => true, :as => Integer
|
28
|
+
opt.on :i, :in, "Open a temporary file containing the Nth input expression. N may be a range",
|
29
|
+
:optional_argument => true, :as => Range, :default => -1..-1
|
30
|
+
opt.on :t, :temp, "Open an empty temporary file"
|
31
|
+
opt.on :l, :line, "Jump to this line in the opened file",
|
32
|
+
:argument => true, :as => Integer
|
33
|
+
opt.on :n, :"no-reload", "Don't automatically reload the edited code"
|
34
|
+
opt.on :c, :current, "Open the current __FILE__ and at __LINE__ (as returned by `whereami`)"
|
35
|
+
opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)"
|
36
|
+
opt.on :p, :patch, "Instead of editing the object's file, try to edit in a tempfile and apply as a monkey patch"
|
37
|
+
opt.on :m, :method, "Explicitly edit the _current_ method (when inside a method context)."
|
38
|
+
end
|
39
|
+
|
40
|
+
def process
|
41
|
+
if bad_option_combination?
|
42
|
+
raise CommandError, "Only one of --ex, --temp, --in, --method and FILE may be specified."
|
43
|
+
end
|
44
|
+
|
45
|
+
if repl_edit?
|
46
|
+
# code defined in pry, eval'd within pry.
|
47
|
+
repl_edit
|
48
|
+
elsif runtime_patch?
|
49
|
+
# patch code without persisting changes
|
50
|
+
apply_runtime_patch
|
51
|
+
else
|
52
|
+
# code stored in actual files, eval'd at top-level
|
53
|
+
file_edit
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def repl_edit?
|
58
|
+
!opts.present?(:ex) && !opts.present?(:current) && !opts.present?(:method) &&
|
59
|
+
filename_argument.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def repl_edit
|
63
|
+
content = Pry::Editor.edit_tempfile_with_content(initial_temp_file_content,
|
64
|
+
initial_temp_file_content.lines.count)
|
65
|
+
if repl_reload?
|
66
|
+
silence_warnings do
|
67
|
+
eval_string.replace content
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def file_based_exception?
|
73
|
+
opts.present?(:ex) && !opts.present?(:patch)
|
74
|
+
end
|
75
|
+
|
76
|
+
def runtime_patch?
|
77
|
+
!file_based_exception? && (opts.present?(:patch) || pry_method?(code_object))
|
78
|
+
end
|
79
|
+
|
80
|
+
def apply_runtime_patch
|
81
|
+
if patch_exception?
|
82
|
+
ExceptionPatcher.new(_pry_, state, file_and_line_for_current_exception).perform_patch
|
83
|
+
else
|
84
|
+
if code_object.is_a?(Pry::Method)
|
85
|
+
MethodPatcher.new(_pry_, code_object).perform_patch
|
86
|
+
else
|
87
|
+
raise NotImplementedError, "Cannot yet patch #{code_object} objects!"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def ensure_file_name_is_valid(file_name)
|
93
|
+
raise CommandError, "Cannot find a valid file for #{filename_argument}" if !file_name
|
94
|
+
raise CommandError, "#{file_name} is not a valid file name, cannot edit!" if not_a_real_file?(file_name)
|
95
|
+
end
|
96
|
+
|
97
|
+
def file_and_line_for_current_exception
|
98
|
+
FileAndLineLocator.from_exception(_pry_.last_exception, opts[:ex].to_i)
|
99
|
+
end
|
100
|
+
|
101
|
+
def file_and_line
|
102
|
+
file_name, line = if opts.present?(:current)
|
103
|
+
FileAndLineLocator.from_binding(target)
|
104
|
+
elsif opts.present?(:ex)
|
105
|
+
file_and_line_for_current_exception
|
106
|
+
elsif code_object
|
107
|
+
FileAndLineLocator.from_code_object(code_object, filename_argument)
|
108
|
+
else
|
109
|
+
# when file and line are passed as a single arg, e.g my_file.rb:30
|
110
|
+
FileAndLineLocator.from_filename_argument(filename_argument)
|
111
|
+
end
|
112
|
+
|
113
|
+
[file_name, opts.present?(:line) ? opts[:l].to_i : line]
|
114
|
+
end
|
115
|
+
|
116
|
+
def file_edit
|
117
|
+
file_name, line = file_and_line
|
118
|
+
|
119
|
+
ensure_file_name_is_valid(file_name)
|
120
|
+
|
121
|
+
Pry::Editor.invoke_editor(file_name, line, reload?(file_name))
|
122
|
+
set_file_and_dir_locals(file_name)
|
123
|
+
|
124
|
+
if reload?(file_name)
|
125
|
+
silence_warnings do
|
126
|
+
TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def filename_argument
|
132
|
+
args.join(' ')
|
133
|
+
end
|
134
|
+
|
135
|
+
def code_object
|
136
|
+
@code_object ||= !probably_a_file?(filename_argument) &&
|
137
|
+
Pry::CodeObject.lookup(filename_argument, _pry_)
|
138
|
+
end
|
139
|
+
|
140
|
+
def pry_method?(code_object)
|
141
|
+
code_object.is_a?(Pry::Method) &&
|
142
|
+
code_object.pry_method?
|
143
|
+
end
|
144
|
+
|
145
|
+
def patch_exception?
|
146
|
+
opts.present?(:ex) && opts.present?(:patch)
|
147
|
+
end
|
148
|
+
|
149
|
+
def bad_option_combination?
|
150
|
+
[opts.present?(:ex), opts.present?(:temp),
|
151
|
+
opts.present?(:in), opts.present?(:method), !filename_argument.empty?].count(true) > 1
|
152
|
+
end
|
153
|
+
|
154
|
+
def input_expression
|
155
|
+
case opts[:i]
|
156
|
+
when Range
|
157
|
+
(_pry_.input_array[opts[:i]] || []).join
|
158
|
+
when Fixnum
|
159
|
+
_pry_.input_array[opts[:i]] || ""
|
160
|
+
else
|
161
|
+
raise Pry::CommandError, "Not a valid range: #{opts[:i]}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def reloadable?
|
166
|
+
opts.present?(:reload) || opts.present?(:ex)
|
167
|
+
end
|
168
|
+
|
169
|
+
def never_reload?
|
170
|
+
opts.present?(:'no-reload') || Pry.config.disable_auto_reload
|
171
|
+
end
|
172
|
+
|
173
|
+
# conditions much less strict than for reload? (which is for file-based reloads)
|
174
|
+
def repl_reload?
|
175
|
+
!never_reload?
|
176
|
+
end
|
177
|
+
|
178
|
+
def reload?(file_name="")
|
179
|
+
(reloadable? || file_name.end_with?(".rb")) && !never_reload?
|
180
|
+
end
|
181
|
+
|
182
|
+
def initial_temp_file_content
|
183
|
+
case
|
184
|
+
when opts.present?(:temp)
|
185
|
+
""
|
186
|
+
when opts.present?(:in)
|
187
|
+
input_expression
|
188
|
+
when eval_string.strip != ""
|
189
|
+
eval_string
|
190
|
+
else
|
191
|
+
_pry_.input_array.reverse_each.find { |x| x && x.strip != "" } || ""
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def probably_a_file?(str)
|
196
|
+
[".rb", ".c", ".py", ".yml", ".gemspec"].include? File.extname(str) ||
|
197
|
+
str =~ /\/|\\/
|
198
|
+
end
|
199
|
+
|
200
|
+
def complete(search)
|
201
|
+
super + Bond::Rc.files(search.split(" ").last || '')
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
Pry::Commands.add_command(Pry::Command::Edit)
|
206
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::Edit
|
3
|
+
class ExceptionPatcher
|
4
|
+
attr_accessor :_pry_
|
5
|
+
attr_accessor :state
|
6
|
+
attr_accessor :file_and_line
|
7
|
+
|
8
|
+
def initialize(_pry_, state, exception_file_and_line)
|
9
|
+
@_pry_ = _pry_
|
10
|
+
@state = state
|
11
|
+
@file_and_line = exception_file_and_line
|
12
|
+
end
|
13
|
+
|
14
|
+
# perform the patch
|
15
|
+
def perform_patch
|
16
|
+
file_name, line = file_and_line
|
17
|
+
lines = state.dynamical_ex_file || File.read(file_name)
|
18
|
+
|
19
|
+
source = Pry::Editor.edit_tempfile_with_content(lines)
|
20
|
+
_pry_.evaluate_ruby source
|
21
|
+
state.dynamical_ex_file = source.split("\n")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::Edit
|
3
|
+
module FileAndLineLocator
|
4
|
+
class << self
|
5
|
+
def from_binding(target)
|
6
|
+
[target.eval("__FILE__"), target.eval("__LINE__")]
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_code_object(code_object, filename_argument)
|
10
|
+
if File.exists?(code_object.source_file.to_s)
|
11
|
+
[code_object.source_file, code_object.source_line]
|
12
|
+
else
|
13
|
+
raise CommandError, "Cannot find a file for #{filename_argument}!"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def from_exception(exception, backtrace_level)
|
18
|
+
raise CommandError, "No exception found." if exception.nil?
|
19
|
+
|
20
|
+
file_name, line = exception.bt_source_location_for(backtrace_level)
|
21
|
+
raise CommandError, "Exception has no associated file." if file_name.nil?
|
22
|
+
raise CommandError, "Cannot edit exceptions raised in REPL." if Pry.eval_path == file_name
|
23
|
+
|
24
|
+
file_name = RbxPath.convert_path_to_full(file_name) if RbxPath.is_core_path?(file_name)
|
25
|
+
|
26
|
+
[file_name, line]
|
27
|
+
end
|
28
|
+
|
29
|
+
# when file and line are passed as a single arg, e.g my_file.rb:30
|
30
|
+
def from_filename_argument(filename_argument)
|
31
|
+
f = File.expand_path(filename_argument)
|
32
|
+
l = f.sub!(/:(\d+)$/, "") ? $1.to_i : 1
|
33
|
+
[f, l]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::Edit
|
3
|
+
class MethodPatcher
|
4
|
+
attr_accessor :_pry_
|
5
|
+
attr_accessor :code_object
|
6
|
+
|
7
|
+
def initialize(_pry_, code_object)
|
8
|
+
@_pry_ = _pry_
|
9
|
+
@code_object = code_object
|
10
|
+
end
|
11
|
+
|
12
|
+
# perform the patch
|
13
|
+
def perform_patch
|
14
|
+
if code_object.alias?
|
15
|
+
with_method_transaction do
|
16
|
+
_pry_.evaluate_ruby patched_code
|
17
|
+
end
|
18
|
+
else
|
19
|
+
_pry_.evaluate_ruby patched_code
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def patched_code
|
26
|
+
@patched_code ||= wrap(Pry::Editor.edit_tempfile_with_content(adjusted_lines))
|
27
|
+
end
|
28
|
+
|
29
|
+
# The method code adjusted so that the first line is rewritten
|
30
|
+
# so that def self.foo --> def foo
|
31
|
+
def adjusted_lines
|
32
|
+
lines = code_object.source.lines.to_a
|
33
|
+
lines[0] = definition_line_for_owner(lines.first)
|
34
|
+
lines
|
35
|
+
end
|
36
|
+
|
37
|
+
# Run some code ensuring that at the end target#meth_name will not have changed.
|
38
|
+
#
|
39
|
+
# When we're redefining aliased methods we will overwrite the method at the
|
40
|
+
# unaliased name (so that super continues to work). By wrapping that code in a
|
41
|
+
# transation we make that not happen, which means that alias_method_chains, etc.
|
42
|
+
# continue to work.
|
43
|
+
#
|
44
|
+
# @param [String] meth_name The method name before aliasing
|
45
|
+
# @param [Module] target The owner of the method
|
46
|
+
|
47
|
+
def with_method_transaction
|
48
|
+
temp_name = "__pry_#{code_object.original_name}__"
|
49
|
+
co = code_object
|
50
|
+
code_object.owner.class_eval do
|
51
|
+
alias_method temp_name, co.original_name
|
52
|
+
yield
|
53
|
+
alias_method co.name, co.original_name
|
54
|
+
alias_method co.original_name, temp_name
|
55
|
+
end
|
56
|
+
|
57
|
+
ensure
|
58
|
+
co.send(:remove_method, temp_name) rescue nil
|
59
|
+
end
|
60
|
+
|
61
|
+
# Update the definition line so that it can be eval'd directly on the Method's
|
62
|
+
# owner instead of from the original context.
|
63
|
+
#
|
64
|
+
# In particular this takes `def self.foo` and turns it into `def foo` so that we
|
65
|
+
# don't end up creating the method on the singleton class of the singleton class
|
66
|
+
# by accident.
|
67
|
+
#
|
68
|
+
# This is necessarily done by String manipulation because we can't find out what
|
69
|
+
# syntax is needed for the argument list by ruby-level introspection.
|
70
|
+
#
|
71
|
+
# @param String The original definition line. e.g. def self.foo(bar, baz=1)
|
72
|
+
# @return String The new definition line. e.g. def foo(bar, baz=1)
|
73
|
+
def definition_line_for_owner(line)
|
74
|
+
if line =~ /^def (?:.*?\.)?#{Regexp.escape(code_object.original_name)}(?=[\(\s;]|$)/
|
75
|
+
"def #{code_object.original_name}#{$'}"
|
76
|
+
else
|
77
|
+
raise CommandError, "Could not find original `def #{code_object.original_name}` line to patch."
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Apply wrap_for_owner and wrap_for_nesting successively to `source`
|
82
|
+
# @param [String] source
|
83
|
+
# @return [String] The wrapped source.
|
84
|
+
def wrap(source)
|
85
|
+
wrap_for_nesting(wrap_for_owner(source))
|
86
|
+
end
|
87
|
+
|
88
|
+
# Update the source code so that when it has the right owner when eval'd.
|
89
|
+
#
|
90
|
+
# This (combined with definition_line_for_owner) is backup for the case that
|
91
|
+
# wrap_for_nesting fails, to ensure that the method will stil be defined in
|
92
|
+
# the correct place.
|
93
|
+
#
|
94
|
+
# @param [String] source The source to wrap
|
95
|
+
# @return [String]
|
96
|
+
def wrap_for_owner(source)
|
97
|
+
Pry.current[:pry_owner] = code_object.owner
|
98
|
+
"Pry.current[:pry_owner].class_eval do\n#{source}\nend"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Update the new source code to have the correct Module.nesting.
|
102
|
+
#
|
103
|
+
# This method uses syntactic analysis of the original source file to determine
|
104
|
+
# the new nesting, so that we can tell the difference between:
|
105
|
+
#
|
106
|
+
# class A; def self.b; end; end
|
107
|
+
# class << A; def b; end; end
|
108
|
+
#
|
109
|
+
# The resulting code should be evaluated in the TOPLEVEL_BINDING.
|
110
|
+
#
|
111
|
+
# @param [String] source The source to wrap.
|
112
|
+
# @return [String]
|
113
|
+
def wrap_for_nesting(source)
|
114
|
+
nesting = Pry::Code.from_file(code_object.source_file).nesting_at(code_object.source_line)
|
115
|
+
|
116
|
+
(nesting + [source] + nesting.map{ "end" } + [""]).join("\n")
|
117
|
+
rescue Pry::Indent::UnparseableNestingError => e
|
118
|
+
source
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::Exit < Pry::ClassCommand
|
3
|
+
match 'exit'
|
4
|
+
group 'Navigating Pry'
|
5
|
+
description 'Pop the previous binding.'
|
6
|
+
command_options :keep_retval => true
|
7
|
+
|
8
|
+
banner <<-'BANNER'
|
9
|
+
Usage: exit [OPTIONS] [--help]
|
10
|
+
Aliases: quit
|
11
|
+
|
12
|
+
Pop the previous binding (does NOT exit program). It can be useful to exit a
|
13
|
+
context with a user-provided value. For instance an exit value can be used to
|
14
|
+
determine program flow.
|
15
|
+
|
16
|
+
exit "pry this"
|
17
|
+
exit
|
18
|
+
|
19
|
+
https://github.com/pry/pry/wiki/State-navigation#wiki-Exit_with_value
|
20
|
+
BANNER
|
21
|
+
|
22
|
+
def process
|
23
|
+
if _pry_.binding_stack.one?
|
24
|
+
_pry_.run_command "exit-all #{arg_string}"
|
25
|
+
else
|
26
|
+
# otherwise just pop a binding and return user supplied value
|
27
|
+
process_pop_and_return
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def process_pop_and_return
|
32
|
+
popped_object = _pry_.binding_stack.pop.eval('self')
|
33
|
+
|
34
|
+
# return a user-specified value if given otherwise return the object
|
35
|
+
return target.eval(arg_string) unless arg_string.empty?
|
36
|
+
popped_object
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Pry::Commands.add_command(Pry::Command::Exit)
|
41
|
+
Pry::Commands.alias_command 'quit', 'exit'
|
42
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::ExitAll < Pry::ClassCommand
|
3
|
+
match 'exit-all'
|
4
|
+
group 'Navigating Pry'
|
5
|
+
description 'End the current Pry session.'
|
6
|
+
|
7
|
+
banner <<-'BANNER'
|
8
|
+
Usage: exit-all [--help]
|
9
|
+
Aliases: !!@
|
10
|
+
|
11
|
+
End the current Pry session (popping all bindings and returning to caller).
|
12
|
+
Accepts optional return value.
|
13
|
+
BANNER
|
14
|
+
|
15
|
+
def process
|
16
|
+
# calculate user-given value
|
17
|
+
exit_value = target.eval(arg_string)
|
18
|
+
|
19
|
+
# clear the binding stack
|
20
|
+
_pry_.binding_stack.clear
|
21
|
+
|
22
|
+
# break out of the repl loop
|
23
|
+
throw(:breakout, exit_value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Pry::Commands.add_command(Pry::Command::ExitAll)
|
28
|
+
Pry::Commands.alias_command '!!@', 'exit-all'
|
29
|
+
end
|