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::Text

Helpers::Text::COLORS

Instance Attribute Summary

Attributes inherited from Pry::ClassCommand

#args, #opts

Attributes inherited from Pry::Command

#_pry_, #arg_string, #captures, #command_block, #command_set, #context, #eval_string, #hooks, #output, #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

#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, #correct_arg_arity, default_options, #dependencies_met?, #description, doc, #find_hooks, group, hooks, #initialize, inspect, #interpolate_string, #match, match_score, matches?, name, #name, options, #pass_block, #process_line, #run, source, #source, source_file, source_line, source_location, #source_location, #state, subclass, #target_self, #text, #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_number, absolute_index_range, #absolute_index_range, command_error, #command_error, #get_method_or_raise, get_method_or_raise, internal_binding?, #internal_binding?, one_index_number, #one_index_number, one_index_range, #one_index_range, #one_index_range_or_number, one_index_range_or_number, #restrict_to_lines, restrict_to_lines, #set_file_and_dir_locals, set_file_and_dir_locals, #temp_file, temp_file, #unindent, unindent

Methods included from Helpers::OptionsHelpers

method_object, #method_object, method_options, #method_options

Methods included from Helpers::BaseHelpers

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

Methods included from Platform

#jruby?, #jruby_19?, #known_engines, #linux?, #mac_osx?, #mri?, #mri_19?, #mri_2?, #rbx?, #windows?, #windows_ansi?

Constructor Details

This class inherits a constructor from Pry::Command

Instance Method Details

#apply_runtime_patchObject


78
79
80
81
82
83
84
85
86
87
88
# File 'lib/pry/commands/edit.rb', line 78

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

#bad_option_combination?Boolean

Returns:

  • (Boolean)

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

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


133
134
135
136
# File 'lib/pry/commands/edit.rb', line 133

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

#ensure_file_name_is_valid(file_name) ⇒ Object

Raises:


90
91
92
93
# File 'lib/pry/commands/edit.rb', line 90

def ensure_file_name_is_valid(file_name)
  raise CommandError, "Cannot find a valid file for #{filename_argument}" if !file_name
  raise CommandError, "#{file_name} is not a valid file name, cannot edit!" if not_a_real_file?(file_name)
end

#file_and_lineObject


99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/pry/commands/edit.rb', line 99

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


95
96
97
# File 'lib/pry/commands/edit.rb', line 95

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

#file_based_exception?Boolean

Returns:

  • (Boolean)

70
71
72
# File 'lib/pry/commands/edit.rb', line 70

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

#file_editObject


114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/pry/commands/edit.rb', line 114

def file_edit
  file_name, line = file_and_line

  ensure_file_name_is_valid(file_name)

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

  if reload?(file_name)
    silence_warnings do
      load file_name
    end
  end
end

#filename_argumentObject


129
130
131
# File 'lib/pry/commands/edit.rb', line 129

def filename_argument
  args.join(' ')
end

#initial_temp_file_contentObject


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

def initial_temp_file_content
  case
  when opts.present?(:temp)
    ""
  when opts.present?(:in)
    input_expression
  when eval_string.strip != ""
    eval_string
  else
    _pry_.input_array.reverse_each.find { |x| x && x.strip != "" } || ""
  end
end

#input_expressionObject


156
157
158
159
160
161
162
163
164
165
# File 'lib/pry/commands/edit.rb', line 156

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

#never_reload?Boolean

Returns:

  • (Boolean)

171
172
173
# File 'lib/pry/commands/edit.rb', line 171

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

#options(opt) ⇒ Object


25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 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)

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

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

#previously_patched?(code_object) ⇒ Boolean

Returns:

  • (Boolean)

143
144
145
# File 'lib/pry/commands/edit.rb', line 143

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)

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

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

#processObject


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/pry/commands/edit.rb', line 40

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)

138
139
140
141
# File 'lib/pry/commands/edit.rb', line 138

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

#reload?(file_name = "") ⇒ Boolean

Returns:

  • (Boolean)

175
176
177
# File 'lib/pry/commands/edit.rb', line 175

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

#reloadable?Boolean

Returns:

  • (Boolean)

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

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

#repl_editObject


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

def repl_edit
  content = Pry::Editor.new(_pry_).edit_tempfile_with_content(initial_temp_file_content,
                                                   initial_temp_file_content.lines.count)
  silence_warnings do
    eval_string.replace content
  end
end

#repl_edit?Boolean

Returns:

  • (Boolean)

57
58
59
60
# File 'lib/pry/commands/edit.rb', line 57

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

#runtime_patch?Boolean

Returns:

  • (Boolean)

74
75
76
# File 'lib/pry/commands/edit.rb', line 74

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