pry 0.10.0.pre2-universal-mswin32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
data/lib/pry/cli.rb ADDED
@@ -0,0 +1,220 @@
1
+ class Pry
2
+
3
+ # Manage the processing of command line options
4
+ class CLI
5
+
6
+ NoOptionsError = Class.new(StandardError)
7
+
8
+ class << self
9
+
10
+ # @return [Proc] The Proc defining the valid command line options.
11
+ attr_accessor :options
12
+
13
+ # @return [Array] The Procs that process the parsed options. Plugins can
14
+ # utilize this facility in order to add and process their own Pry
15
+ # options.
16
+ attr_accessor :option_processors
17
+
18
+ # @return [Array<String>] The input array of strings to process
19
+ # as CLI options.
20
+ attr_accessor :input_args
21
+
22
+ # Add another set of CLI options (a Slop block)
23
+ def add_options(&block)
24
+ if options
25
+ old_options = options
26
+ self.options = proc do
27
+ instance_exec(&old_options)
28
+ instance_exec(&block)
29
+ end
30
+ else
31
+ self.options = block
32
+ end
33
+
34
+ self
35
+ end
36
+
37
+ # Bring in options defined in plugins
38
+ def add_plugin_options
39
+ Pry.plugins.values.each do |plugin|
40
+ plugin.load_cli_options
41
+ end
42
+
43
+ self
44
+ end
45
+
46
+ # Add a block responsible for processing parsed options.
47
+ def add_option_processor(&block)
48
+ self.option_processors ||= []
49
+ option_processors << block
50
+
51
+ self
52
+ end
53
+
54
+ # Clear `options` and `option_processors`
55
+ def reset
56
+ self.options = nil
57
+ self.option_processors = nil
58
+ end
59
+
60
+ def parse_options(args=ARGV)
61
+ unless options
62
+ raise NoOptionsError, "No command line options defined! Use Pry::CLI.add_options to add command line options."
63
+ end
64
+
65
+ self.input_args = args
66
+
67
+ begin
68
+ opts = Slop.parse!(
69
+ args,
70
+ :help => true,
71
+ :multiple_switches => false,
72
+ :strict => true,
73
+ &options
74
+ )
75
+ rescue Slop::InvalidOptionError
76
+ # Display help message on unknown switches and exit.
77
+ puts Slop.new(&options)
78
+ exit
79
+ end
80
+
81
+ # Option processors are optional.
82
+ if option_processors
83
+ option_processors.each { |processor| processor.call(opts) }
84
+ end
85
+
86
+ self
87
+ end
88
+
89
+ end
90
+
91
+ reset
92
+ end
93
+ end
94
+
95
+
96
+ # String that is built to be executed on start (created by -e and -exec switches)
97
+ exec_string = ""
98
+
99
+ # Bring in options defined by plugins
100
+ Slop.new do
101
+ on "no-plugins" do
102
+ Pry.config.should_load_plugins = false
103
+ end
104
+ end.parse(ARGV.dup)
105
+
106
+ if Pry.config.should_load_plugins
107
+ Pry::CLI.add_plugin_options
108
+ end
109
+
110
+ # The default Pry command line options (before plugin options are included)
111
+ Pry::CLI.add_options do
112
+ banner %{Usage: pry [OPTIONS]
113
+ Start a Pry session.
114
+ See http://pryrepl.org/ for more information.
115
+ Copyright (c) 2013 John Mair (banisterfiend)
116
+ --
117
+ }
118
+ on :e, :exec=, "A line of code to execute in context before the session starts" do |input|
119
+ exec_string << input << "\n"
120
+ end
121
+
122
+ on "no-pager", "Disable pager for long output" do
123
+ Pry.config.pager = false
124
+ end
125
+
126
+ on "no-history", "Disable history loading" do
127
+ Pry.config.history.should_load = false
128
+ end
129
+
130
+ on "no-color", "Disable syntax highlighting for session" do
131
+ Pry.config.color = false
132
+ end
133
+
134
+ on :f, "Suppress loading of ~/.pryrc and ./.pryrc" do
135
+ Pry.config.should_load_rc = false
136
+ Pry.config.should_load_local_rc = false
137
+ end
138
+
139
+ on :s, "select-plugin=", "Only load specified plugin (and no others)." do |plugin_name|
140
+ Pry.config.should_load_plugins = false
141
+ Pry.plugins[plugin_name].activate!
142
+ end
143
+
144
+ on :d, "disable-plugin=", "Disable a specific plugin." do |plugin_name|
145
+ Pry.plugins[plugin_name].disable!
146
+ end
147
+
148
+ on "no-plugins", "Suppress loading of plugins." do
149
+ Pry.config.should_load_plugins = false
150
+ end
151
+
152
+ on "plugins", "List installed plugins." do
153
+ puts "Installed Plugins:"
154
+ puts "--"
155
+ Pry.locate_plugins.each do |plugin|
156
+ puts "#{plugin.name}".ljust(18) << plugin.spec.summary
157
+ end
158
+ exit
159
+ end
160
+
161
+ on "simple-prompt", "Enable simple prompt mode" do
162
+ Pry.config.prompt = Pry::SIMPLE_PROMPT
163
+ end
164
+
165
+ on "noprompt", "No prompt mode" do
166
+ Pry.config.prompt = Pry::NO_PROMPT
167
+ end
168
+
169
+ on :r, :require=, "`require` a Ruby script at startup" do |file|
170
+ Pry.config.requires << file
171
+ end
172
+
173
+ on :I=, "Add a path to the $LOAD_PATH", :as => Array, :delimiter => ":" do |load_path|
174
+ load_path.map! do |path|
175
+ /\A\.\// =~ path ? path : File.expand_path(path)
176
+ end
177
+
178
+ $LOAD_PATH.unshift(*load_path)
179
+ end
180
+
181
+ on "gem", "Shorthand for -I./lib -rgemname" do |load_path|
182
+ $LOAD_PATH.unshift("./lib")
183
+ Dir["./lib/*.rb"].each do |file|
184
+ Pry.config.requires << file
185
+ end
186
+ end
187
+
188
+ on :v, :version, "Display the Pry version" do
189
+ puts "Pry version #{Pry::VERSION} on Ruby #{RUBY_VERSION}"
190
+ exit
191
+ end
192
+
193
+ on(:c, :context=,
194
+ "Start the session in the specified context. Equivalent to `context.pry` in a session.",
195
+ :default => "Pry.toplevel_binding"
196
+ )
197
+ end.add_option_processor do |opts|
198
+
199
+ exit if opts.help?
200
+
201
+ # invoked via cli
202
+ Pry.cli = true
203
+
204
+ # create the actual context
205
+ if opts[:context]
206
+ Pry.initial_session_setup
207
+ context = Pry.binding_for(eval(opts[:context]))
208
+ else
209
+ context = Pry.toplevel_binding
210
+ end
211
+
212
+ if Pry::CLI.input_args.any? && Pry::CLI.input_args != ["pry"]
213
+ full_name = File.expand_path(Pry::CLI.input_args.first)
214
+ Pry.load_file_through_repl(full_name)
215
+ exit
216
+ end
217
+
218
+ # Start the session (running any code passed with -e, if there is any)
219
+ Pry.start(context, :input => StringIO.new(exec_string))
220
+ end
data/lib/pry/code.rb ADDED
@@ -0,0 +1,346 @@
1
+ require 'pry/code/loc'
2
+ require 'pry/code/code_range'
3
+ require 'pry/code/code_file'
4
+
5
+ class Pry
6
+ class << self
7
+ # Convert the given object into an instance of `Pry::Code`, if it isn't
8
+ # already one.
9
+ #
10
+ # @param [Code, Method, UnboundMethod, Proc, Pry::Method, String, Array,
11
+ # IO] obj
12
+ def Code(obj)
13
+ case obj
14
+ when Code
15
+ obj
16
+ when ::Method, UnboundMethod, Proc, Pry::Method
17
+ Code.from_method(obj)
18
+ else
19
+ Code.new(obj)
20
+ end
21
+ end
22
+ end
23
+
24
+ # `Pry::Code` is a class that encapsulates lines of source code and their
25
+ # line numbers and formats them for terminal output. It can read from a file
26
+ # or method definition or be instantiated with a `String` or an `Array`.
27
+ #
28
+ # In general, the formatting methods in `Code` return a new `Code` object
29
+ # which will format the text as specified when `#to_s` is called. This allows
30
+ # arbitrary chaining of formatting methods without mutating the original
31
+ # object.
32
+ class Code
33
+ class << self
34
+ include MethodSource::CodeHelpers
35
+
36
+ # Instantiate a `Code` object containing code loaded from a file or
37
+ # Pry's line buffer.
38
+ #
39
+ # @param [String] filename The name of a file, or "(pry)".
40
+ # @param [Symbol] code_type The type of code the file contains.
41
+ # @return [Code]
42
+ def from_file(filename, code_type = nil)
43
+ code_file = CodeFile.new(filename, code_type)
44
+ new(code_file.code, 1, code_file.code_type)
45
+ end
46
+
47
+ # Instantiate a `Code` object containing code extracted from a
48
+ # `::Method`, `UnboundMethod`, `Proc`, or `Pry::Method` object.
49
+ #
50
+ # @param [::Method, UnboundMethod, Proc, Pry::Method] meth The method
51
+ # object.
52
+ # @param [Integer, nil] start_line The line number to start on, or nil to
53
+ # use the method's original line numbers.
54
+ # @return [Code]
55
+ def from_method(meth, start_line = nil)
56
+ meth = Pry::Method(meth)
57
+ start_line ||= meth.source_line || 1
58
+ new(meth.source, start_line, meth.source_type)
59
+ end
60
+
61
+ # Attempt to extract the source code for module (or class) `mod`.
62
+ #
63
+ # @param [Module, Class] mod The module (or class) of interest.
64
+ # @param [Integer] candidate_rank The module candidate (by rank)
65
+ # to use (see `Pry::WrappedModule::Candidate` for more information).
66
+ # @param [Integer, nil] start_line The line number to start on, or nil to
67
+ # use the method's original line numbers.
68
+ # @return [Code]
69
+ def from_module(mod, candidate_rank = 0, start_line=nil)
70
+ candidate = Pry::WrappedModule(mod).candidate(candidate_rank)
71
+ start_line ||= candidate.line
72
+ new(candidate.source, start_line, :ruby)
73
+ end
74
+ end
75
+
76
+ # @return [Symbol] The type of code stored in this wrapper.
77
+ attr_accessor :code_type
78
+
79
+ # Instantiate a `Code` object containing code from the given `Array`,
80
+ # `String`, or `IO`. The first line will be line 1 unless specified
81
+ # otherwise. If you need non-contiguous line numbers, you can create an
82
+ # empty `Code` object and then use `#push` to insert the lines.
83
+ #
84
+ # @param [Array<String>, String, IO] lines
85
+ # @param [Integer?] start_line
86
+ # @param [Symbol?] code_type
87
+ def initialize(lines = [], start_line = 1, code_type = :ruby)
88
+ if lines.is_a? String
89
+ lines = lines.lines
90
+ end
91
+ @lines = lines.each_with_index.map { |line, lineno|
92
+ LOC.new(line, lineno + start_line.to_i) }
93
+ @code_type = code_type
94
+ end
95
+
96
+ # Append the given line. +lineno+ is one more than the last existing
97
+ # line, unless specified otherwise.
98
+ #
99
+ # @param [String] line
100
+ # @param [Integer?] lineno
101
+ # @return [String] The inserted line.
102
+ def push(line, lineno = nil)
103
+ if lineno.nil?
104
+ lineno = @lines.last.lineno + 1
105
+ end
106
+ @lines.push(LOC.new(line, lineno))
107
+ line
108
+ end
109
+ alias << push
110
+
111
+ # Filter the lines using the given block.
112
+ #
113
+ # @yield [LOC]
114
+ # @return [Code]
115
+ def select(&block)
116
+ alter do
117
+ @lines = @lines.select(&block)
118
+ end
119
+ end
120
+
121
+ # Remove all lines that aren't in the given range, expressed either as a
122
+ # `Range` object or a first and last line number (inclusive). Negative
123
+ # indices count from the end of the array of lines.
124
+ #
125
+ # @param [Range, Integer] start_line
126
+ # @param [Integer?] end_line
127
+ # @return [Code]
128
+ def between(start_line, end_line = nil)
129
+ return self unless start_line
130
+
131
+ code_range = CodeRange.new(start_line, end_line)
132
+
133
+ alter do
134
+ @lines = @lines[code_range.indices_range(@lines)] || []
135
+ end
136
+ end
137
+
138
+ # Take `num_lines` from `start_line`, forward or backwards.
139
+ #
140
+ # @param [Integer] start_line
141
+ # @param [Integer] num_lines
142
+ # @return [Code]
143
+ def take_lines(start_line, num_lines)
144
+ start_idx =
145
+ if start_line >= 0
146
+ @lines.index { |loc| loc.lineno >= start_line } || @lines.length
147
+ else
148
+ [@lines.length + start_line, 0].max
149
+ end
150
+
151
+ alter do
152
+ @lines = @lines.slice(start_idx, num_lines)
153
+ end
154
+ end
155
+
156
+ # Remove all lines except for the +lines+ up to and excluding +lineno+.
157
+ #
158
+ # @param [Integer] lineno
159
+ # @param [Integer] lines
160
+ # @return [Code]
161
+ def before(lineno, lines = 1)
162
+ return self unless lineno
163
+
164
+ select do |loc|
165
+ loc.lineno >= lineno - lines && loc.lineno < lineno
166
+ end
167
+ end
168
+
169
+ # Remove all lines except for the +lines+ on either side of and including
170
+ # +lineno+.
171
+ #
172
+ # @param [Integer] lineno
173
+ # @param [Integer] lines
174
+ # @return [Code]
175
+ def around(lineno, lines = 1)
176
+ return self unless lineno
177
+
178
+ select do |loc|
179
+ loc.lineno >= lineno - lines && loc.lineno <= lineno + lines
180
+ end
181
+ end
182
+
183
+ # Remove all lines except for the +lines+ after and excluding +lineno+.
184
+ #
185
+ # @param [Integer] lineno
186
+ # @param [Integer] lines
187
+ # @return [Code]
188
+ def after(lineno, lines = 1)
189
+ return self unless lineno
190
+
191
+ select do |loc|
192
+ loc.lineno > lineno && loc.lineno <= lineno + lines
193
+ end
194
+ end
195
+
196
+ # Remove all lines that don't match the given `pattern`.
197
+ #
198
+ # @param [Regexp] pattern
199
+ # @return [Code]
200
+ def grep(pattern)
201
+ return self unless pattern
202
+ pattern = Regexp.new(pattern)
203
+
204
+ select do |loc|
205
+ loc.line =~ pattern
206
+ end
207
+ end
208
+
209
+ # Format output with line numbers next to it, unless `y_n` is falsy.
210
+ #
211
+ # @param [Boolean?] y_n
212
+ # @return [Code]
213
+ def with_line_numbers(y_n = true)
214
+ alter do
215
+ @with_line_numbers = y_n
216
+ end
217
+ end
218
+
219
+ # Format output with a marker next to the given +lineno+, unless +lineno+ is
220
+ # falsy.
221
+ #
222
+ # @param [Integer?] lineno
223
+ # @return [Code]
224
+ def with_marker(lineno = 1)
225
+ alter do
226
+ @with_marker = !!lineno
227
+ @marker_lineno = lineno
228
+ end
229
+ end
230
+
231
+ # Format output with the specified number of spaces in front of every line,
232
+ # unless `spaces` is falsy.
233
+ #
234
+ # @param [Integer?] spaces
235
+ # @return [Code]
236
+ def with_indentation(spaces = 0)
237
+ alter do
238
+ @with_indentation = !!spaces
239
+ @indentation_num = spaces
240
+ end
241
+ end
242
+
243
+ # @return [String]
244
+ def inspect
245
+ Object.instance_method(:to_s).bind(self).call
246
+ end
247
+
248
+ # @return [Integer] the number of digits in the last line.
249
+ def max_lineno_width
250
+ @lines.length > 0 ? @lines.last.lineno.to_s.length : 0
251
+ end
252
+
253
+ # @return [String] a formatted representation (based on the configuration of
254
+ # the object).
255
+ def to_s
256
+ print_to_output("", false)
257
+ end
258
+
259
+ # @return [String] a (possibly highlighted) copy of the source code.
260
+ def highlighted
261
+ print_to_output("", true)
262
+ end
263
+
264
+ # Writes a formatted representation (based on the configuration of the
265
+ # object) to the given output, which must respond to `#<<`.
266
+ def print_to_output(output, color=false)
267
+ @lines.each do |loc|
268
+ loc = loc.dup
269
+ loc.colorize(@code_type) if color
270
+ loc.add_line_number(max_lineno_width, color) if @with_line_numbers
271
+ loc.add_marker(@marker_lineno) if @with_marker
272
+ loc.indent(@indentation_num) if @with_indentation
273
+ output << loc.line
274
+ output << "\n"
275
+ end
276
+ output
277
+ end
278
+
279
+ # Get the comment that describes the expression on the given line number.
280
+ #
281
+ # @param [Integer] line_number (1-based)
282
+ # @return [String] the code.
283
+ def comment_describing(line_number)
284
+ self.class.comment_describing(raw, line_number)
285
+ end
286
+
287
+ # Get the multiline expression that starts on the given line number.
288
+ #
289
+ # @param [Integer] line_number (1-based)
290
+ # @return [String] the code.
291
+ def expression_at(line_number, consume = 0)
292
+ self.class.expression_at(raw, line_number, :consume => consume)
293
+ end
294
+
295
+ # Get the (approximate) Module.nesting at the give line number.
296
+ #
297
+ # @param [Integer] line_number line number starting from 1
298
+ # @param [Module] top_module the module in which this code exists
299
+ # @return [Array<Module>] a list of open modules.
300
+ def nesting_at(line_number, top_module = Object)
301
+ Pry::Indent.nesting_at(raw, line_number)
302
+ end
303
+
304
+ # Return an unformatted String of the code.
305
+ #
306
+ # @return [String]
307
+ def raw
308
+ @lines.map(&:line).join("\n") << "\n"
309
+ end
310
+
311
+ # Return the number of lines stored.
312
+ #
313
+ # @return [Integer]
314
+ def length
315
+ @lines ? @lines.length : 0
316
+ end
317
+
318
+ # Two `Code` objects are equal if they contain the same lines with the same
319
+ # numbers. Otherwise, call `to_s` and `chomp` and compare as Strings.
320
+ #
321
+ # @param [Code, Object] other
322
+ # @return [Boolean]
323
+ def ==(other)
324
+ if other.is_a?(Code)
325
+ other_lines = other.instance_variable_get(:@lines)
326
+ @lines.each_with_index.all? { |loc, i| loc == other_lines[i] }
327
+ else
328
+ to_s.chomp == other.to_s.chomp
329
+ end
330
+ end
331
+
332
+ # Forward any missing methods to the output of `#to_s`.
333
+ def method_missing(name, *args, &block)
334
+ to_s.send(name, *args, &block)
335
+ end
336
+ undef =~
337
+
338
+ protected
339
+
340
+ # An abstraction of the `dup.instance_eval` pattern used throughout this
341
+ # class.
342
+ def alter(&block)
343
+ dup.tap { |o| o.instance_eval(&block) }
344
+ end
345
+ end
346
+ end