pry 0.10.0.pre2-universal-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +702 -0
  3. data/LICENSE +25 -0
  4. data/README.md +406 -0
  5. data/bin/pry +16 -0
  6. data/lib/pry.rb +161 -0
  7. data/lib/pry/cli.rb +220 -0
  8. data/lib/pry/code.rb +346 -0
  9. data/lib/pry/code/code_file.rb +103 -0
  10. data/lib/pry/code/code_range.rb +71 -0
  11. data/lib/pry/code/loc.rb +92 -0
  12. data/lib/pry/code_object.rb +172 -0
  13. data/lib/pry/color_printer.rb +55 -0
  14. data/lib/pry/command.rb +692 -0
  15. data/lib/pry/command_set.rb +443 -0
  16. data/lib/pry/commands.rb +6 -0
  17. data/lib/pry/commands/amend_line.rb +99 -0
  18. data/lib/pry/commands/bang.rb +20 -0
  19. data/lib/pry/commands/bang_pry.rb +17 -0
  20. data/lib/pry/commands/cat.rb +62 -0
  21. data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
  22. data/lib/pry/commands/cat/exception_formatter.rb +77 -0
  23. data/lib/pry/commands/cat/file_formatter.rb +67 -0
  24. data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
  25. data/lib/pry/commands/cd.rb +41 -0
  26. data/lib/pry/commands/change_inspector.rb +27 -0
  27. data/lib/pry/commands/change_prompt.rb +26 -0
  28. data/lib/pry/commands/code_collector.rb +165 -0
  29. data/lib/pry/commands/disable_pry.rb +27 -0
  30. data/lib/pry/commands/disabled_commands.rb +2 -0
  31. data/lib/pry/commands/easter_eggs.rb +112 -0
  32. data/lib/pry/commands/edit.rb +195 -0
  33. data/lib/pry/commands/edit/exception_patcher.rb +25 -0
  34. data/lib/pry/commands/edit/file_and_line_locator.rb +36 -0
  35. data/lib/pry/commands/exit.rb +42 -0
  36. data/lib/pry/commands/exit_all.rb +29 -0
  37. data/lib/pry/commands/exit_program.rb +23 -0
  38. data/lib/pry/commands/find_method.rb +193 -0
  39. data/lib/pry/commands/fix_indent.rb +19 -0
  40. data/lib/pry/commands/gem_cd.rb +26 -0
  41. data/lib/pry/commands/gem_install.rb +32 -0
  42. data/lib/pry/commands/gem_list.rb +33 -0
  43. data/lib/pry/commands/gem_open.rb +29 -0
  44. data/lib/pry/commands/gist.rb +101 -0
  45. data/lib/pry/commands/help.rb +164 -0
  46. data/lib/pry/commands/hist.rb +180 -0
  47. data/lib/pry/commands/import_set.rb +22 -0
  48. data/lib/pry/commands/install_command.rb +53 -0
  49. data/lib/pry/commands/jump_to.rb +29 -0
  50. data/lib/pry/commands/list_inspectors.rb +35 -0
  51. data/lib/pry/commands/list_prompts.rb +35 -0
  52. data/lib/pry/commands/ls.rb +114 -0
  53. data/lib/pry/commands/ls/constants.rb +47 -0
  54. data/lib/pry/commands/ls/formatter.rb +49 -0
  55. data/lib/pry/commands/ls/globals.rb +48 -0
  56. data/lib/pry/commands/ls/grep.rb +21 -0
  57. data/lib/pry/commands/ls/instance_vars.rb +39 -0
  58. data/lib/pry/commands/ls/interrogatable.rb +18 -0
  59. data/lib/pry/commands/ls/jruby_hacks.rb +49 -0
  60. data/lib/pry/commands/ls/local_names.rb +35 -0
  61. data/lib/pry/commands/ls/local_vars.rb +39 -0
  62. data/lib/pry/commands/ls/ls_entity.rb +70 -0
  63. data/lib/pry/commands/ls/methods.rb +57 -0
  64. data/lib/pry/commands/ls/methods_helper.rb +46 -0
  65. data/lib/pry/commands/ls/self_methods.rb +32 -0
  66. data/lib/pry/commands/nesting.rb +25 -0
  67. data/lib/pry/commands/play.rb +103 -0
  68. data/lib/pry/commands/pry_backtrace.rb +25 -0
  69. data/lib/pry/commands/pry_version.rb +17 -0
  70. data/lib/pry/commands/raise_up.rb +32 -0
  71. data/lib/pry/commands/reload_code.rb +62 -0
  72. data/lib/pry/commands/reset.rb +18 -0
  73. data/lib/pry/commands/ri.rb +60 -0
  74. data/lib/pry/commands/save_file.rb +61 -0
  75. data/lib/pry/commands/shell_command.rb +48 -0
  76. data/lib/pry/commands/shell_mode.rb +25 -0
  77. data/lib/pry/commands/show_doc.rb +83 -0
  78. data/lib/pry/commands/show_info.rb +195 -0
  79. data/lib/pry/commands/show_input.rb +17 -0
  80. data/lib/pry/commands/show_source.rb +50 -0
  81. data/lib/pry/commands/simple_prompt.rb +22 -0
  82. data/lib/pry/commands/stat.rb +40 -0
  83. data/lib/pry/commands/switch_to.rb +23 -0
  84. data/lib/pry/commands/toggle_color.rb +24 -0
  85. data/lib/pry/commands/watch_expression.rb +105 -0
  86. data/lib/pry/commands/watch_expression/expression.rb +38 -0
  87. data/lib/pry/commands/whereami.rb +190 -0
  88. data/lib/pry/commands/wtf.rb +57 -0
  89. data/lib/pry/config.rb +24 -0
  90. data/lib/pry/config/behavior.rb +139 -0
  91. data/lib/pry/config/convenience.rb +26 -0
  92. data/lib/pry/config/default.rb +165 -0
  93. data/lib/pry/core_extensions.rb +131 -0
  94. data/lib/pry/editor.rb +133 -0
  95. data/lib/pry/exceptions.rb +77 -0
  96. data/lib/pry/helpers.rb +5 -0
  97. data/lib/pry/helpers/base_helpers.rb +113 -0
  98. data/lib/pry/helpers/command_helpers.rb +156 -0
  99. data/lib/pry/helpers/documentation_helpers.rb +75 -0
  100. data/lib/pry/helpers/options_helpers.rb +27 -0
  101. data/lib/pry/helpers/table.rb +109 -0
  102. data/lib/pry/helpers/text.rb +107 -0
  103. data/lib/pry/history.rb +125 -0
  104. data/lib/pry/history_array.rb +121 -0
  105. data/lib/pry/hooks.rb +230 -0
  106. data/lib/pry/indent.rb +406 -0
  107. data/lib/pry/input_completer.rb +242 -0
  108. data/lib/pry/input_lock.rb +132 -0
  109. data/lib/pry/inspector.rb +27 -0
  110. data/lib/pry/last_exception.rb +61 -0
  111. data/lib/pry/method.rb +546 -0
  112. data/lib/pry/method/disowned.rb +53 -0
  113. data/lib/pry/method/patcher.rb +125 -0
  114. data/lib/pry/method/weird_method_locator.rb +186 -0
  115. data/lib/pry/module_candidate.rb +136 -0
  116. data/lib/pry/object_path.rb +82 -0
  117. data/lib/pry/output.rb +50 -0
  118. data/lib/pry/pager.rb +234 -0
  119. data/lib/pry/plugins.rb +103 -0
  120. data/lib/pry/prompt.rb +26 -0
  121. data/lib/pry/pry_class.rb +375 -0
  122. data/lib/pry/pry_instance.rb +654 -0
  123. data/lib/pry/rbx_path.rb +22 -0
  124. data/lib/pry/repl.rb +202 -0
  125. data/lib/pry/repl_file_loader.rb +74 -0
  126. data/lib/pry/rubygem.rb +82 -0
  127. data/lib/pry/terminal.rb +79 -0
  128. data/lib/pry/test/helper.rb +170 -0
  129. data/lib/pry/version.rb +3 -0
  130. data/lib/pry/wrapped_module.rb +373 -0
  131. metadata +248 -0
@@ -0,0 +1,53 @@
1
+ class Pry
2
+ class Method
3
+ # A Disowned Method is one that's been removed from the class on which it was defined.
4
+ #
5
+ # e.g.
6
+ # class C
7
+ # def foo
8
+ # C.send(:undefine_method, :foo)
9
+ # Pry::Method.from_binding(binding)
10
+ # end
11
+ # end
12
+ #
13
+ # In this case we assume that the "owner" is the singleton class of the receiver.
14
+ #
15
+ # This occurs mainly in Sinatra applications.
16
+ class Disowned < Method
17
+ attr_reader :receiver, :name
18
+
19
+ # Create a new Disowned method.
20
+ #
21
+ # @param [Object] receiver
22
+ # @param [String] method_name
23
+ def initialize(receiver, method_name, binding=nil)
24
+ @receiver, @name = receiver, method_name
25
+ end
26
+
27
+ # Is the method undefined? (aka `Disowned`)
28
+ # @return [Boolean] true
29
+ def undefined?
30
+ true
31
+ end
32
+
33
+ # Can we get the source for this method?
34
+ # @return [Boolean] false
35
+ def source?
36
+ false
37
+ end
38
+
39
+ # Get the hypothesized owner of the method.
40
+ #
41
+ # @return [Object]
42
+ def owner
43
+ class << receiver; self; end
44
+ end
45
+
46
+ # Raise a more useful error message instead of trying to forward to nil.
47
+ def method_missing(meth_name, *args, &block)
48
+ raise "Cannot call '#{meth_name}' on an undef'd method." if method(:name).respond_to?(meth_name)
49
+ Object.instance_method(:method_missing).bind(self).call(meth_name, *args, &block)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,125 @@
1
+ class Pry
2
+ class Method
3
+ class Patcher
4
+ attr_accessor :method
5
+
6
+ @@source_cache = {}
7
+
8
+ def initialize(method)
9
+ @method = method
10
+ end
11
+
12
+ def self.code_for(filename)
13
+ @@source_cache[filename]
14
+ end
15
+
16
+ # perform the patch
17
+ def patch_in_ram(source)
18
+ if method.alias?
19
+ with_method_transaction do
20
+ redefine source
21
+ end
22
+ else
23
+ redefine source
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def redefine(source)
30
+ @@source_cache[cache_key] = source
31
+ TOPLEVEL_BINDING.eval wrap(source), cache_key
32
+ end
33
+
34
+ def cache_key
35
+ "pry-redefined(0x#{method.owner.object_id.to_s(16)}##{method.name})"
36
+ end
37
+
38
+ # Run some code ensuring that at the end target#meth_name will not have changed.
39
+ #
40
+ # When we're redefining aliased methods we will overwrite the method at the
41
+ # unaliased name (so that super continues to work). By wrapping that code in a
42
+ # transation we make that not happen, which means that alias_method_chains, etc.
43
+ # continue to work.
44
+ #
45
+ # @param [String] meth_name The method name before aliasing
46
+ # @param [Module] target The owner of the method
47
+
48
+ def with_method_transaction
49
+ temp_name = "__pry_#{method.original_name}__"
50
+ method = self.method
51
+ method.owner.class_eval do
52
+ alias_method temp_name, method.original_name
53
+ yield
54
+ alias_method method.name, method.original_name
55
+ alias_method method.original_name, temp_name
56
+ end
57
+
58
+ ensure
59
+ method.send(:remove_method, temp_name) rescue nil
60
+ end
61
+
62
+ # Update the definition line so that it can be eval'd directly on the Method's
63
+ # owner instead of from the original context.
64
+ #
65
+ # In particular this takes `def self.foo` and turns it into `def foo` so that we
66
+ # don't end up creating the method on the singleton class of the singleton class
67
+ # by accident.
68
+ #
69
+ # This is necessarily done by String manipulation because we can't find out what
70
+ # syntax is needed for the argument list by ruby-level introspection.
71
+ #
72
+ # @param [String] line The original definition line. e.g. def self.foo(bar, baz=1)
73
+ # @return [String] The new definition line. e.g. def foo(bar, baz=1)
74
+ def definition_for_owner(line)
75
+ if line =~ /\Adef (?:.*?\.)?#{Regexp.escape(method.original_name)}(?=[\(\s;]|$)/
76
+ "def #{method.original_name}#{$'}"
77
+ else
78
+ raise CommandError, "Could not find original `def #{method.original_name}` line to patch."
79
+ end
80
+ end
81
+
82
+ # Apply wrap_for_owner and wrap_for_nesting successively to `source`
83
+ # @param [String] source
84
+ # @return [String] The wrapped source.
85
+ def wrap(source)
86
+ wrap_for_nesting(wrap_for_owner(source))
87
+ end
88
+
89
+ # Update the source code so that when it has the right owner when eval'd.
90
+ #
91
+ # This (combined with definition_for_owner) is backup for the case that
92
+ # wrap_for_nesting fails, to ensure that the method will stil be defined in
93
+ # the correct place.
94
+ #
95
+ # @param [String] source The source to wrap
96
+ # @return [String]
97
+ def wrap_for_owner(source)
98
+ Pry.current[:pry_owner] = method.owner
99
+ owner_source = definition_for_owner(source)
100
+ visibility_fix = "#{method.visibility.to_s} #{method.name.to_sym.inspect}"
101
+ "Pry.current[:pry_owner].class_eval do; #{owner_source}\n#{visibility_fix}\nend"
102
+ end
103
+
104
+ # Update the new source code to have the correct Module.nesting.
105
+ #
106
+ # This method uses syntactic analysis of the original source file to determine
107
+ # the new nesting, so that we can tell the difference between:
108
+ #
109
+ # class A; def self.b; end; end
110
+ # class << A; def b; end; end
111
+ #
112
+ # The resulting code should be evaluated in the TOPLEVEL_BINDING.
113
+ #
114
+ # @param [String] source The source to wrap.
115
+ # @return [String]
116
+ def wrap_for_nesting(source)
117
+ nesting = Pry::Code.from_file(method.source_file).nesting_at(method.source_line)
118
+
119
+ (nesting + [source] + nesting.map{ "end" } + [""]).join(";")
120
+ rescue Pry::Indent::UnparseableNestingError
121
+ source
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,186 @@
1
+ class Pry
2
+ class Method
3
+
4
+ # This class is responsible for locating the *real* `Pry::Method`
5
+ # object captured by a binding.
6
+ #
7
+ # Given a `Binding` from inside a method and a 'seed' Pry::Method object,
8
+ # there are primarily two situations where the seed method doesn't match
9
+ # the Binding:
10
+ # 1. The Pry::Method is from a subclass 2. The Pry::Method represents a method of the same name
11
+ # while the original was renamed to something else. For 1. we
12
+ # search vertically up the inheritance chain,
13
+ # and for 2. we search laterally along the object's method table.
14
+ #
15
+ # When we locate the method that matches the Binding we wrap it in
16
+ # Pry::Method and return it, or return nil if we fail.
17
+ class WeirdMethodLocator
18
+ class << self
19
+
20
+ # Whether the given method object matches the associated binding.
21
+ # If the method object does not match the binding, then it's
22
+ # most likely not the method captured by the binding, and we
23
+ # must commence a search.
24
+ #
25
+ # @param [Pry::Method] method
26
+ # @param [Binding] b
27
+ # @return [Boolean]
28
+ def normal_method?(method, b)
29
+ method && (method.source_file && method.source_range rescue false) &&
30
+ File.expand_path(method.source_file) == File.expand_path(b.eval('__FILE__')) &&
31
+ method.source_range.include?(b.eval('__LINE__'))
32
+ end
33
+
34
+ def weird_method?(method, b)
35
+ !normal_method?(method, b)
36
+ end
37
+ end
38
+
39
+ attr_accessor :method
40
+ attr_accessor :target
41
+
42
+ # @param [Pry::Method] method The seed method.
43
+ # @param [Binding] target The Binding that captures the method
44
+ # we want to locate.
45
+ def initialize(method, target)
46
+ @method, @target = method, target
47
+ end
48
+
49
+ # @return [Pry::Method, nil] The Pry::Method that matches the
50
+ # given binding.
51
+ def get_method
52
+ find_method_in_superclass || find_renamed_method
53
+ end
54
+
55
+ # @return [Boolean] Whether the Pry::Method is unrecoverable
56
+ # This usually happens when the method captured by the Binding
57
+ # has been subsequently deleted.
58
+ def lost_method?
59
+ !!(get_method.nil? && renamed_method_source_location)
60
+ end
61
+
62
+ private
63
+
64
+ def normal_method?(method)
65
+ self.class.normal_method?(method, target)
66
+ end
67
+
68
+ def target_self
69
+ target.eval('self')
70
+ end
71
+
72
+ def target_file
73
+ pry_file? ? target.eval('__FILE__') : File.expand_path(target.eval('__FILE__'))
74
+ end
75
+
76
+ def target_line
77
+ target.eval('__LINE__')
78
+ end
79
+
80
+ def pry_file?
81
+ Pry.eval_path == target.eval('__FILE__')
82
+ end
83
+
84
+ # it's possible in some cases that the method we find by this approach is a sub-method of
85
+ # the one we're currently in, consider:
86
+ #
87
+ # class A; def b; binding.pry; end; end
88
+ # class B < A; def b; super; end; end
89
+ #
90
+ # Given that we can normally find the source_range of methods, and that we know which
91
+ # __FILE__ and __LINE__ the binding is at, we can hope to disambiguate these cases.
92
+ #
93
+ # This obviously won't work if the source is unavaiable for some reason, or if both
94
+ # methods have the same __FILE__ and __LINE__, or if we're in rbx where b.eval('__LINE__')
95
+ # is broken.
96
+ #
97
+ # @return [Pry::Method, nil] The Pry::Method representing the
98
+ # superclass method.
99
+ def find_method_in_superclass
100
+ guess = method
101
+
102
+ while guess
103
+ # needs rescue if this is a Disowned method or a C method or something...
104
+ # TODO: Fix up the exception handling so we don't need a bare rescue
105
+ if normal_method?(guess)
106
+ return guess
107
+ else
108
+ guess = guess.super
109
+ end
110
+ end
111
+
112
+ # Uhoh... none of the methods in the chain had the right __FILE__ and __LINE__
113
+ # This may be caused by rbx https://github.com/rubinius/rubinius/issues/953,
114
+ # or other unknown circumstances (TODO: we should warn the user when this happens)
115
+ nil
116
+ end
117
+
118
+ # This is the case where the name of a method has changed
119
+ # (via alias_method) so we locate the Method object for the
120
+ # renamed method.
121
+ #
122
+ # @return [Pry::Method, nil] The Pry::Method representing the
123
+ # renamed method
124
+ def find_renamed_method
125
+ return if !valid_file?(target_file)
126
+ alias_name = all_methods_for(target_self).find do |v|
127
+ expanded_source_location(target_self.method(v).source_location) == renamed_method_source_location
128
+ end
129
+
130
+ alias_name && Pry::Method(target_self.method(alias_name))
131
+ end
132
+
133
+ def expanded_source_location(sl)
134
+ return if !sl
135
+
136
+ if pry_file?
137
+ sl
138
+ else
139
+ [File.expand_path(sl.first), sl.last]
140
+ end
141
+ end
142
+
143
+ # Use static analysis to locate the start of the method definition.
144
+ # We have the `__FILE__` and `__LINE__` from the binding and the
145
+ # original name of the method so we search up until we find a
146
+ # def/define_method, etc defining a method of the appropriate name.
147
+ #
148
+ # @return [Array<String, Fixnum>] The `source_location` of the
149
+ # renamed method
150
+ def renamed_method_source_location
151
+ return @original_method_source_location if defined?(@original_method_source_location)
152
+
153
+ source_index = lines_for_file(target_file)[0..(target_line - 1)].rindex do |v|
154
+ Pry::Method.method_definition?(method.name, v)
155
+ end
156
+
157
+ @original_method_source_location = source_index &&
158
+ [target_file, index_to_line_number(source_index)]
159
+ end
160
+
161
+ def index_to_line_number(index)
162
+ # Pry.line_buffer is 0-indexed
163
+ pry_file? ? index : index + 1
164
+ end
165
+
166
+ def valid_file?(file)
167
+ (File.exists?(file) && !File.directory?(file)) || Pry.eval_path == file
168
+ end
169
+
170
+ def lines_for_file(file)
171
+ @lines_for_file ||= {}
172
+ @lines_for_file[file] ||= if Pry.eval_path == file
173
+ Pry.line_buffer
174
+ else
175
+ File.readlines(file)
176
+ end
177
+ end
178
+
179
+ def all_methods_for(obj)
180
+ obj.public_methods(false) +
181
+ obj.private_methods(false) +
182
+ obj.protected_methods(false)
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,136 @@
1
+ require 'pry/helpers/documentation_helpers'
2
+ require 'forwardable'
3
+
4
+ class Pry
5
+ class WrappedModule
6
+
7
+ # This class represents a single candidate for a module/class definition.
8
+ # It provides access to the source, documentation, line and file
9
+ # for a monkeypatch (reopening) of a class/module.
10
+ class Candidate
11
+ include Pry::Helpers::DocumentationHelpers
12
+ include Pry::CodeObject::Helpers
13
+ extend Forwardable
14
+
15
+ # @return [String] The file where the module definition is located.
16
+ attr_reader :file
17
+ alias_method :source_file, :file
18
+
19
+ # @return [Fixnum] The line where the module definition is located.
20
+ attr_reader :line
21
+ alias_method :source_line, :line
22
+
23
+ # Methods to delegate to associated `Pry::WrappedModule
24
+ # instance`.
25
+ private_delegates = [:lines_for_file, :method_candidates,
26
+ :yard_docs?]
27
+
28
+ public_delegates = [:wrapped, :module?, :class?, :name, :nonblank_name,
29
+ :number_of_candidates]
30
+
31
+ def_delegators :@wrapper, *(private_delegates + public_delegates)
32
+ private(*private_delegates)
33
+ public(*public_delegates)
34
+
35
+ # @raise [Pry::CommandError] If `rank` is out of bounds.
36
+ # @param [Pry::WrappedModule] wrapper The associated
37
+ # `Pry::WrappedModule` instance that owns the candidates.
38
+ # @param [Fixnum] rank The rank of the candidate to
39
+ # retrieve. Passing 0 returns 'primary candidate' (the candidate with largest
40
+ # number of methods), passing 1 retrieves candidate with
41
+ # second largest number of methods, and so on, up to
42
+ # `Pry::WrappedModule#number_of_candidates() - 1`
43
+ def initialize(wrapper, rank)
44
+ @wrapper = wrapper
45
+
46
+ if number_of_candidates <= 0
47
+ raise CommandError, "Cannot find a definition for #{name} module!"
48
+ elsif rank > (number_of_candidates - 1)
49
+ raise CommandError, "No such module candidate. Allowed candidates range is from 0 to #{number_of_candidates - 1}"
50
+ end
51
+
52
+ @rank = rank
53
+ @file, @line = source_location
54
+ end
55
+
56
+ # @raise [Pry::CommandError] If source code cannot be found.
57
+ # @return [String] The source for the candidate, i.e the
58
+ # complete module/class definition.
59
+ def source
60
+ return nil if file.nil?
61
+ return @source if @source
62
+
63
+ @source = strip_leading_whitespace(Pry::Code.from_file(file).expression_at(line, number_of_lines_in_first_chunk))
64
+ end
65
+
66
+ # @raise [Pry::CommandError] If documentation cannot be found.
67
+ # @return [String] The documentation for the candidate.
68
+ def doc
69
+ return nil if file.nil?
70
+ return @doc if @doc
71
+
72
+ @doc = get_comment_content(Pry::Code.from_file(file).comment_describing(line))
73
+ end
74
+
75
+ # @return [Array, nil] A `[String, Fixnum]` pair representing the
76
+ # source location (file and line) for the candidate or `nil`
77
+ # if no source location found.
78
+ def source_location
79
+ return @source_location if @source_location
80
+
81
+ file, line = first_method_source_location
82
+ return nil if !file.is_a?(String)
83
+
84
+ @source_location = [file, first_line_of_module_definition(file, line)]
85
+ rescue Pry::RescuableException
86
+ nil
87
+ end
88
+
89
+ private
90
+
91
+ # Locate the first line of the module definition.
92
+ # @param [String] file The file that contains the module
93
+ # definition (somewhere).
94
+ # @param [Fixnum] line The module definition should appear
95
+ # before this line (if it exists).
96
+ # @return [Fixnum] The line where the module is defined. This
97
+ # line number is one-indexed.
98
+ def first_line_of_module_definition(file, line)
99
+ searchable_lines = lines_for_file(file)[0..(line - 2)]
100
+ searchable_lines.rindex { |v| class_regexes.any? { |r| r =~ v } } + 1
101
+ end
102
+
103
+ def class_regexes
104
+ mod_type_string = wrapped.class.to_s.downcase
105
+ [/^\s*#{mod_type_string}\s+(?:(?:\w*)::)*?#{wrapped.name.split(/::/).last}/,
106
+ /^\s*(::)?#{wrapped.name.split(/::/).last}\s*?=\s*?#{wrapped.class}/,
107
+ /^\s*(::)?#{wrapped.name.split(/::/).last}\.(class|instance)_eval/]
108
+ end
109
+
110
+ # This method is used by `Candidate#source_location` as a
111
+ # starting point for the search for the candidate's definition.
112
+ # @return [Array] The source location of the base method used to
113
+ # calculate the source location of the candidate.
114
+ def first_method_source_location
115
+ @first_method_source_location ||= method_candidates[@rank].first.source_location
116
+ end
117
+
118
+ # @return [Array] The source location of the last method in this
119
+ # candidate's module definition.
120
+ def last_method_source_location
121
+ @end_method_source_location ||= method_candidates[@rank].last.source_location
122
+ end
123
+
124
+ # Return the number of lines between the start of the class definition
125
+ # and the start of the last method. We use this value so we can
126
+ # quickly grab these lines from the file (without having to
127
+ # check each intervening line for validity, which is expensive) speeding up source extraction.
128
+ # @return [Fixum] Number of lines.
129
+ def number_of_lines_in_first_chunk
130
+ end_method_line = last_method_source_location.last
131
+
132
+ end_method_line - line
133
+ end
134
+ end
135
+ end
136
+ end