pry 0.10.3 → 0.12.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.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +251 -16
  3. data/LICENSE +1 -1
  4. data/README.md +35 -51
  5. data/bin/pry +3 -11
  6. data/lib/pry/basic_object.rb +6 -0
  7. data/lib/pry/cli.rb +50 -52
  8. data/lib/pry/code/code_file.rb +13 -6
  9. data/lib/pry/code/code_range.rb +3 -3
  10. data/lib/pry/code/loc.rb +14 -8
  11. data/lib/pry/code.rb +12 -5
  12. data/lib/pry/code_object.rb +27 -4
  13. data/lib/pry/color_printer.rb +20 -10
  14. data/lib/pry/command.rb +76 -45
  15. data/lib/pry/command_set.rb +17 -45
  16. data/lib/pry/commands/amend_line.rb +3 -4
  17. data/lib/pry/commands/bang.rb +1 -1
  18. data/lib/pry/commands/cat/exception_formatter.rb +10 -8
  19. data/lib/pry/commands/cat/file_formatter.rb +7 -3
  20. data/lib/pry/commands/cat/input_expression_formatter.rb +1 -1
  21. data/lib/pry/commands/cat.rb +7 -6
  22. data/lib/pry/commands/change_prompt.rb +29 -9
  23. data/lib/pry/commands/clear_screen.rb +14 -0
  24. data/lib/pry/commands/code_collector.rb +25 -23
  25. data/lib/pry/commands/easter_eggs.rb +12 -12
  26. data/lib/pry/commands/edit/file_and_line_locator.rb +1 -1
  27. data/lib/pry/commands/edit.rb +15 -10
  28. data/lib/pry/commands/exit.rb +2 -1
  29. data/lib/pry/commands/find_method.rb +12 -14
  30. data/lib/pry/commands/gem_cd.rb +1 -1
  31. data/lib/pry/commands/gem_install.rb +2 -2
  32. data/lib/pry/commands/gem_list.rb +2 -2
  33. data/lib/pry/commands/gem_open.rb +2 -2
  34. data/lib/pry/commands/gem_readme.rb +25 -0
  35. data/lib/pry/commands/gem_search.rb +40 -0
  36. data/lib/pry/commands/gem_stats.rb +83 -0
  37. data/lib/pry/commands/gist.rb +7 -6
  38. data/lib/pry/commands/help.rb +3 -3
  39. data/lib/pry/commands/hist.rb +11 -10
  40. data/lib/pry/commands/import_set.rb +2 -1
  41. data/lib/pry/commands/install_command.rb +7 -6
  42. data/lib/pry/commands/jump_to.rb +7 -7
  43. data/lib/pry/commands/list_inspectors.rb +2 -2
  44. data/lib/pry/commands/ls/constants.rb +14 -3
  45. data/lib/pry/commands/ls/formatter.rb +4 -2
  46. data/lib/pry/commands/ls/globals.rb +0 -2
  47. data/lib/pry/commands/ls/grep.rb +0 -2
  48. data/lib/pry/commands/ls/instance_vars.rb +0 -1
  49. data/lib/pry/commands/ls/jruby_hacks.rb +2 -2
  50. data/lib/pry/commands/ls/local_names.rb +0 -2
  51. data/lib/pry/commands/ls/local_vars.rb +0 -2
  52. data/lib/pry/commands/ls/ls_entity.rb +0 -1
  53. data/lib/pry/commands/ls/methods.rb +0 -3
  54. data/lib/pry/commands/ls/methods_helper.rb +1 -1
  55. data/lib/pry/commands/ls/self_methods.rb +2 -1
  56. data/lib/pry/commands/ls.rb +30 -31
  57. data/lib/pry/commands/play.rb +3 -4
  58. data/lib/pry/commands/pry_backtrace.rb +1 -1
  59. data/lib/pry/commands/raise_up.rb +2 -1
  60. data/lib/pry/commands/reload_code.rb +2 -2
  61. data/lib/pry/commands/ri.rb +9 -4
  62. data/lib/pry/commands/shell_command.rb +36 -9
  63. data/lib/pry/commands/shell_mode.rb +6 -6
  64. data/lib/pry/commands/show_doc.rb +5 -7
  65. data/lib/pry/commands/show_info.rb +41 -20
  66. data/lib/pry/commands/show_source.rb +5 -2
  67. data/lib/pry/commands/stat.rb +1 -1
  68. data/lib/pry/commands/watch_expression/expression.rb +1 -1
  69. data/lib/pry/commands/watch_expression.rb +9 -7
  70. data/lib/pry/commands/whereami.rb +16 -9
  71. data/lib/pry/commands/wtf.rb +15 -2
  72. data/lib/pry/config/behavior.rb +230 -114
  73. data/lib/pry/config/convenience.rb +24 -21
  74. data/lib/pry/config/default.rb +151 -153
  75. data/lib/pry/config/memoization.rb +48 -0
  76. data/lib/pry/config.rb +30 -19
  77. data/lib/pry/core_extensions.rb +15 -4
  78. data/lib/pry/editor.rb +5 -12
  79. data/lib/pry/exceptions.rb +1 -3
  80. data/lib/pry/forwardable.rb +23 -0
  81. data/lib/pry/helpers/base_helpers.rb +197 -110
  82. data/lib/pry/helpers/command_helpers.rb +5 -4
  83. data/lib/pry/helpers/documentation_helpers.rb +3 -2
  84. data/lib/pry/helpers/options_helpers.rb +6 -6
  85. data/lib/pry/helpers/platform.rb +58 -0
  86. data/lib/pry/helpers/table.rb +20 -15
  87. data/lib/pry/helpers/text.rb +82 -74
  88. data/lib/pry/helpers.rb +1 -0
  89. data/lib/pry/history.rb +44 -10
  90. data/lib/pry/hooks.rb +50 -109
  91. data/lib/pry/indent.rb +21 -19
  92. data/lib/pry/input_completer.rb +146 -123
  93. data/lib/pry/input_lock.rb +0 -2
  94. data/lib/pry/last_exception.rb +2 -2
  95. data/lib/pry/method/disowned.rb +3 -1
  96. data/lib/pry/method/patcher.rb +2 -5
  97. data/lib/pry/method/weird_method_locator.rb +21 -11
  98. data/lib/pry/method.rb +44 -38
  99. data/lib/pry/object_path.rb +5 -4
  100. data/lib/pry/output.rb +37 -37
  101. data/lib/pry/pager.rb +195 -181
  102. data/lib/pry/platform.rb +91 -0
  103. data/lib/pry/plugins.rb +27 -8
  104. data/lib/pry/prompt.rb +144 -25
  105. data/lib/pry/pry_class.rb +83 -33
  106. data/lib/pry/pry_instance.rb +94 -59
  107. data/lib/pry/repl.rb +70 -11
  108. data/lib/pry/repl_file_loader.rb +2 -3
  109. data/lib/pry/ring.rb +84 -0
  110. data/lib/pry/rubygem.rb +9 -7
  111. data/lib/pry/slop/LICENSE +20 -0
  112. data/lib/pry/slop/commands.rb +195 -0
  113. data/lib/pry/slop/option.rb +206 -0
  114. data/lib/pry/slop.rb +661 -0
  115. data/lib/pry/terminal.rb +18 -6
  116. data/lib/pry/testable/evalable.rb +15 -0
  117. data/lib/pry/testable/mockable.rb +14 -0
  118. data/lib/pry/testable/pry_tester.rb +73 -0
  119. data/lib/pry/testable/utility.rb +26 -0
  120. data/lib/pry/testable/variables.rb +46 -0
  121. data/lib/pry/testable.rb +70 -0
  122. data/lib/pry/version.rb +1 -1
  123. data/lib/pry/{module_candidate.rb → wrapped_module/candidate.rb} +9 -14
  124. data/lib/pry/wrapped_module.rb +22 -21
  125. data/lib/pry.rb +21 -50
  126. metadata +35 -46
  127. data/lib/pry/commands/list_prompts.rb +0 -35
  128. data/lib/pry/commands/simple_prompt.rb +0 -22
  129. data/lib/pry/history_array.rb +0 -121
  130. data/lib/pry/rbx_path.rb +0 -22
  131. data/lib/pry/test/helper.rb +0 -170
@@ -3,8 +3,8 @@ class Pry
3
3
  match(/\.(.*)/)
4
4
  group 'Input and Output'
5
5
  description "All text following a '.' is forwarded to the shell."
6
- command_options :listing => '.<shell command>', :use_prefix => false,
7
- :takes_block => true
6
+ command_options listing: '.<shell command>', use_prefix: false,
7
+ takes_block: true
8
8
 
9
9
  banner <<-'BANNER'
10
10
  Usage: .COMMAND_NAME
@@ -30,18 +30,45 @@ class Pry
30
30
 
31
31
  private
32
32
 
33
- def parse_destination(dest)
34
- return "~" if dest.empty?
35
- return dest unless dest == "-"
36
- state.old_pwd || raise(CommandError, "No prior directory available")
37
- end
33
+ def parse_destination(dest)
34
+ return "~" if dest.empty?
35
+ return dest unless dest == "-"
36
+
37
+ state.old_pwd || raise(CommandError, "No prior directory available")
38
+ end
38
39
 
39
- def process_cd(dest)
40
+ def process_cd(dest)
41
+ begin
40
42
  state.old_pwd = Dir.pwd
41
- Dir.chdir File.expand_path(dest)
43
+ Dir.chdir(File.expand_path(path_from_cd_path(dest) || dest))
42
44
  rescue Errno::ENOENT
43
45
  raise CommandError, "No such directory: #{dest}"
44
46
  end
47
+ end
48
+
49
+ def cd_path_env
50
+ ENV['CDPATH']
51
+ end
52
+
53
+ def cd_path_exists?
54
+ cd_path_env && cd_path_env.length.nonzero?
55
+ end
56
+
57
+ def path_from_cd_path(dest)
58
+ return if !(dest && cd_path_exists?) || special_case_path?(dest)
59
+
60
+ cd_path_env.split(File::PATH_SEPARATOR).each do |path|
61
+ if File.directory?(path) && path.split(File::SEPARATOR).last == dest
62
+ return path
63
+ end
64
+ end
65
+
66
+ return nil
67
+ end
68
+
69
+ def special_case_path?(dest)
70
+ ['.', '..', '-'].include?(dest) || dest =~ /\A[#{File::PATH_SEPARATOR}~]/
71
+ end
45
72
  end
46
73
 
47
74
  Pry::Commands.add_command(Pry::Command::ShellCommand)
@@ -9,13 +9,13 @@ class Pry
9
9
  BANNER
10
10
 
11
11
  def process
12
- case _pry_.prompt
13
- when Pry::SHELL_PROMPT
14
- _pry_.pop_prompt
15
- _pry_.custom_completions = _pry_.config.file_completions
12
+ state.disabled ^= true
13
+
14
+ if state.disabled
15
+ state.prev_prompt = _pry_.prompt
16
+ _pry_.prompt = Pry::Prompt[:shell][:value]
16
17
  else
17
- _pry_.push_prompt Pry::SHELL_PROMPT
18
- _pry_.custom_completions = _pry_.config.command_completions
18
+ _pry_.prompt = state.prev_prompt
19
19
  end
20
20
  end
21
21
  end
@@ -62,19 +62,17 @@ class Pry
62
62
  # Which sections to include in the 'header', can toggle: :owner,
63
63
  # :signature and visibility.
64
64
  def header_options
65
- super.merge :signature => true
65
+ super.merge signature: true
66
66
  end
67
67
 
68
68
  # figure out start line of docs by back-calculating based on
69
69
  # number of lines in the comment and the start line of the code_object
70
70
  # @return [Fixnum] start line of docs
71
71
  def start_line_for(code_object)
72
- if code_object.command? || opts.present?(:'base-one')
73
- 1
74
- else
75
- code_object.source_line.nil? ? 1 :
76
- (code_object.source_line - code_object.doc.lines.count)
77
- end
72
+ return 1 if code_object.command? || opts.present?(:'base-one')
73
+ return 1 unless code_object.source_line
74
+
75
+ code_object.source_line - code_object.doc.lines.count
78
76
  end
79
77
  end
80
78
 
@@ -2,21 +2,36 @@ class Pry
2
2
  class Command::ShowInfo < Pry::ClassCommand
3
3
  extend Pry::Helpers::BaseHelpers
4
4
 
5
- command_options :shellwords => false, :interpolate => false
5
+ command_options shellwords: false, interpolate: false
6
+
7
+ def initialize(*)
8
+ super
9
+
10
+ @used_super = nil
11
+ end
6
12
 
7
13
  def options(opt)
8
- opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors", :as => :count
14
+ opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors", as: :count
9
15
  opt.on :l, "line-numbers", "Show line numbers"
10
16
  opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)"
11
- opt.on :a, :all, "Show all definitions and monkeypatches of the module/class"
17
+ opt.on :a, :all, "Show all definitions and monkeypatches of the module/class"
12
18
  end
13
19
 
14
20
  def process
15
- code_object = Pry::CodeObject.lookup(obj_name, _pry_, :super => opts[:super])
21
+ code_object = Pry::CodeObject.lookup(obj_name, _pry_, super: opts[:super])
16
22
  raise CommandError, no_definition_message if !code_object
23
+
17
24
  @original_code_object = code_object
18
25
 
19
- if show_all_modules?(code_object)
26
+ if !obj_name && code_object.c_module? && !opts[:all]
27
+ result = "Warning: You're inside an object, whose class is defined by means\n" +
28
+ " of the C Ruby API. Pry cannot display the information for\n" +
29
+ " this class."
30
+ if code_object.candidates.any?
31
+ result += "\n However, you can view monkey-patches applied to this class.\n" +
32
+ " Just execute the same command with the '--all' switch."
33
+ end
34
+ elsif show_all_modules?(code_object)
20
35
  # show all monkey patches for a module
21
36
 
22
37
  result = content_and_headers_for_all_module_candidates(code_object)
@@ -66,7 +81,7 @@ class Pry
66
81
  mod.number_of_candidates.times do |v|
67
82
  candidate = mod.candidate(v)
68
83
  begin
69
- result << "\nCandidate #{v+1}/#{mod.number_of_candidates}: #{candidate.source_file} @ line #{candidate.source_line}:\n"
84
+ result << "\nCandidate #{v + 1}/#{mod.number_of_candidates}: #{candidate.source_file} @ line #{candidate.source_line}:\n"
70
85
  content = content_for(candidate)
71
86
 
72
87
  result << "Number of lines: #{content.lines.count}\n\n" << content
@@ -79,18 +94,24 @@ class Pry
79
94
  end
80
95
 
81
96
  def no_definition_message
82
- "Couldn't locate a definition for #{obj_name}!"
97
+ "Couldn't locate a definition for #{obj_name}"
83
98
  end
84
99
 
85
100
  # Generate a header (meta-data information) for all the code
86
101
  # object types: methods, modules, commands, procs...
87
102
  def header(code_object)
88
103
  file_name, line_num = file_and_line_for(code_object)
89
- h = "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} "
104
+ content = content_for(code_object)
105
+
106
+ h = "\n#{bold('From:')} #{file_name} "
90
107
  h << code_object_header(code_object, line_num)
91
- h << "\n#{Pry::Helpers::Text.bold('Number of lines:')} " <<
92
- "#{content_for(code_object).lines.count}\n\n"
93
- h << Helpers::Text.bold('** Warning:') << " Cannot find code for #{@original_code_object.nonblank_name}. Showing superclass #{code_object.nonblank_name} instead. **\n\n" if @used_super
108
+ h << "\n#{bold('Number of lines:')} " << "#{content.lines.count}\n\n"
109
+ h << bold('** Warning:') << " Cannot find code for #{@original_code_object.nonblank_name}. Showing superclass #{code_object.nonblank_name} instead. **\n\n" if @used_super
110
+
111
+ if content.lines.none?
112
+ h << bold('** Warning:') << " Cannot find code for '#{code_object.name}' (source_location is nil)"
113
+ end
114
+
94
115
  h
95
116
  end
96
117
 
@@ -119,11 +140,11 @@ class Pry
119
140
  def module_header(code_object, line_num)
120
141
  h = ""
121
142
  h << "@ line #{line_num}:\n"
122
- h << text.bold(code_object.module? ? "Module" : "Class")
123
- h << " #{text.bold('name:')} #{code_object.nonblank_name}"
143
+ h << bold(code_object.module? ? "Module" : "Class")
144
+ h << " #{bold('name:')} #{code_object.nonblank_name}"
124
145
 
125
146
  if code_object.number_of_candidates > 1
126
- h << (text.bold("\nNumber of monkeypatches: ") << code_object.number_of_candidates.to_s)
147
+ h << (bold("\nNumber of monkeypatches: ") << code_object.number_of_candidates.to_s)
127
148
  h << ". Use the `-a` option to display all available monkeypatches"
128
149
  end
129
150
  h
@@ -131,17 +152,17 @@ class Pry
131
152
 
132
153
  def method_sections(code_object)
133
154
  {
134
- :owner => "\n#{text.bold("Owner:")} #{code_object.owner || "N/A"}\n",
135
- :visibility => "#{text.bold("Visibility:")} #{code_object.visibility}",
136
- :signature => "\n#{text.bold("Signature:")} #{code_object.signature}"
155
+ owner: "\n#{bold("Owner:")} #{code_object.owner || "N/A"}\n",
156
+ visibility: "#{bold("Visibility:")} #{code_object.visibility}",
157
+ signature: "\n#{bold("Signature:")} #{code_object.signature}"
137
158
  }.merge(header_options) { |key, old, new| (new && old).to_s }
138
159
  end
139
160
 
140
161
  def header_options
141
162
  {
142
- :owner => true,
143
- :visibility => true,
144
- :signature => nil
163
+ owner: true,
164
+ visibility: true,
165
+ signature: nil
145
166
  }
146
167
  end
147
168
 
@@ -39,8 +39,11 @@ class Pry
39
39
 
40
40
  # The source for code_object prepared for display.
41
41
  def content_for(code_object)
42
- Code.new(code_object.source, start_line_for(code_object)).
43
- with_line_numbers(use_line_numbers?).highlighted
42
+ code = Code.new(
43
+ code_object.source || [],
44
+ start_line_for(code_object)
45
+ )
46
+ code.with_line_numbers(use_line_numbers?).highlighted
44
47
  end
45
48
  end
46
49
 
@@ -3,7 +3,7 @@ class Pry
3
3
  match 'stat'
4
4
  group 'Introspection'
5
5
  description 'View method information and set _file_ and _dir_ locals.'
6
- command_options :shellwords => false
6
+ command_options shellwords: false
7
7
 
8
8
  banner <<-'BANNER'
9
9
  Usage: stat [OPTIONS] [METH]
@@ -10,7 +10,7 @@ class Pry
10
10
  end
11
11
 
12
12
  def eval!
13
- @previous_value = @value
13
+ @previous_value = value
14
14
  @value = Pry::ColorPrinter.pp(target_eval(target, source), "")
15
15
  end
16
16
 
@@ -5,7 +5,7 @@ class Pry
5
5
  match 'watch'
6
6
  group 'Context'
7
7
  description 'Watch the value of an expression and print a notification whenever it changes.'
8
- command_options :use_prefix => false
8
+ command_options use_prefix: false
9
9
 
10
10
  banner <<-'BANNER'
11
11
  Usage: watch [EXPRESSION]
@@ -29,7 +29,7 @@ class Pry
29
29
  def options(opt)
30
30
  opt.on :d, :delete,
31
31
  "Delete the watch expression with the given index. If no index is given; clear all watch expressions.",
32
- :optional_argument => true, :as => Integer
32
+ optional_argument: true, as: Integer
33
33
  opt.on :l, :list,
34
34
  "Show all current watch expressions and their values. Calling watch with no expressions or options will also show the watch expressions."
35
35
  end
@@ -54,8 +54,8 @@ class Pry
54
54
 
55
55
  def delete(index)
56
56
  if index
57
- output.puts "Deleting watch expression ##{index}: #{expressions[index-1]}"
58
- expressions.delete_at(index-1)
57
+ output.puts "Deleting watch expression ##{index}: #{expressions[index - 1]}"
58
+ expressions.delete_at(index - 1)
59
59
  else
60
60
  output.puts "Deleting all watched expressions"
61
61
  expressions.clear
@@ -70,7 +70,7 @@ class Pry
70
70
  pager.puts "Listing all watched expressions:"
71
71
  pager.puts ""
72
72
  expressions.each_with_index do |expr, index|
73
- pager.print text.with_line_numbers(expr.to_s, index+1)
73
+ pager.print with_line_numbers(expr.to_s, index + 1)
74
74
  end
75
75
  pager.puts ""
76
76
  end
@@ -81,12 +81,14 @@ class Pry
81
81
  expressions.each do |expr|
82
82
  expr.eval!
83
83
  if expr.changed?
84
- output.puts "#{text.blue "watch"}: #{expr.to_s}"
84
+ output.puts "#{blue "watch"}: #{expr}"
85
85
  end
86
86
  end
87
87
  end
88
88
 
89
- def add_expression(arguments)
89
+ # TODO: fix arguments.
90
+ # https://github.com/pry/pry/commit/b031df2f2f5850ee6e9018f33d35f3485a9b0423
91
+ def add_expression(_arguments)
90
92
  expressions << Expression.new(_pry_, target, arg_string)
91
93
  output.puts "Watching #{Code.new(arg_string).highlighted}"
92
94
  end
@@ -1,5 +1,10 @@
1
1
  class Pry
2
2
  class Command::Whereami < Pry::ClassCommand
3
+ def initialize(*)
4
+ super
5
+
6
+ @method_code = nil
7
+ end
3
8
 
4
9
  class << self
5
10
  attr_accessor :method_size_cutoff
@@ -88,7 +93,7 @@ class Pry
88
93
 
89
94
  set_file_and_dir_locals(@file)
90
95
 
91
- out = "\n#{text.bold('From:')} #{location}:\n\n" <<
96
+ out = "\n#{bold('From:')} #{location}:\n\n" <<
92
97
  code.with_line_numbers(use_line_numbers?).with_marker(marker).highlighted << "\n"
93
98
 
94
99
  _pry_.pager.page out
@@ -148,17 +153,18 @@ class Pry
148
153
  # or it returns the class of `target_self` if `target_self` is not a class.
149
154
  # @return [Pry::WrappedModule]
150
155
  def target_class
151
- target_self.is_a?(Module) ? Pry::WrappedModule(target_self) :
152
- Pry::WrappedModule(target_self.class)
156
+ return Pry::WrappedModule(target_self) if target_self.is_a?(Module)
157
+
158
+ Pry::WrappedModule(target_self.class)
153
159
  end
154
160
 
155
161
  def class_code
156
- return @class_code if @class_code
157
-
158
- mod = @method ? Pry::WrappedModule(@method.owner) : target_class
159
-
160
- idx = mod.candidates.find_index { |v| expand_path(v.source_file) == @file }
161
- @class_code = idx && Pry::Code.from_module(mod, idx)
162
+ @class_code ||=
163
+ begin
164
+ mod = @method ? Pry::WrappedModule(@method.owner) : target_class
165
+ idx = mod.candidates.find_index { |v| expand_path(v.source_file) == @file }
166
+ idx && Pry::Code.from_module(mod, idx)
167
+ end
162
168
  end
163
169
 
164
170
  def valid_method?
@@ -187,4 +193,5 @@ class Pry
187
193
 
188
194
  Pry::Commands.add_command(Pry::Command::Whereami)
189
195
  Pry::Commands.alias_command '@', 'whereami'
196
+ Pry::Commands.alias_command(/whereami[!?]+/, 'whereami')
190
197
  end
@@ -3,7 +3,7 @@ class Pry
3
3
  match(/wtf([?!]*)/)
4
4
  group 'Context'
5
5
  description 'Show the backtrace of the most recent exception.'
6
- options :listing => 'wtf?'
6
+ options listing: 'wtf?'
7
7
 
8
8
  banner <<-'BANNER'
9
9
  Usage: wtf[?|!]
@@ -26,12 +26,25 @@ class Pry
26
26
  def process
27
27
  raise Pry::CommandError, "No most-recent exception" unless exception
28
28
 
29
- output.puts "#{text.bold('Exception:')} #{exception.class}: #{exception}\n--"
29
+ output.puts "#{bold('Exception:')} #{exception.class}: #{exception}\n--"
30
30
  if opts.verbose?
31
31
  output.puts with_line_numbers(backtrace)
32
32
  else
33
33
  output.puts with_line_numbers(backtrace.first(size_of_backtrace))
34
34
  end
35
+
36
+ if exception.respond_to? :cause
37
+ cause = exception.cause
38
+ while cause
39
+ output.puts "#{text.bold('Caused by:')} #{cause.class}: #{cause}\n--"
40
+ if opts.verbose?
41
+ output.puts with_line_numbers(cause.backtrace)
42
+ else
43
+ output.puts with_line_numbers(cause.backtrace.first(size_of_backtrace))
44
+ end
45
+ cause = cause.cause
46
+ end
47
+ end
35
48
  end
36
49
 
37
50
  private