Class: Pry::Command::ShowInfo

Inherits:
Pry::ClassCommand show all
Extended by:
Helpers::BaseHelpers
Defined in:
lib/pry/commands/show_info.rb

Direct Known Subclasses

ShowDoc, ShowSource

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 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?

Methods inherited from Pry::ClassCommand

#call, 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, convert_to_regex, #correct_arg_arity, default_options, #dependencies_met?, #description, doc, #find_hooks, group, hooks, 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

Constructor Details

#initializeShowInfo

Returns a new instance of ShowInfo



7
8
9
10
11
# File 'lib/pry/commands/show_info.rb', line 7

def initialize(*)
  super

  @used_super = nil
end

Instance Method Details

#code_object_header(code_object, line_num) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/pry/commands/show_info.rb', line 111

def code_object_header(code_object, line_num)
  if code_object.real_method_object?
    method_header(code_object, line_num)

    # It sucks we have to test for both Pry::WrappedModule and WrappedModule::Candidate,
    # probably indicates a deep refactor needs to happen in those classes.
  elsif code_object.is_a?(Pry::WrappedModule) || code_object.is_a?(Pry::WrappedModule::Candidate)
    module_header(code_object, line_num)
  else
    ""
  end
end

#code_object_with_accessible_source(code_object) ⇒ Pry::WrappedModule, ...

This method checks whether the code_object is a WrappedModule, if it is, then it returns the first candidate (monkeypatch) with accessible source (or docs). If code_object is not a WrappedModule (i.e a method or a command) then the code_object itself is just returned.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/pry/commands/show_info.rb', line 54

def code_object_with_accessible_source(code_object)
  if code_object.is_a?(WrappedModule)
    candidate = code_object.candidates.find(&:source)
    if candidate
      return candidate
    else
      raise CommandError, no_definition_message if !valid_superclass?(code_object)

      @used_super = true
      code_object_with_accessible_source(code_object.super)
    end
  else
    code_object
  end
end

#complete(input) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/pry/commands/show_info.rb', line 193

def complete(input)
  if input =~ /([^ ]*)#([a-z0-9_]*)\z/
    prefix, search = [$1, $2]
    methods = begin
                Pry::Method.all_from_class(binding.eval(prefix))
              rescue RescuableException
                return super
              end
    methods.map do |method|
      [prefix, method.name].join('#') if method.name.start_with?(search)
    end.compact
  else
    super
  end
end

#content_and_header_for_code_object(code_object) ⇒ Object



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

def content_and_header_for_code_object(code_object)
  header(code_object) << content_for(code_object)
end

#content_and_headers_for_all_module_candidates(mod) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/pry/commands/show_info.rb', line 78

def content_and_headers_for_all_module_candidates(mod)
  result = "Found #{mod.number_of_candidates} candidates for `#{mod.name}` definition:\n"
  mod.number_of_candidates.times do |v|
    candidate = mod.candidate(v)
    begin
      result << "\nCandidate #{v+1}/#{mod.number_of_candidates}: #{candidate.source_file} @ line #{candidate.source_line}:\n"
      content = content_for(candidate)

      result << "Number of lines: #{content.lines.count}\n\n" << content
    rescue Pry::RescuableException
      result << "\nNo content found.\n"
      next
    end
  end
  result
end

#file_and_line_for(code_object) ⇒ Object

takes into account possible yard docs, and returns yard_file / yard_line Also adjusts for start line of comments (using start_line_for), which it has to infer by subtracting number of lines of comment from start line of code_object



185
186
187
188
189
190
191
# File 'lib/pry/commands/show_info.rb', line 185

def file_and_line_for(code_object)
  if code_object.module_with_yard_docs?
    [code_object.yard_file, code_object.yard_line]
  else
    [code_object.source_file, start_line_for(code_object)]
  end
end

#header(code_object) ⇒ Object

Generate a header (meta-data information) for all the code object types: methods, modules, commands, procs...



101
102
103
104
105
106
107
108
109
# File 'lib/pry/commands/show_info.rb', line 101

def header(code_object)
  file_name, line_num = file_and_line_for(code_object)
  h = "\n#{bold('From:')} #{file_name} "
  h << code_object_header(code_object, line_num)
  h << "\n#{bold('Number of lines:')} " <<
    "#{content_for(code_object).lines.count}\n\n"
  h << bold('** Warning:') << " Cannot find code for #{@original_code_object.nonblank_name}. Showing superclass #{code_object.nonblank_name} instead. **\n\n" if @used_super
  h
end

#header_optionsObject



154
155
156
157
158
159
160
# File 'lib/pry/commands/show_info.rb', line 154

def header_options
  {
    :owner => true,
    :visibility => true,
    :signature => nil
  }
end

#method_header(code_object, line_num) ⇒ Object



124
125
126
127
128
129
130
131
# File 'lib/pry/commands/show_info.rb', line 124

def method_header(code_object, line_num)
  h = ""
  h << (code_object.c_method? ? "(C Method):" : "@ line #{line_num}:")
  h << method_sections(code_object)[:owner]
  h << method_sections(code_object)[:visibility]
  h << method_sections(code_object)[:signature]
  h
end

#method_sections(code_object) ⇒ Object



146
147
148
149
150
151
152
# File 'lib/pry/commands/show_info.rb', line 146

def method_sections(code_object)
  {
    :owner => "\n#{bold("Owner:")} #{code_object.owner || "N/A"}\n",
    :visibility => "#{bold("Visibility:")} #{code_object.visibility}",
    :signature => "\n#{bold("Signature:")} #{code_object.signature}"
  }.merge(header_options) { |key, old, new| (new && old).to_s }
end

#module_header(code_object, line_num) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/pry/commands/show_info.rb', line 133

def module_header(code_object, line_num)
  h = ""
  h << "@ line #{line_num}:\n"
  h << bold(code_object.module? ? "Module" : "Class")
  h << " #{bold('name:')} #{code_object.nonblank_name}"

  if code_object.number_of_candidates > 1
    h << (bold("\nNumber of monkeypatches: ") << code_object.number_of_candidates.to_s)
    h << ". Use the `-a` option to display all available monkeypatches"
  end
  h
end

#no_definition_messageObject



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

def no_definition_message
  "Couldn't locate a definition for #{obj_name}"
end

#obj_nameObject



166
167
168
# File 'lib/pry/commands/show_info.rb', line 166

def obj_name
  @obj_name ||= args.empty? ? nil : args.join(' ')
end

#options(opt) ⇒ Object



13
14
15
16
17
18
# File 'lib/pry/commands/show_info.rb', line 13

def options(opt)
  opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors", :as => :count
  opt.on :l, "line-numbers", "Show line numbers"
  opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)"
  opt.on :a, :all,  "Show all definitions and monkeypatches of the module/class"
end

#processObject

Raises:



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/pry/commands/show_info.rb', line 20

def process
  code_object = Pry::CodeObject.lookup(obj_name, _pry_, :super => opts[:super])
  raise CommandError, no_definition_message if !code_object
  @original_code_object = code_object

  if !obj_name && code_object.c_module? && !opts[:all]
    result = "Warning: You're inside an object, whose class is defined by means\n" +
             "         of the C Ruby API. Pry cannot display the information for\n" +
             "         this class."
    if code_object.candidates.any?
      result += "\n         However, you can view monkey-patches applied to this class.\n" +
                "         Just execute the same command with the '--all' switch."
    end
  elsif show_all_modules?(code_object)
    # show all monkey patches for a module

    result = content_and_headers_for_all_module_candidates(code_object)
  else
    # show a specific code object
    co = code_object_with_accessible_source(code_object)
    result = content_and_header_for_code_object(co)
  end

  set_file_and_dir_locals(code_object.source_file)
  _pry_.pager.page result
end

#show_all_modules?(code_object) ⇒ Boolean

Returns:

  • (Boolean)


162
163
164
# File 'lib/pry/commands/show_info.rb', line 162

def show_all_modules?(code_object)
  code_object.is_a?(Pry::WrappedModule) && opts.present?(:all)
end

#start_line_for(code_object) ⇒ Object



174
175
176
177
178
179
180
# File 'lib/pry/commands/show_info.rb', line 174

def start_line_for(code_object)
  if opts.present?(:'base-one')
    1
  else
    code_object.source_line || 1
  end
end

#use_line_numbers?Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/pry/commands/show_info.rb', line 170

def use_line_numbers?
  opts.present?(:b) || opts.present?(:l)
end

#valid_superclass?(code_object) ⇒ Boolean

Returns:

  • (Boolean)


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

def valid_superclass?(code_object)
  code_object.super && code_object.super.wrapped != Object
end