puppet-debugger 0.4.1 → 0.4.2

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.
@@ -1,334 +1,333 @@
1
+ # frozen_string_literal: true
1
2
  require_relative 'code/loc'
2
3
  require_relative 'code/code_range'
3
4
  require_relative 'code/code_file'
4
5
 
5
- # `Pry::Code` is a class that encapsulates lines of source code and their
6
- # line numbers and formats them for terminal output. It can read from a file
7
- # or method definition or be instantiated with a `String` or an `Array`.
8
- #
9
- # In general, the formatting methods in `Code` return a new `Code` object
10
- # which will format the text as specified when `#to_s` is called. This allows
11
- # arbitrary chaining of formatting methods without mutating the original
12
- # object.
13
- class DebuggerCode
14
- class << self
15
- # include MethodSource::CodeHelpers
16
-
17
- # Instantiate a `Code` object containing code loaded from a file or
18
- # Pry's line buffer.
19
- #
20
- # @param [String] filename The name of a file, or "(pry)".
21
- # @param [Symbol] code_type The type of code the file contains.
22
- # @return [Code]
23
- def from_file(filename, code_type = nil)
24
- code_file = CodeFile.new(filename, code_type)
25
- new(code_file.code, 1, code_file.code_type, filename)
26
- end
27
-
28
- # Instantiate a `Code` object containing code loaded from a file or
29
- # Pry's line buffer.
30
- #
31
- # @param [String] source code".
32
- # @param [Symbol] code_type The type of code the file contains.
33
- # @return [Code]
34
- def from_string(code, code_type = nil)
35
- new(code, 1, code_type)
36
- end
37
- end
38
-
39
- # @return [Symbol] The type of code stored in this wrapper.
40
- attr_accessor :code_type, :filename
41
-
42
- # Instantiate a `Code` object containing code from the given `Array`,
43
- # `String`, or `IO`. The first line will be line 1 unless specified
44
- # otherwise. If you need non-contiguous line numbers, you can create an
45
- # empty `Code` object and then use `#push` to insert the lines.
46
- #
47
- # @param [Array<String>, String, IO] lines
48
- # @param [Integer?] start_line
49
- # @param [Symbol?] code_type
50
- def initialize(lines = [], start_line = 1, code_type = :ruby, filename=nil)
51
- if lines.is_a? String
52
- lines = lines.lines
53
- end
54
- @lines = lines.each_with_index.map { |line, lineno|
55
- LOC.new(line, lineno + start_line.to_i) }
56
- @code_type = code_type
57
- @filename = filename
58
- @with_file_reference = nil
59
- @with_marker = @with_indentation = nil
60
- end
61
-
62
- # Append the given line. +lineno+ is one more than the last existing
63
- # line, unless specified otherwise.
64
- #
65
- # @param [String] line
66
- # @param [Integer?] lineno
67
- # @return [String] The inserted line.
68
- def push(line, lineno = nil)
69
- if lineno.nil?
70
- lineno = @lines.last.lineno + 1
71
- end
72
- @lines.push(LOC.new(line, lineno))
73
- line
74
- end
75
- alias << push
76
-
77
- # Filter the lines using the given block.
6
+ # `Pry::Code` is a class that encapsulates lines of source code and their
7
+ # line numbers and formats them for terminal output. It can read from a file
8
+ # or method definition or be instantiated with a `String` or an `Array`.
9
+ #
10
+ # In general, the formatting methods in `Code` return a new `Code` object
11
+ # which will format the text as specified when `#to_s` is called. This allows
12
+ # arbitrary chaining of formatting methods without mutating the original
13
+ # object.
14
+ class DebuggerCode
15
+ class << self
16
+ # include MethodSource::CodeHelpers
17
+
18
+ # Instantiate a `Code` object containing code loaded from a file or
19
+ # Pry's line buffer.
78
20
  #
79
- # @yield [LOC]
21
+ # @param [String] filename The name of a file, or "(pry)".
22
+ # @param [Symbol] code_type The type of code the file contains.
80
23
  # @return [Code]
81
- def select(&block)
82
- alter do
83
- @lines = @lines.select(&block)
84
- end
24
+ def from_file(filename, code_type = nil)
25
+ code_file = CodeFile.new(filename, code_type)
26
+ new(code_file.code, 1, code_file.code_type, filename)
85
27
  end
86
28
 
87
- # Remove all lines that aren't in the given range, expressed either as a
88
- # `Range` object or a first and last line number (inclusive). Negative
89
- # indices count from the end of the array of lines.
29
+ # Instantiate a `Code` object containing code loaded from a file or
30
+ # Pry's line buffer.
90
31
  #
91
- # @param [Range, Integer] start_line
92
- # @param [Integer?] end_line
32
+ # @param [String] source code".
33
+ # @param [Symbol] code_type The type of code the file contains.
93
34
  # @return [Code]
94
- def between(start_line, end_line = nil)
95
- return self unless start_line
96
-
97
- code_range = CodeRange.new(start_line, end_line)
98
-
99
- alter do
100
- @lines = @lines[code_range.indices_range(@lines)] || []
101
- end
102
- end
103
-
104
- # Take `num_lines` from `start_line`, forward or backwards.
105
- #
106
- # @param [Integer] start_line
107
- # @param [Integer] num_lines
108
- # @return [Code]
109
- def take_lines(start_line, num_lines)
110
- start_idx =
111
- if start_line >= 0
112
- @lines.index { |loc| loc.lineno >= start_line } || @lines.length
113
- else
114
- [@lines.length + start_line, 0].max
115
- end
116
-
117
- alter do
118
- @lines = @lines.slice(start_idx, num_lines)
119
- end
35
+ def from_string(code, code_type = nil)
36
+ new(code, 1, code_type)
120
37
  end
38
+ end
121
39
 
122
- # Remove all lines except for the +lines+ up to and excluding +lineno+.
123
- #
124
- # @param [Integer] lineno
125
- # @param [Integer] lines
126
- # @return [Code]
127
- def before(lineno, lines = 1)
128
- return self unless lineno
40
+ # @return [Symbol] The type of code stored in this wrapper.
41
+ attr_accessor :code_type, :filename
129
42
 
130
- select do |loc|
131
- loc.lineno >= lineno - lines && loc.lineno < lineno
132
- end
43
+ # Instantiate a `Code` object containing code from the given `Array`,
44
+ # `String`, or `IO`. The first line will be line 1 unless specified
45
+ # otherwise. If you need non-contiguous line numbers, you can create an
46
+ # empty `Code` object and then use `#push` to insert the lines.
47
+ #
48
+ # @param [Array<String>, String, IO] lines
49
+ # @param [Integer?] start_line
50
+ # @param [Symbol?] code_type
51
+ def initialize(lines = [], start_line = 1, code_type = :ruby, filename = nil)
52
+ lines = lines.lines if lines.is_a? String
53
+ @lines = lines.each_with_index.map do |line, lineno|
54
+ LOC.new(line, lineno + start_line.to_i)
133
55
  end
56
+ @code_type = code_type
57
+ @filename = filename
58
+ @with_file_reference = nil
59
+ @with_marker = @with_indentation = nil
60
+ end
134
61
 
135
- # Remove all lines except for the +lines+ on either side of and including
136
- # +lineno+.
137
- #
138
- # @param [Integer] lineno
139
- # @param [Integer] lines
140
- # @return [Code]
141
- def around(lineno, lines = 1)
142
- return self unless lineno
62
+ # Append the given line. +lineno+ is one more than the last existing
63
+ # line, unless specified otherwise.
64
+ #
65
+ # @param [String] line
66
+ # @param [Integer?] lineno
67
+ # @return [String] The inserted line.
68
+ def push(line, lineno = nil)
69
+ lineno = @lines.last.lineno + 1 if lineno.nil?
70
+ @lines.push(LOC.new(line, lineno))
71
+ line
72
+ end
73
+ alias << push
143
74
 
144
- select do |loc|
145
- loc.lineno >= lineno - lines && loc.lineno <= lineno + lines
146
- end
75
+ # Filter the lines using the given block.
76
+ #
77
+ # @yield [LOC]
78
+ # @return [Code]
79
+ def select(&block)
80
+ alter do
81
+ @lines = @lines.select(&block)
147
82
  end
83
+ end
148
84
 
149
- # Remove all lines except for the +lines+ after and excluding +lineno+.
150
- #
151
- # @param [Integer] lineno
152
- # @param [Integer] lines
153
- # @return [Code]
154
- def after(lineno, lines = 1)
155
- return self unless lineno
156
-
157
- select do |loc|
158
- loc.lineno > lineno && loc.lineno <= lineno + lines
159
- end
160
- end
85
+ # Remove all lines that aren't in the given range, expressed either as a
86
+ # `Range` object or a first and last line number (inclusive). Negative
87
+ # indices count from the end of the array of lines.
88
+ #
89
+ # @param [Range, Integer] start_line
90
+ # @param [Integer?] end_line
91
+ # @return [Code]
92
+ def between(start_line, end_line = nil)
93
+ return self unless start_line
161
94
 
162
- # Remove all lines that don't match the given `pattern`.
163
- #
164
- # @param [Regexp] pattern
165
- # @return [Code]
166
- def grep(pattern)
167
- return self unless pattern
168
- pattern = Regexp.new(pattern)
95
+ code_range = CodeRange.new(start_line, end_line)
169
96
 
170
- select do |loc|
171
- loc.line =~ pattern
172
- end
97
+ alter do
98
+ @lines = @lines[code_range.indices_range(@lines)] || []
173
99
  end
100
+ end
174
101
 
175
- # Format output with line numbers next to it, unless `y_n` is falsy.
176
- #
177
- # @param [Boolean?] y_n
178
- # @return [Code]
179
- def with_line_numbers(y_n = true)
180
- alter do
181
- @with_line_numbers = y_n
102
+ # Take `num_lines` from `start_line`, forward or backwards.
103
+ #
104
+ # @param [Integer] start_line
105
+ # @param [Integer] num_lines
106
+ # @return [Code]
107
+ def take_lines(start_line, num_lines)
108
+ start_idx =
109
+ if start_line >= 0
110
+ @lines.index { |loc| loc.lineno >= start_line } || @lines.length
111
+ else
112
+ [@lines.length + start_line, 0].max
182
113
  end
183
- end
184
114
 
185
- # Format output with line numbers next to it, unless `y_n` is falsy.
186
- #
187
- # @param [Boolean?] y_n
188
- # @return [Code]
189
- def with_file_reference(y_n = true)
190
- alter do
191
- @with_file_reference = y_n
192
- end
115
+ alter do
116
+ @lines = @lines.slice(start_idx, num_lines)
193
117
  end
118
+ end
194
119
 
195
- # Format output with a marker next to the given +lineno+, unless +lineno+ is
196
- # falsy.
197
- #
198
- # @param [Integer?] lineno
199
- # @return [Code]
200
- def with_marker(lineno = 1)
201
- alter do
202
- @with_marker = !!lineno
203
- @marker_lineno = lineno
204
- end
120
+ # Remove all lines except for the +lines+ up to and excluding +lineno+.
121
+ #
122
+ # @param [Integer] lineno
123
+ # @param [Integer] lines
124
+ # @return [Code]
125
+ def before(lineno, lines = 1)
126
+ return self unless lineno
127
+
128
+ select do |loc|
129
+ loc.lineno >= lineno - lines && loc.lineno < lineno
205
130
  end
131
+ end
206
132
 
207
- # Format output with the specified number of spaces in front of every line,
208
- # unless `spaces` is falsy.
209
- #
210
- # @param [Integer?] spaces
211
- # @return [Code]
212
- def with_indentation(spaces = 0)
213
- alter do
214
- @with_indentation = !!spaces
215
- @indentation_num = spaces
216
- end
133
+ # Remove all lines except for the +lines+ on either side of and including
134
+ # +lineno+.
135
+ #
136
+ # @param [Integer] lineno
137
+ # @param [Integer] lines
138
+ # @return [Code]
139
+ def around(lineno, lines = 1)
140
+ return self unless lineno
141
+
142
+ select do |loc|
143
+ loc.lineno >= lineno - lines && loc.lineno <= lineno + lines
217
144
  end
145
+ end
218
146
 
219
- # @return [String]
220
- def inspect
221
- Object.instance_method(:to_s).bind(self).call
147
+ # Remove all lines except for the +lines+ after and excluding +lineno+.
148
+ #
149
+ # @param [Integer] lineno
150
+ # @param [Integer] lines
151
+ # @return [Code]
152
+ def after(lineno, lines = 1)
153
+ return self unless lineno
154
+
155
+ select do |loc|
156
+ loc.lineno > lineno && loc.lineno <= lineno + lines
222
157
  end
158
+ end
223
159
 
224
- # @return [Integer] the number of digits in the last line.
225
- def max_lineno_width
226
- @lines.length > 0 ? @lines.last.lineno.to_s.length : 0
160
+ # Remove all lines that don't match the given `pattern`.
161
+ #
162
+ # @param [Regexp] pattern
163
+ # @return [Code]
164
+ def grep(pattern)
165
+ return self unless pattern
166
+ pattern = Regexp.new(pattern)
167
+
168
+ select do |loc|
169
+ loc.line =~ pattern
227
170
  end
171
+ end
228
172
 
229
- # @return [String] a formatted representation (based on the configuration of
230
- # the object).
231
- def to_s
232
- print_to_output("", false)
173
+ # Format output with line numbers next to it, unless `y_n` is falsy.
174
+ #
175
+ # @param [Boolean?] y_n
176
+ # @return [Code]
177
+ def with_line_numbers(y_n = true)
178
+ alter do
179
+ @with_line_numbers = y_n
233
180
  end
181
+ end
234
182
 
235
- # @return [String] a (possibly highlighted) copy of the source code.
236
- def highlighted
237
- print_to_output("", true)
183
+ # Format output with line numbers next to it, unless `y_n` is falsy.
184
+ #
185
+ # @param [Boolean?] y_n
186
+ # @return [Code]
187
+ def with_file_reference(y_n = true)
188
+ alter do
189
+ @with_file_reference = y_n
238
190
  end
191
+ end
239
192
 
240
- def add_file_reference
241
- "From file: #{File.basename(filename)}\n"
193
+ # Format output with a marker next to the given +lineno+, unless +lineno+ is
194
+ # falsy.
195
+ #
196
+ # @param [Integer?] lineno
197
+ # @return [Code]
198
+ def with_marker(lineno = 1)
199
+ alter do
200
+ @with_marker = !!lineno
201
+ @marker_lineno = lineno
242
202
  end
203
+ end
243
204
 
244
- # Writes a formatted representation (based on the configuration of the
245
- # object) to the given output, which must respond to `#<<`.
246
- def print_to_output(output, color=false)
247
- output << add_file_reference if @with_file_reference
248
- @lines.each do |loc|
249
- loc = loc.dup
250
- loc.add_line_number(max_lineno_width) if @with_line_numbers
251
- loc.add_marker(@marker_lineno) if @with_marker
252
- loc.indent(@indentation_num) if @with_indentation
253
- output << loc.line
254
- output << "\n"
255
- end
256
- output
205
+ # Format output with the specified number of spaces in front of every line,
206
+ # unless `spaces` is falsy.
207
+ #
208
+ # @param [Integer?] spaces
209
+ # @return [Code]
210
+ def with_indentation(spaces = 0)
211
+ alter do
212
+ @with_indentation = !!spaces
213
+ @indentation_num = spaces
257
214
  end
215
+ end
258
216
 
259
- # Get the comment that describes the expression on the given line number.
260
- #
261
- # @param [Integer] line_number (1-based)
262
- # @return [String] the code.
263
- def comment_describing(line_number)
264
- self.class.comment_describing(raw, line_number)
265
- end
217
+ # @return [String]
218
+ def inspect
219
+ Object.instance_method(:to_s).bind(self).call
220
+ end
266
221
 
267
- # Get the multiline expression that starts on the given line number.
268
- #
269
- # @param [Integer] line_number (1-based)
270
- # @return [String] the code.
271
- def expression_at(line_number, consume = 0)
272
- self.class.expression_at(raw, line_number, :consume => consume)
273
- end
222
+ # @return [Integer] the number of digits in the last line.
223
+ def max_lineno_width
224
+ !@lines.empty? ? @lines.last.lineno.to_s.length : 0
225
+ end
274
226
 
275
- # Get the multiline expression that starts on the given line number.
276
- #
277
- # @param [Integer] line_number (1-based)
278
- # @return [String] the code.
279
- def self.expression_at(raw, line_number, consume = 0)
280
- #self.class.expression_at(raw, line_number, :consume => consume)
281
- raw
282
- end
227
+ # @return [String] a formatted representation (based on the configuration of
228
+ # the object).
229
+ def to_s
230
+ print_to_output('', false)
231
+ end
283
232
 
284
- # Get the (approximate) Module.nesting at the give line number.
285
- #
286
- # @param [Integer] line_number line number starting from 1
287
- # @param [Module] top_module the module in which this code exists
288
- # @return [Array<Module>] a list of open modules.
289
- def nesting_at(line_number, top_module = Object)
290
- Indent.nesting_at(raw, line_number)
291
- end
233
+ # @return [String] a (possibly highlighted) copy of the source code.
234
+ def highlighted
235
+ print_to_output('', true)
236
+ end
292
237
 
293
- # Return an unformatted String of the code.
294
- #
295
- # @return [String]
296
- def raw
297
- @lines.map(&:line).join("\n") << "\n"
298
- end
238
+ def add_file_reference
239
+ return "From inline code: \n" unless filename
240
+ "From file: #{File.basename(filename)}\n"
241
+ end
299
242
 
300
- # Return the number of lines stored.
301
- #
302
- # @return [Integer]
303
- def length
304
- @lines ? @lines.length : 0
243
+ # Writes a formatted representation (based on the configuration of the
244
+ # object) to the given output, which must respond to `#<<`.
245
+ def print_to_output(output, _color = false)
246
+ output << add_file_reference if @with_file_reference
247
+ @lines.each do |loc|
248
+ loc = loc.dup
249
+ loc.add_line_number(max_lineno_width) if @with_line_numbers
250
+ loc.add_marker(@marker_lineno) if @with_marker
251
+ loc.indent(@indentation_num) if @with_indentation
252
+ output << loc.line
253
+ output << "\n"
305
254
  end
255
+ output
256
+ end
306
257
 
307
- # Two `Code` objects are equal if they contain the same lines with the same
308
- # numbers. Otherwise, call `to_s` and `chomp` and compare as Strings.
309
- #
310
- # @param [Code, Object] other
311
- # @return [Boolean]
312
- def ==(other)
313
- if other.is_a?(Code)
314
- other_lines = other.instance_variable_get(:@lines)
315
- @lines.each_with_index.all? { |loc, i| loc == other_lines[i] }
316
- else
317
- to_s.chomp == other.to_s.chomp
318
- end
319
- end
258
+ # Get the comment that describes the expression on the given line number.
259
+ #
260
+ # @param [Integer] line_number (1-based)
261
+ # @return [String] the code.
262
+ def comment_describing(line_number)
263
+ self.class.comment_describing(raw, line_number)
264
+ end
320
265
 
321
- # Forward any missing methods to the output of `#to_s`.
322
- def method_missing(name, *args, &block)
323
- to_s.send(name, *args, &block)
324
- end
325
- undef =~
266
+ # Get the multiline expression that starts on the given line number.
267
+ #
268
+ # @param [Integer] line_number (1-based)
269
+ # @return [String] the code.
270
+ def expression_at(line_number, consume = 0)
271
+ self.class.expression_at(raw, line_number, consume: consume)
272
+ end
273
+
274
+ # Get the multiline expression that starts on the given line number.
275
+ #
276
+ # @param [Integer] line_number (1-based)
277
+ # @return [String] the code.
278
+ def self.expression_at(raw, _line_number, _consume = 0)
279
+ # self.class.expression_at(raw, line_number, :consume => consume)
280
+ raw
281
+ end
282
+
283
+ # Get the (approximate) Module.nesting at the give line number.
284
+ #
285
+ # @param [Integer] line_number line number starting from 1
286
+ # @param [Module] top_module the module in which this code exists
287
+ # @return [Array<Module>] a list of open modules.
288
+ def nesting_at(line_number, _top_module = Object)
289
+ Indent.nesting_at(raw, line_number)
290
+ end
326
291
 
327
- protected
292
+ # Return an unformatted String of the code.
293
+ #
294
+ # @return [String]
295
+ def raw
296
+ @lines.map(&:line).join("\n") << "\n"
297
+ end
328
298
 
329
- # An abstraction of the `dup.instance_eval` pattern used throughout this
330
- # class.
331
- def alter(&block)
332
- dup.tap { |o| o.instance_eval(&block) }
299
+ # Return the number of lines stored.
300
+ #
301
+ # @return [Integer]
302
+ def length
303
+ @lines ? @lines.length : 0
304
+ end
305
+
306
+ # Two `Code` objects are equal if they contain the same lines with the same
307
+ # numbers. Otherwise, call `to_s` and `chomp` and compare as Strings.
308
+ #
309
+ # @param [Code, Object] other
310
+ # @return [Boolean]
311
+ def ==(other)
312
+ if other.is_a?(Code)
313
+ other_lines = other.instance_variable_get(:@lines)
314
+ @lines.each_with_index.all? { |loc, i| loc == other_lines[i] }
315
+ else
316
+ to_s.chomp == other.to_s.chomp
333
317
  end
334
318
  end
319
+
320
+ # Forward any missing methods to the output of `#to_s`.
321
+ def method_missing(name, *args, &block)
322
+ to_s.send(name, *args, &block)
323
+ end
324
+ undef =~
325
+
326
+ protected
327
+
328
+ # An abstraction of the `dup.instance_eval` pattern used throughout this
329
+ # class.
330
+ def alter(&block)
331
+ dup.tap { |o| o.instance_eval(&block) }
332
+ end
333
+ end