pry 0.8.4pre1-i386-mswin32 → 0.9.0-i386-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +25 -6
  3. data/README.markdown +11 -4
  4. data/Rakefile +15 -19
  5. data/TODO +28 -2
  6. data/bin/pry +28 -11
  7. data/examples/example_basic.rb +2 -4
  8. data/examples/example_command_override.rb +2 -5
  9. data/examples/example_commands.rb +1 -4
  10. data/examples/example_hooks.rb +2 -5
  11. data/examples/example_image_edit.rb +4 -8
  12. data/examples/example_input.rb +1 -4
  13. data/examples/example_input2.rb +1 -4
  14. data/examples/example_output.rb +1 -4
  15. data/examples/example_print.rb +2 -5
  16. data/examples/example_prompt.rb +2 -5
  17. data/examples/helper.rb +6 -0
  18. data/lib/pry.rb +59 -3
  19. data/lib/pry/command_context.rb +10 -9
  20. data/lib/pry/command_processor.rb +51 -73
  21. data/lib/pry/command_set.rb +79 -28
  22. data/lib/pry/commands.rb +9 -123
  23. data/lib/pry/completion.rb +30 -29
  24. data/lib/pry/config.rb +100 -0
  25. data/lib/pry/default_commands/basic.rb +37 -0
  26. data/lib/pry/default_commands/context.rb +16 -15
  27. data/lib/pry/default_commands/documentation.rb +73 -54
  28. data/lib/pry/default_commands/easter_eggs.rb +1 -20
  29. data/lib/pry/default_commands/gems.rb +31 -40
  30. data/lib/pry/default_commands/input.rb +223 -15
  31. data/lib/pry/default_commands/introspection.rb +108 -73
  32. data/lib/pry/default_commands/ls.rb +25 -11
  33. data/lib/pry/default_commands/shell.rb +29 -39
  34. data/lib/pry/extended_commands/experimental.rb +17 -0
  35. data/lib/pry/extended_commands/user_command_api.rb +22 -0
  36. data/lib/pry/helpers.rb +1 -0
  37. data/lib/pry/helpers/base_helpers.rb +15 -104
  38. data/lib/pry/helpers/command_helpers.rb +96 -59
  39. data/lib/pry/helpers/text.rb +83 -0
  40. data/lib/pry/history_array.rb +105 -0
  41. data/lib/pry/plugins.rb +79 -0
  42. data/lib/pry/pry_class.rb +102 -114
  43. data/lib/pry/pry_instance.rb +123 -55
  44. data/lib/pry/version.rb +1 -1
  45. data/pry.gemspec +45 -0
  46. data/test/helper.rb +57 -7
  47. data/test/test_command_processor.rb +205 -0
  48. data/test/{test_commandset.rb → test_command_set.rb} +18 -12
  49. data/test/test_default_commands.rb +59 -0
  50. data/test/test_default_commands/test_context.rb +64 -0
  51. data/test/test_default_commands/test_documentation.rb +31 -0
  52. data/test/test_default_commands/test_gems.rb +14 -0
  53. data/test/test_default_commands/test_input.rb +327 -0
  54. data/test/test_default_commands/test_introspection.rb +155 -0
  55. data/test/test_history_array.rb +65 -0
  56. data/test/test_pry.rb +548 -313
  57. metadata +48 -15
  58. data/lib/pry/hooks.rb +0 -17
  59. data/lib/pry/print.rb +0 -16
  60. data/lib/pry/prompts.rb +0 -31
@@ -0,0 +1,83 @@
1
+ class Pry
2
+ module Helpers
3
+
4
+ # The methods defined on {Text} are available to custom commands via {Pry::CommandContext#text}.
5
+ module Text
6
+
7
+ COLORS =
8
+ {
9
+ "black" => 0,
10
+ "red" => 1,
11
+ "green" => 2,
12
+ "yellow" => 3,
13
+ "blue" => 4,
14
+ "purple" => 5,
15
+ "magenta" => 5,
16
+ "cyan" => 6,
17
+ "white" => 7
18
+ }
19
+
20
+ class << self
21
+
22
+ COLORS.each_pair do |color, value|
23
+ define_method color do |text|
24
+ Pry.color ? "\033[0;#{30+value}m#{text}\033[0m" : text.to_s
25
+ end
26
+
27
+ define_method "bright_#{color}" do |text|
28
+ Pry.color ? "\033[1;#{30+value}m#{text}\033[0m" : text.to_s
29
+ end
30
+ end
31
+
32
+ alias_method :grey, :bright_black
33
+ alias_method :gray, :bright_black
34
+
35
+
36
+ # Remove any color codes from _text_.
37
+ #
38
+ # @param [String, #to_s] text
39
+ # @return [String] _text_ stripped of any color codes.
40
+ def strip_color text
41
+ text.to_s.gsub(/\e\[.*?(\d)+m/ , '')
42
+ end
43
+
44
+ # Returns _text_ as bold text for use on a terminal.
45
+ # _Pry.color_ must be true for this method to perform any transformations.
46
+ #
47
+ # @param [String, #to_s] text
48
+ # @return [String] _text_
49
+ def bold text
50
+ Pry.color ? "\e[1m#{text}\e[0m" : text.to_s
51
+ end
52
+
53
+ # Executes _block_ with _Pry.color_ set to false.
54
+ #
55
+ # @param [Proc]
56
+ # @return [void]
57
+ def no_color &block
58
+ boolean = Pry.color
59
+ Pry.color = false
60
+ yield
61
+ ensure
62
+ Pry.color = boolean
63
+ end
64
+
65
+ # Returns _text_ in a numbered list, beginning at _offset_.
66
+ #
67
+ # @param [#each_line] text
68
+ # @param [Fixnum] offset
69
+ # @return [String]
70
+ def with_line_numbers text, offset
71
+ lines = text.each_line.to_a
72
+ lines.each_with_index.map do |line, index|
73
+ adjusted_index = index + offset
74
+ "#{self.blue adjusted_index}: #{line}"
75
+ end.join
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+ end
83
+
@@ -0,0 +1,105 @@
1
+ class Pry
2
+ # A history array is an array to which you can only add elements. Older
3
+ # entries are removed progressively, so that the aray never contains more than
4
+ # N elements.
5
+ #
6
+ # History arrays are used by Pry to store the output of the last commands.
7
+ #
8
+ # @example
9
+ # ary = Pry::HistoryArray.new 10
10
+ # ary << 1 << 2 << 3
11
+ # ary[0] # => 1
12
+ # ary[1] # => 2
13
+ # 10.times { |n| ary << n }
14
+ # ary[0] # => nil
15
+ # ary[-1] # => 9
16
+ class HistoryArray
17
+ include Enumerable
18
+
19
+ # @param [Integer] size Maximum amount of objects in the array
20
+ def initialize(size)
21
+ @max_size = size
22
+
23
+ @hash = {}
24
+ @count = 0
25
+ end
26
+
27
+ # Pushes an object at the end of the array
28
+ # @param [Object] value Object to be added
29
+ def <<(value)
30
+ @hash[@count] = value
31
+
32
+ if @hash.size > max_size
33
+ @hash.delete(@count - max_size)
34
+ end
35
+
36
+ @count += 1
37
+
38
+ self
39
+ end
40
+
41
+ # @overload [](index)
42
+ # @param [Integer] index Index of the item to access.
43
+ # @return [Object, nil] Item at that index or nil if it has been removed.
44
+ # @overload [](index, size)
45
+ # @param [Integer] index Index of the first item to access.
46
+ # @param [Integer] size Amount of items to access
47
+ # @return [Array, nil] The selected items. Nil if index is greater than
48
+ # the size of the array.
49
+ # @overload [](range)
50
+ # @param [Range<Integer>] range Range of indices to access.
51
+ # @return [Array, nil] The selected items. Nil if index is greater than
52
+ # the size of the array.
53
+ def [](index_or_range, size = nil)
54
+ if index_or_range.is_a? Integer
55
+ index = convert_index(index_or_range)
56
+
57
+ if size
58
+ end_index = index + size
59
+ index > @count ? nil : (index...[end_index, @count].min).map do |n|
60
+ @hash[n]
61
+ end
62
+ else
63
+ @hash[index]
64
+ end
65
+ else
66
+ range = convert_range(index_or_range)
67
+ range.begin > @count ? nil : range.map { |n| @hash[n] }
68
+ end
69
+ end
70
+
71
+ # @return [Integer] Amount of objects in the array
72
+ def size
73
+ @count
74
+ end
75
+
76
+ def each
77
+ ((@count - size)...@count).each do |n|
78
+ yield @hash[n]
79
+ end
80
+ end
81
+
82
+ def to_a
83
+ ((@count - size)...@count).map { |n| @hash[n] }
84
+ end
85
+
86
+ def inspect
87
+ "#<#{self.class} size=#{size} first=#{@count - size} max_size=#{max_size}>"
88
+ end
89
+
90
+ # @return [Integer] Maximum amount of objects in the array
91
+ attr_reader :max_size
92
+
93
+ private
94
+ def convert_index(n)
95
+ n >= 0 ? n : @count + n
96
+ end
97
+
98
+ def convert_range(range)
99
+ end_index = convert_index(range.end)
100
+ end_index += 1 unless range.exclude_end?
101
+
102
+ Range.new(convert_index(range.begin), [end_index, @count].min, true)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,79 @@
1
+ class Pry
2
+ class PluginManager
3
+ PRY_PLUGIN_PREFIX = /^pry-/
4
+ PluginNotFound = Class.new(LoadError)
5
+
6
+ MessageSink = Object.new.tap { |o| def o.method_missing(*args) end }
7
+
8
+ class Plugin
9
+ attr_accessor :name, :gem_name, :enabled, :spec, :active
10
+
11
+ def initialize(name, gem_name, spec, enabled)
12
+ @name, @gem_name, @enabled, @spec = name, gem_name, enabled, spec
13
+ end
14
+
15
+ # Disable a plugin.
16
+ def disable!
17
+ self.enabled = false
18
+ end
19
+
20
+ # Enable a plugin.
21
+ def enable!
22
+ self.enabled = true
23
+ end
24
+
25
+ # Activate the plugin (require the gem).
26
+ def activate!
27
+ begin
28
+ require gem_name
29
+ rescue LoadError
30
+ raise PluginNotFound, "The plugin '#{gem_name}' was not found!"
31
+ end
32
+ self.active = true
33
+ self.enabled = true
34
+ end
35
+
36
+ alias active? active
37
+ alias enabled? enabled
38
+ end
39
+
40
+ def initialize
41
+ @plugins = []
42
+ end
43
+
44
+ # Find all installed Pry plugins and store them in an internal array.
45
+ def locate_plugins
46
+ Gem.refresh
47
+ (Gem::Specification.respond_to?(:each) ? Gem::Specification : Gem.source_index.find_name('')).each do |gem|
48
+ next if gem.name !~ PRY_PLUGIN_PREFIX
49
+ plugin_name = gem.name.split('-', 2).last
50
+ @plugins << Plugin.new(plugin_name, gem.name, gem, true) if !gem_located?(gem.name)
51
+ end
52
+ @plugins
53
+ end
54
+
55
+ # @return [Hash] A hash with all plugin names (minus the 'pry-') as
56
+ # keys and Plugin objects as values.
57
+ def plugins
58
+ h = Pry.config.plugins.strict_loading ? {} : Hash.new { MessageSink }
59
+ @plugins.each do |plugin|
60
+ h[plugin.name] = plugin
61
+ end
62
+ h
63
+ end
64
+
65
+ # Require all enabled plugins, disabled plugins are skipped.
66
+ def load_plugins
67
+ @plugins.each do |plugin|
68
+ plugin.activate! if plugin.enabled?
69
+ end
70
+ end
71
+
72
+ private
73
+ def gem_located?(gem_name)
74
+ @plugins.any? { |plugin| plugin.gem_name == gem_name }
75
+ end
76
+ end
77
+
78
+ end
79
+
@@ -1,3 +1,7 @@
1
+ require 'ostruct'
2
+ require 'forwardable'
3
+ require 'pry/config'
4
+
1
5
  # @author John Mair (banisterfiend)
2
6
  class Pry
3
7
 
@@ -6,6 +10,13 @@ class Pry
6
10
 
7
11
  # class accessors
8
12
  class << self
13
+ extend Forwardable
14
+
15
+ # convenience method
16
+ def self.delegate_accessors(delagatee, *names)
17
+ def_delegators delagatee, *names
18
+ def_delegators delagatee, *names.map { |v| "#{v}=" }
19
+ end
9
20
 
10
21
  # Get nesting data.
11
22
  # This method should not need to be accessed directly.
@@ -27,41 +38,6 @@ class Pry
27
38
  # @return [Pry] The active Pry instance.
28
39
  attr_accessor :active_instance
29
40
 
30
- # Get/Set the object to use for input by default by all Pry instances.
31
- # @return [#readline] The object to use for input by default by all
32
- # Pry instances.
33
- attr_accessor :input
34
-
35
- # Get/Set the object to use for output by default by all Pry instances.
36
- # @return [#puts] The object to use for output by default by all
37
- # Pry instances.
38
- attr_accessor :output
39
-
40
- # Get/Set the object to use for commands by default by all Pry instances.
41
- # @return [Pry::CommandBase] The object to use for commands by default by all
42
- # Pry instances.
43
- attr_accessor :commands
44
-
45
- # Get/Set the Proc to use for printing by default by all Pry
46
- # instances.
47
- # This is the 'print' component of the REPL.
48
- # @return [Proc] The Proc to use for printing by default by all
49
- # Pry instances.
50
- attr_accessor :print
51
-
52
- # @return [Proc] The Proc to use for printing exceptions by default by all
53
- # Pry instances.
54
- attr_accessor :exception_handler
55
-
56
- # Get/Set the Hash that defines Pry hooks used by default by all Pry
57
- # instances.
58
- # @return [Hash] The hooks used by default by all Pry instances.
59
- # @example
60
- # Pry.hooks :before_session => proc { puts "hello" },
61
- # :after_session => proc { puts "goodbye" }
62
- attr_accessor :hooks
63
-
64
-
65
41
  # Get/Set the Proc that defines extra Readline completions (on top
66
42
  # of the ones defined for IRB).
67
43
  # @return [Proc] The Proc that defines extra Readline completions (on top
@@ -69,49 +45,31 @@ class Pry
69
45
  # Pry.custom_completions = proc { Dir.entries('.') }
70
46
  attr_accessor :custom_completions
71
47
 
72
- # Get the array of Procs to be used for the prompts by default by
73
- # all Pry instances.
74
- # @return [Array<Proc>] The array of Procs to be used for the
75
- # prompts by default by all Pry instances.
76
- attr_accessor :prompt
77
-
78
48
  # Value returned by last executed Pry command.
79
49
  # @return [Object] The command value
80
50
  attr_accessor :cmd_ret_value
81
51
 
82
- # Determines whether colored output is enabled.
83
- # @return [Boolean]
84
- attr_accessor :color
52
+ # @return [Fixnum] The current input line.
53
+ attr_accessor :current_line
54
+
55
+ # @return [Array] The Array of evaluated expressions.
56
+ attr_accessor :line_buffer
85
57
 
86
- # Determines whether paging (of long blocks of text) is enabled.
87
- # @return [Boolean]
88
- attr_accessor :pager
58
+ # @return [String] The __FILE__ for the `eval()`. Should be "(pry)"
59
+ # by default.
60
+ attr_accessor :eval_path
89
61
 
90
- # Determines whether the rc file (~/.pryrc) should be loaded.
91
- # @return [Boolean]
92
- attr_accessor :should_load_rc
62
+ # @return [OpenStruct] Return Pry's config object.
63
+ attr_accessor :config
93
64
 
94
- # Set to true if Pry is invoked from command line using `pry` executable
95
- # @return [Boolean]
65
+ # @return [Boolean] Whether Pry was activated from the command line.
96
66
  attr_accessor :cli
97
67
 
98
- # Set to true if the pry-doc extension is loaded.
99
- # @return [Boolean]
100
- attr_accessor :has_pry_doc
101
-
102
- # The default editor to use. Defaults to $EDITOR or nano if
103
- # $EDITOR is not defined.
104
- # If `editor` is a String then that string is used as the shell
105
- # command to invoke the editor. If `editor` is callable (e.g a
106
- # Proc) then `file` and `line` are passed in as parameters and the
107
- # return value of that callable invocation is used as the exact
108
- # shell command to invoke the editor.
109
- # @example String
110
- # Pry.editor = "emacsclient"
111
- # @example Callable
112
- # Pry.editor = proc { |file, line| "emacsclient #{file} +#{line}" }
113
- # @return [String, #call]
114
- attr_accessor :editor
68
+ # plugin forwardables
69
+ def_delegators :@plugin_manager, :plugins, :load_plugins, :locate_plugins
70
+
71
+ delegate_accessors :@config, :input, :output, :commands, :prompt, :print, :exception_handler,
72
+ :hooks, :color, :pager, :editor, :memory_size
115
73
  end
116
74
 
117
75
  # Load the rc files given in the `Pry::RC_FILES` array.
@@ -133,25 +91,26 @@ class Pry
133
91
  # @example
134
92
  # Pry.start(Object.new, :input => MyInput.new)
135
93
  def self.start(target=TOPLEVEL_BINDING, options={})
136
- if should_load_rc && !@rc_loaded
137
- load_rc
138
- @rc_loaded = true
94
+ if initial_session?
95
+ # note these have to be loaded here rather than in pry_instance as
96
+ # we only want them loaded once per entire Pry lifetime, not
97
+ # multiple times per each new session (i.e in debugging)
98
+ load_rc if Pry.config.should_load_rc
99
+ load_plugins if Pry.config.plugins.enabled
100
+ load_history if Pry.config.history.should_load
101
+
102
+ @initial_session = false
139
103
  end
140
104
 
141
105
  new(options).repl(target)
142
106
  end
143
107
 
144
- # A custom version of `Kernel#inspect`.
108
+ # A custom version of `Kernel#pretty_inspect`.
145
109
  # This method should not need to be accessed directly.
146
110
  # @param obj The object to view.
147
111
  # @return [String] The string representation of `obj`.
148
112
  def self.view(obj)
149
- case obj
150
- when String, Hash, Array, Symbol, Exception, nil
151
- obj.inspect
152
- else
153
- obj.to_s
154
- end
113
+ obj.pretty_inspect
155
114
 
156
115
  rescue NoMethodError
157
116
  "unknown"
@@ -163,17 +122,27 @@ class Pry
163
122
  # @param max_size The maximum number of chars before clipping occurs.
164
123
  # @return [String] The string representation of `obj`.
165
124
  def self.view_clip(obj, max_size=60)
166
- if Pry.view(obj).size < max_size
167
- Pry.view(obj)
125
+ if obj.inspect.size < max_size
126
+ obj.inspect
168
127
  else
169
128
  "#<#{obj.class}:%#x>" % (obj.object_id << 1)
170
129
  end
171
130
  end
172
131
 
132
+ # Load Readline history if required.
133
+ def self.load_history
134
+ history_file = File.expand_path(Pry.config.history.file)
135
+ Readline::HISTORY.push(*File.readlines(history_file).map(&:chomp)) if File.exists?(history_file)
136
+ end
137
+
138
+ # @return [Boolean] Whether this is the first time a Pry session has
139
+ # been started since loading the Pry class.
140
+ def self.initial_session?
141
+ @initial_session
142
+ end
143
+
173
144
  # Run a Pry command from outside a session. The commands available are
174
145
  # those referenced by `Pry.commands` (the default command set).
175
- # Command output is suppresed by default, this is because the return
176
- # value (if there is one) is likely to be more useful.
177
146
  # @param [String] arg_string The Pry command (including arguments,
178
147
  # if any).
179
148
  # @param [Hash] options Optional named parameters.
@@ -181,35 +150,24 @@ class Pry
181
150
  # @option options [Object, Binding] :context The object context to run the
182
151
  # command under. Defaults to `TOPLEVEL_BINDING` (main).
183
152
  # @option options [Boolean] :show_output Whether to show command
184
- # output. Defaults to false.
153
+ # output. Defaults to true.
185
154
  # @example Run at top-level with no output.
186
155
  # Pry.run_command "ls"
187
156
  # @example Run under Pry class, returning only public methods.
188
157
  # Pry.run_command "ls -m", :context => Pry
189
158
  # @example Display command output.
190
159
  # Pry.run_command "ls -av", :show_output => true
191
- def self.run_command(arg_string, options={})
192
- name, arg_string = arg_string.split(/\s+/, 2)
193
- arg_string = "" if !arg_string
194
-
160
+ def self.run_command(command_string, options={})
195
161
  options = {
196
162
  :context => TOPLEVEL_BINDING,
197
- :show_output => false,
163
+ :show_output => true,
198
164
  :output => Pry.output,
199
165
  :commands => Pry.commands
200
166
  }.merge!(options)
201
167
 
202
- null_output = StringIO.new
168
+ output = options[:show_output] ? options[:output] : StringIO.new
203
169
 
204
- context = CommandContext.new
205
- commands = options[:commands]
206
-
207
- context.opts = {}
208
- context.output = options[:show_output] ? options[:output] : null_output
209
- context.target = Pry.binding_for(options[:context])
210
- context.command_set = commands
211
-
212
- commands.run_command(context, name, *Shellwords.shellwords(arg_string))
170
+ Pry.new(:output => output, :input => StringIO.new(command_string), :commands => options[:commands]).rep(options[:context])
213
171
  end
214
172
 
215
173
  def self.default_editor_for_platform
@@ -220,25 +178,53 @@ class Pry
220
178
  end
221
179
  end
222
180
 
181
+ def self.set_config_defaults
182
+ config.input = Readline
183
+ config.output = $stdout
184
+ config.commands = Pry::Commands
185
+ config.prompt = DEFAULT_PROMPT
186
+ config.print = DEFAULT_PRINT
187
+ config.exception_handler = DEFAULT_EXCEPTION_HANDLER
188
+ config.hooks = DEFAULT_HOOKS
189
+ config.color = true
190
+ config.pager = true
191
+ config.editor = default_editor_for_platform
192
+ config.should_load_rc = true
193
+
194
+ config.plugins ||= OpenStruct.new
195
+ config.plugins.enabled = true
196
+ config.plugins.strict_loading = true
197
+
198
+ config.history ||= OpenStruct.new
199
+ config.history.should_save = true
200
+ config.history.should_load = true
201
+ config.history.file = File.expand_path("~/.pry_history")
202
+
203
+ config.memory_size = 100
204
+ config.results_pager = true
205
+ end
206
+
223
207
  # Set all the configurable options back to their default values
224
208
  def self.reset_defaults
225
- @input = Readline
226
- @output = $stdout
227
- @commands = Pry::Commands
228
- @prompt = DEFAULT_PROMPT
229
- @print = DEFAULT_PRINT
230
- @exception_handler = DEFAULT_EXCEPTION_HANDLER
231
- @hooks = DEFAULT_HOOKS
232
- @custom_completions = DEFAULT_CUSTOM_COMPLETIONS
233
- @color = true
234
- @pager = true
235
- @should_load_rc = true
236
- @rc_loaded = false
237
- @cli = false
238
- @editor = default_editor_for_platform
209
+ set_config_defaults
210
+
211
+ @initial_session = true
212
+
213
+ self.custom_completions = DEFAULT_CUSTOM_COMPLETIONS
214
+ self.cli = false
215
+ self.current_line = 0
216
+ self.line_buffer = []
217
+ self.eval_path = "(pry)"
239
218
  end
240
219
 
241
- self.reset_defaults
220
+ # Basic initialization.
221
+ def self.init
222
+ @plugin_manager ||= PluginManager.new
223
+
224
+ self.config ||= Config.new
225
+ reset_defaults
226
+ locate_plugins
227
+ end
242
228
 
243
229
  @nesting = []
244
230
  def @nesting.level
@@ -269,3 +255,5 @@ class Pry
269
255
  end
270
256
  end
271
257
  end
258
+
259
+ Pry.init