Class: Pry::WrappedModule

Inherits:
Object show all
Includes:
Helpers::DocumentationHelpers
Defined in:
lib/pry/wrapped_module.rb,
lib/pry/module_candidate.rb

Defined Under Namespace

Classes: Candidate

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers::DocumentationHelpers

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

Constructor Details

#initialize(mod) ⇒ WrappedModule

Returns a new instance of WrappedModule.

Raises:

  • (ArgumentError)

    if the argument is not a Module



45
46
47
48
49
50
51
52
53
# File 'lib/pry/wrapped_module.rb', line 45

def initialize(mod)
  raise ArgumentError, "Tried to initialize a WrappedModule with a non-module #{mod.inspect}" unless ::Module === mod
  @wrapped = mod
  @memoized_candidates = []
  @host_file_lines = nil
  @source = nil
  @source_location = nil
  @doc = nil
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object

Forward method invocations to the wrapped module



105
106
107
# File 'lib/pry/wrapped_module.rb', line 105

def method_missing(method_name, *args, &block)
  wrapped.send(method_name, *args, &block)
end

Instance Attribute Details

#wrappedObject (readonly, private)

Returns the value of attribute wrapped.



19
20
21
# File 'lib/pry/wrapped_module.rb', line 19

def wrapped
  @wrapped
end

Class Method Details

.from_str(mod_name, target = TOPLEVEL_BINDING) ⇒ Module?

Convert a string to a module.

Examples:

Pry::WrappedModule.from_str("Pry::Code")


29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/pry/wrapped_module.rb', line 29

def self.from_str(mod_name, target=TOPLEVEL_BINDING)
  kind = target.eval("defined?(#{mod_name})")

  # if we dont limit it to constants then from_str could end up
  # executing methods which is not good, i.e `show-source pry`
  if (kind == "constant" && target.eval(mod_name).is_a?(Module))
    Pry::WrappedModule.new(target.eval(mod_name))
  else
    nil
  end
rescue RescuableException
  nil
end

Instance Method Details

#all_from_common(mod, method_type) ⇒ Object (private)

FIXME: a variant of this method is also found in Pry::Method



250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/pry/wrapped_module.rb', line 250

def all_from_common(mod, method_type)
  %w(public protected private).map do |visibility|
    safe_send(mod, :"#{visibility}_#{method_type}s", false).select do |method_name|
      if method_type == :method
        safe_send(mod, method_type, method_name).owner == class << mod; self; end
      else
        safe_send(mod, method_type, method_name).owner == mod
      end
    end.map do |method_name|
      Pry::Method.new(safe_send(mod, method_type, method_name), :visibility => visibility.to_sym)
    end
  end.flatten
end

#all_methods_for(mod) ⇒ Object (private)

Return all methods (instance methods and class methods) for a given module.



245
246
247
# File 'lib/pry/wrapped_module.rb', line 245

def all_methods_for(mod)
  all_from_common(mod, :instance_method) + all_from_common(mod, :method)
end

#all_source_locations_by_popularityObject (private)

A helper method.



231
232
233
234
235
236
237
238
239
240
241
# File 'lib/pry/wrapped_module.rb', line 231

def all_source_locations_by_popularity
  return @all_source_locations_by_popularity if @all_source_locations_by_popularity

  ims = all_methods_for(wrapped)

  # reject __class_init__ because it's an odd rbx specific thing that causes tests to fail
  ims = ims.select(&:source_location).reject{ |x| x.name == '__class_init__' }

  @all_source_locations_by_popularity = ims.group_by { |v| Array(v.source_location).first }.
    sort_by { |k, v| -v.size }
end

#candidate(rank) ⇒ Pry::WrappedModule::Candidate

Return a candidate for this module of specified rank. A rank of 0 is equivalent to the 'primary candidate', which is the module definition with the highest number of methods. A rank of 1 is the module definition with the second highest number of methods, and so on. Module candidates are necessary as modules can be reopened multiple times and in multiple places in Ruby, the candidate API gives you access to the module definition representing each of those reopenings.

Raises:

  • (Pry::CommandError)

    If the rank is out of range. That is greater than number_of_candidates - 1.



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

def candidate(rank)
  @memoized_candidates[rank] ||= Candidate.new(self, rank)
end

#docString

Returns documentation for the module. This documentation is for the primary candidate, if you would like documentation for other candidates use WrappedModule#candidate to select the candidate you're interested in.

Raises:



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

def doc
  @doc ||= primary_candidate.doc
end

#fileString? Also known as: source_file



128
129
130
# File 'lib/pry/wrapped_module.rb', line 128

def file
  Array(source_location).first
end

#lineFixnum? Also known as: source_line



135
136
137
# File 'lib/pry/wrapped_module.rb', line 135

def line
  Array(source_location).last
end

#lines_for_file(file) ⇒ Object (private)

memoized lines for file



265
266
267
268
269
270
271
272
273
# File 'lib/pry/wrapped_module.rb', line 265

def lines_for_file(file)
  @lines_for_file ||= {}

  if file == Pry.eval_path
    @lines_for_file[file] ||= Pry.line_buffer.drop(1)
  else
    @lines_for_file[file] ||= File.readlines(file)
  end
end

#method_candidatesArray<Array<Pry::Method>> (private)



223
224
225
226
227
228
# File 'lib/pry/wrapped_module.rb', line 223

def method_candidates
  @method_candidates ||= all_source_locations_by_popularity.map do |group|
    methods_sorted_by_source_line  = group.last.sort_by(&:source_line)
    [methods_sorted_by_source_line.first, methods_sorted_by_source_line.last]
  end
end

#method_prefixObject

The prefix that would appear before methods defined on this class.

i.e. the "String." or "String#" in String.new and String#initialize.



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/pry/wrapped_module.rb', line 60

def method_prefix
  if singleton_class?
    if Module === singleton_instance
      "#{WrappedModule.new(singleton_instance).nonblank_name}."
    else
      "self."
    end
  else
    "#{nonblank_name}#"
  end
end

#nonblank_nameString

The name of the Module if it has one, otherwise #Class:0xf00.



75
76
77
78
79
80
81
# File 'lib/pry/wrapped_module.rb', line 75

def nonblank_name
  if name.to_s == ""
    wrapped.inspect
  else
    name
  end
end

#number_of_candidatesFixnum



198
199
200
# File 'lib/pry/wrapped_module.rb', line 198

def number_of_candidates
  method_candidates.count
end

#primary_candidatePry::WrappedModule::Candidate (private)



213
214
215
# File 'lib/pry/wrapped_module.rb', line 213

def primary_candidate
  @primary_candidate ||= candidate(0)
end

#process_doc(doc) ⇒ String (private)



282
283
284
# File 'lib/pry/wrapped_module.rb', line 282

def process_doc(doc)
   process_comment_markup(strip_leading_hash_and_whitespace_from_ruby_comments(doc))
end

#respond_to?(method_name) ⇒ Boolean



109
110
111
# File 'lib/pry/wrapped_module.rb', line 109

def respond_to?(method_name)
  super || wrapped.respond_to?(method_name)
end

#safe_send(obj, method, *args, &block) ⇒ Object (private)

FIXME: this method is also found in Pry::Method



276
277
278
# File 'lib/pry/wrapped_module.rb', line 276

def safe_send(obj, method, *args, &block)
    (Module === obj ? Module : Object).instance_method(method).bind(obj).call(*args, &block)
end

#singleton_class?Boolean

Is this a singleton class?



85
86
87
# File 'lib/pry/wrapped_module.rb', line 85

def singleton_class?
  wrapped != wrapped.ancestors.first
end

#singleton_instanceObject

Get the instance associated with this singleton class.

Raises:

  • ArgumentError: tried to get instance of non singleton class



94
95
96
97
98
99
100
101
102
# File 'lib/pry/wrapped_module.rb', line 94

def singleton_instance
  raise ArgumentError, "tried to get instance of non singleton class" unless singleton_class?

  if Helpers::BaseHelpers.jruby?
    wrapped.to_java.attached
  else
    @singleton_instance ||= ObjectSpace.each_object(wrapped).detect{ |x| (class << x; self; end) == wrapped }
  end
end

#sourceString

Returns the source for the module. This source is for the primary candidate, if you would like source for other candidates use WrappedModule#candidate to select the candidate you're interested in.

Raises:



158
159
160
# File 'lib/pry/wrapped_module.rb', line 158

def source
  @source ||= primary_candidate.source
end

#source_locationArray<String, Fixnum>?

Retrieve the source location of a module. Return value is in same format as Method#source_location. If the source location cannot be found this method returns nil.



120
121
122
123
124
# File 'lib/pry/wrapped_module.rb', line 120

def source_location
  @source_location ||= primary_candidate.source_location
rescue Pry::RescuableException
  nil
end

#yard_docString



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

def yard_doc
  YARD::Registry.at(name).docstring.to_s if yard_docs?
end

#yard_docs?Boolean



203
204
205
# File 'lib/pry/wrapped_module.rb', line 203

def yard_docs?
  !!(defined?(YARD) && YARD::Registry.at(name))
end

#yard_fileString



164
165
166
# File 'lib/pry/wrapped_module.rb', line 164

def yard_file
  YARD::Registry.at(name).file if yard_docs?
end

#yard_lineFixnum



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

def yard_line
  YARD::Registry.at(name).line if yard_docs?
end