Class: Pry::Command::Edit

Inherits:
Pry::ClassCommand show all
Defined in:
lib/pry/commands/edit.rb,
lib/pry/commands/edit/exception_patcher.rb,
lib/pry/commands/edit/file_and_line_locator.rb

Defined Under Namespace

Modules: FileAndLineLocator Classes: ExceptionPatcher

Constant Summary

Constants inherited from Pry::Command

VOID_VALUE

Constants included from Helpers::DocumentationHelpers

Helpers::DocumentationHelpers::YARD_TAGS

Constants included from Helpers::Text

Helpers::Text::COLORS

Instance Attribute Summary

Attributes inherited from Pry::ClassCommand

#args, #opts

Attributes inherited from Pry::Command

#arg_string, #captures, #command_block, #command_set, #context, #eval_string, #hooks, #output, #pry_instance, #target

Instance Method Summary collapse

Methods inherited from Pry::ClassCommand

#call, #complete, doc, #help, inherited, #setup, #slop, source, source_file, source_line, source_location, source_object, #subcommands

Methods inherited from Pry::Command

#_pry_, #after_hooks, banner, #before_hooks, #block, #call_safely, #call_with_hooks, #check_for_command_collision, command_name, #command_name, #command_options, command_regex, #commands, #complete, convert_to_regex, default_options, #description, doc, #find_hooks, group, #initialize, inspect, #interpolate_string, #match, match_score, matches?, name, #name, #normalize_method_args, options, #pass_block, #process_line, #run, #source, source, source_file, source_line, #state, state, subclass, #target_self, #tokenize, #use_unpatched_symbol, #void

Methods included from Pry::CodeObject::Helpers

#c_method?, #c_module?, #command?, #module_with_yard_docs?, #real_method_object?

Methods included from Helpers::DocumentationHelpers

#get_comment_content, get_comment_content, process_comment_markup, #process_comment_markup, #process_rdoc, process_rdoc, #process_yardoc, process_yardoc, process_yardoc_tag, #process_yardoc_tag, #strip_comments_from_c_code, strip_comments_from_c_code, #strip_leading_whitespace, strip_leading_whitespace

Methods included from Helpers::Text

#bold, #default, #indent, #no_color, #no_pager, #strip_color, #with_line_numbers

Methods included from Helpers::CommandHelpers

#absolute_index_number, #absolute_index_range, #get_method_or_raise, #internal_binding?, #one_index_number, #one_index_range, #one_index_range_or_number, #restrict_to_lines, #set_file_and_dir_locals, #temp_file, #unindent

Methods included from Helpers::OptionsHelpers

method_object, #method_object, method_options, #method_options

Methods included from Helpers::BaseHelpers

#colorize_code, #find_command, #heading, #highlight, #not_a_real_file?, #safe_send, #silence_warnings, #stagger_output, #use_ansi_codes?

Constructor Details

This class inherits a constructor from Pry::Command

Instance Method Details

#apply_runtime_patchObject


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/pry/commands/edit.rb', line 89

def apply_runtime_patch
  if patch_exception?
    ExceptionPatcher.new(
      pry_instance, state, file_and_line_for_current_exception
    ).perform_patch
  elsif code_object.is_a?(Pry::Method)
    code_object.redefine(
      Pry::Editor.new(pry_instance).edit_tempfile_with_content(
        code_object.source
      )
    )
  else
    raise NotImplementedError, "Cannot yet patch #{code_object} objects!"
  end
end

#bad_option_combination?Boolean

Returns:

  • (Boolean)

172
173
174
175
176
177
178
# File 'lib/pry/commands/edit.rb', line 172

def bad_option_combination?
  [
    opts.present?(:ex), opts.present?(:temp),
    opts.present?(:in), opts.present?(:method),
    !filename_argument.empty?
  ].count(true) > 1
end

#code_objectObject


152
153
154
155
156
# File 'lib/pry/commands/edit.rb', line 152

def code_object
  @code_object ||=
    !probably_a_file?(filename_argument) &&
    Pry::CodeObject.lookup(filename_argument, pry_instance)
end

#ensure_file_name_is_valid(file_name) ⇒ Object

Raises:


105
106
107
108
109
110
111
112
113
# File 'lib/pry/commands/edit.rb', line 105

def ensure_file_name_is_valid(file_name)
  unless file_name
    raise CommandError, "Cannot find a valid file for #{filename_argument}"
  end

  return unless not_a_real_file?(file_name)

  raise CommandError, "#{file_name} is not a valid file name, cannot edit!"
end

#file_and_lineObject


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/pry/commands/edit.rb', line 119

def file_and_line
  file_name, line =
    if opts.present?(:current)
      FileAndLineLocator.from_binding(target)
    elsif opts.present?(:ex)
      file_and_line_for_current_exception
    elsif code_object
      FileAndLineLocator.from_code_object(code_object, filename_argument)
    else
      # when file and line are passed as a single arg, e.g my_file.rb:30
      FileAndLineLocator.from_filename_argument(filename_argument)
    end

  [file_name, opts.present?(:line) ? opts[:l].to_i : line]
end

#file_and_line_for_current_exceptionObject


115
116
117
# File 'lib/pry/commands/edit.rb', line 115

def file_and_line_for_current_exception
  FileAndLineLocator.from_exception(pry_instance.last_exception, opts[:ex].to_i)
end

#file_based_exception?Boolean

Returns:

  • (Boolean)

78
79
80
# File 'lib/pry/commands/edit.rb', line 78

def file_based_exception?
  opts.present?(:ex) && !opts.present?(:patch)
end

#file_editObject


135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/pry/commands/edit.rb', line 135

def file_edit
  file_name, line = file_and_line

  ensure_file_name_is_valid(file_name)

  Pry::Editor.new(pry_instance).invoke_editor(file_name, line, reload?(file_name))
  set_file_and_dir_locals(file_name)

  return unless reload?(file_name)

  silence_warnings { load(file_name) }
end

#filename_argumentObject


148
149
150
# File 'lib/pry/commands/edit.rb', line 148

def filename_argument
  args.join(' ')
end

#initial_temp_file_contentObject


203
204
205
206
207
208
209
210
211
212
213
# File 'lib/pry/commands/edit.rb', line 203

def initial_temp_file_content
  if opts.present?(:temp)
    ""
  elsif opts.present?(:in)
    input_expression
  elsif eval_string.strip != ""
    eval_string
  else
    pry_instance.input_ring.to_a.reverse_each.find { |x| x && x.strip != "" } || ""
  end
end

#input_expressionObject


180
181
182
183
184
185
186
187
188
189
# File 'lib/pry/commands/edit.rb', line 180

def input_expression
  case opts[:i]
  when Range
    (pry_instance.input_ring[opts[:i]] || []).join
  when Integer
    pry_instance.input_ring[opts[:i]] || ""
  else
    raise Pry::CommandError, "Not a valid range: #{opts[:i]}"
  end
end

#never_reload?Boolean

Returns:

  • (Boolean)

195
196
197
# File 'lib/pry/commands/edit.rb', line 195

def never_reload?
  opts.present?(:'no-reload') || pry_instance.config.disable_auto_reload
end

#options(opt) ⇒ Object


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/pry/commands/edit.rb', line 25

def options(opt)
  opt.on :e, :ex, "Open the file that raised the most recent exception " \
                  "(_ex_.file)",
         optional_argument: true, as: Integer
  opt.on :i, :in, "Open a temporary file containing the Nth input " \
                  "expression. N may be a range",
         optional_argument: true, as: Range, default: -1..-1
  opt.on :t, :temp, "Open an empty temporary file"
  opt.on :l, :line, "Jump to this line in the opened file",
         argument: true, as: Integer
  opt.on :n, :"no-reload", "Don't automatically reload the edited file"
  opt.on :c, :current, "Open the current __FILE__ and at __LINE__ (as " \
                       "returned by `whereami`)"
  opt.on :r, :reload, "Reload the edited code immediately (default for " \
                      "ruby files)"
  opt.on :p, :patch, "Instead of editing the object's file, try to edit " \
                     "in a tempfile and apply as a monkey patch"
  opt.on :m, :method, "Explicitly edit the _current_ method (when " \
                      "inside a method context)."
end

#patch_exception?Boolean

Returns:

  • (Boolean)

168
169
170
# File 'lib/pry/commands/edit.rb', line 168

def patch_exception?
  opts.present?(:ex) && opts.present?(:patch)
end

#previously_patched?(code_object) ⇒ Boolean

Returns:

  • (Boolean)

163
164
165
166
# File 'lib/pry/commands/edit.rb', line 163

def previously_patched?(code_object)
  code_object.is_a?(Pry::Method) &&
    Pry::Method::Patcher.code_for(code_object.source_location.first)
end

#probably_a_file?(str) ⇒ Boolean

Returns:

  • (Boolean)

215
216
217
218
# File 'lib/pry/commands/edit.rb', line 215

def probably_a_file?(str)
  [".rb", ".c", ".py", ".yml", ".gemspec"].include?(File.extname(str)) ||
    str =~ %r{/|\\}
end

#processObject


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/pry/commands/edit.rb', line 46

def process
  if bad_option_combination?
    raise CommandError, "Only one of --ex, --temp, --in, --method and " \
                        "FILE may be specified."
  end

  if repl_edit?
    # code defined in pry, eval'd within pry.
    repl_edit
  elsif runtime_patch?
    # patch code without persisting changes, implies future changes are patches
    apply_runtime_patch
  else
    # code stored in actual files, eval'd at top-level
    file_edit
  end
end

#pry_method?(code_object) ⇒ Boolean

Returns:

  • (Boolean)

158
159
160
161
# File 'lib/pry/commands/edit.rb', line 158

def pry_method?(code_object)
  code_object.is_a?(Pry::Method) &&
    code_object.pry_method?
end

#reload?(file_name = "") ⇒ Boolean

Returns:

  • (Boolean)

199
200
201
# File 'lib/pry/commands/edit.rb', line 199

def reload?(file_name = "")
  (reloadable? || file_name.end_with?(".rb")) && !never_reload?
end

#reloadable?Boolean

Returns:

  • (Boolean)

191
192
193
# File 'lib/pry/commands/edit.rb', line 191

def reloadable?
  opts.present?(:reload) || opts.present?(:ex)
end

#repl_editObject


69
70
71
72
73
74
75
76
# File 'lib/pry/commands/edit.rb', line 69

def repl_edit
  content = Pry::Editor.new(pry_instance).edit_tempfile_with_content(
    initial_temp_file_content,
    initial_temp_file_content.lines.count
  )
  pry_instance.eval_string = content
  Pry.history.push(content)
end

#repl_edit?Boolean

Returns:

  • (Boolean)

64
65
66
67
# File 'lib/pry/commands/edit.rb', line 64

def repl_edit?
  !opts.present?(:ex) && !opts.present?(:current) && !opts.present?(:method) &&
    filename_argument.empty?
end

#runtime_patch?Boolean

Returns:

  • (Boolean)

82
83
84
85
86
87
# File 'lib/pry/commands/edit.rb', line 82

def runtime_patch?
  !file_based_exception? &&
    (opts.present?(:patch) ||
     previously_patched?(code_object) ||
     pry_method?(code_object))
end