puts_debuggerer 0.7.1 → 0.10.0

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.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.10.0
@@ -0,0 +1 @@
1
+ require 'puts_debuggerer'
@@ -1,21 +1,70 @@
1
- require 'ripper'
2
- require 'awesome_print'
1
+ require 'stringio'
2
+
3
+ require 'puts_debuggerer/core_ext/kernel'
4
+ require 'puts_debuggerer/run_determiner'
5
+ require 'puts_debuggerer/source_file'
6
+
7
+ # in case 'logger' is not required
8
+ class Logger
9
+ end
10
+
11
+ # in case 'logging' is not required
12
+ module Logging
13
+ class Logger
14
+ end
15
+ end
3
16
 
4
17
  module PutsDebuggerer
18
+ SOURCE_LINE_COUNT_DEFAULT = 1
5
19
  HEADER_DEFAULT = '*'*80
20
+ WRAPPER_DEFAULT = '*'*80
6
21
  FOOTER_DEFAULT = '*'*80
22
+ LOGGER_FORMATTER_DECORATOR = proc { |original_formatter|
23
+ proc { |severity, datetime, progname, msg|
24
+ original_formatter.call(severity, datetime, progname, msg.pd_inspect)
25
+ }
26
+ }
27
+ LOGGING_LAYOUT_DECORATOR = proc {|original_layout|
28
+ original_layout.clone.tap do |layout|
29
+ layout.singleton_class.class_eval do
30
+ alias original_format_obj format_obj
31
+ def format_obj(obj)
32
+ obj.pdi # alias to pd_inspect
33
+ end
34
+ end
35
+ end
36
+ }
37
+ RETURN_DEFAULT = true
38
+ OBJECT_PRINTER_DEFAULT = lambda do |object, print_engine_options=nil, source_line_count=nil, run_number=nil|
39
+ lambda do
40
+ if object.is_a?(Exception) && object.respond_to?(:full_message)
41
+ puts object.full_message
42
+ elsif PutsDebuggerer.print_engine.is_a?(Proc)
43
+ PutsDebuggerer.print_engine.call(object)
44
+ else
45
+ send(PutsDebuggerer.print_engine, object)
46
+ end
47
+ end
48
+ end
49
+ PRINTER_DEFAULT = :puts
50
+ PRINTER_RAILS = lambda do |output|
51
+ puts output if Rails.env.test?
52
+ Rails.logger.debug(output)
53
+ end
7
54
  PRINT_ENGINE_DEFAULT = :ap
8
- PRINT_ENGINE_MESSAGE_INVALID = 'print_engine must be a valid global method symbol (e.g. :p or :puts) or lambda/proc'
55
+ PRINTER_MESSAGE_INVALID = 'printer must be a valid global method symbol (e.g. :puts), a logger, or a lambda/proc receiving a text arg'
56
+ PRINT_ENGINE_MESSAGE_INVALID = 'print_engine must be a valid global method symbol (e.g. :p, :ap or :pp) or lambda/proc receiving an object arg'
9
57
  ANNOUNCER_DEFAULT = '[PD]'
10
58
  FORMATTER_DEFAULT = -> (data) {
59
+ puts data[:wrapper] if data[:wrapper]
11
60
  puts data[:header] if data[:header]
12
- print "#{data[:announcer]} #{data[:file]}:#{data[:line_number]}#{__format_pd_expression__(data[:pd_expression], data[:object])} "
61
+ print "#{data[:announcer]} #{data[:file]}:#{data[:line_number]}#{" (run:#{data[:run_number]})" if data[:run_number]}#{__format_pd_expression__(data[:pd_expression], data[:object])} "
13
62
  data[:object_printer].call
14
63
  puts data[:caller].map {|l| ' ' + l} unless data[:caller].to_a.empty?
15
64
  puts data[:footer] if data[:footer]
65
+ puts data[:wrapper] if data[:wrapper]
16
66
  }
17
67
  CALLER_DEPTH_ZERO = 4 #depth includes pd + with_options method + nested block + build_pd_data method
18
- OBJECT_RUN_AT = {}
19
68
  STACK_TRACE_CALL_LINE_NUMBER_REGEX = /\:(\d+)\:in /
20
69
  STACK_TRACE_CALL_SOURCE_FILE_REGEX = /[ ]*([^:]+)\:\d+\:in /
21
70
 
@@ -39,6 +88,28 @@ module PutsDebuggerer
39
88
  @app_path = (path || Rails.root.to_s) rescue nil
40
89
  end
41
90
 
91
+ # Source Line Count.
92
+ # * Default value is `1`
93
+ #
94
+ # Example:
95
+ #
96
+ # PutsDebuggerer.source_line_count = 2
97
+ # pd (true ||
98
+ # false), source_line_count: 2
99
+ #
100
+ # Prints out:
101
+ #
102
+ # ********************************************************************************
103
+ # [PD] /Users/User/example.rb:2
104
+ # > pd (true ||
105
+ # false), source_line_count: 2
106
+ # => "true"
107
+ attr_reader :source_line_count
108
+
109
+ def source_line_count=(value)
110
+ @source_line_count = value || SOURCE_LINE_COUNT_DEFAULT
111
+ end
112
+
42
113
  # Header to include at the top of every print out.
43
114
  # * Default value is `nil`
44
115
  # * Value `true` enables header as `'*'*80`
@@ -58,19 +129,24 @@ module PutsDebuggerer
58
129
  # => "1"
59
130
  attr_reader :header
60
131
 
61
- def header=(value)
62
- if value.equal?(true)
63
- @header = HEADER_DEFAULT
64
- elsif value == ''
65
- @header = nil
66
- else
67
- @header = value
68
- end
69
- end
70
-
71
- def header?
72
- !!@header
73
- end
132
+ # Wrapper to include at the top and bottom of every print out (both header and footer).
133
+ # * Default value is `nil`
134
+ # * Value `true` enables wrapper as `'*'*80`
135
+ # * Value `false`, `nil`, or empty string disables wrapper
136
+ # * Any other string value gets set as a custom wrapper
137
+ #
138
+ # Example:
139
+ #
140
+ # PutsDebuggerer.wrapper = true
141
+ # pd (x=1)
142
+ #
143
+ # Prints out:
144
+ #
145
+ # [PD] /Users/User/example.rb:2
146
+ # > pd x=1
147
+ # => "1"
148
+ # ********************************************************************************
149
+ attr_reader :wrapper
74
150
 
75
151
  # Footer to include at the bottom of every print out.
76
152
  # * Default value is `nil`
@@ -90,25 +166,87 @@ module PutsDebuggerer
90
166
  # => "1"
91
167
  # ********************************************************************************
92
168
  attr_reader :footer
169
+
170
+ ['header', 'footer', 'wrapper'].each do |boundary_option|
171
+ define_method("#{boundary_option}=") do |value|
172
+ if value.equal?(true)
173
+ instance_variable_set(:"@#{boundary_option}", const_get(:"#{boundary_option.upcase}_DEFAULT"))
174
+ elsif value == ''
175
+ instance_variable_set(:"@#{boundary_option}", nil)
176
+ else
177
+ instance_variable_set(:"@#{boundary_option}", value)
178
+ end
179
+ end
180
+
181
+ define_method("#{boundary_option}?") do
182
+ !!instance_variable_get(:"@#{boundary_option}")
183
+ end
184
+ end
93
185
 
94
- def footer=(value)
95
- if value.equal?(true)
96
- @footer = FOOTER_DEFAULT
97
- elsif value == ''
98
- @footer = nil
186
+ # Printer is a global method symbol, lambda expression, or logger to use in printing to the user.
187
+ # Examples of a global method are `:puts` and `:print`.
188
+ # An example of a lambda expression is `lambda {|output| Rails.logger.ap(output)}`
189
+ # Examples of a logger are a Ruby `Logger` instance or `Logging::Logger` instance
190
+ #
191
+ # Defaults to `:puts`
192
+ # In Rails, it defaults to: `lambda {|output| Rails.logger.ap(output)}`
193
+ #
194
+ # Example:
195
+ #
196
+ # # File Name: /Users/User/example.rb
197
+ # PutsDebuggerer.printer = lambda {|output| Rails.logger.error(output)}
198
+ # str = "Hello"
199
+ # pd str
200
+ #
201
+ # Prints out in the Rails app log as error lines:
202
+ #
203
+ # [PD] /Users/User/example.rb:5
204
+ # > pd str
205
+ # => Hello
206
+ attr_reader :printer
207
+
208
+ def printer=(printer)
209
+ if printer.nil?
210
+ @printer = printer_default
211
+ elsif printer.is_a?(Logger)
212
+ @printer = printer
213
+ @logger_original_formatter = printer.formatter || Logger::Formatter.new
214
+ printer.formatter = LOGGER_FORMATTER_DECORATOR.call(@logger_original_formatter)
215
+ elsif printer.is_a?(Logging::Logger)
216
+ @printer = printer
217
+ @logging_original_layouts = printer.appenders.reduce({}) do |hash, appender|
218
+ hash.merge(appender => appender.layout)
219
+ end
220
+ printer.appenders.each do |appender|
221
+ appender.layout = LOGGING_LAYOUT_DECORATOR.call(appender.layout)
222
+ end
223
+ elsif printer == false || printer.is_a?(Proc) || printer.respond_to?(:log) # a logger
224
+ @printer = printer
99
225
  else
100
- @footer = value
226
+ @printer = method(printer).name rescue raise(PRINTER_MESSAGE_INVALID)
101
227
  end
102
228
  end
103
-
104
- def footer?
105
- !!@footer
229
+
230
+ def printer_default
231
+ Object.const_defined?(:Rails) ? PRINTER_RAILS : PRINTER_DEFAULT
106
232
  end
107
-
108
- # Print engine to use in object printout (e.g. `p`, `ap`, `pp`).
109
- # It is represented by the print engine's global method name as a symbol
110
- # (e.g. `:ap` for awesome_print).
111
- # Defaults to awesome_print loaded.
233
+
234
+ # Logger original formatter before it was decorated with PutsDebuggerer::LOGGER_FORMATTER_DECORATOR
235
+ # upon setting the logger as a printer.
236
+ attr_reader :logger_original_formatter
237
+
238
+ # Logging library original layouts before being decorated with PutsDebuggerer::LOGGING_LAYOUT_DECORATOR
239
+ # upon setting the Logging library logger as a printer.
240
+ attr_reader :logging_original_layouts
241
+
242
+ # Print engine is similar to `printer`, except it is focused on the scope of formatting
243
+ # the data object being printed (excluding metadata such as file name, line number,
244
+ # and expression, which are handled by the `printer`).
245
+ # As such, it is also a global method symbol or lambda expression.
246
+ # Examples of global methods are `:p`, `:ap`, and `:pp`.
247
+ # An example of a lambda expression is `lambda {|object| puts object.to_a.join(" | ")}`
248
+ #
249
+ # Defaults to [awesome_print](https://github.com/awesome-print/awesome_print).
112
250
  #
113
251
  # Example:
114
252
  #
@@ -128,17 +266,17 @@ module PutsDebuggerer
128
266
 
129
267
  def print_engine=(engine)
130
268
  if engine.nil?
131
- if Object.const_defined?(:Rails)
132
- @print_engine = lambda {|object| Rails.logger.ap(object)}
133
- else
134
- @print_engine = PRINT_ENGINE_DEFAULT
135
- end
269
+ @print_engine = print_engine_default
136
270
  elsif engine.is_a?(Proc)
137
271
  @print_engine = engine
138
272
  else
139
273
  @print_engine = method(engine).name rescue raise(PRINT_ENGINE_MESSAGE_INVALID)
140
274
  end
141
275
  end
276
+
277
+ def print_engine_default
278
+ Object.const_defined?(:AwesomePrint) ? PRINT_ENGINE_DEFAULT : :p
279
+ end
142
280
 
143
281
  # Announcer (e.g. [PD]) to announce every print out with (default: "[PD]")
144
282
  #
@@ -164,12 +302,14 @@ module PutsDebuggerer
164
302
  # * :announcer (string)
165
303
  # * :caller (array)
166
304
  # * :file (string)
305
+ # * :wrapper (string)
167
306
  # * :footer (string)
168
307
  # * :header (string)
169
308
  # * :line_number (string)
170
309
  # * :pd_expression (string)
171
310
  # * :object (object)
172
311
  # * :object_printer (proc)
312
+ # * :source_line_count (integer)
173
313
  #
174
314
  # NOTE: data for :object_printer is not a string, yet a proc that must
175
315
  # be called to output value. It is a proc as it automatically handles usage
@@ -247,8 +387,11 @@ module PutsDebuggerer
247
387
  def options
248
388
  {
249
389
  header: header,
390
+ wrapper: wrapper,
250
391
  footer: footer,
392
+ printer: printer,
251
393
  print_engine: print_engine,
394
+ source_line_count: source_line_count,
252
395
  app_path: app_path,
253
396
  announcer: announcer,
254
397
  formatter: formatter,
@@ -325,53 +468,37 @@ module PutsDebuggerer
325
468
  !!@run_at
326
469
  end
327
470
 
328
- attr_reader :run_at_global_number
329
-
330
- def run_at_global_number=(value)
331
- @run_at_global_number = value
471
+ def determine_options(objects)
472
+ objects.delete_at(-1) if objects.size > 1 && objects.last.is_a?(Hash)
332
473
  end
333
474
 
334
- def init_run_at_global_number(object, run_at)
335
- @run_at_global_number = 1
475
+ def determine_object(objects)
476
+ objects.compact.size > 1 ? objects : objects.first
336
477
  end
337
478
 
338
- def increment_run_at_global_number(object, run_at)
339
- @run_at_global_number += 1
479
+ def determine_run_at(options)
480
+ ((options && options[:run_at]) || PutsDebuggerer.run_at)
340
481
  end
341
482
 
342
- def reset_run_at_global_number(object, run_at)
343
- @run_at_global_number = nil
344
- end
345
-
346
- def run_at_number(object, run_at)
347
- PutsDebuggerer::OBJECT_RUN_AT[[object,run_at]]
348
- end
349
-
350
- def init_run_at_number(object, run_at)
351
- PutsDebuggerer::OBJECT_RUN_AT[[object,run_at]] = 1
352
- end
353
-
354
- def increment_run_at_number(object, run_at)
355
- PutsDebuggerer::OBJECT_RUN_AT[[object,run_at]] += 1
356
- end
357
-
358
- def reset_run_at_number(object, run_at)
359
- PutsDebuggerer::OBJECT_RUN_AT.delete([object, run_at])
360
- end
361
-
362
- def reset_run_at_numbers
363
- PutsDebuggerer::OBJECT_RUN_AT.clear
483
+ def determine_printer(options)
484
+ if options && options.has_key?(:printer)
485
+ options[:printer]
486
+ else
487
+ PutsDebuggerer.printer
488
+ end
364
489
  end
365
-
366
490
  end
367
491
  end
368
492
 
369
- PutsDebuggerer.print_engine = PutsDebuggerer::PRINT_ENGINE_DEFAULT
370
- PutsDebuggerer.announcer = PutsDebuggerer::ANNOUNCER_DEFAULT
371
- PutsDebuggerer.formatter = PutsDebuggerer::FORMATTER_DEFAULT
493
+ # setting values to nil defaults them properly
494
+ PutsDebuggerer.printer = nil
495
+ PutsDebuggerer.print_engine = nil
496
+ PutsDebuggerer.announcer = nil
497
+ PutsDebuggerer.formatter = nil
372
498
  PutsDebuggerer.app_path = nil
373
499
  PutsDebuggerer.caller = nil
374
500
  PutsDebuggerer.run_at = nil
501
+ PutsDebuggerer.source_line_count = nil
375
502
 
376
503
  # Prints object with bonus info such as file name, line number and source
377
504
  # expression. Optionally prints out header and footer.
@@ -402,48 +529,57 @@ PutsDebuggerer.run_at = nil
402
529
  # > pd "Show me the source of the bug: #{bug}"
403
530
  # => "Show me the source of the bug: beattle"
404
531
  # [PD] /Users/User/finance_calculator_app/pd_test.rb:4 "What line number am I?"
405
- def pd(object, options=nil)
406
- run_at = ((options && options[:run_at]) || PutsDebuggerer.run_at)
407
-
408
- if __run_pd__(object, run_at)
532
+ def pd(*objects)
533
+ require 'awesome_print' if ['awesome_print', 'ap'].include?(PutsDebuggerer.print_engine.to_s) && RUBY_PLATFORM != 'opal'
534
+ options = PutsDebuggerer.determine_options(objects) || {}
535
+ object = PutsDebuggerer.determine_object(objects)
536
+ run_at = PutsDebuggerer.determine_run_at(options)
537
+ printer = PutsDebuggerer.determine_printer(options)
538
+ pd_inspect = options.delete(:pd_inspect)
539
+ logger_formatter_decorated = PutsDebuggerer.printer.is_a?(Logger) && PutsDebuggerer.printer.formatter != PutsDebuggerer.logger_original_formatter
540
+ logging_layouts_decorated = PutsDebuggerer.printer.is_a?(Logging::Logger) && PutsDebuggerer.printer.appenders.map(&:layout) != (PutsDebuggerer.logging_original_layouts.values)
541
+
542
+ string = nil
543
+ if PutsDebuggerer::RunDeterminer.run_pd?(object, run_at)
409
544
  __with_pd_options__(options) do |print_engine_options|
410
- formatter_pd_data = __build_pd_data__(object, print_engine_options) #depth adds build method
545
+ run_number = PutsDebuggerer::RunDeterminer.run_number(object, run_at)
546
+ formatter_pd_data = __build_pd_data__(object, print_engine_options, PutsDebuggerer.source_line_count, run_number, pd_inspect, logger_formatter_decorated, logging_layouts_decorated) #depth adds build method
547
+ stdout = $stdout
548
+ $stdout = sio = StringIO.new
411
549
  PutsDebuggerer.formatter.call(formatter_pd_data)
412
- end
413
- end
414
-
415
- object
416
- end
417
-
418
- def __run_pd__(object, run_at)
419
- run_pd = false
420
- if run_at.nil?
421
- run_pd = true
422
- else
423
- if PutsDebuggerer.run_at_global_number.nil?
424
- if PutsDebuggerer.run_at_number(object, run_at).nil?
425
- PutsDebuggerer.init_run_at_number(object, run_at)
426
- else
427
- PutsDebuggerer.increment_run_at_number(object, run_at)
428
- end
429
- run_number = PutsDebuggerer.run_at_number(object, run_at)
430
- else
431
- if PutsDebuggerer.run_at_global_number.nil?
432
- PutsDebuggerer.init_run_at_global_number
433
- else
434
- PutsDebuggerer.increment_run_at_global_number
550
+ $stdout = stdout
551
+ string = sio.string
552
+ if PutsDebuggerer.printer.is_a?(Proc)
553
+ PutsDebuggerer.printer.call(string)
554
+ elsif PutsDebuggerer.printer.is_a?(Logger)
555
+ logger_formatter = PutsDebuggerer.printer.formatter
556
+ begin
557
+ PutsDebuggerer.printer.formatter = PutsDebuggerer.logger_original_formatter
558
+ PutsDebuggerer.printer.debug(string)
559
+ ensure
560
+ PutsDebuggerer.printer.formatter = logger_formatter
561
+ end
562
+ elsif PutsDebuggerer.printer.is_a?(Logging::Logger)
563
+ logging_layouts = PutsDebuggerer.printer.appenders.reduce({}) do |hash, appender|
564
+ hash.merge(appender => appender.layout)
565
+ end
566
+ begin
567
+ PutsDebuggerer.logging_original_layouts.each do |appender, original_layout|
568
+ appender.layout = original_layout
569
+ end
570
+ PutsDebuggerer.printer.debug(string)
571
+ ensure
572
+ PutsDebuggerer.logging_original_layouts.each do |appender, original_layout|
573
+ appender.layout = logging_layouts[appender]
574
+ end
575
+ end
576
+ elsif PutsDebuggerer.printer != false
577
+ send(PutsDebuggerer.send(:printer), string)
435
578
  end
436
- run_number = PutsDebuggerer.run_at_global_number
437
- end
438
- if run_at.is_a?(Integer)
439
- run_pd = true if run_at == run_number
440
- elsif run_at.is_a?(Array)
441
- run_pd = true if run_at.include?(run_number)
442
- elsif run_at.is_a?(Range)
443
- run_pd = true if run_at.cover?(run_number) || (run_at.end == -1 && run_number >= run_at.begin)
444
579
  end
445
580
  end
446
- run_pd
581
+
582
+ printer ? object : string
447
583
  end
448
584
 
449
585
  # Provides caller line number starting 1 level above caller of
@@ -457,7 +593,7 @@ end
457
593
  #
458
594
  # prints out `3`
459
595
  def __caller_line_number__(caller_depth=0)
460
- caller[caller_depth][PutsDebuggerer::STACK_TRACE_CALL_LINE_NUMBER_REGEX, 1].to_i
596
+ caller[caller_depth] && caller[caller_depth][PutsDebuggerer::STACK_TRACE_CALL_LINE_NUMBER_REGEX, 1].to_i
461
597
  end
462
598
 
463
599
  # Provides caller file starting 1 level above caller of
@@ -470,7 +606,7 @@ end
470
606
  #
471
607
  # prints out `lib/example.rb`
472
608
  def __caller_file__(caller_depth=0)
473
- caller[caller_depth][PutsDebuggerer::STACK_TRACE_CALL_SOURCE_FILE_REGEX, 1]
609
+ result = caller[caller_depth] && caller[caller_depth][PutsDebuggerer::STACK_TRACE_CALL_SOURCE_FILE_REGEX, 1]
474
610
  end
475
611
 
476
612
 
@@ -482,23 +618,14 @@ end
482
618
  # puts __caller_source_line__
483
619
  #
484
620
  # prints out `puts __caller_source_line__`
485
- def __caller_source_line__(caller_depth=0, source_file=nil, source_line_number=nil)
621
+ def __caller_source_line__(caller_depth=0, source_line_count=nil, source_file=nil, source_line_number=nil)
486
622
  source_line_number ||= __caller_line_number__(caller_depth+1)
487
623
  source_file ||= __caller_file__(caller_depth+1)
488
- source_line = nil
624
+ source_line = ''
489
625
  if source_file == '(irb)'
490
- source_line = conf.io.line(source_line_number)
626
+ source_line = conf.io.line(source_line_number) # TODO handle multi-lines in source_line_count
491
627
  else
492
- f = File.new(source_file)
493
- source_line = ''
494
- done = false
495
- f.each_line do |line|
496
- if !done && f.lineno == source_line_number
497
- source_line << line
498
- done = true if Ripper.sexp_raw(source_line) || source_line.include?('%>') #the last condition is for erb support (unofficial)
499
- source_line_number+=1
500
- end
501
- end
628
+ source_line = PutsDebuggerer::SourceFile.new(source_file).source(source_line_count, source_line_number)
502
629
  end
503
630
  source_line
504
631
  end
@@ -514,43 +641,42 @@ def __with_pd_options__(options=nil)
514
641
  PutsDebuggerer.options = permanent_options
515
642
  end
516
643
 
517
- def __build_pd_data__(object, print_engine_options=nil)
644
+ def __build_pd_data__(object, print_engine_options=nil, source_line_count=nil, run_number=nil, pd_inspect=false, logger_formatter_decorated=false, logging_layouts_decorated=false)
518
645
  depth = PutsDebuggerer::CALLER_DEPTH_ZERO
646
+ depth += 1 if pd_inspect
647
+ depth += 4 if pd_inspect && logger_formatter_decorated
648
+ depth += 8 if pd_inspect && logging_layouts_decorated
519
649
  pd_data = {
520
650
  announcer: PutsDebuggerer.announcer,
521
- file: __caller_file__(depth).sub(PutsDebuggerer.app_path.to_s, ''),
651
+ file: __caller_file__(depth)&.sub(PutsDebuggerer.app_path.to_s, ''),
522
652
  line_number: __caller_line_number__(depth),
523
- pd_expression: __caller_pd_expression__(depth),
653
+ pd_expression: __caller_pd_expression__(depth, source_line_count),
654
+ run_number: run_number,
524
655
  object: object,
525
- object_printer: lambda do
526
- if PutsDebuggerer.print_engine.is_a?(Proc)
527
- PutsDebuggerer.print_engine.call(object)
528
- else
529
- if print_engine_options.to_h.empty?
530
- send(PutsDebuggerer.print_engine, object)
531
- else
532
- send(PutsDebuggerer.print_engine, object, print_engine_options) rescue send(PutsDebuggerer.print_engine, object)
533
- end
534
- end
535
- end
656
+ object_printer: PutsDebuggerer::OBJECT_PRINTER_DEFAULT.call(object, print_engine_options, source_line_count, run_number)
536
657
  }
537
- if PutsDebuggerer.caller?
538
- start_depth = depth.to_i
539
- caller_depth = PutsDebuggerer.caller == -1 ? -1 : (start_depth + PutsDebuggerer.caller)
540
- pd_data[:caller] = caller[start_depth..caller_depth].to_a
658
+ pd_data[:caller] = __caller_caller__(depth)
659
+ ['header', 'wrapper', 'footer'].each do |boundary_option|
660
+ pd_data[boundary_option.to_sym] = PutsDebuggerer.send(boundary_option) if PutsDebuggerer.send("#{boundary_option}?")
541
661
  end
542
- pd_data[:header] = PutsDebuggerer.header if PutsDebuggerer.header?
543
- pd_data[:footer] = PutsDebuggerer.footer if PutsDebuggerer.footer?
544
662
  pd_data
545
663
  end
546
664
 
665
+ # Returns the caller stack trace of the caller of pd
666
+ def __caller_caller__(depth)
667
+ return unless PutsDebuggerer.caller?
668
+ start_depth = depth.to_i + 1
669
+ caller_depth = PutsDebuggerer.caller == -1 ? -1 : (start_depth + PutsDebuggerer.caller)
670
+ caller[start_depth..caller_depth].to_a
671
+ end
672
+
547
673
  def __format_pd_expression__(expression, object)
548
674
  "\n > #{expression}\n =>"
549
675
  end
550
676
 
551
- def __caller_pd_expression__(depth=0)
677
+ def __caller_pd_expression__(depth=0, source_line_count=nil)
552
678
  # Caller Source Line Depth 2 = 1 to pd method + 1 to caller
553
- source_line = __caller_source_line__(depth+1)
679
+ source_line = __caller_source_line__(depth+1, source_line_count)
554
680
  source_line = __extract_pd_expression__(source_line)
555
681
  source_line = source_line.gsub(/(^'|'$)/, '"') if source_line.start_with?("'") && source_line.end_with?("'")
556
682
  source_line = source_line.gsub(/(^\(|\)$)/, '') if source_line.start_with?("(") && source_line.end_with?(")")
@@ -565,5 +691,5 @@ end
565
691
  #
566
692
  # outputs `(x=1)`
567
693
  def __extract_pd_expression__(source_line)
568
- source_line.strip
694
+ source_line.to_s.strip
569
695
  end