pry 0.9.10pre1-i386-mingw32 → 0.9.11-i386-mingw32

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 (194) hide show
  1. data/.travis.yml +3 -1
  2. data/CHANGELOG +63 -2
  3. data/CONTRIBUTORS +43 -25
  4. data/Gemfile +7 -0
  5. data/Guardfile +62 -0
  6. data/README.markdown +4 -4
  7. data/Rakefile +34 -35
  8. data/lib/pry.rb +107 -54
  9. data/lib/pry/cli.rb +34 -11
  10. data/lib/pry/code.rb +165 -182
  11. data/lib/pry/code/code_range.rb +70 -0
  12. data/lib/pry/code/loc.rb +92 -0
  13. data/lib/pry/code_object.rb +153 -0
  14. data/lib/pry/command.rb +160 -22
  15. data/lib/pry/command_set.rb +37 -26
  16. data/lib/pry/commands.rb +4 -27
  17. data/lib/pry/commands/amend_line.rb +99 -0
  18. data/lib/pry/commands/bang.rb +20 -0
  19. data/lib/pry/commands/bang_pry.rb +17 -0
  20. data/lib/pry/commands/cat.rb +53 -0
  21. data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
  22. data/lib/pry/commands/cat/exception_formatter.rb +78 -0
  23. data/lib/pry/commands/cat/file_formatter.rb +84 -0
  24. data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
  25. data/lib/pry/commands/cd.rb +30 -0
  26. data/lib/pry/commands/code_collector.rb +165 -0
  27. data/lib/pry/commands/deprecated_commands.rb +2 -0
  28. data/lib/pry/commands/disable_pry.rb +27 -0
  29. data/lib/pry/commands/easter_eggs.rb +112 -0
  30. data/lib/pry/commands/edit.rb +206 -0
  31. data/lib/pry/commands/edit/exception_patcher.rb +25 -0
  32. data/lib/pry/commands/edit/file_and_line_locator.rb +38 -0
  33. data/lib/pry/commands/edit/method_patcher.rb +122 -0
  34. data/lib/pry/commands/exit.rb +42 -0
  35. data/lib/pry/commands/exit_all.rb +29 -0
  36. data/lib/pry/commands/exit_program.rb +24 -0
  37. data/lib/pry/commands/find_method.rb +199 -0
  38. data/lib/pry/commands/fix_indent.rb +19 -0
  39. data/lib/pry/commands/gem_cd.rb +26 -0
  40. data/lib/pry/commands/gem_install.rb +29 -0
  41. data/lib/pry/commands/gem_list.rb +33 -0
  42. data/lib/pry/commands/gem_open.rb +29 -0
  43. data/lib/pry/commands/gist.rb +95 -0
  44. data/lib/pry/commands/help.rb +164 -0
  45. data/lib/pry/commands/hist.rb +161 -0
  46. data/lib/pry/commands/import_set.rb +22 -0
  47. data/lib/pry/commands/install_command.rb +51 -0
  48. data/lib/pry/commands/jump_to.rb +29 -0
  49. data/lib/pry/commands/ls.rb +339 -0
  50. data/lib/pry/commands/nesting.rb +25 -0
  51. data/lib/pry/commands/play.rb +69 -0
  52. data/lib/pry/commands/pry_backtrace.rb +26 -0
  53. data/lib/pry/commands/pry_version.rb +17 -0
  54. data/lib/pry/commands/raise_up.rb +32 -0
  55. data/lib/pry/commands/reload_code.rb +39 -0
  56. data/lib/pry/commands/reset.rb +18 -0
  57. data/lib/pry/commands/ri.rb +56 -0
  58. data/lib/pry/commands/save_file.rb +61 -0
  59. data/lib/pry/commands/shell_command.rb +43 -0
  60. data/lib/pry/commands/shell_mode.rb +27 -0
  61. data/lib/pry/commands/show_doc.rb +78 -0
  62. data/lib/pry/commands/show_info.rb +139 -0
  63. data/lib/pry/commands/show_input.rb +17 -0
  64. data/lib/pry/commands/show_source.rb +37 -0
  65. data/lib/pry/commands/simple_prompt.rb +22 -0
  66. data/lib/pry/commands/stat.rb +40 -0
  67. data/lib/pry/commands/switch_to.rb +23 -0
  68. data/lib/pry/commands/toggle_color.rb +20 -0
  69. data/lib/pry/commands/whereami.rb +114 -0
  70. data/lib/pry/commands/wtf.rb +57 -0
  71. data/lib/pry/completion.rb +120 -46
  72. data/lib/pry/config.rb +11 -0
  73. data/lib/pry/core_extensions.rb +30 -19
  74. data/lib/pry/editor.rb +129 -0
  75. data/lib/pry/helpers.rb +1 -0
  76. data/lib/pry/helpers/base_helpers.rb +89 -119
  77. data/lib/pry/helpers/command_helpers.rb +7 -122
  78. data/lib/pry/helpers/table.rb +100 -0
  79. data/lib/pry/helpers/text.rb +4 -4
  80. data/lib/pry/history_array.rb +5 -0
  81. data/lib/pry/hooks.rb +1 -3
  82. data/lib/pry/indent.rb +104 -30
  83. data/lib/pry/method.rb +66 -22
  84. data/lib/pry/module_candidate.rb +26 -15
  85. data/lib/pry/pager.rb +70 -0
  86. data/lib/pry/plugins.rb +1 -2
  87. data/lib/pry/pry_class.rb +63 -22
  88. data/lib/pry/pry_instance.rb +58 -37
  89. data/lib/pry/rubygem.rb +74 -0
  90. data/lib/pry/terminal_info.rb +43 -0
  91. data/lib/pry/test/helper.rb +185 -0
  92. data/lib/pry/version.rb +1 -1
  93. data/lib/pry/wrapped_module.rb +58 -24
  94. data/pry.gemspec +21 -37
  95. data/{test/test_cli.rb → spec/cli_spec.rb} +0 -0
  96. data/spec/code_object_spec.rb +277 -0
  97. data/{test/test_code.rb → spec/code_spec.rb} +19 -1
  98. data/{test/test_command_helpers.rb → spec/command_helpers_spec.rb} +0 -0
  99. data/{test/test_command_integration.rb → spec/command_integration_spec.rb} +38 -46
  100. data/{test/test_command_set.rb → spec/command_set_spec.rb} +18 -1
  101. data/{test/test_command.rb → spec/command_spec.rb} +250 -149
  102. data/spec/commands/amend_line_spec.rb +247 -0
  103. data/spec/commands/bang_spec.rb +19 -0
  104. data/spec/commands/cat_spec.rb +164 -0
  105. data/spec/commands/cd_spec.rb +250 -0
  106. data/spec/commands/disable_pry_spec.rb +25 -0
  107. data/spec/commands/edit_spec.rb +727 -0
  108. data/spec/commands/exit_all_spec.rb +34 -0
  109. data/spec/commands/exit_program_spec.rb +19 -0
  110. data/spec/commands/exit_spec.rb +34 -0
  111. data/{test/test_default_commands/test_find_method.rb → spec/commands/find_method_spec.rb} +27 -7
  112. data/spec/commands/gem_list_spec.rb +26 -0
  113. data/spec/commands/gist_spec.rb +75 -0
  114. data/{test/test_default_commands/test_help.rb → spec/commands/help_spec.rb} +8 -9
  115. data/spec/commands/hist_spec.rb +181 -0
  116. data/spec/commands/jump_to_spec.rb +15 -0
  117. data/spec/commands/ls_spec.rb +177 -0
  118. data/spec/commands/play_spec.rb +140 -0
  119. data/spec/commands/raise_up_spec.rb +56 -0
  120. data/spec/commands/save_file_spec.rb +177 -0
  121. data/spec/commands/show_doc_spec.rb +378 -0
  122. data/spec/commands/show_input_spec.rb +17 -0
  123. data/spec/commands/show_source_spec.rb +597 -0
  124. data/spec/commands/whereami_spec.rb +154 -0
  125. data/spec/completion_spec.rb +233 -0
  126. data/spec/control_d_handler_spec.rb +58 -0
  127. data/spec/editor_spec.rb +79 -0
  128. data/{test/test_exception_whitelist.rb → spec/exception_whitelist_spec.rb} +0 -0
  129. data/{test → spec/fixtures}/candidate_helper1.rb +0 -0
  130. data/{test → spec/fixtures}/candidate_helper2.rb +0 -0
  131. data/{test/test_default_commands → spec/fixtures}/example.erb +0 -0
  132. data/spec/fixtures/example_nesting.rb +33 -0
  133. data/spec/fixtures/show_source_doc_examples.rb +15 -0
  134. data/{test → spec/fixtures}/testrc +0 -0
  135. data/{test → spec/fixtures}/testrcbad +0 -0
  136. data/spec/helper.rb +34 -0
  137. data/spec/helpers/bacon.rb +86 -0
  138. data/spec/helpers/mock_pry.rb +43 -0
  139. data/spec/helpers/table_spec.rb +83 -0
  140. data/{test/test_history_array.rb → spec/history_array_spec.rb} +21 -19
  141. data/{test/test_hooks.rb → spec/hooks_spec.rb} +0 -0
  142. data/{test/test_indent.rb → spec/indent_spec.rb} +24 -0
  143. data/{test/test_input_stack.rb → spec/input_stack_spec.rb} +4 -0
  144. data/{test/test_method.rb → spec/method_spec.rb} +65 -1
  145. data/{test/test_prompt.rb → spec/prompt_spec.rb} +0 -0
  146. data/{test/test_pry_defaults.rb → spec/pry_defaults_spec.rb} +14 -14
  147. data/{test/test_pry_history.rb → spec/pry_history_spec.rb} +15 -0
  148. data/spec/pry_output_spec.rb +95 -0
  149. data/{test/test_pry.rb → spec/pry_spec.rb} +74 -32
  150. data/{test/test_sticky_locals.rb → spec/sticky_locals_spec.rb} +27 -25
  151. data/{test/test_syntax_checking.rb → spec/syntax_checking_spec.rb} +17 -1
  152. data/{test/test_wrapped_module.rb → spec/wrapped_module_spec.rb} +92 -5
  153. metadata +239 -115
  154. data/examples/example_basic.rb +0 -15
  155. data/examples/example_command_override.rb +0 -32
  156. data/examples/example_commands.rb +0 -36
  157. data/examples/example_hooks.rb +0 -9
  158. data/examples/example_image_edit.rb +0 -67
  159. data/examples/example_input.rb +0 -7
  160. data/examples/example_input2.rb +0 -29
  161. data/examples/example_output.rb +0 -11
  162. data/examples/example_print.rb +0 -6
  163. data/examples/example_prompt.rb +0 -9
  164. data/examples/helper.rb +0 -6
  165. data/lib/pry/default_commands/cd.rb +0 -81
  166. data/lib/pry/default_commands/commands.rb +0 -62
  167. data/lib/pry/default_commands/context.rb +0 -98
  168. data/lib/pry/default_commands/easter_eggs.rb +0 -95
  169. data/lib/pry/default_commands/editing.rb +0 -420
  170. data/lib/pry/default_commands/find_method.rb +0 -169
  171. data/lib/pry/default_commands/gems.rb +0 -84
  172. data/lib/pry/default_commands/gist.rb +0 -187
  173. data/lib/pry/default_commands/help.rb +0 -127
  174. data/lib/pry/default_commands/hist.rb +0 -120
  175. data/lib/pry/default_commands/input_and_output.rb +0 -306
  176. data/lib/pry/default_commands/introspection.rb +0 -410
  177. data/lib/pry/default_commands/ls.rb +0 -272
  178. data/lib/pry/default_commands/misc.rb +0 -38
  179. data/lib/pry/default_commands/navigating_pry.rb +0 -110
  180. data/lib/pry/default_commands/whereami.rb +0 -92
  181. data/lib/pry/extended_commands/experimental.rb +0 -7
  182. data/test/helper.rb +0 -223
  183. data/test/test_completion.rb +0 -62
  184. data/test/test_control_d_handler.rb +0 -45
  185. data/test/test_default_commands/test_cd.rb +0 -321
  186. data/test/test_default_commands/test_context.rb +0 -288
  187. data/test/test_default_commands/test_documentation.rb +0 -315
  188. data/test/test_default_commands/test_gems.rb +0 -18
  189. data/test/test_default_commands/test_input.rb +0 -428
  190. data/test/test_default_commands/test_introspection.rb +0 -511
  191. data/test/test_default_commands/test_ls.rb +0 -151
  192. data/test/test_default_commands/test_shell.rb +0 -343
  193. data/test/test_default_commands/test_show_source.rb +0 -432
  194. data/test/test_pry_output.rb +0 -41
@@ -0,0 +1,164 @@
1
+ class Pry
2
+ class Command::Help < Pry::ClassCommand
3
+ match 'help'
4
+ group 'Help'
5
+ description 'Show a list of commands or information about a specific command'
6
+
7
+ banner <<-'BANNER'
8
+ Usage: help [COMMAND]
9
+
10
+ With no arguments, help lists all the available commands in the current
11
+ command-set along with their description. When given a command name as an
12
+ argument, shows the help for that command.
13
+ BANNER
14
+
15
+ # We only want to show commands that have descriptions, so that the
16
+ # easter eggs don't show up.
17
+ def visible_commands
18
+ visible = {}
19
+ commands.each do |key, command|
20
+ visible[key] = command if command.description && !command.description.empty?
21
+ end
22
+ visible
23
+ end
24
+
25
+ # Get a hash of available commands grouped by the "group" name.
26
+ def command_groups
27
+ visible_commands.values.group_by(&:group)
28
+ end
29
+
30
+ def process
31
+ if args.empty?
32
+ display_index(command_groups)
33
+ else
34
+ display_search(args.first)
35
+ end
36
+ end
37
+
38
+ # Display the index view, with headings and short descriptions per command.
39
+ #
40
+ # @param Hash[String => Array[Commands]]
41
+ def display_index(groups)
42
+ help_text = []
43
+
44
+ sorted_group_names(groups).each do |group_name|
45
+ commands = sorted_commands(groups[group_name])
46
+
47
+ if commands.any?
48
+ help_text << help_text_for_commands(group_name, commands)
49
+ end
50
+ end
51
+
52
+ stagger_output(help_text.join("\n\n"))
53
+ end
54
+
55
+ # Given a group name and an array of commands,
56
+ # return the help string for those commands.
57
+ #
58
+ # @param [String] name The group name.
59
+ # @param [Array<Pry::Command>]] commands
60
+ # @return [String] The generated help string.
61
+ def help_text_for_commands(name, commands)
62
+ "#{text.bold(name)}\n" + commands.map do |command|
63
+ " #{command.options[:listing].to_s.ljust(18)} #{command.description}"
64
+ end.join("\n")
65
+ end
66
+
67
+ # @param [Hash] groups
68
+ # @return [Array<String>] An array of sorted group names.
69
+ def sorted_group_names(groups)
70
+ groups.keys.sort_by(&method(:group_sort_key))
71
+ end
72
+
73
+ # Sort an array of commands by their `listing` name.
74
+ #
75
+ # @param [Array<Pry::Command>] commands The commands to sort
76
+ # @return [Array<Pry::Command>] commands sorted by listing name.
77
+ def sorted_commands(commands)
78
+ commands.sort_by{ |command| command.options[:listing].to_s }
79
+ end
80
+
81
+ # Display help for an individual command or group.
82
+ #
83
+ # @param [String] search The string to search for.
84
+ def display_search(search)
85
+ if command = command_set.find_command_for_help(search)
86
+ display_command(command)
87
+ else
88
+ display_filtered_search_results(search)
89
+ end
90
+ end
91
+
92
+ # Display help for a searched item, filtered first by group
93
+ # and if that fails, filtered by command name.
94
+ #
95
+ # @param [String] search The string to search for.
96
+ def display_filtered_search_results(search)
97
+ groups = search_hash(search, command_groups)
98
+
99
+ if groups.size > 0
100
+ display_index(groups)
101
+ else
102
+ display_filtered_commands(search)
103
+ end
104
+ end
105
+
106
+ # Display help for a searched item, filtered by group
107
+ #
108
+ # @param [String] search The string to search for.
109
+ def display_filtered_commands(search)
110
+ filtered = search_hash(search, visible_commands)
111
+ raise CommandError, "No help found for '#{args.first}'" if filtered.empty?
112
+
113
+ if filtered.size == 1
114
+ display_command(filtered.values.first)
115
+ else
116
+ display_index({"'#{search}' commands" => filtered.values})
117
+ end
118
+ end
119
+
120
+ # Display help for an individual command.
121
+ #
122
+ # @param [Pry::Command] command
123
+ def display_command(command)
124
+ stagger_output command.new.help
125
+ end
126
+
127
+ # Find a subset of a hash that matches the user's search term.
128
+ #
129
+ # If there's an exact match a Hash of one element will be returned,
130
+ # otherwise a sub-Hash with every key that matches the search will
131
+ # be returned.
132
+ #
133
+ # @param [String] the search term
134
+ # @param [Hash] the hash to search
135
+ def search_hash(search, hash)
136
+ matching = {}
137
+
138
+ hash.each_pair do |key, value|
139
+ next unless key.is_a?(String)
140
+ if normalize(key) == normalize(search)
141
+ return {key => value}
142
+ elsif normalize(key).start_with?(normalize(search))
143
+ matching[key] = value
144
+ end
145
+ end
146
+
147
+ matching
148
+ end
149
+
150
+ # Clean search terms to make it easier to search group names
151
+ #
152
+ # @param String
153
+ # @return String
154
+ def normalize(key)
155
+ key.downcase.gsub(/pry\W+/, '')
156
+ end
157
+
158
+ def group_sort_key(group_name)
159
+ [%w(Help Context Editing Introspection Input_and_output Navigating_pry Gems Basic Commands).index(group_name.gsub(' ', '_')) || 99, group_name]
160
+ end
161
+ end
162
+
163
+ Pry::Commands.add_command(Pry::Command::Help)
164
+ end
@@ -0,0 +1,161 @@
1
+ class Pry
2
+ class Command::Hist < Pry::ClassCommand
3
+ match 'hist'
4
+ group 'Editing'
5
+ description 'Show and replay Readline history.'
6
+
7
+ banner <<-'BANNER'
8
+ Usage: hist [--head|--tail]
9
+ hist --head N
10
+ hist --tail N
11
+ hist --show START..END
12
+ hist --grep PATTERN
13
+ hist --clear
14
+ hist --replay START..END
15
+ hist --save [START..END] FILE
16
+ Aliases: history
17
+
18
+ Show and replay Readline history.
19
+ BANNER
20
+
21
+ def options(opt)
22
+ opt.on :H, :head, "Display the first N items", :optional_argument => true, :as => Integer
23
+ opt.on :T, :tail, "Display the last N items", :optional_argument => true, :as => Integer
24
+ opt.on :s, :show, "Show the given range of lines", :optional_argument => true, :as => Range
25
+ opt.on :G, :grep, "Show lines matching the given pattern", :argument => true, :as => String
26
+ opt.on :c, :clear , "Clear the current session's history"
27
+ opt.on :r, :replay, "Replay a line or range of lines", :argument => true, :as => Range
28
+ opt.on :save, "Save history to a file", :argument => true, :as => Range
29
+ opt.on :e, :'exclude-pry', "Exclude Pry commands from the history"
30
+ opt.on :n, :'no-numbers', "Omit line numbers"
31
+ opt.on :f, :flood, "Do not use a pager to view text longer than one screen"
32
+ end
33
+
34
+ def process
35
+ @history = Pry::Code(Pry.history.to_a)
36
+
37
+ if opts.present?(:show)
38
+ @history = @history.between(opts[:show])
39
+ end
40
+
41
+ if opts.present?(:grep)
42
+ @history = @history.grep(opts[:grep])
43
+ end
44
+
45
+ @history = case
46
+ when opts.present?(:head)
47
+ @history.take_lines(1, opts[:head] || 10)
48
+ when opts.present?(:tail)
49
+ @history.take_lines(-(opts[:tail] || 10), opts[:tail] || 10)
50
+ when opts.present?(:show)
51
+ @history.between(opts[:show])
52
+ else
53
+ @history
54
+ end
55
+
56
+ if opts.present?(:'exclude-pry')
57
+ @history = @history.select { |l, ln| !command_set.valid_command?(l) }
58
+ end
59
+
60
+ if opts.present?(:save)
61
+ process_save
62
+ elsif opts.present?(:clear)
63
+ process_clear
64
+ elsif opts.present?(:replay)
65
+ process_replay
66
+ else
67
+ process_display
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def process_display
74
+ unless opts.present?(:'no-numbers')
75
+ @history = @history.with_line_numbers
76
+ end
77
+
78
+ render_output(@history, opts)
79
+ end
80
+
81
+ def process_save
82
+ case opts[:save]
83
+ when Range
84
+ @history = @history.between(opts[:save])
85
+
86
+ unless args.first
87
+ raise CommandError, "Must provide a file name."
88
+ end
89
+
90
+ file_name = File.expand_path(args.first)
91
+ when String
92
+ file_name = File.expand_path(opts[:save])
93
+ end
94
+
95
+ output.puts "Saving history in #{file_name}..."
96
+
97
+ File.open(file_name, 'w') { |f| f.write(@history.raw) }
98
+
99
+ output.puts "History saved."
100
+ end
101
+
102
+ def process_clear
103
+ Pry.history.clear
104
+ output.puts "History cleared."
105
+ end
106
+
107
+ def process_replay
108
+ @history = @history.between(opts[:r])
109
+ replay_sequence = @history.raw
110
+
111
+ # If we met follow-up "hist" call, check for the "--replay" option
112
+ # presence. If "hist" command is called with other options, proceed
113
+ # further.
114
+ check_for_juxtaposed_replay(replay_sequence)
115
+
116
+ _pry_.input_stack.push _pry_.input
117
+ _pry_.input = StringIO.new(replay_sequence)
118
+ # eval_string << "#{@history.raw}\n"
119
+ # run "show-input" unless _pry_.complete_expression?(eval_string)
120
+ end
121
+
122
+ # Checks +replay_sequence+ for the presence of neighboring replay calls.
123
+ # @example
124
+ # [1] pry(main)> hist --show 46894
125
+ # 46894: hist --replay 46675..46677
126
+ # [2] pry(main)> hist --show 46675..46677
127
+ # 46675: 1+1
128
+ # 46676: a = 100
129
+ # 46677: hist --tail
130
+ # [3] pry(main)> hist --replay 46894
131
+ # Error: Replay index 46894 points out to another replay call: `hist -r 46675..46677`
132
+ # [4] pry(main)>
133
+ #
134
+ # @raise [Pry::CommandError] If +replay_sequence+ contains another
135
+ # "hist --replay" call
136
+ # @param [String] replay_sequence The sequence of commands to be replayed
137
+ # (per saltum)
138
+ # @return [Boolean] `false` if +replay_sequence+ does not contain another
139
+ # "hist --replay" call
140
+ def check_for_juxtaposed_replay(replay_sequence)
141
+ if replay_sequence =~ /\Ahist(?:ory)?\b/
142
+ # Create *fresh* instance of Options for parsing of "hist" command.
143
+ _slop = self.slop
144
+ _slop.parse replay_sequence.split(' ')[1..-1]
145
+
146
+ if _slop.present?(:r)
147
+ replay_sequence = replay_sequence.split("\n").join('; ')
148
+ index = opts[:r]
149
+ index = index.min if index.min == index.max || index.max.nil?
150
+
151
+ raise CommandError, "Replay index #{ index } points out to another replay call: `#{ replay_sequence }`"
152
+ end
153
+ else
154
+ false
155
+ end
156
+ end
157
+ end
158
+
159
+ Pry::Commands.add_command(Pry::Command::Hist)
160
+ Pry::Commands.alias_command 'history', 'hist'
161
+ end
@@ -0,0 +1,22 @@
1
+ class Pry
2
+ class Command::ImportSet < Pry::ClassCommand
3
+ match 'import-set'
4
+ group 'Commands'
5
+ # TODO: Provide a better description with examples and a general conception
6
+ # of this command.
7
+ description 'Import a Pry command set.'
8
+
9
+ banner <<-'BANNER'
10
+ Import a Pry command set.
11
+ BANNER
12
+
13
+ def process(command_set_name)
14
+ raise CommandError, "Provide a command set name" if command_set.nil?
15
+
16
+ set = target.eval(arg_string)
17
+ _pry_.commands.import set
18
+ end
19
+ end
20
+
21
+ Pry::Commands.add_command(Pry::Command::ImportSet)
22
+ end
@@ -0,0 +1,51 @@
1
+ class Pry
2
+ class Command::InstallCommand < Pry::ClassCommand
3
+ match 'install-command'
4
+ group 'Commands'
5
+ description 'Install a disabled command.'
6
+
7
+ banner <<-'BANNER'
8
+ Usage: install-command COMMAND
9
+
10
+ Installs the gems necessary to run the given COMMAND. You will generally not
11
+ need to run this unless told to by an error message.
12
+ BANNER
13
+
14
+ def process(name)
15
+ require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller
16
+ command = find_command(name)
17
+
18
+ if command_dependencies_met?(command.options)
19
+ output.puts "Dependencies for #{command.name} are met. Nothing to do."
20
+ return
21
+ end
22
+
23
+ output.puts "Attempting to install `#{name}` command..."
24
+ gems_to_install = Array(command.options[:requires_gem])
25
+
26
+ gems_to_install.each do |g|
27
+ next if Rubygem.installed?(g)
28
+ output.puts "Installing `#{g}` gem..."
29
+
30
+ begin
31
+ Gem::DependencyInstaller.new.install(g)
32
+ rescue Gem::GemNotFoundException
33
+ raise CommandError, "Required Gem: `#{g}` not found. Aborting command installation."
34
+ end
35
+ end
36
+
37
+ Gem.refresh
38
+ gems_to_install.each do |g|
39
+ begin
40
+ require g
41
+ rescue LoadError
42
+ raise CommandError, "Required Gem: `#{g}` installed but not found?!. Aborting command installation."
43
+ end
44
+ end
45
+
46
+ output.puts "Installation of `#{name}` successful! Type `help #{name}` for information"
47
+ end
48
+ end
49
+
50
+ Pry::Commands.add_command(Pry::Command::InstallCommand)
51
+ end
@@ -0,0 +1,29 @@
1
+ class Pry
2
+ class Command::JumpTo < Pry::ClassCommand
3
+ match 'jump-to'
4
+ group 'Navigating Pry'
5
+ description 'Jump to a binding further up the stack.'
6
+
7
+ banner <<-'BANNER'
8
+ Jump to a binding further up the stack, popping all bindings below.
9
+ BANNER
10
+
11
+ def process(break_level)
12
+ break_level = break_level.to_i
13
+ nesting_level = _pry_.binding_stack.size - 1
14
+
15
+ case break_level
16
+ when nesting_level
17
+ output.puts "Already at nesting level #{nesting_level}"
18
+ when (0...nesting_level)
19
+ _pry_.binding_stack.slice!(break_level + 1, _pry_.binding_stack.size)
20
+
21
+ else
22
+ max_nest_level = nesting_level - 1
23
+ output.puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}."
24
+ end
25
+ end
26
+ end
27
+
28
+ Pry::Commands.add_command(Pry::Command::JumpTo)
29
+ end
@@ -0,0 +1,339 @@
1
+ class Pry
2
+ class Command::Ls < Pry::ClassCommand
3
+ match 'ls'
4
+ group 'Context'
5
+ description 'Show the list of vars and methods in the current scope.'
6
+ command_options :shellwords => false, :interpolate => false
7
+
8
+ def options(opt)
9
+ opt.banner unindent <<-'BANNER'
10
+ Usage: ls [-m|-M|-p|-pM] [-q|-v] [-c|-i] [Object]
11
+ ls [-g] [-l]
12
+
13
+ ls shows you which methods, constants and variables are accessible to Pry. By
14
+ default it shows you the local variables defined in the current shell, and any
15
+ public methods or instance variables defined on the current object.
16
+
17
+ The colours used are configurable using Pry.config.ls.*_color, and the separator
18
+ is Pry.config.ls.separator.
19
+
20
+ Pry.config.ls.ceiling is used to hide methods defined higher up in the
21
+ inheritance chain, this is by default set to [Object, Module, Class] so that
22
+ methods defined on all Objects are omitted. The -v flag can be used to ignore
23
+ this setting and show all methods, while the -q can be used to set the ceiling
24
+ much lower and show only methods defined on the object or its direct class.
25
+ BANNER
26
+
27
+ opt.on :m, :methods, "Show public methods defined on the Object (default)"
28
+ opt.on :M, "instance-methods", "Show methods defined in a Module or Class"
29
+ opt.on :p, :ppp, "Show public, protected (in yellow) and private (in green) methods"
30
+ opt.on :q, :quiet, "Show only methods defined on object.singleton_class and object.class"
31
+ opt.on :v, :verbose, "Show methods and constants on all super-classes (ignores Pry.config.ls.ceiling)"
32
+ opt.on :g, :globals, "Show global variables, including those builtin to Ruby (in cyan)"
33
+ opt.on :l, :locals, "Show hash of local vars, sorted by descending size"
34
+ opt.on :c, :constants, "Show constants, highlighting classes (in blue), and exceptions (in purple).\n" +
35
+ " " * 32 + "Constants that are pending autoload? are also shown (in yellow)"
36
+ opt.on :i, :ivars, "Show instance variables (in blue) and class variables (in bright blue)"
37
+ opt.on :G, :grep, "Filter output by regular expression", :argument => true
38
+
39
+ if jruby?
40
+ opt.on :J, "all-java", "Show all the aliases for methods from java (default is to show only prettiest)"
41
+ end
42
+ end
43
+
44
+ attr_reader :object_to_interrogate, :has_user_specified_any_options, :grep, :grep_regex
45
+
46
+ def process
47
+ @object_to_interrogate = args.empty? ? target_self : target.eval(args.join(" "))
48
+
49
+ # exclude -q, -v and --grep because they don't specify what the user wants to see.
50
+ @has_user_specified_any_options = (opts.present?(:methods) || opts.present?(:'instance-methods') || opts.present?(:ppp) ||
51
+ opts.present?(:globals) || opts.present?(:locals) || opts.present?(:constants) ||
52
+ opts.present?(:ivars))
53
+
54
+ @grep_regex, @grep = [Regexp.new(opts[:G] || "."), lambda{ |x| x.grep(@grep_regex) }]
55
+
56
+ raise_errors_if_arguments_are_weird
57
+
58
+ all_output = [
59
+ write_out_globals,
60
+ write_out_constants,
61
+ write_out_methods,
62
+ write_out_self_methods,
63
+ write_out_ivars,
64
+ write_out_local_names,
65
+ write_out_locals,
66
+ ].compact.join("")
67
+
68
+ stagger_output(all_output)
69
+ end
70
+
71
+ private
72
+
73
+ # http://ruby.runpaint.org/globals, and running "puts global_variables.inspect".
74
+ BUILTIN_GLOBALS = %w($" $$ $* $, $-0 $-F $-I $-K $-W $-a $-d $-i $-l $-p $-v $-w $. $/ $\\
75
+ $: $; $< $= $> $0 $ARGV $CONSOLE $DEBUG $DEFAULT_INPUT $DEFAULT_OUTPUT
76
+ $FIELD_SEPARATOR $FILENAME $FS $IGNORECASE $INPUT_LINE_NUMBER
77
+ $INPUT_RECORD_SEPARATOR $KCODE $LOADED_FEATURES $LOAD_PATH $NR $OFS
78
+ $ORS $OUTPUT_FIELD_SEPARATOR $OUTPUT_RECORD_SEPARATOR $PID $PROCESS_ID
79
+ $PROGRAM_NAME $RS $VERBOSE $deferr $defout $stderr $stdin $stdout)
80
+
81
+ # $SAFE and $? are thread-local, the exception stuff only works in a rescue clause,
82
+ # everything else is basically a local variable with a $ in its name.
83
+ PSEUDO_GLOBALS = %w($! $' $& $` $@ $? $+ $_ $~ $1 $2 $3 $4 $5 $6 $7 $8 $9
84
+ $CHILD_STATUS $SAFE $ERROR_INFO $ERROR_POSITION $LAST_MATCH_INFO
85
+ $LAST_PAREN_MATCH $LAST_READ_LINE $MATCH $POSTMATCH $PREMATCH)
86
+
87
+ # Get all the methods that we'll want to output
88
+ def all_methods(obj, instance_methods=false)
89
+ methods = if instance_methods || opts.present?(:'instance-methods')
90
+ Pry::Method.all_from_class(obj)
91
+ else
92
+ Pry::Method.all_from_obj(obj)
93
+ end
94
+
95
+ if jruby? && !opts.present?(:J)
96
+ methods = trim_jruby_aliases(methods)
97
+ end
98
+
99
+ methods.select{ |method| opts.present?(:ppp) || method.visibility == :public }
100
+ end
101
+
102
+ # JRuby creates lots of aliases for methods imported from java in an attempt to
103
+ # make life easier for ruby programmers.
104
+ # (e.g. getFooBar becomes get_foo_bar and foo_bar, and maybe foo_bar? if it
105
+ # returns a Boolean).
106
+ # The full transformations are in the assignAliases method of:
107
+ # https://github.com/jruby/jruby/blob/master/src/org/jruby/javasupport/JavaClass.java
108
+ #
109
+ # This has the unfortunate side-effect of making the output of ls even more
110
+ # incredibly verbose than it normally would be for these objects; and so we filter
111
+ # out all but the nicest of these aliases here.
112
+ #
113
+ # TODO: This is a little bit vague, better heuristics could be used.
114
+ # JRuby also has a lot of scala-specific logic, which we don't copy.
115
+ #
116
+ def trim_jruby_aliases(methods)
117
+ grouped = methods.group_by do |m|
118
+ m.name.sub(/\A(is|get|set)(?=[A-Z_])/, '').gsub(/[_?=]/, '').downcase
119
+ end
120
+
121
+ grouped.map do |key, values|
122
+ values = values.sort_by do |m|
123
+ rubbishness(m.name)
124
+ end
125
+
126
+ found = []
127
+ values.select do |x|
128
+ (!found.any?{ |y| x == y }) && found << x
129
+ end
130
+ end.flatten(1)
131
+ end
132
+
133
+ # When removing jruby aliases, we want to keep the alias that is "least rubbish"
134
+ # according to this metric.
135
+ def rubbishness(name)
136
+ name.each_char.map{ |x|
137
+ case x
138
+ when /[A-Z]/
139
+ 1
140
+ when '?', '=', '!'
141
+ -2
142
+ else
143
+ 0
144
+ end
145
+ }.inject(&:+) + (name.size / 100.0)
146
+ end
147
+
148
+ def resolution_order(obj)
149
+ opts.present?(:'instance-methods') ? Pry::Method.instance_resolution_order(obj) : Pry::Method.resolution_order(obj)
150
+ end
151
+
152
+ # Get a lambda that can be used with .take_while to prevent over-eager
153
+ # traversal of the Object's ancestry graph.
154
+ def below_ceiling(obj)
155
+ ceiling = if opts.present?(:quiet)
156
+ [opts.present?(:'instance-methods') ? obj.ancestors[1] : obj.class.ancestors[1]] + Pry.config.ls.ceiling
157
+ elsif opts.present?(:verbose)
158
+ []
159
+ else
160
+ Pry.config.ls.ceiling.dup
161
+ end
162
+
163
+ lambda { |klass| !ceiling.include?(klass) }
164
+ end
165
+
166
+ def raise_errors_if_arguments_are_weird
167
+ [
168
+ ["-l does not make sense with a specified Object", :locals, !args.empty?],
169
+ ["-g does not make sense with a specified Object", :globals, !args.empty?],
170
+ ["-q does not make sense with -v", :quiet, opts.present?(:verbose)],
171
+ ["-M only makes sense with a Module or a Class", :'instance-methods', !interrogating_a_module?],
172
+ ["-c only makes sense with a Module or a Class", :constants, !args.empty? && !interrogating_a_module?],
173
+ ].each do |message, option, expression|
174
+ raise Pry::CommandError, message if opts.present?(option) && expression
175
+ end
176
+ end
177
+
178
+ def interrogating_a_module?
179
+ (Module === object_to_interrogate)
180
+ end
181
+
182
+ def write_out_globals
183
+ return unless opts.present?(:globals)
184
+
185
+ output_section("global variables", grep[format_globals(target.eval("global_variables"))])
186
+ end
187
+
188
+ def write_out_constants
189
+ return unless opts.present?(:constants) || (!has_user_specified_any_options && interrogating_a_module?)
190
+
191
+ mod = interrogating_a_module? ? object_to_interrogate : Object
192
+ constants = mod.constants
193
+ constants -= (mod.ancestors - [mod]).map(&:constants).flatten unless opts.present?(:verbose)
194
+ output_section("constants", grep[format_constants(mod, constants)])
195
+ end
196
+
197
+ def write_out_methods
198
+ return unless opts.present?(:methods) || opts.present?(:'instance-methods') || opts.present?(:ppp) || !has_user_specified_any_options
199
+
200
+ # methods is a hash {Module/Class => [Pry::Methods]}
201
+ methods = all_methods(object_to_interrogate).group_by(&:owner)
202
+
203
+ output = ""
204
+ # reverse the resolution order so that the most useful information appears right by the prompt
205
+ resolution_order(object_to_interrogate).take_while(&below_ceiling(object_to_interrogate)).reverse.each do |klass|
206
+ methods_here = format_methods((methods[klass] || []).select{ |m| m.name =~ grep_regex })
207
+ output << output_section("#{Pry::WrappedModule.new(klass).method_prefix}methods", methods_here)
208
+ end
209
+ output
210
+ end
211
+
212
+ def write_out_self_methods
213
+ return unless (!has_user_specified_any_options && interrogating_a_module?)
214
+
215
+ methods = all_methods(object_to_interrogate, true).select{ |m| m.owner == object_to_interrogate && m.name =~ grep_regex }
216
+ output_section("#{Pry::WrappedModule.new(object_to_interrogate).method_prefix}methods", format_methods(methods))
217
+ end
218
+
219
+ def write_out_ivars
220
+ return unless opts.present?(:ivars) || !has_user_specified_any_options
221
+
222
+ klass = (interrogating_a_module? ? object_to_interrogate : object_to_interrogate.class)
223
+ ivars = Pry::Method.safe_send(object_to_interrogate, :instance_variables)
224
+ kvars = Pry::Method.safe_send(klass, :class_variables)
225
+ output_section("instance variables", format_variables(:instance_var, ivars)) +
226
+ output_section("class variables", format_variables(:class_var, kvars))
227
+ end
228
+
229
+ def write_out_local_names
230
+ return unless !has_user_specified_any_options && args.empty?
231
+
232
+ output_section("locals", format_local_names(grep[target.eval("local_variables")]))
233
+ end
234
+
235
+ def write_out_locals
236
+ return unless opts.present?(:locals)
237
+
238
+ loc_names = target.eval('local_variables').reject do |e|
239
+ _pry_.sticky_locals.keys.include? e.to_sym
240
+ end
241
+ name_value_pairs = loc_names.map do |name|
242
+ [name, (target.eval name.to_s)]
243
+ end
244
+ format_locals(name_value_pairs).join("")
245
+ end
246
+
247
+ # Format and colourise a list of methods.
248
+ def format_methods(methods)
249
+ methods.sort_by(&:name).map do |method|
250
+ if method.name == 'method_missing'
251
+ color(:method_missing, 'method_missing')
252
+ elsif method.visibility == :private
253
+ color(:private_method, method.name)
254
+ elsif method.visibility == :protected
255
+ color(:protected_method, method.name)
256
+ else
257
+ color(:public_method, method.name)
258
+ end
259
+ end
260
+ end
261
+
262
+ def format_variables(type, vars)
263
+ vars.sort_by(&:downcase).map{ |var| color(type, var) }
264
+ end
265
+
266
+ def format_constants(mod, constants)
267
+ constants.sort_by(&:downcase).map do |name|
268
+ if const = (!mod.autoload?(name) && (mod.const_get(name) || true) rescue nil)
269
+ if (const < Exception rescue false)
270
+ color(:exception_constant, name)
271
+ elsif (Module === mod.const_get(name) rescue false)
272
+ color(:class_constant, name)
273
+ else
274
+ color(:constant, name)
275
+ end
276
+ else
277
+ color(:unloaded_constant, name)
278
+ end
279
+ end
280
+ end
281
+
282
+ def format_globals(globals)
283
+ globals.sort_by(&:downcase).map do |name|
284
+ if PSEUDO_GLOBALS.include?(name)
285
+ color(:pseudo_global, name)
286
+ elsif BUILTIN_GLOBALS.include?(name)
287
+ color(:builtin_global, name)
288
+ else
289
+ color(:global_var, name)
290
+ end
291
+ end
292
+ end
293
+
294
+ def format_local_names(locals)
295
+ locals.sort_by(&:downcase).map do |name|
296
+ if _pry_.sticky_locals.include?(name.to_sym)
297
+ color(:pry_var, name)
298
+ else
299
+ color(:local_var, name)
300
+ end
301
+ end
302
+ end
303
+
304
+ def format_locals(name_value_pairs)
305
+ name_value_pairs.sort_by do |name, value|
306
+ value.to_s.size
307
+ end.reverse.map do |name, value|
308
+ colorized_assignment_style(name, format_value(value))
309
+ end
310
+ end
311
+
312
+ def colorized_assignment_style(lhs, rhs, desired_width = 7)
313
+ colorized_lhs = color(:local_var, lhs)
314
+ color_escape_padding = colorized_lhs.size - lhs.size
315
+ pad = desired_width + color_escape_padding
316
+ "%-#{pad}s = %s" % [color(:local_var, colorized_lhs), rhs]
317
+ end
318
+
319
+ def format_value(value)
320
+ accumulator = StringIO.new
321
+ Pry.output_with_default_format(accumulator, value, :hashrocket => false)
322
+ accumulator.string
323
+ end
324
+
325
+ # Add a new section to the output. Outputs nothing if the section would be empty.
326
+ def output_section(heading, body)
327
+ return "" if body.compact.empty?
328
+ table = Pry::Helpers.tablify_to_screen_width(body)
329
+ "#{text.bold(color(:heading, heading))}: \n#{table}\n"
330
+ end
331
+
332
+ # Color output based on config.ls.*_color
333
+ def color(type, str)
334
+ text.send(Pry.config.ls.send(:"#{type}_color"), str)
335
+ end
336
+ end
337
+
338
+ Pry::Commands.add_command(Pry::Command::Ls)
339
+ end