pry 0.10.3 → 0.14.2

Sign up to get free protection for your applications and to get access to all the features.
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