irb 1.14.0 → 1.14.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b96add3ef12d981b483ae225bfd8bca8a1a477f0b03c8040a0dfbf047bd0d1fb
4
- data.tar.gz: efe91e97fab6b11a239c4774da9d5ecfe39bbc364d61a6b2c7fd6ec8b9c01a72
3
+ metadata.gz: 606da5c01c0630f572812c844da8f331fd487fa50060db8c95a61aef14660d68
4
+ data.tar.gz: 5d1749fea9672c734b9bdce740f6f43d90b2479e2a06de09d9604265317fab1e
5
5
  SHA512:
6
- metadata.gz: 0eaa119e765d958cdab2ba80fa12e47a9727d389a37f255e174ec260279af8e2c2edb510689364541fe40f3c202a3b3d4f2d7dc7fbe30030b04e89bc2c851a3a
7
- data.tar.gz: 71904280b978ac48763d7bc965f053fd5580ec7876c40cba76a1a9c26ac7aec2f4ad98deb1d9c8d3635f5222a0b757d458d7fded9264411b05f19bfe77ad2526
6
+ metadata.gz: 478ceef6ddf60e4bf8ddf2f1586129eab9bcff9e40bb9af8662a1c7f46d7c406f7d896395d3459cbde5ac2a427b73e474327033647e6c742691c185a553a1d71
7
+ data.tar.gz: da1f92f1403c9fee631f7fc85f1bf60120db710bd171a98be1b428a22c4545fed4d4e4dd7692d90220520609047bd4fc6d00882da0bce7bf1a67e05dc41dd8e1
data/README.md CHANGED
@@ -114,6 +114,7 @@ Help
114
114
  help List all available commands. Use `help <command>` to get information about a specific command.
115
115
 
116
116
  IRB
117
+ context Displays current configuration.
117
118
  exit Exit the current irb session.
118
119
  exit! Exit the current process.
119
120
  irb_load Load a Ruby file.
@@ -121,6 +122,7 @@ IRB
121
122
  source Loads a given file in the current session.
122
123
  irb_info Show information about IRB.
123
124
  history Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output.
125
+ disable_irb Disable binding.irb.
124
126
 
125
127
  Workspace
126
128
  cwws Show the current workspace.
@@ -128,6 +130,7 @@ Workspace
128
130
  workspaces Show workspaces.
129
131
  pushws Push an object to the workspace stack.
130
132
  popws Pop a workspace from the workspace stack.
133
+ cd Move into the given object or leave the current context.
131
134
 
132
135
  Multi-irb (DEPRECATED)
133
136
  irb Start a child IRB.
@@ -152,11 +155,14 @@ Misc
152
155
  measure `measure` enables the mode to measure processing time. `measure :off` disables it.
153
156
 
154
157
  Context
155
- show_doc Enter the mode to look up RI documents.
158
+ show_doc Look up documentation with RI.
156
159
  ls Show methods, constants, and variables.
157
- show_source Show the source code of a given method or constant.
160
+ show_source Show the source code of a given method, class/module, or constant.
158
161
  whereami Show the source code around binding.irb again.
159
162
 
163
+ Helper methods
164
+ conf Returns the current IRB context.
165
+
160
166
  Aliases
161
167
  $ Alias for `show_source`
162
168
  @ Alias for `whereami`
@@ -164,6 +170,13 @@ Aliases
164
170
 
165
171
  ## Debugging with IRB
166
172
 
173
+ ### Getting Started
174
+
175
+ - In `binding.irb`, use the `debug` command to start a `irb:rdbg` session with access to all `debug.gem` commands.
176
+ - Use `RUBY_DEBUG_IRB_CONSOLE=1` environment variable to make `debug.gem` use IRB as the debugging console.
177
+
178
+ ### Details
179
+
167
180
  Starting from version 1.8.0, IRB boasts a powerful integration with `debug.gem`, providing a debugging experience akin to `pry-byebug`.
168
181
 
169
182
  After hitting a `binding.irb` breakpoint, you can activate the debugger with the `debug` command. Alternatively, if the `debug` method happens to already be defined in the current scope, you can call `irb_debug`.
@@ -348,6 +361,10 @@ irb(main):002> a.first. # Completes Integer methods
348
361
  - `VISUAL`: Its value would be used to open files by the `edit` command.
349
362
  - `EDITOR`: Its value would be used to open files by the `edit` command if `VISUAL` is unset.
350
363
  - `IRBRC`: The file specified would be evaluated as IRB's rc-file.
364
+ - `XDG_CONFIG_HOME`: If it is set and `IRBRC` is unset, the file `$XDG_CONFIG_HOME/irb/irbrc` would be evaluated as IRB's rc-file.
365
+ - `RI_PAGER`: The command specified would be used as a pager.
366
+ - `PAGER`: The command specified would be used as a pager if `RI_PAGER` is unset.
367
+ - `IRB_LANG`, `LC_MESSAGES`, `LC_ALL`, `LANG`: The first of these that is set would be used as the locale value.
351
368
 
352
369
  ## Documentation
353
370
 
@@ -10,8 +10,10 @@ module IRB
10
10
  module Command
11
11
  class CommandArgumentError < StandardError; end
12
12
 
13
- def self.extract_ruby_args(*args, **kwargs)
14
- throw :EXTRACT_RUBY_ARGS, [args, kwargs]
13
+ class << self
14
+ def extract_ruby_args(*args, **kwargs)
15
+ throw :EXTRACT_RUBY_ARGS, [args, kwargs]
16
+ end
15
17
  end
16
18
 
17
19
  class Base
@@ -31,6 +33,12 @@ module IRB
31
33
  @help_message
32
34
  end
33
35
 
36
+ def execute(irb_context, arg)
37
+ new(irb_context).execute(arg)
38
+ rescue CommandArgumentError => e
39
+ puts e.message
40
+ end
41
+
34
42
  private
35
43
 
36
44
  def highlight(text)
@@ -38,12 +46,6 @@ module IRB
38
46
  end
39
47
  end
40
48
 
41
- def self.execute(irb_context, arg)
42
- new(irb_context).execute(arg)
43
- rescue CommandArgumentError => e
44
- puts e.message
45
- end
46
-
47
49
  def initialize(irb_context)
48
50
  @irb_context = irb_context
49
51
  end
@@ -58,13 +58,15 @@ module IRB
58
58
  end
59
59
 
60
60
  class DebugCommand < Debug
61
- def self.category
62
- "Debugging"
63
- end
61
+ class << self
62
+ def category
63
+ "Debugging"
64
+ end
64
65
 
65
- def self.description
66
- command_name = self.name.split("::").last.downcase
67
- "Start the debugger of debug.gem and run its `#{command_name}` command."
66
+ def description
67
+ command_name = self.name.split("::").last.downcase
68
+ "Start the debugger of debug.gem and run its `#{command_name}` command."
69
+ end
68
70
  end
69
71
  end
70
72
  end
@@ -39,7 +39,7 @@ module IRB
39
39
 
40
40
  help_cmds = commands_grouped_by_categories.delete("Help")
41
41
  no_category_cmds = commands_grouped_by_categories.delete("No category")
42
- aliases = irb_context.instance_variable_get(:@user_aliases).map do |alias_name, target|
42
+ aliases = irb_context.instance_variable_get(:@command_aliases).map do |alias_name, target|
43
43
  { display_name: alias_name, description: "Alias for `#{target}`" }
44
44
  end
45
45
 
@@ -19,7 +19,7 @@ module IRB
19
19
  # Use throw and catch to handle arg that includes `;`
20
20
  # For example: "1, kw: (2; 3); 4" will be parsed to [[1], { kw: 3 }]
21
21
  catch(:EXTRACT_RUBY_ARGS) do
22
- @irb_context.workspace.binding.eval "IRB::Command.extract_ruby_args #{arg}"
22
+ @irb_context.workspace.binding.eval "::IRB::Command.extract_ruby_args #{arg}"
23
23
  end || [[], {}]
24
24
  end
25
25
  end
@@ -11,7 +11,7 @@ module IRB
11
11
 
12
12
  module Command
13
13
  class Ls < Base
14
- include RubyArgsExtractor
14
+ class EvaluationError < StandardError; end
15
15
 
16
16
  category "Context"
17
17
  description "Show methods, constants, and variables."
@@ -22,24 +22,35 @@ module IRB
22
22
  -g [query] Filter the output with a query.
23
23
  HELP_MESSAGE
24
24
 
25
+ def evaluate(code)
26
+ @irb_context.workspace.binding.eval(code)
27
+ rescue Exception => e
28
+ puts "#{e.class}: #{e.message}"
29
+ raise EvaluationError
30
+ end
31
+
25
32
  def execute(arg)
26
33
  if match = arg.match(/\A(?<target>.+\s|)(-g|-G)\s+(?<grep>.+)$/)
27
- if match[:target].empty?
28
- use_main = true
29
- else
30
- obj = @irb_context.workspace.binding.eval(match[:target])
31
- end
34
+ target = match[:target]
32
35
  grep = Regexp.new(match[:grep])
36
+ elsif match = arg.match(/\A((?<target>.+),|)\s*grep:(?<grep>.+)/)
37
+ # Legacy style `ls obj, grep: /regexp/`
38
+ # Evaluation order should be eval(target) then eval(grep)
39
+ target = match[:target] || ''
40
+ grep_regexp_code = match[:grep]
33
41
  else
34
- args, kwargs = ruby_args(arg)
35
- use_main = args.empty?
36
- obj = args.first
37
- grep = kwargs[:grep]
42
+ target = arg.strip
38
43
  end
39
44
 
40
- if use_main
45
+ if target.empty?
41
46
  obj = irb_context.workspace.main
42
47
  locals = irb_context.workspace.binding.local_variables
48
+ else
49
+ obj = evaluate(target)
50
+ end
51
+
52
+ if grep_regexp_code
53
+ grep = evaluate(grep_regexp_code)
43
54
  end
44
55
 
45
56
  o = Output.new(grep: grep)
@@ -52,6 +63,7 @@ module IRB
52
63
  o.dump("class variables", klass.class_variables)
53
64
  o.dump("locals", locals) if locals
54
65
  o.print_result
66
+ rescue EvaluationError
55
67
  end
56
68
 
57
69
  def dump_methods(o, klass, obj)
@@ -137,26 +137,33 @@ module IRB
137
137
  end
138
138
 
139
139
  class RegexpCompletor < BaseCompletor # :nodoc:
140
+ KERNEL_METHODS = ::Kernel.instance_method(:methods)
141
+ KERNEL_PRIVATE_METHODS = ::Kernel.instance_method(:private_methods)
142
+ KERNEL_INSTANCE_VARIABLES = ::Kernel.instance_method(:instance_variables)
143
+ OBJECT_CLASS_INSTANCE_METHOD = ::Object.instance_method(:class)
144
+ MODULE_CONSTANTS_INSTANCE_METHOD = ::Module.instance_method(:constants)
145
+
140
146
  using Module.new {
141
147
  refine ::Binding do
142
148
  def eval_methods
143
- ::Kernel.instance_method(:methods).bind(eval("self")).call
149
+ KERNEL_METHODS.bind_call(receiver)
144
150
  end
145
151
 
146
152
  def eval_private_methods
147
- ::Kernel.instance_method(:private_methods).bind(eval("self")).call
153
+ KERNEL_PRIVATE_METHODS.bind_call(receiver)
148
154
  end
149
155
 
150
156
  def eval_instance_variables
151
- ::Kernel.instance_method(:instance_variables).bind(eval("self")).call
157
+ KERNEL_INSTANCE_VARIABLES.bind_call(receiver)
152
158
  end
153
159
 
154
160
  def eval_global_variables
155
- ::Kernel.instance_method(:global_variables).bind(eval("self")).call
161
+ ::Kernel.global_variables
156
162
  end
157
163
 
158
164
  def eval_class_constants
159
- ::Module.instance_method(:constants).bind(eval("self.class")).call
165
+ klass = OBJECT_CLASS_INSTANCE_METHOD.bind_call(receiver)
166
+ MODULE_CONSTANTS_INSTANCE_METHOD.bind_call(klass)
160
167
  end
161
168
  end
162
169
  }
data/lib/irb/context.rb CHANGED
@@ -13,6 +13,10 @@ module IRB
13
13
  # A class that wraps the current state of the irb session, including the
14
14
  # configuration of IRB.conf.
15
15
  class Context
16
+ KERNEL_PUBLIC_METHOD = ::Kernel.instance_method(:public_method)
17
+ KERNEL_METHOD = ::Kernel.instance_method(:method)
18
+
19
+ ASSIGN_OPERATORS_REGEXP = Regexp.union(%w[= += -= *= /= %= **= &= |= &&= ||= ^= <<= >>=])
16
20
  # Creates a new IRB context.
17
21
  #
18
22
  # The optional +input_method+ argument:
@@ -148,8 +152,7 @@ module IRB
148
152
  @newline_before_multiline_output = true
149
153
  end
150
154
 
151
- @user_aliases = IRB.conf[:COMMAND_ALIASES].dup
152
- @command_aliases = @user_aliases.merge(KEYWORD_ALIASES)
155
+ @command_aliases = IRB.conf[:COMMAND_ALIASES].dup
153
156
  end
154
157
 
155
158
  private def term_interactive?
@@ -157,17 +160,6 @@ module IRB
157
160
  STDIN.tty? && ENV['TERM'] != 'dumb'
158
161
  end
159
162
 
160
- # because all input will eventually be evaluated as Ruby code,
161
- # command names that conflict with Ruby keywords need special workaround
162
- # we can remove them once we implemented a better command system for IRB
163
- KEYWORD_ALIASES = {
164
- :break => :irb_break,
165
- :catch => :irb_catch,
166
- :next => :irb_next,
167
- }.freeze
168
-
169
- private_constant :KEYWORD_ALIASES
170
-
171
163
  def use_tracer=(val)
172
164
  require_relative "ext/tracer" if val
173
165
  IRB.conf[:USE_TRACER] = val
@@ -187,11 +179,17 @@ module IRB
187
179
 
188
180
  private def build_completor
189
181
  completor_type = IRB.conf[:COMPLETOR]
182
+
183
+ # Gem repl_type_completor is added to bundled gems in Ruby 3.4.
184
+ # Use :type as default completor only in Ruby 3.4 or later.
185
+ verbose = !!completor_type
186
+ completor_type ||= RUBY_VERSION >= '3.4' ? :type : :regexp
187
+
190
188
  case completor_type
191
189
  when :regexp
192
190
  return RegexpCompletor.new
193
191
  when :type
194
- completor = build_type_completor
192
+ completor = build_type_completor(verbose: verbose)
195
193
  return completor if completor
196
194
  else
197
195
  warn "Invalid value for IRB.conf[:COMPLETOR]: #{completor_type}"
@@ -200,17 +198,17 @@ module IRB
200
198
  RegexpCompletor.new
201
199
  end
202
200
 
203
- private def build_type_completor
201
+ private def build_type_completor(verbose:)
204
202
  if RUBY_ENGINE == 'truffleruby'
205
203
  # Avoid SyntaxError. truffleruby does not support endless method definition yet.
206
- warn 'TypeCompletor is not supported on TruffleRuby yet'
204
+ warn 'TypeCompletor is not supported on TruffleRuby yet' if verbose
207
205
  return
208
206
  end
209
207
 
210
208
  begin
211
209
  require 'repl_type_completor'
212
210
  rescue LoadError => e
213
- warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}"
211
+ warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}" if verbose
214
212
  return
215
213
  end
216
214
 
@@ -635,6 +633,46 @@ module IRB
635
633
  result
636
634
  end
637
635
 
636
+ def parse_command(code)
637
+ command_name, arg = code.strip.split(/\s+/, 2)
638
+ return unless code.lines.size == 1 && command_name
639
+
640
+ arg ||= ''
641
+ command = command_name.to_sym
642
+ # Command aliases are always command. example: $, @
643
+ if (alias_name = command_aliases[command])
644
+ return [alias_name, arg]
645
+ end
646
+
647
+ # Assignment-like expression is not a command
648
+ return if arg.start_with?(ASSIGN_OPERATORS_REGEXP) && !arg.start_with?(/==|=~/)
649
+
650
+ # Local variable have precedence over command
651
+ return if local_variables.include?(command)
652
+
653
+ # Check visibility
654
+ public_method = !!KERNEL_PUBLIC_METHOD.bind_call(main, command) rescue false
655
+ private_method = !public_method && !!KERNEL_METHOD.bind_call(main, command) rescue false
656
+ if Command.execute_as_command?(command, public_method: public_method, private_method: private_method)
657
+ [command, arg]
658
+ end
659
+ end
660
+
661
+ def colorize_input(input, complete:)
662
+ if IRB.conf[:USE_COLORIZE] && IRB::Color.colorable?
663
+ lvars = local_variables || []
664
+ if parse_command(input)
665
+ name, sep, arg = input.split(/(\s+)/, 2)
666
+ arg = IRB::Color.colorize_code(arg, complete: complete, local_variables: lvars)
667
+ "#{IRB::Color.colorize(name, [:BOLD])}\e[m#{sep}#{arg}"
668
+ else
669
+ IRB::Color.colorize_code(input, complete: complete, local_variables: lvars)
670
+ end
671
+ else
672
+ Reline::Unicode.escape_for_print(input)
673
+ end
674
+ end
675
+
638
676
  def inspect_last_value # :nodoc:
639
677
  @inspect_method.inspect_value(@last_value)
640
678
  end
@@ -669,5 +707,10 @@ module IRB
669
707
  def local_variables # :nodoc:
670
708
  workspace.binding.local_variables
671
709
  end
710
+
711
+ def safe_method_call_on_main(method_name)
712
+ main_object = main
713
+ Object === main_object ? main_object.__send__(method_name) : Object.instance_method(method_name).bind_call(main_object)
714
+ end
672
715
  end
673
716
  end
data/lib/irb/debug/ui.rb CHANGED
@@ -45,9 +45,7 @@ module IRB
45
45
  $stdout.puts line.chomp
46
46
  }
47
47
  when String
48
- str.each_line{|line|
49
- $stdout.puts line.chomp
50
- }
48
+ Pager.page_content(str, retain_content: true)
51
49
  when nil
52
50
  $stdout.puts
53
51
  end
@@ -56,7 +54,7 @@ module IRB
56
54
  def readline _
57
55
  setup_interrupt do
58
56
  tc = DEBUGGER__::SESSION.instance_variable_get(:@tc)
59
- cmd = @irb.debug_readline(tc.current_frame.binding || TOPLEVEL_BINDING)
57
+ cmd = @irb.debug_readline(tc.current_frame.eval_binding || TOPLEVEL_BINDING)
60
58
 
61
59
  case cmd
62
60
  when nil # when user types C-d
data/lib/irb/debug.rb CHANGED
@@ -57,22 +57,18 @@ module IRB
57
57
  DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
58
58
  end
59
59
 
60
- if !@output_modifier_defined && !DEBUGGER__::CONFIG[:no_hint]
61
- irb_output_modifier_proc = Reline.output_modifier_proc
62
-
63
- Reline.output_modifier_proc = proc do |output, complete:|
64
- unless output.strip.empty?
65
- cmd = output.split(/\s/, 2).first
60
+ if !DEBUGGER__::CONFIG[:no_hint] && irb.context.io.is_a?(RelineInputMethod)
61
+ Reline.output_modifier_proc = proc do |input, complete:|
62
+ unless input.strip.empty?
63
+ cmd = input.split(/\s/, 2).first
66
64
 
67
65
  if !complete && DEBUGGER__.commands.key?(cmd)
68
- output = output.sub(/\n$/, " # debug command\n")
66
+ input = input.sub(/\n$/, " # debug command\n")
69
67
  end
70
68
  end
71
69
 
72
- irb_output_modifier_proc.call(output, complete: complete)
70
+ irb.context.colorize_input(input, complete: complete)
73
71
  end
74
-
75
- @output_modifier_defined = true
76
72
  end
77
73
 
78
74
  true
@@ -181,9 +181,15 @@ module IRB
181
181
  [:edit, NO_OVERRIDE]
182
182
  )
183
183
 
184
- _register_with_aliases(:irb_break, Command::Break)
185
- _register_with_aliases(:irb_catch, Command::Catch)
186
- _register_with_aliases(:irb_next, Command::Next)
184
+ _register_with_aliases(:irb_break, Command::Break,
185
+ [:break, OVERRIDE_ALL]
186
+ )
187
+ _register_with_aliases(:irb_catch, Command::Catch,
188
+ [:catch, OVERRIDE_PRIVATE_ONLY]
189
+ )
190
+ _register_with_aliases(:irb_next, Command::Next,
191
+ [:next, OVERRIDE_ALL]
192
+ )
187
193
  _register_with_aliases(:irb_delete, Command::Delete,
188
194
  [:delete, NO_OVERRIDE]
189
195
  )
@@ -259,10 +265,12 @@ module IRB
259
265
  # Deprecated. Doesn't have any effect.
260
266
  @EXTEND_COMMANDS = []
261
267
 
262
- # Drepcated. Use Command.regiser instead.
263
- def self.def_extend_command(cmd_name, cmd_class, _, *aliases)
264
- Command._register_with_aliases(cmd_name, cmd_class, *aliases)
265
- Command.class_variable_set(:@@command_override_policies, nil)
268
+ class << self
269
+ # Drepcated. Use Command.regiser instead.
270
+ def def_extend_command(cmd_name, cmd_class, _, *aliases)
271
+ Command._register_with_aliases(cmd_name, cmd_class, *aliases)
272
+ Command.class_variable_set(:@@command_override_policies, nil)
273
+ end
266
274
  end
267
275
  end
268
276
  end
@@ -100,19 +100,21 @@ module IRB
100
100
 
101
101
  private def easter_egg_logo(type)
102
102
  @easter_egg_logos ||= File.read(File.join(__dir__, 'ruby_logo.aa'), encoding: 'UTF-8:UTF-8')
103
- .split(/TYPE: ([A-Z]+)\n/)[1..]
103
+ .split(/TYPE: ([A-Z_]+)\n/)[1..]
104
104
  .each_slice(2)
105
105
  .to_h
106
106
  @easter_egg_logos[type.to_s.upcase]
107
107
  end
108
108
 
109
109
  private def easter_egg(type = nil)
110
+ print "\e[?1049h"
110
111
  type ||= [:logo, :dancing].sample
111
112
  case type
112
113
  when :logo
113
- require "rdoc"
114
- RDoc::RI::Driver.new.page do |io|
115
- io.write easter_egg_logo(:large)
114
+ Pager.page do |io|
115
+ logo_type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode_large : :ascii_large
116
+ io.write easter_egg_logo(logo_type)
117
+ STDIN.raw { STDIN.getc } if io == STDOUT
116
118
  end
117
119
  when :dancing
118
120
  STDOUT.cooked do
@@ -123,7 +125,7 @@ module IRB
123
125
  canvas = Canvas.new(Reline.get_screen_size)
124
126
  end
125
127
  ruby_model = RubyModel.new
126
- print "\e[?1049h"
128
+ print "\e[?25l" # hide cursor
127
129
  0.step do |i| # TODO (0..).each needs Ruby 2.6 or later
128
130
  buff = canvas.draw do
129
131
  ruby_model.render_frame(i) do |p1, p2|
@@ -137,10 +139,12 @@ module IRB
137
139
  end
138
140
  rescue Interrupt
139
141
  ensure
140
- print "\e[0m\e[?1049l"
142
+ print "\e[?25h" # show cursor
141
143
  trap("SIGINT", prev_trap)
142
144
  end
143
145
  end
146
+ ensure
147
+ print "\e[0m\e[?1049l"
144
148
  end
145
149
  end
146
150
  end