pry 0.10.3 → 0.14.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 (159) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +439 -16
  3. data/LICENSE +1 -1
  4. data/README.md +362 -302
  5. data/bin/pry +4 -7
  6. data/lib/pry/basic_object.rb +10 -0
  7. data/lib/pry/block_command.rb +22 -0
  8. data/lib/pry/class_command.rb +194 -0
  9. data/lib/pry/cli.rb +84 -97
  10. data/lib/pry/code/code_file.rb +37 -26
  11. data/lib/pry/code/code_range.rb +7 -5
  12. data/lib/pry/code/loc.rb +26 -13
  13. data/lib/pry/code.rb +42 -31
  14. data/lib/pry/code_object.rb +53 -28
  15. data/lib/pry/color_printer.rb +46 -35
  16. data/lib/pry/command.rb +197 -369
  17. data/lib/pry/command_set.rb +89 -114
  18. data/lib/pry/command_state.rb +31 -0
  19. data/lib/pry/commands/amend_line.rb +86 -82
  20. data/lib/pry/commands/bang.rb +18 -14
  21. data/lib/pry/commands/bang_pry.rb +15 -11
  22. data/lib/pry/commands/cat/abstract_formatter.rb +23 -18
  23. data/lib/pry/commands/cat/exception_formatter.rb +85 -72
  24. data/lib/pry/commands/cat/file_formatter.rb +56 -46
  25. data/lib/pry/commands/cat/input_expression_formatter.rb +35 -30
  26. data/lib/pry/commands/cat.rb +62 -54
  27. data/lib/pry/commands/cd.rb +40 -35
  28. data/lib/pry/commands/change_inspector.rb +29 -22
  29. data/lib/pry/commands/change_prompt.rb +48 -23
  30. data/lib/pry/commands/clear_screen.rb +20 -0
  31. data/lib/pry/commands/code_collector.rb +148 -131
  32. data/lib/pry/commands/disable_pry.rb +23 -19
  33. data/lib/pry/commands/easter_eggs.rb +23 -34
  34. data/lib/pry/commands/edit/exception_patcher.rb +21 -17
  35. data/lib/pry/commands/edit/file_and_line_locator.rb +34 -23
  36. data/lib/pry/commands/edit.rb +185 -157
  37. data/lib/pry/commands/exit.rb +40 -35
  38. data/lib/pry/commands/exit_all.rb +24 -20
  39. data/lib/pry/commands/exit_program.rb +20 -16
  40. data/lib/pry/commands/find_method.rb +168 -162
  41. data/lib/pry/commands/fix_indent.rb +16 -12
  42. data/lib/pry/commands/help.rb +140 -133
  43. data/lib/pry/commands/hist.rb +151 -149
  44. data/lib/pry/commands/import_set.rb +20 -15
  45. data/lib/pry/commands/jump_to.rb +25 -21
  46. data/lib/pry/commands/list_inspectors.rb +35 -28
  47. data/lib/pry/commands/ls/constants.rb +59 -31
  48. data/lib/pry/commands/ls/formatter.rb +42 -36
  49. data/lib/pry/commands/ls/globals.rb +38 -36
  50. data/lib/pry/commands/ls/grep.rb +17 -15
  51. data/lib/pry/commands/ls/instance_vars.rb +29 -28
  52. data/lib/pry/commands/ls/interrogatable.rb +18 -12
  53. data/lib/pry/commands/ls/jruby_hacks.rb +47 -41
  54. data/lib/pry/commands/ls/local_names.rb +26 -24
  55. data/lib/pry/commands/ls/local_vars.rb +38 -30
  56. data/lib/pry/commands/ls/ls_entity.rb +47 -52
  57. data/lib/pry/commands/ls/methods.rb +49 -51
  58. data/lib/pry/commands/ls/methods_helper.rb +46 -42
  59. data/lib/pry/commands/ls/self_methods.rb +23 -21
  60. data/lib/pry/commands/ls.rb +124 -103
  61. data/lib/pry/commands/nesting.rb +21 -17
  62. data/lib/pry/commands/play.rb +92 -82
  63. data/lib/pry/commands/pry_backtrace.rb +22 -17
  64. data/lib/pry/commands/pry_version.rb +15 -11
  65. data/lib/pry/commands/raise_up.rb +33 -27
  66. data/lib/pry/commands/reload_code.rb +60 -48
  67. data/lib/pry/commands/reset.rb +16 -12
  68. data/lib/pry/commands/ri.rb +57 -42
  69. data/lib/pry/commands/save_file.rb +45 -43
  70. data/lib/pry/commands/shell_command.rb +56 -29
  71. data/lib/pry/commands/shell_mode.rb +22 -18
  72. data/lib/pry/commands/show_doc.rb +80 -70
  73. data/lib/pry/commands/show_info.rb +194 -155
  74. data/lib/pry/commands/show_input.rb +16 -11
  75. data/lib/pry/commands/show_source.rb +110 -42
  76. data/lib/pry/commands/stat.rb +35 -31
  77. data/lib/pry/commands/switch_to.rb +21 -15
  78. data/lib/pry/commands/toggle_color.rb +20 -16
  79. data/lib/pry/commands/watch_expression/expression.rb +32 -27
  80. data/lib/pry/commands/watch_expression.rb +89 -84
  81. data/lib/pry/commands/whereami.rb +156 -141
  82. data/lib/pry/commands/wtf.rb +78 -40
  83. data/lib/pry/config/attributable.rb +22 -0
  84. data/lib/pry/config/lazy_value.rb +29 -0
  85. data/lib/pry/config/memoized_value.rb +34 -0
  86. data/lib/pry/config/value.rb +24 -0
  87. data/lib/pry/config.rb +310 -20
  88. data/lib/pry/control_d_handler.rb +28 -0
  89. data/lib/pry/core_extensions.rb +22 -9
  90. data/lib/pry/editor.rb +56 -34
  91. data/lib/pry/env.rb +18 -0
  92. data/lib/pry/exception_handler.rb +43 -0
  93. data/lib/pry/exceptions.rb +13 -18
  94. data/lib/pry/forwardable.rb +27 -0
  95. data/lib/pry/helpers/base_helpers.rb +20 -62
  96. data/lib/pry/helpers/command_helpers.rb +52 -62
  97. data/lib/pry/helpers/documentation_helpers.rb +21 -12
  98. data/lib/pry/helpers/options_helpers.rb +15 -8
  99. data/lib/pry/helpers/platform.rb +55 -0
  100. data/lib/pry/helpers/table.rb +44 -32
  101. data/lib/pry/helpers/text.rb +96 -85
  102. data/lib/pry/helpers.rb +3 -0
  103. data/lib/pry/history.rb +81 -55
  104. data/lib/pry/hooks.rb +60 -110
  105. data/lib/pry/indent.rb +74 -68
  106. data/lib/pry/input_completer.rb +199 -158
  107. data/lib/pry/input_lock.rb +7 -10
  108. data/lib/pry/inspector.rb +36 -24
  109. data/lib/pry/last_exception.rb +45 -45
  110. data/lib/pry/method/disowned.rb +19 -5
  111. data/lib/pry/method/patcher.rb +14 -8
  112. data/lib/pry/method/weird_method_locator.rb +79 -45
  113. data/lib/pry/method.rb +178 -124
  114. data/lib/pry/object_path.rb +37 -28
  115. data/lib/pry/output.rb +102 -16
  116. data/lib/pry/pager.rb +187 -174
  117. data/lib/pry/prompt.rb +213 -25
  118. data/lib/pry/pry_class.rb +119 -98
  119. data/lib/pry/pry_instance.rb +261 -224
  120. data/lib/pry/repl.rb +83 -29
  121. data/lib/pry/repl_file_loader.rb +27 -22
  122. data/lib/pry/ring.rb +89 -0
  123. data/lib/pry/slop/LICENSE +20 -0
  124. data/lib/pry/slop/commands.rb +190 -0
  125. data/lib/pry/slop/option.rb +210 -0
  126. data/lib/pry/slop.rb +672 -0
  127. data/lib/pry/syntax_highlighter.rb +26 -0
  128. data/lib/pry/system_command_handler.rb +17 -0
  129. data/lib/pry/testable/evalable.rb +24 -0
  130. data/lib/pry/testable/mockable.rb +22 -0
  131. data/lib/pry/testable/pry_tester.rb +88 -0
  132. data/lib/pry/testable/utility.rb +34 -0
  133. data/lib/pry/testable/variables.rb +52 -0
  134. data/lib/pry/testable.rb +68 -0
  135. data/lib/pry/version.rb +3 -1
  136. data/lib/pry/warning.rb +20 -0
  137. data/lib/pry/{module_candidate.rb → wrapped_module/candidate.rb} +35 -32
  138. data/lib/pry/wrapped_module.rb +68 -63
  139. data/lib/pry.rb +133 -149
  140. metadata +58 -69
  141. data/lib/pry/commands/disabled_commands.rb +0 -2
  142. data/lib/pry/commands/gem_cd.rb +0 -26
  143. data/lib/pry/commands/gem_install.rb +0 -32
  144. data/lib/pry/commands/gem_list.rb +0 -33
  145. data/lib/pry/commands/gem_open.rb +0 -29
  146. data/lib/pry/commands/gist.rb +0 -101
  147. data/lib/pry/commands/install_command.rb +0 -53
  148. data/lib/pry/commands/list_prompts.rb +0 -35
  149. data/lib/pry/commands/simple_prompt.rb +0 -22
  150. data/lib/pry/commands.rb +0 -6
  151. data/lib/pry/config/behavior.rb +0 -139
  152. data/lib/pry/config/convenience.rb +0 -25
  153. data/lib/pry/config/default.rb +0 -161
  154. data/lib/pry/history_array.rb +0 -121
  155. data/lib/pry/plugins.rb +0 -103
  156. data/lib/pry/rbx_path.rb +0 -22
  157. data/lib/pry/rubygem.rb +0 -82
  158. data/lib/pry/terminal.rb +0 -79
  159. data/lib/pry/test/helper.rb +0 -170
@@ -1,36 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Pry
2
4
  module Helpers
3
- def self.tablify_or_one_line(heading, things)
5
+ def self.tablify_or_one_line(heading, things, pry_instance = Pry.new)
4
6
  plain_heading = Pry::Helpers::Text.strip_color(heading)
5
- attempt = Table.new(things, :column_count => things.size)
6
- if attempt.fits_on_line?(Terminal.width! - plain_heading.size - 2)
7
+ attempt = Table.new(things, column_count: things.size)
8
+ if attempt.fits_on_line?(pry_instance.output.width - plain_heading.size - 2)
7
9
  "#{heading}: #{attempt}\n"
8
10
  else
9
- "#{heading}: \n#{tablify_to_screen_width(things, :indent => ' ')}\n"
11
+ content = tablify_to_screen_width(things, { indent: ' ' }, pry_instance)
12
+ "#{heading}: \n#{content}\n"
10
13
  end
11
14
  end
12
15
 
13
- def self.tablify_to_screen_width(things, options = {})
16
+ def self.tablify_to_screen_width(things, options, pry_instance = Pry.new)
17
+ options ||= {}
14
18
  things = things.compact
15
- if indent = options[:indent]
16
- usable_width = Terminal.width! - indent.size
17
- tablify(things, usable_width).to_s.gsub(/^/, indent)
19
+ if (indent = options[:indent])
20
+ usable_width = pry_instance.output.width - indent.size
21
+ tablify(things, usable_width, pry_instance).to_s.gsub(/^/, indent)
18
22
  else
19
- tablify(things, Terminal.width!).to_s
23
+ tablify(things, pry_instance.output.width, pry_instance).to_s
20
24
  end
21
25
  end
22
26
 
23
- def self.tablify(things, line_length)
24
- table = Table.new(things, :column_count => things.size)
25
- table.column_count -= 1 until 1 == table.column_count or
26
- table.fits_on_line?(line_length)
27
+ def self.tablify(things, line_length, pry_instance = Pry.new)
28
+ table = Table.new(things, { column_count: things.size }, pry_instance)
29
+ until (table.column_count == 1) || table.fits_on_line?(line_length)
30
+ table.column_count -= 1
31
+ end
27
32
  table
28
33
  end
29
34
 
30
35
  class Table
31
36
  attr_reader :items, :column_count
32
- def initialize items, args = {}
37
+ def initialize(items, args, pry_instance = Pry.new)
33
38
  @column_count = args[:column_count]
39
+ @config = pry_instance.config
34
40
  self.items = items
35
41
  end
36
42
 
@@ -38,44 +44,50 @@ class Pry
38
44
  rows_to_s.join("\n")
39
45
  end
40
46
 
41
- def rows_to_s style = :color_on
42
- widths = columns.map{|e| _max_width(e)}
47
+ def rows_to_s(style = :color_on)
48
+ widths = columns.map { |e| _max_width(e) }
43
49
  @rows_without_colors.map do |r|
44
50
  padded = []
45
- r.each_with_index do |e,i|
51
+ r.each_with_index do |e, i|
46
52
  next unless e
53
+
47
54
  item = e.ljust(widths[i])
48
- item.sub! e, _recall_color_for(e) if :color_on == style
55
+ item.sub! e, _recall_color_for(e) if style == :color_on
49
56
  padded << item
50
57
  end
51
- padded.join(Pry.config.ls.separator)
58
+ padded.join(@config.ls.separator)
52
59
  end
53
60
  end
54
61
 
55
- def items= items
62
+ def items=(items)
56
63
  @items = items
57
64
  _rebuild_colorless_cache
58
65
  _recolumn
59
- items
60
66
  end
61
67
 
62
- def column_count= n
63
- @column_count = n
68
+ def column_count=(count)
69
+ @column_count = count
64
70
  _recolumn
65
71
  end
66
72
 
67
- def fits_on_line? line_length
68
- _max_width(rows_to_s :no_color) <= line_length
73
+ def fits_on_line?(line_length)
74
+ _max_width(rows_to_s(:no_color)) <= line_length
69
75
  end
70
76
 
71
77
  def columns
72
78
  @rows_without_colors.transpose
73
79
  end
74
80
 
75
- def ==(other); items == other.to_a end
76
- def to_a; items.to_a end
81
+ def ==(other)
82
+ items == other.to_a
83
+ end
84
+
85
+ def to_a
86
+ items.to_a
87
+ end
77
88
 
78
89
  private
90
+
79
91
  def _max_width(things)
80
92
  things.compact.map(&:size).max || 0
81
93
  end
@@ -93,17 +105,17 @@ class Pry
93
105
  def _recolumn
94
106
  @rows_without_colors = []
95
107
  return if items.size.zero?
96
- row_count = (items.size.to_f/column_count).ceil
108
+
109
+ row_count = (items.size.to_f / column_count).ceil
97
110
  row_count.times do |i|
98
- row_indices = (0...column_count).map{|e| row_count*e+i}
99
- @rows_without_colors << row_indices.map{|e| @plain_items[e]}
111
+ row_indices = (0...column_count).map { |e| row_count * e + i }
112
+ @rows_without_colors << row_indices.map { |e| @plain_items[e] }
100
113
  end
101
114
  end
102
115
 
103
- def _recall_color_for thing
116
+ def _recall_color_for(thing)
104
117
  @colorless_cache[thing]
105
118
  end
106
119
  end
107
-
108
120
  end
109
121
  end
@@ -1,107 +1,118 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Pry
2
4
  module Helpers
3
-
4
- # The methods defined on {Text} are available to custom commands via {Pry::Command#text}.
5
+ # The methods defined on {Text} are available to custom commands via
6
+ # {Pry::Command#text}.
5
7
  module Text
8
+ extend self
6
9
 
7
- COLORS =
8
- {
9
- "black" => 0,
10
- "red" => 1,
11
- "green" => 2,
12
- "yellow" => 3,
13
- "blue" => 4,
14
- "purple" => 5,
10
+ COLORS = {
11
+ "black" => 0,
12
+ "red" => 1,
13
+ "green" => 2,
14
+ "yellow" => 3,
15
+ "blue" => 4,
16
+ "purple" => 5,
15
17
  "magenta" => 5,
16
- "cyan" => 6,
17
- "white" => 7
18
- }
18
+ "cyan" => 6,
19
+ "white" => 7
20
+ }.freeze
19
21
 
20
- class << self
22
+ COLORS.each_pair do |color, value|
23
+ define_method color do |text|
24
+ "\033[0;#{30 + value}m#{text}\033[0m"
25
+ end
21
26
 
22
- COLORS.each_pair do |color, value|
23
- define_method color do |text|
24
- "\033[0;#{30+value}m#{text}\033[0m"
25
- end
27
+ define_method "bright_#{color}" do |text|
28
+ "\033[1;#{30 + value}m#{text}\033[0m"
29
+ end
26
30
 
27
- define_method "bright_#{color}" do |text|
28
- "\033[1;#{30+value}m#{text}\033[0m"
31
+ COLORS.each_pair do |bg_color, bg_value|
32
+ define_method "#{color}_on_#{bg_color}" do |text|
33
+ "\033[0;#{30 + value};#{40 + bg_value}m#{text}\033[0m"
29
34
  end
30
- end
31
35
 
32
- # Remove any color codes from _text_.
33
- #
34
- # @param [String, #to_s] text
35
- # @return [String] _text_ stripped of any color codes.
36
- def strip_color(text)
37
- text.to_s.gsub(/\e\[.*?(\d)+m/ , '')
36
+ define_method "bright_#{color}_on_#{bg_color}" do |text|
37
+ "\033[1;#{30 + value};#{40 + bg_value}m#{text}\033[0m"
38
+ end
38
39
  end
40
+ end
39
41
 
40
- # Returns _text_ as bold text for use on a terminal.
41
- #
42
- # @param [String, #to_s] text
43
- # @return [String] _text_
44
- def bold(text)
45
- "\e[1m#{text}\e[0m"
46
- end
42
+ # Remove any color codes from _text_.
43
+ #
44
+ # @param [String, #to_s] text
45
+ # @return [String] _text_ stripped of any color codes.
46
+ def strip_color(text)
47
+ text.to_s.gsub(/(\001)?(\e\[(\d[;\d]?)*m)(\002)?/, '')
48
+ end
47
49
 
48
- # Returns `text` in the default foreground colour.
49
- # Use this instead of "black" or "white" when you mean absence of colour.
50
- #
51
- # @param [String, #to_s] text
52
- # @return [String]
53
- def default(text)
54
- text.to_s
55
- end
56
- alias_method :bright_default, :bold
50
+ # Returns _text_ as bold text for use on a terminal.
51
+ #
52
+ # @param [String, #to_s] text
53
+ # @return [String] _text_
54
+ def bold(text)
55
+ "\e[1m#{text}\e[0m"
56
+ end
57
57
 
58
- # Executes the block with `Pry.config.color` set to false.
59
- # @yield
60
- # @return [void]
61
- def no_color(&block)
62
- boolean = Pry.config.color
63
- Pry.config.color = false
64
- yield
65
- ensure
66
- Pry.config.color = boolean
67
- end
58
+ # Returns `text` in the default foreground colour.
59
+ # Use this instead of "black" or "white" when you mean absence of colour.
60
+ #
61
+ # @param [String, #to_s] text
62
+ # @return [String]
63
+ def default(text)
64
+ text.to_s
65
+ end
68
66
 
69
- # Executes the block with `Pry.config.pager` set to false.
70
- # @yield
71
- # @return [void]
72
- def no_pager(&block)
73
- boolean = Pry.config.pager
74
- Pry.config.pager = false
75
- yield
76
- ensure
77
- Pry.config.pager = boolean
78
- end
67
+ #
68
+ # @yield
69
+ # Yields a block with color turned off.
70
+ #
71
+ # @return [void]
72
+ #
73
+ def no_color
74
+ boolean = Pry.config.color
75
+ Pry.config.color = false
76
+ yield
77
+ ensure
78
+ Pry.config.color = boolean
79
+ end
79
80
 
80
- # Returns _text_ in a numbered list, beginning at _offset_.
81
- #
82
- # @param [#each_line] text
83
- # @param [Fixnum] offset
84
- # @return [String]
85
- def with_line_numbers(text, offset, color=:blue)
86
- lines = text.each_line.to_a
87
- max_width = (offset + lines.count).to_s.length
88
- lines.each_with_index.map do |line, index|
89
- adjusted_index = (index + offset).to_s.rjust(max_width)
90
- "#{self.send(color, adjusted_index)}: #{line}"
91
- end.join
92
- end
81
+ #
82
+ # @yield
83
+ # Yields a block with paging turned off.
84
+ #
85
+ # @return [void]
86
+ #
87
+ def no_pager
88
+ boolean = Pry.config.pager
89
+ Pry.config.pager = false
90
+ yield
91
+ ensure
92
+ Pry.config.pager = boolean
93
+ end
93
94
 
94
- # Returns _text_ indented by _chars_ spaces.
95
- #
96
- # @param [String] text
97
- # @param [Fixnum] chars
98
- def indent(text, chars)
99
- text.lines.map { |l| "#{' ' * chars}#{l}" }.join
100
- end
95
+ # Returns _text_ in a numbered list, beginning at _offset_.
96
+ #
97
+ # @param [#each_line] text
98
+ # @param [Fixnum] offset
99
+ # @return [String]
100
+ def with_line_numbers(text, offset, color = :blue)
101
+ lines = text.each_line.to_a
102
+ max_width = (offset + lines.count).to_s.length
103
+ lines.each_with_index.map do |line, index|
104
+ adjusted_index = (index + offset).to_s.rjust(max_width)
105
+ "#{send(color, adjusted_index)}: #{line}"
106
+ end.join
101
107
  end
102
108
 
109
+ # Returns _text_ indented by _chars_ spaces.
110
+ #
111
+ # @param [String] text
112
+ # @param [Fixnum] chars
113
+ def indent(text, chars)
114
+ text.lines.map { |l| "#{' ' * chars}#{l}" }.join
115
+ end
103
116
  end
104
-
105
117
  end
106
118
  end
107
-
data/lib/pry/helpers.rb CHANGED
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "pry/helpers/base_helpers"
2
4
  require "pry/helpers/options_helpers"
3
5
  require "pry/helpers/command_helpers"
4
6
  require "pry/helpers/text"
5
7
  require "pry/helpers/table"
8
+ require "pry/helpers/platform"
data/lib/pry/history.rb CHANGED
@@ -1,42 +1,49 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Pry
2
4
  # The History class is responsible for maintaining the user's input history,
3
5
  # both internally and within Readline.
4
6
  class History
5
- attr_accessor :loader, :saver, :pusher, :clearer
7
+ def self.default_file
8
+ history_file =
9
+ if (xdg_home = Pry::Env['XDG_DATA_HOME'])
10
+ # See XDG Base Directory Specification at
11
+ # https://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
12
+ xdg_home + '/pry/pry_history'
13
+ elsif File.exist?(File.expand_path('~/.pry_history'))
14
+ '~/.pry_history'
15
+ else
16
+ '~/.local/share/pry/pry_history'
17
+ end
18
+ File.expand_path(history_file)
19
+ end
20
+
21
+ attr_accessor :loader, :saver
6
22
 
7
23
  # @return [Fixnum] Number of lines in history when Pry first loaded.
8
24
  attr_reader :original_lines
9
25
 
10
- def initialize(options={})
11
- @history = []
12
- @original_lines = 0
13
- @file_path = options[:file_path]
14
- restore_default_behavior
15
- end
16
-
17
- # Assign the default methods for loading, saving, pushing, and clearing.
18
- def restore_default_behavior
19
- Pry.config.input # force Readline to load if applicable
26
+ # @return [Integer] total number of lines, including original lines
27
+ attr_reader :history_line_count
20
28
 
29
+ def initialize(options = {})
30
+ @history = options[:history] || []
31
+ @history_line_count = @history.count
32
+ @file_path = options[:file_path]
33
+ @original_lines = 0
21
34
  @loader = method(:read_from_file)
22
- @saver = method(:save_to_file)
23
-
24
- if defined?(Readline)
25
- @pusher = method(:push_to_readline)
26
- @clearer = method(:clear_readline)
27
- else
28
- @pusher = proc { }
29
- @clearer = proc { }
30
- end
35
+ @saver = method(:save_to_file)
31
36
  end
32
37
 
33
38
  # Load the input history using `History.loader`.
34
39
  # @return [Integer] The number of lines loaded
35
40
  def load
36
41
  @loader.call do |line|
37
- @pusher.call(line.chomp)
42
+ next if invalid_readline_line?(line)
43
+
38
44
  @history << line.chomp
39
45
  @original_lines += 1
46
+ @history_line_count += 1
40
47
  end
41
48
  end
42
49
 
@@ -44,11 +51,20 @@ class Pry
44
51
  # @param [String] line
45
52
  # @return [String] The same line that was passed in
46
53
  def push(line)
47
- unless line.empty? || (@history.last && line == @history.last)
48
- @pusher.call(line)
49
- @history << line
50
- @saver.call(line) if Pry.config.history.should_save
54
+ return line if line.empty? || invalid_readline_line?(line)
55
+
56
+ begin
57
+ last_line = @history[-1]
58
+ rescue IndexError
59
+ last_line = nil
51
60
  end
61
+
62
+ return line if line == last_line
63
+
64
+ @history << line
65
+ @history_line_count += 1
66
+ @saver.call(line) if !should_ignore?(line) && Pry.config.history_save
67
+
52
68
  line
53
69
  end
54
70
  alias << push
@@ -56,52 +72,53 @@ class Pry
56
72
  # Clear this session's history. This won't affect the contents of the
57
73
  # history file.
58
74
  def clear
59
- @clearer.call
60
- @history = []
61
- end
62
-
63
- # @return [Fixnum] The number of lines in history.
64
- def history_line_count
65
- @history.count
75
+ @history.clear
76
+ @history_line_count = 0
77
+ @original_lines = 0
66
78
  end
67
79
 
68
80
  # @return [Fixnum] The number of lines in history from just this session.
69
81
  def session_line_count
70
- @history.count - @original_lines
82
+ @history_line_count - @original_lines
71
83
  end
72
84
 
73
85
  # Return an Array containing all stored history.
74
86
  # @return [Array<String>] An Array containing all lines of history loaded
75
87
  # or entered by the user in the current session.
76
88
  def to_a
77
- @history.dup
89
+ @history.to_a
90
+ end
91
+
92
+ # Filter the history with the histignore options
93
+ # @return [Array<String>] An array containing all the lines that are not
94
+ # included in the histignore.
95
+ def filter(history)
96
+ history.select { |l| l unless should_ignore?(l) }
78
97
  end
79
98
 
80
99
  private
81
100
 
82
- # The default loader. Yields lines from `Pry.history.config.file`.
83
- def read_from_file
84
- path = history_file_path
101
+ # Check if the line match any option in the histignore
102
+ # [Pry.config.history_ignorelist]
103
+ # @return [Boolean] a boolean that notifies if the line was found in the
104
+ # histignore array.
105
+ def should_ignore?(line)
106
+ hist_ignore = Pry.config.history_ignorelist
107
+ return false if hist_ignore.nil? || hist_ignore.empty?
85
108
 
86
- if File.exists?(path)
87
- File.foreach(path) { |line| yield(line) }
88
- end
89
- rescue => error
90
- warn "History file not loaded: #{error.message}"
109
+ hist_ignore.any? { |p| line.to_s.match(p) }
91
110
  end
92
111
 
93
- # The default pusher. Appends the given line to Readline::HISTORY.
94
- # @param [String] line
95
- def push_to_readline(line)
96
- Readline::HISTORY << line
97
- end
112
+ # The default loader. Yields lines from `Pry.config.history_file`.
113
+ def read_from_file
114
+ path = history_file_path
98
115
 
99
- # The default clearer. Clears Readline::HISTORY.
100
- def clear_readline
101
- Readline::HISTORY.shift until Readline::HISTORY.empty?
116
+ File.foreach(path) { |line| yield(line) } if File.exist?(path)
117
+ rescue SystemCallError => error
118
+ warn "Unable to read history file: #{error.message}"
102
119
  end
103
120
 
104
- # The default saver. Appends the given line to `Pry.history.config.file`.
121
+ # The default saver. Appends the given line to `Pry.config.history_file`.
105
122
  def save_to_file(line)
106
123
  history_file.puts line if history_file
107
124
  end
@@ -111,17 +128,26 @@ class Pry
111
128
  if defined?(@history_file)
112
129
  @history_file
113
130
  else
114
- @history_file = File.open(history_file_path, 'a', 0600).tap do |file|
131
+ unless File.exist?(history_file_path)
132
+ FileUtils.mkdir_p(File.dirname(history_file_path))
133
+ end
134
+ @history_file = File.open(history_file_path, 'a', 0o600).tap do |file|
115
135
  file.sync = true
116
136
  end
117
137
  end
118
- rescue Errno::EACCES
119
- warn 'History not saved; unable to open your history file for writing.'
138
+ rescue SystemCallError => error
139
+ warn "Unable to write history file: #{error.message}"
120
140
  @history_file = false
121
141
  end
122
142
 
123
143
  def history_file_path
124
- File.expand_path(@file_path || Pry.config.history.file)
144
+ File.expand_path(@file_path || Pry.config.history_file)
145
+ end
146
+
147
+ def invalid_readline_line?(line)
148
+ # `Readline::HISTORY << line` raises an `ArgumentError` if `line`
149
+ # includes a null byte
150
+ line.include?("\0")
125
151
  end
126
152
  end
127
153
  end