irb 1.6.3 → 1.7.0

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: f82a38c3bf30c31ffcac5b5dd8f7883d9edd65edfbba779d87a18eb028c88c93
4
- data.tar.gz: d45c6f3671612e3186a902c9c3406df16b350ae9a91e89d85383544267bc3eed
3
+ metadata.gz: fa3c9603f48d730988d34f454a10b58021caa677ab8832d9764e39e61bb49abb
4
+ data.tar.gz: c46d1e32c81a8f22593e174af095070159af6a61508c97b3ef4b0b9d28301d58
5
5
  SHA512:
6
- metadata.gz: 32eee54235bcc829238f55cb70d29cebce2c0024b6ebb76d9dfc6e168fd4d35fffccd228fa1b848ac4b5a3a0f35e4743533499a060ae2cf5858ffc9caee4ee8c
7
- data.tar.gz: 20bc4fdda9f15c9c668ece83acf81c0b9828664d74dac042430cbbfe798e8467ddf9af0c41a63267ceee402eb92f71c9bc4413f7e91b95b5f8ba2bf64c989505
6
+ metadata.gz: 3e99185c909180d01a3310f7db11437181268b930d267f2fe365c06cd7a442ad3a8cdf7d5863fb19e17885a23aad46b993a2e5c21fb8632ff2f91285e469be4b
7
+ data.tar.gz: 44978be86d00d0fc435e81e4cadc5abad08d47519a189db02e34d7eb3435e9ac0cc0adf470e845edba1e7d866574298e1b7b8bba5190d8be538c396cd0179d07
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # IRB
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/irb.svg)](https://badge.fury.io/rb/irb)
4
+ [![build](https://github.com/ruby/irb/actions/workflows/test.yml/badge.svg)](https://github.com/ruby/irb/actions/workflows/test.yml)
5
+
3
6
  IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby expressions read from the standard input.
4
7
 
5
8
  The `irb` command from your shell will start the interpreter.
data/irb.gemspec CHANGED
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
39
39
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
40
40
  spec.require_paths = ["lib"]
41
41
 
42
- spec.required_ruby_version = Gem::Requirement.new(">= 2.6")
42
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7")
43
43
 
44
44
  spec.add_dependency "reline", ">= 0.3.0"
45
45
  end
data/lib/irb/cmd/help.rb CHANGED
@@ -1,57 +1,23 @@
1
- # frozen_string_literal: false
2
- #
3
- # help.rb - helper using ri
4
- #
1
+ # frozen_string_literal: true
5
2
 
6
- require_relative "nop"
3
+ require_relative "show_doc"
7
4
 
8
5
  module IRB
9
- # :stopdoc:
10
-
11
6
  module ExtendCommand
12
- class Help < Nop
13
- class << self
14
- def transform_args(args)
15
- # Return a string literal as is for backward compatibility
16
- if args.empty? || string_literal?(args)
17
- args
18
- else # Otherwise, consider the input as a String for convenience
19
- args.strip.dump
20
- end
21
- end
22
- end
23
-
7
+ class Help < ShowDoc
24
8
  category "Context"
25
- description "Enter the mode to look up RI documents."
9
+ description "[DEPRECATED] Enter the mode to look up RI documents."
10
+
11
+ DEPRECATION_MESSAGE = <<~MSG
12
+ [Deprecation] The `help` command will be repurposed to display command help in the future.
13
+ For RI document lookup, please use the `show_doc` command instead.
14
+ For command help, please use `show_cmds` for now.
15
+ MSG
26
16
 
27
17
  def execute(*names)
28
- require 'rdoc/ri/driver'
29
- opts = RDoc::RI::Driver.process_args([])
30
- IRB::ExtendCommand::Help.const_set(:Ri, RDoc::RI::Driver.new(opts))
31
- rescue LoadError, SystemExit
32
- IRB::ExtendCommand::Help.remove_method(:execute)
33
- # raise NoMethodError in ensure
34
- else
35
- def execute(*names)
36
- if names.empty?
37
- Ri.interactive
38
- return
39
- end
40
- names.each do |name|
41
- begin
42
- Ri.display_name(name.to_s)
43
- rescue RDoc::RI::Error
44
- puts $!.message
45
- end
46
- end
47
- nil
48
- end
49
- nil
50
- ensure
51
- execute(*names)
18
+ warn DEPRECATION_MESSAGE
19
+ super
52
20
  end
53
21
  end
54
22
  end
55
-
56
- # :startdoc:
57
23
  end
data/lib/irb/cmd/ls.rb CHANGED
@@ -39,8 +39,12 @@ module IRB
39
39
  def dump_methods(o, klass, obj)
40
40
  singleton_class = begin obj.singleton_class; rescue TypeError; nil end
41
41
  dumped_mods = Array.new
42
+ ancestors = klass.ancestors
43
+ ancestors = ancestors.reject { |c| c >= Object } if klass < Object
44
+ singleton_ancestors = (singleton_class&.ancestors || []).reject { |c| c >= Class }
45
+
42
46
  # singleton_class' ancestors should be at the front
43
- maps = class_method_map(singleton_class&.ancestors || [], dumped_mods) + class_method_map(klass.ancestors, dumped_mods)
47
+ maps = class_method_map(singleton_ancestors, dumped_mods) + class_method_map(ancestors, dumped_mods)
44
48
  maps.each do |mod, methods|
45
49
  name = mod == singleton_class ? "#{klass}.methods" : "#{mod}#methods"
46
50
  o.dump(name, methods)
@@ -49,7 +53,6 @@ module IRB
49
53
 
50
54
  def class_method_map(classes, dumped_mods)
51
55
  dumped_methods = Array.new
52
- classes = classes.reject { |mod| mod >= Object }
53
56
  classes.map do |mod|
54
57
  next if dumped_mods.include? mod
55
58
 
data/lib/irb/cmd/nop.rb CHANGED
@@ -30,20 +30,11 @@ module IRB
30
30
  end
31
31
  end
32
32
 
33
- if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
34
- def self.execute(conf, *opts, **kwargs, &block)
35
- command = new(conf)
36
- command.execute(*opts, **kwargs, &block)
37
- rescue CommandArgumentError => e
38
- puts e.message
39
- end
40
- else
41
- def self.execute(conf, *opts, &block)
42
- command = new(conf)
43
- command.execute(*opts, &block)
44
- rescue CommandArgumentError => e
45
- puts e.message
46
- end
33
+ def self.execute(conf, *opts, **kwargs, &block)
34
+ command = new(conf)
35
+ command.execute(*opts, **kwargs, &block)
36
+ rescue CommandArgumentError => e
37
+ puts e.message
47
38
  end
48
39
 
49
40
  def initialize(conf)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "nop"
4
+
5
+ module IRB
6
+ module ExtendCommand
7
+ class ShowDoc < Nop
8
+ class << self
9
+ def transform_args(args)
10
+ # Return a string literal as is for backward compatibility
11
+ if args.empty? || string_literal?(args)
12
+ args
13
+ else # Otherwise, consider the input as a String for convenience
14
+ args.strip.dump
15
+ end
16
+ end
17
+ end
18
+
19
+ category "Context"
20
+ description "Enter the mode to look up RI documents."
21
+
22
+ def execute(*names)
23
+ require 'rdoc/ri/driver'
24
+
25
+ unless ShowDoc.const_defined?(:Ri)
26
+ opts = RDoc::RI::Driver.process_args([])
27
+ ShowDoc.const_set(:Ri, RDoc::RI::Driver.new(opts))
28
+ end
29
+
30
+ if names.empty?
31
+ Ri.interactive
32
+ else
33
+ names.each do |name|
34
+ begin
35
+ Ri.display_name(name.to_s)
36
+ rescue RDoc::RI::Error
37
+ puts $!.message
38
+ end
39
+ end
40
+ end
41
+
42
+ nil
43
+ rescue LoadError, SystemExit
44
+ warn "Can't display document because `rdoc` is not installed."
45
+ end
46
+ end
47
+ end
48
+ end
@@ -27,17 +27,18 @@ module IRB
27
27
  when /\A[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
28
28
  eval(str, irb_context.workspace.binding) # trigger autoload
29
29
  base = irb_context.workspace.binding.receiver.yield_self { |r| r.is_a?(Module) ? r : Object }
30
- file, line = base.const_source_location(str) if base.respond_to?(:const_source_location) # Ruby 2.7+
30
+ file, line = base.const_source_location(str)
31
31
  when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
32
32
  owner = eval(Regexp.last_match[:owner], irb_context.workspace.binding)
33
33
  method = Regexp.last_match[:method]
34
- if owner.respond_to?(:instance_method) && owner.instance_methods.include?(method.to_sym)
35
- file, line = owner.instance_method(method).source_location
34
+ if owner.respond_to?(:instance_method)
35
+ methods = owner.instance_methods + owner.private_instance_methods
36
+ file, line = owner.instance_method(method).source_location if methods.include?(method.to_sym)
36
37
  end
37
38
  when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
38
39
  receiver = eval(Regexp.last_match[:receiver] || 'self', irb_context.workspace.binding)
39
40
  method = Regexp.last_match[:method]
40
- file, line = receiver.method(method).source_location if receiver.respond_to?(method)
41
+ file, line = receiver.method(method).source_location if receiver.respond_to?(method, true)
41
42
  end
42
43
  if file && line
43
44
  Source.new(file: file, first_line: line, last_line: find_end(file, line, irb_context))
data/lib/irb/color.rb CHANGED
@@ -197,15 +197,9 @@ module IRB # :nodoc:
197
197
  end
198
198
  end
199
199
 
200
- if lexer.respond_to?(:scan) # Ruby 2.7+
201
- lexer.scan.each do |elem|
202
- next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
203
- on_scan.call(elem)
204
- end
205
- else
206
- lexer.parse.sort_by(&:pos).each do |elem|
207
- on_scan.call(elem)
208
- end
200
+ lexer.scan.each do |elem|
201
+ next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
202
+ on_scan.call(elem)
209
203
  end
210
204
  # yield uncolorable DATA section
211
205
  yield(nil, inner_code.byteslice(byte_pos...inner_code.bytesize), nil) if byte_pos < inner_code.bytesize
@@ -4,6 +4,9 @@ require_relative 'color'
4
4
 
5
5
  module IRB
6
6
  class ColorPrinter < ::PP
7
+ METHOD_RESPOND_TO = Object.instance_method(:respond_to?)
8
+ METHOD_INSPECT = Object.instance_method(:inspect)
9
+
7
10
  class << self
8
11
  def pp(obj, out = $>, width = screen_width)
9
12
  q = ColorPrinter.new(out, width)
@@ -22,9 +25,11 @@ module IRB
22
25
  end
23
26
 
24
27
  def pp(obj)
25
- if obj.is_a?(String)
28
+ if String === obj
26
29
  # Avoid calling Ruby 2.4+ String#pretty_print that splits a string by "\n"
27
30
  text(obj.inspect)
31
+ elsif !METHOD_RESPOND_TO.bind(obj).call(:inspect)
32
+ text(METHOD_INSPECT.bind(obj).call)
28
33
  else
29
34
  super
30
35
  end
@@ -58,19 +58,11 @@ module IRB
58
58
 
59
59
  BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
60
60
 
61
- def self.absolute_path?(p) # TODO Remove this method after 2.6 EOL.
62
- if File.respond_to?(:absolute_path?)
63
- File.absolute_path?(p)
64
- else
65
- File.absolute_path(p) == p
66
- end
67
- end
68
-
69
61
  GEM_PATHS =
70
62
  if defined?(Gem::Specification)
71
63
  Gem::Specification.latest_specs(true).map { |s|
72
64
  s.require_paths.map { |p|
73
- if absolute_path?(p)
65
+ if File.absolute_path?(p)
74
66
  p
75
67
  else
76
68
  File.join(s.full_gem_path, p)
@@ -450,30 +442,5 @@ module IRB
450
442
  end
451
443
  end
452
444
  end
453
-
454
- def self.ignored_modules
455
- # We could cache the result, but this is very fast already.
456
- # By using this approach, we avoid Module#name calls, which are
457
- # relatively slow when there are a lot of anonymous modules defined.
458
- s = {}
459
-
460
- scanner = lambda do |m|
461
- next if s.include?(m) # IRB::ExtendCommandBundle::EXCB recurses.
462
- s[m] = true
463
- m.constants(false).each do |c|
464
- value = m.const_get(c)
465
- scanner.call(value) if value.is_a?(Module)
466
- end
467
- end
468
-
469
- %i(IRB RubyLex).each do |sym|
470
- next unless Object.const_defined?(sym)
471
- scanner.call(Object.const_get(sym))
472
- end
473
-
474
- s.delete(IRB::Context) if defined?(IRB::Context)
475
-
476
- s
477
- end
478
445
  end
479
446
  end
@@ -24,31 +24,8 @@ module IRB # :nodoc:
24
24
  load_file(path, priv)
25
25
  end
26
26
 
27
- if File.respond_to?(:absolute_path?)
28
- def absolute_path?(path)
29
- File.absolute_path?(path)
30
- end
31
- else
32
- separator =
33
- if File::ALT_SEPARATOR
34
- "[#{Regexp.quote(File::SEPARATOR + File::ALT_SEPARATOR)}]"
35
- else
36
- File::SEPARATOR
37
- end
38
- ABSOLUTE_PATH_PATTERN = # :nodoc:
39
- case Dir.pwd
40
- when /\A\w:/, /\A#{separator}{2}/
41
- /\A(?:\w:|#{separator})#{separator}/
42
- else
43
- /\A#{separator}/
44
- end
45
- def absolute_path?(path)
46
- ABSOLUTE_PATH_PATTERN =~ path
47
- end
48
- end
49
-
50
27
  def search_file_from_ruby_path(fn) # :nodoc:
51
- if absolute_path?(fn)
28
+ if File.absolute_path?(fn)
52
29
  return fn if File.exist?(fn)
53
30
  return nil
54
31
  end
@@ -7,9 +7,8 @@
7
7
  begin
8
8
  require "tracer"
9
9
  rescue LoadError
10
- $stderr.puts "Tracer extension of IRB is enabled but tracer gem doesn't found."
10
+ $stderr.puts "Tracer extension of IRB is enabled but tracer gem wasn't found."
11
11
  module IRB
12
- TracerLoadError = true
13
12
  class Context
14
13
  def use_tracer=(opt)
15
14
  # do nothing
@@ -157,10 +157,14 @@ module IRB # :nodoc:
157
157
 
158
158
  [
159
159
  :irb_help, :Help, "cmd/help",
160
- [:show_doc, NO_OVERRIDE],
161
160
  [:help, NO_OVERRIDE],
162
161
  ],
163
162
 
163
+ [
164
+ :irb_show_doc, :ShowDoc, "cmd/show_doc",
165
+ [:show_doc, NO_OVERRIDE],
166
+ ],
167
+
164
168
  [
165
169
  :irb_info, :IrbInfo, "cmd/irb_info"
166
170
  ],
@@ -246,7 +250,7 @@ module IRB # :nodoc:
246
250
  #
247
251
  # The optional +load_file+ parameter will be required within the method
248
252
  # definition.
249
- def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
253
+ def self.def_extend_command(cmd_name, cmd_class, load_file, *aliases)
250
254
  case cmd_class
251
255
  when Symbol
252
256
  cmd_class = cmd_class.id2name
@@ -255,34 +259,12 @@ module IRB # :nodoc:
255
259
  cmd_class = cmd_class.name
256
260
  end
257
261
 
258
- if load_file
259
- kwargs = ", **kwargs" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
260
- line = __LINE__; eval %[
261
- def #{cmd_name}(*opts#{kwargs}, &b)
262
- Kernel.require_relative "#{load_file}"
263
- arity = ::IRB::ExtendCommand::#{cmd_class}.instance_method(:execute).arity
264
- args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s }
265
- args << "*opts#{kwargs}" if arity < 0
266
- args << "&block"
267
- args = args.join(", ")
268
- line = __LINE__; eval %[
269
- unless singleton_class.class_variable_defined?(:@@#{cmd_name}_)
270
- singleton_class.class_variable_set(:@@#{cmd_name}_, true)
271
- def self.#{cmd_name}_(\#{args})
272
- ::IRB::ExtendCommand::#{cmd_class}.execute(irb_context, \#{args})
273
- end
274
- end
275
- ], nil, __FILE__, line
276
- __send__ :#{cmd_name}_, *opts#{kwargs}, &b
277
- end
278
- ], nil, __FILE__, line
279
- else
280
- line = __LINE__; eval %[
281
- def #{cmd_name}(*opts, &b)
282
- ::IRB::ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b)
283
- end
284
- ], nil, __FILE__, line
285
- end
262
+ line = __LINE__; eval %[
263
+ def #{cmd_name}(*opts, **kwargs, &b)
264
+ Kernel.require_relative "#{load_file}"
265
+ ::IRB::ExtendCommand::#{cmd_class}.execute(irb_context, *opts, **kwargs, &b)
266
+ end
267
+ ], nil, __FILE__, line
286
268
 
287
269
  for ali, flag in aliases
288
270
  @ALIASES.push [ali, cmd_name, flag]
@@ -371,58 +353,4 @@ module IRB # :nodoc:
371
353
 
372
354
  CE.install_extend_commands
373
355
  end
374
-
375
- # A convenience module for extending Ruby methods.
376
- module MethodExtender
377
- # Extends the given +base_method+ with a prefix call to the given
378
- # +extend_method+.
379
- def def_pre_proc(base_method, extend_method)
380
- base_method = base_method.to_s
381
- extend_method = extend_method.to_s
382
-
383
- alias_name = new_alias_name(base_method)
384
- module_eval %[
385
- alias_method alias_name, base_method
386
- def #{base_method}(*opts)
387
- __send__ :#{extend_method}, *opts
388
- __send__ :#{alias_name}, *opts
389
- end
390
- ]
391
- end
392
-
393
- # Extends the given +base_method+ with a postfix call to the given
394
- # +extend_method+.
395
- def def_post_proc(base_method, extend_method)
396
- base_method = base_method.to_s
397
- extend_method = extend_method.to_s
398
-
399
- alias_name = new_alias_name(base_method)
400
- module_eval %[
401
- alias_method alias_name, base_method
402
- def #{base_method}(*opts)
403
- __send__ :#{alias_name}, *opts
404
- __send__ :#{extend_method}, *opts
405
- end
406
- ]
407
- end
408
-
409
- # Returns a unique method name to use as an alias for the given +name+.
410
- #
411
- # Usually returns <code>#{prefix}#{name}#{postfix}<num></code>, example:
412
- #
413
- # new_alias_name('foo') #=> __alias_of__foo__
414
- # def bar; end
415
- # new_alias_name('bar') #=> __alias_of__bar__2
416
- def new_alias_name(name, prefix = "__alias_of__", postfix = "__")
417
- base_name = "#{prefix}#{name}#{postfix}"
418
- all_methods = instance_methods(true) + private_instance_methods(true)
419
- same_methods = all_methods.grep(/^#{Regexp.quote(base_name)}[0-9]*$/)
420
- return base_name if same_methods.empty?
421
- no = same_methods.size
422
- while !same_methods.include?(alias_name = base_name + no)
423
- no += 1
424
- end
425
- alias_name
426
- end
427
- end
428
356
  end
data/lib/irb/help.rb CHANGED
@@ -4,15 +4,13 @@
4
4
  # by Keiju ISHITSUKA(keiju@ishitsuka.com)
5
5
  #
6
6
 
7
- require_relative 'magic-file'
8
-
9
7
  module IRB
10
8
  # Outputs the irb help message, see IRB@Command+line+options.
11
9
  def IRB.print_usage
12
10
  lc = IRB.conf[:LC_MESSAGES]
13
11
  path = lc.find("irb/help-message")
14
12
  space_line = false
15
- IRB::MagicFile.open(path){|f|
13
+ File.open(path){|f|
16
14
  f.each_line do |l|
17
15
  if /^\s*$/ =~ l
18
16
  lc.puts l unless space_line
@@ -5,7 +5,6 @@
5
5
  #
6
6
 
7
7
  require_relative 'src_encoding'
8
- require_relative 'magic-file'
9
8
  require_relative 'completion'
10
9
  require 'io/console'
11
10
  require 'reline'
@@ -132,7 +131,7 @@ module IRB
132
131
  # Creates a new input method object
133
132
  def initialize(file)
134
133
  super
135
- @io = file.is_a?(IO) ? file : IRB::MagicFile.open(file)
134
+ @io = file.is_a?(IO) ? file : File.open(file)
136
135
  @external_encoding = @io.external_encoding
137
136
  end
138
137
  # The file name of this input method, usually given during initialization.
@@ -399,8 +398,10 @@ module IRB
399
398
  formatter = RDoc::Markup::ToAnsi.new
400
399
  formatter.width = width
401
400
  dialog.trap_key = alt_d
402
- message = 'Press Alt+d to read the full document'
401
+ mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
402
+ message = "Press #{mod_key}+d to read the full document"
403
403
  contents = [message] + doc.accept(formatter).split("\n")
404
+ contents = contents.take(preferred_dialog_height) if respond_to?(:preferred_dialog_height)
404
405
 
405
406
  y = cursor_pos_to_render.y
406
407
  DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
data/lib/irb/inspector.rb CHANGED
@@ -98,8 +98,7 @@ module IRB # :nodoc:
98
98
  puts "An error occurred when inspecting the object: #{e.inspect}"
99
99
 
100
100
  begin
101
- # TODO: change this to bind_call when we drop support for Ruby 2.6
102
- puts "Result of Kernel#inspect: #{KERNEL_INSPECT.bind(v).call}"
101
+ puts "Result of Kernel#inspect: #{KERNEL_INSPECT.bind_call(v)}"
103
102
  ''
104
103
  rescue => e
105
104
  puts "An error occurred when running Kernel#inspect: #{e.inspect}"
data/lib/irb/locale.rb CHANGED
@@ -15,7 +15,11 @@ module IRB # :nodoc:
15
15
  ]x
16
16
  LOCALE_DIR = "/lc/"
17
17
 
18
- @@legacy_encoding_alias_map = {}.freeze
18
+ LEGACY_ENCODING_ALIAS_MAP = {
19
+ 'ujis' => Encoding::EUC_JP,
20
+ 'euc' => Encoding::EUC_JP
21
+ }
22
+
19
23
  @@loaded = []
20
24
 
21
25
  def initialize(locale = nil)
@@ -26,11 +30,11 @@ module IRB # :nodoc:
26
30
  @lang, @territory, @encoding_name, @modifier = m[:language], m[:territory], m[:codeset], m[:modifier]
27
31
 
28
32
  if @encoding_name
29
- begin load 'irb/encoding_aliases.rb'; rescue LoadError; end
30
- if @encoding = @@legacy_encoding_alias_map[@encoding_name]
33
+ if @encoding = LEGACY_ENCODING_ALIAS_MAP[@encoding_name]
31
34
  warn(("%s is obsolete. use %s" % ["#{@lang}_#{@territory}.#{@encoding_name}", "#{@lang}_#{@territory}.#{@encoding.name}"]), uplevel: 1)
35
+ else
36
+ @encoding = Encoding.find(@encoding_name) rescue nil
32
37
  end
33
- @encoding = Encoding.find(@encoding_name) rescue nil
34
38
  end
35
39
  end
36
40
  @encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT)
@@ -78,39 +82,12 @@ module IRB # :nodoc:
78
82
  super(*ary)
79
83
  end
80
84
 
81
- def require(file, priv = nil)
82
- rex = Regexp.new("lc/#{Regexp.quote(file)}\.(so|o|sl|rb)?")
83
- return false if $".find{|f| f =~ rex}
84
-
85
- case file
86
- when /\.rb$/
87
- begin
88
- load(file, priv)
89
- $".push file
90
- return true
91
- rescue LoadError
92
- end
93
- when /\.(so|o|sl)$/
94
- return super
95
- end
96
-
97
- begin
98
- load(f = file + ".rb")
99
- $".push f #"
100
- return true
101
- rescue LoadError
102
- return ruby_require(file)
103
- end
104
- end
105
-
106
- alias toplevel_load load
107
-
108
- def load(file, priv=nil)
85
+ def load(file)
109
86
  found = find(file)
110
87
  if found
111
88
  unless @@loaded.include?(found)
112
89
  @@loaded << found # cache
113
- return real_load(found, priv)
90
+ Kernel.load(found)
114
91
  end
115
92
  else
116
93
  raise LoadError, "No such file to load -- #{file}"
@@ -129,16 +106,6 @@ module IRB # :nodoc:
129
106
  end
130
107
  end
131
108
 
132
- private
133
- def real_load(path, priv)
134
- src = MagicFile.open(path){|f| f.read}
135
- if priv
136
- eval("self", TOPLEVEL_BINDING).extend(Module.new {eval(src, nil, path)})
137
- else
138
- eval(src, TOPLEVEL_BINDING, path)
139
- end
140
- end
141
-
142
109
  # @param paths load paths in which IRB find a localized file.
143
110
  # @param dir directory
144
111
  # @param file basename to be localized
data/lib/irb/ruby-lex.rb CHANGED
@@ -18,10 +18,7 @@ class RubyLex
18
18
 
19
19
  def initialize(context)
20
20
  @context = context
21
- @exp_line_no = @line_no = 1
22
- @indent = 0
23
- @continue = false
24
- @line = ""
21
+ @line_no = 1
25
22
  @prompt = nil
26
23
  end
27
24
 
@@ -42,8 +39,17 @@ class RubyLex
42
39
  result
43
40
  end
44
41
 
42
+ def single_line_command?(code)
43
+ command = code.split(/\s/, 2).first
44
+ @context.symbol_alias?(command) || @context.transform_args?(command)
45
+ end
46
+
45
47
  # io functions
46
- def set_input(io, &block)
48
+ def set_input(&block)
49
+ @input = block
50
+ end
51
+
52
+ def configure_io(io)
47
53
  @io = io
48
54
  if @io.respond_to?(:check_termination)
49
55
  @io.check_termination do |code|
@@ -61,14 +67,9 @@ class RubyLex
61
67
  end
62
68
  else
63
69
  # Accept any single-line input for symbol aliases or commands that transform args
64
- command = code.split(/\s/, 2).first
65
- if @context.symbol_alias?(command) || @context.transform_args?(command)
66
- next true
67
- end
70
+ next true if single_line_command?(code)
68
71
 
69
- code.gsub!(/\s*\z/, '').concat("\n")
70
- tokens = self.class.ripper_lex_without_warning(code, context: @context)
71
- ltype, indent, continue, code_block_open = check_state(code, tokens)
72
+ ltype, indent, continue, code_block_open = check_code_state(code)
72
73
  if ltype or indent > 0 or continue or code_block_open
73
74
  false
74
75
  else
@@ -112,10 +113,22 @@ class RubyLex
112
113
  end
113
114
  end
114
115
 
115
- if block_given?
116
- @input = block
117
- else
118
- @input = Proc.new{@io.gets}
116
+ if @io.respond_to?(:auto_indent) and @context.auto_indent_mode
117
+ @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
118
+ if is_newline
119
+ @tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"), context: @context)
120
+ prev_spaces = find_prev_spaces(line_index)
121
+ depth_difference = check_newline_depth_difference
122
+ depth_difference = 0 if depth_difference < 0
123
+ prev_spaces + depth_difference * 2
124
+ else
125
+ code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
126
+ last_line = lines[line_index]&.byteslice(0, byte_pointer)
127
+ code += last_line if last_line
128
+ @tokens = self.class.ripper_lex_without_warning(code, context: @context)
129
+ check_corresponding_token_depth(lines, line_index)
130
+ end
131
+ end
119
132
  end
120
133
  end
121
134
 
@@ -148,19 +161,15 @@ class RubyLex
148
161
 
149
162
  compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
150
163
  lexer = Ripper::Lexer.new(inner_code, '-', line_no)
151
- if lexer.respond_to?(:scan) # Ruby 2.7+
152
- lexer.scan.each_with_object([]) do |t, tokens|
153
- next if t.pos.first == 0
154
- prev_tk = tokens.last
155
- position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
156
- if position_overlapped
157
- tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
158
- else
159
- tokens << t
160
- end
164
+ lexer.scan.each_with_object([]) do |t, tokens|
165
+ next if t.pos.first == 0
166
+ prev_tk = tokens.last
167
+ position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
168
+ if position_overlapped
169
+ tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
170
+ else
171
+ tokens << t
161
172
  end
162
- else
163
- lexer.parse.reject { |it| it.pos.first == 0 }.sort_by(&:pos)
164
173
  end
165
174
  end
166
175
  ensure
@@ -188,26 +197,6 @@ class RubyLex
188
197
  prev_spaces
189
198
  end
190
199
 
191
- def set_auto_indent
192
- if @io.respond_to?(:auto_indent) and @context.auto_indent_mode
193
- @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
194
- if is_newline
195
- @tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"), context: @context)
196
- prev_spaces = find_prev_spaces(line_index)
197
- depth_difference = check_newline_depth_difference
198
- depth_difference = 0 if depth_difference < 0
199
- prev_spaces + depth_difference * 2
200
- else
201
- code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
202
- last_line = lines[line_index]&.byteslice(0, byte_pointer)
203
- code += last_line if last_line
204
- @tokens = self.class.ripper_lex_without_warning(code, context: @context)
205
- check_corresponding_token_depth(lines, line_index)
206
- end
207
- end
208
- end
209
- end
210
-
211
200
  def check_state(code, tokens)
212
201
  ltype = process_literal_type(tokens)
213
202
  indent = process_nesting_level(tokens)
@@ -218,67 +207,56 @@ class RubyLex
218
207
  [ltype, indent, continue, code_block_open]
219
208
  end
220
209
 
221
- def prompt
222
- if @prompt
223
- @prompt.call(@ltype, @indent, @continue, @line_no)
224
- end
210
+ def check_code_state(code)
211
+ check_target_code = code.gsub(/\s*\z/, '').concat("\n")
212
+ tokens = self.class.ripper_lex_without_warning(check_target_code, context: @context)
213
+ check_state(check_target_code, tokens)
225
214
  end
226
215
 
227
- def initialize_input
228
- @ltype = nil
229
- @indent = 0
230
- @continue = false
231
- @line = ""
232
- @exp_line_no = @line_no
233
- @code_block_open = false
216
+ def save_prompt_to_context_io(ltype, indent, continue, line_num_offset)
217
+ # Implicitly saves prompt string to `@context.io.prompt`. This will be used in the next `@input.call`.
218
+ @prompt.call(ltype, indent, continue, @line_no + line_num_offset)
234
219
  end
235
220
 
236
- def each_top_level_statement
237
- initialize_input
238
- catch(:TERM_INPUT) do
239
- loop do
240
- begin
241
- prompt
242
- unless l = lex
243
- throw :TERM_INPUT if @line == ''
244
- else
245
- @line_no += l.count("\n")
246
- if l == "\n"
247
- @exp_line_no += 1
248
- next
249
- end
250
- @line.concat l
251
- if @code_block_open or @ltype or @continue or @indent > 0
252
- next
253
- end
254
- end
255
- if @line != "\n"
256
- @line.force_encoding(@io.encoding)
257
- yield @line, @exp_line_no
258
- end
259
- raise TerminateLineInput if @io.eof?
260
- @line = ''
261
- @exp_line_no = @line_no
262
-
263
- @indent = 0
264
- rescue TerminateLineInput
265
- initialize_input
266
- prompt
267
- end
221
+ def readmultiline
222
+ save_prompt_to_context_io(nil, 0, false, 0)
223
+
224
+ # multiline
225
+ return @input.call if @io.respond_to?(:check_termination)
226
+
227
+ # nomultiline
228
+ code = ''
229
+ line_offset = 0
230
+ loop do
231
+ line = @input.call
232
+ unless line
233
+ return code.empty? ? nil : code
268
234
  end
235
+
236
+ code << line
237
+ # Accept any single-line input for symbol aliases or commands that transform args
238
+ return code if single_line_command?(code)
239
+
240
+ ltype, indent, continue, code_block_open = check_code_state(code)
241
+ return code unless ltype or indent > 0 or continue or code_block_open
242
+
243
+ line_offset += 1
244
+ save_prompt_to_context_io(ltype, indent, continue, line_offset)
269
245
  end
270
246
  end
271
247
 
272
- def lex
273
- line = @input.call
274
- if @io.respond_to?(:check_termination)
275
- return line # multiline
248
+ def each_top_level_statement
249
+ loop do
250
+ code = readmultiline
251
+ break unless code
252
+
253
+ if code != "\n"
254
+ code.force_encoding(@io.encoding)
255
+ yield code, @line_no
256
+ end
257
+ @line_no += code.count("\n")
258
+ rescue TerminateLineInput
276
259
  end
277
- code = @line + (line.nil? ? '' : line)
278
- code.gsub!(/\s*\z/, '').concat("\n")
279
- @tokens = self.class.ripper_lex_without_warning(code, context: @context)
280
- @ltype, @indent, @continue, @code_block_open = check_state(code, @tokens)
281
- line
282
260
  end
283
261
 
284
262
  def process_continue(tokens)
data/lib/irb/version.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  #
6
6
 
7
7
  module IRB # :nodoc:
8
- VERSION = "1.6.3"
8
+ VERSION = "1.7.0"
9
9
  @RELEASE_VERSION = VERSION
10
- @LAST_UPDATE_DATE = "2023-03-06"
10
+ @LAST_UPDATE_DATE = "2023-06-03"
11
11
  end
data/lib/irb.rb CHANGED
@@ -416,11 +416,6 @@ module IRB
416
416
  irb.run(@CONF)
417
417
  end
418
418
 
419
- # Calls each event hook of <code>IRB.conf[:AT_EXIT]</code> when the current session quits.
420
- def IRB.irb_at_exit
421
- @CONF[:AT_EXIT].each{|hook| hook.call}
422
- end
423
-
424
419
  # Quits irb
425
420
  def IRB.irb_exit(irb, ret)
426
421
  throw :IRB_EXIT, ret
@@ -542,7 +537,7 @@ module IRB
542
537
  @context.io.prompt
543
538
  end
544
539
 
545
- @scanner.set_input(@context.io) do
540
+ @scanner.set_input do
546
541
  signal_status(:IN_INPUT) do
547
542
  if l = @context.io.gets
548
543
  print l if @context.verbose?
@@ -560,12 +555,11 @@ module IRB
560
555
  end
561
556
  end
562
557
 
563
- @scanner.set_auto_indent
558
+ @scanner.configure_io(@context.io)
564
559
 
565
560
  @scanner.each_top_level_statement do |line, line_no|
566
561
  signal_status(:IN_EVAL) do
567
562
  begin
568
- line.untaint if RUBY_VERSION < '2.7'
569
563
  if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
570
564
  IRB.set_measure_callback
571
565
  end
@@ -897,11 +891,6 @@ module IRB
897
891
  ensure
898
892
  $VERBOSE = verbose
899
893
  end
900
-
901
- ATTR_TTY = "\e[%sm"
902
- def ATTR_TTY.[](*a) self % a.join(";"); end
903
- ATTR_PLAIN = ""
904
- def ATTR_PLAIN.[](*) self; end
905
894
  end
906
895
 
907
896
  def @CONF.inspect
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: irb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.3
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-03-07 00:00:00.000000000 Z
12
+ date: 2023-06-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: reline
@@ -66,6 +66,7 @@ files:
66
66
  - lib/irb/cmd/nop.rb
67
67
  - lib/irb/cmd/pushws.rb
68
68
  - lib/irb/cmd/show_cmds.rb
69
+ - lib/irb/cmd/show_doc.rb
69
70
  - lib/irb/cmd/show_source.rb
70
71
  - lib/irb/cmd/step.rb
71
72
  - lib/irb/cmd/subirb.rb
@@ -91,11 +92,9 @@ files:
91
92
  - lib/irb/inspector.rb
92
93
  - lib/irb/lc/error.rb
93
94
  - lib/irb/lc/help-message
94
- - lib/irb/lc/ja/encoding_aliases.rb
95
95
  - lib/irb/lc/ja/error.rb
96
96
  - lib/irb/lc/ja/help-message
97
97
  - lib/irb/locale.rb
98
- - lib/irb/magic-file.rb
99
98
  - lib/irb/notifier.rb
100
99
  - lib/irb/output-method.rb
101
100
  - lib/irb/ruby-lex.rb
@@ -123,14 +122,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
122
  requirements:
124
123
  - - ">="
125
124
  - !ruby/object:Gem::Version
126
- version: '2.6'
125
+ version: '2.7'
127
126
  required_rubygems_version: !ruby/object:Gem::Requirement
128
127
  requirements:
129
128
  - - ">="
130
129
  - !ruby/object:Gem::Version
131
130
  version: '0'
132
131
  requirements: []
133
- rubygems_version: 3.4.1
132
+ rubygems_version: 3.5.0.dev
134
133
  signing_key:
135
134
  specification_version: 4
136
135
  summary: Interactive Ruby command-line tool for REPL (Read Eval Print Loop).
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: false
2
- module IRB
3
- # :stopdoc:
4
-
5
- class Locale
6
- @@legacy_encoding_alias_map = {
7
- 'ujis' => Encoding::EUC_JP,
8
- 'euc' => Encoding::EUC_JP
9
- }.freeze
10
- end
11
-
12
- # :startdoc:
13
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: false
2
- module IRB
3
- class << (MagicFile = Object.new)
4
- # see parser_magic_comment in parse.y
5
- ENCODING_SPEC_RE = %r"coding\s*[=:]\s*([[:alnum:]\-_]+)"
6
-
7
- def open(path)
8
- io = File.open(path, 'rb')
9
- line = io.gets
10
- line = io.gets if line[0,2] == "#!"
11
- encoding = detect_encoding(line)
12
- internal_encoding = encoding
13
- encoding ||= IRB.default_src_encoding
14
- io.rewind
15
- io.set_encoding(encoding, internal_encoding)
16
-
17
- if block_given?
18
- begin
19
- return (yield io)
20
- ensure
21
- io.close
22
- end
23
- else
24
- return io
25
- end
26
- end
27
-
28
- private
29
- def detect_encoding(line)
30
- return unless line[0] == ?#
31
- line = line[1..-1]
32
- line = $1 if line[/-\*-\s*(.*?)\s*-*-$/]
33
- return nil unless ENCODING_SPEC_RE =~ line
34
- encoding = $1
35
- return encoding.sub(/-(?:mac|dos|unix)/i, '')
36
- end
37
- end
38
- end