irb 1.6.3 → 1.7.0

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.
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