irb 1.2.9 → 1.3.4

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: cb526faa67bbfaad97480a6e642dc161725c6c444dcb6e6080498fae665173a6
4
- data.tar.gz: 58c89d71946d694826f2409eaf4a49ed88644bf640564e2f3a6c9ab3d8e9c0e1
3
+ metadata.gz: e897a7306cd4fde4a54fa2cc4c8dff34ccf4ecd5e69e324d9c91901c9a683cde
4
+ data.tar.gz: d424e3853889fef65b7e01df7d58e27bbd7467e081c733d7937aadde0544f4e9
5
5
  SHA512:
6
- metadata.gz: 9e101c1374b8ea161ec76217739ce5dbcd93c9e85e3cc147852717634085b97e5bd1aa71a9a6c316a660e9c60f0d16a03d08c26e7b7e65bdbb44886295bfa8dd
7
- data.tar.gz: 6243fb79d8747f0c507ebbd7e3f4efd486b3848ea7b2bf4db5ee4bb48591ee20857bcf5d86f61520c7d17b1d9307dc28a2ac785a64dda83ba1c78ebff90d53b6
6
+ metadata.gz: 77001229102437b40664c561a4b2ef1f5672e2e82661332be8a9f770356640a7de588b17c6d66164edbcd504158effd2b075b58172b2863b3862aa8735a1a72f
7
+ data.tar.gz: f83d98526ea74c4f015c85377f3c8d569a4d2a1f507331db80c41ab2225d4512c8ad6937d9bb90f703b7c95c214cb36e2f1c1e5107bed62554ecf2ba2cc2aa91
data/irb.gemspec CHANGED
@@ -32,11 +32,14 @@ Gem::Specification.new do |spec|
32
32
  "lib/irb/cmd/chws.rb",
33
33
  "lib/irb/cmd/fork.rb",
34
34
  "lib/irb/cmd/help.rb",
35
+ "lib/irb/cmd/info.rb",
35
36
  "lib/irb/cmd/load.rb",
37
+ "lib/irb/cmd/measure.rb",
36
38
  "lib/irb/cmd/nop.rb",
37
39
  "lib/irb/cmd/pushws.rb",
38
40
  "lib/irb/cmd/subirb.rb",
39
41
  "lib/irb/color.rb",
42
+ "lib/irb/color_printer.rb",
40
43
  "lib/irb/completion.rb",
41
44
  "lib/irb/context.rb",
42
45
  "lib/irb/easter-egg.rb",
data/lib/irb.rb CHANGED
@@ -525,7 +525,7 @@ module IRB
525
525
  printf "Use \"exit\" to leave %s\n", @context.ap_name
526
526
  end
527
527
  else
528
- print "\n"
528
+ print "\n" if @context.prompting?
529
529
  end
530
530
  end
531
531
  l
@@ -574,10 +574,35 @@ module IRB
574
574
  next
575
575
  end
576
576
  handle_exception(exc)
577
+ @context.workspace.local_variable_set(:_, exc)
578
+ exc = nil
577
579
  end
578
580
  end
579
581
  end
580
582
 
583
+ def convert_invalid_byte_sequence(str)
584
+ str = str.force_encoding(Encoding::ASCII_8BIT)
585
+ conv = Encoding::Converter.new(Encoding::ASCII_8BIT, Encoding::UTF_8)
586
+ dst = String.new
587
+ begin
588
+ ret = conv.primitive_convert(str, dst)
589
+ case ret
590
+ when :invalid_byte_sequence
591
+ conv.insert_output(conf.primitive_errinfo[3].dump[1..-2])
592
+ redo
593
+ when :undefined_conversion
594
+ c = conv.primitive_errinfo[3].dup.force_encoding(conv.primitive_errinfo[1])
595
+ conv.insert_output(c.dump[1..-2])
596
+ redo
597
+ when :incomplete_input
598
+ conv.insert_output(conv.primitive_errinfo[3].dump[1..-2])
599
+ when :finished
600
+ end
601
+ break
602
+ end while nil
603
+ dst
604
+ end
605
+
581
606
  def handle_exception(exc)
582
607
  if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
583
608
  !(SyntaxError === exc) && !(EncodingError === exc)
@@ -587,49 +612,44 @@ module IRB
587
612
  irb_bug = false
588
613
  end
589
614
 
590
- if STDOUT.tty?
591
- attr = ATTR_TTY
592
- print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n"
593
- else
594
- attr = ATTR_PLAIN
595
- end
596
- messages = []
597
- lasts = []
598
- levels = 0
599
615
  if exc.backtrace
600
- count = 0
601
- exc.backtrace.each do |m|
602
- m = @context.workspace.filter_backtrace(m) or next unless irb_bug
603
- count += 1
604
- if attr == ATTR_TTY
605
- m = sprintf("%9d: from %s", count, m)
616
+ order = nil
617
+ if '2.5.0' == RUBY_VERSION
618
+ # Exception#full_message doesn't have keyword arguments.
619
+ message = exc.full_message # the same of (highlight: true, order: bottom)
620
+ order = :bottom
621
+ elsif '2.5.1' <= RUBY_VERSION && RUBY_VERSION < '3.0.0'
622
+ if STDOUT.tty?
623
+ message = exc.full_message(order: :bottom)
624
+ order = :bottom
606
625
  else
607
- m = "\tfrom #{m}"
608
- end
609
- if messages.size < @context.back_trace_limit
610
- messages.push(m)
611
- elsif lasts.size < @context.back_trace_limit
612
- lasts.push(m).shift
613
- levels += 1
626
+ message = exc.full_message(order: :top)
627
+ order = :top
614
628
  end
629
+ else # '3.0.0' <= RUBY_VERSION
630
+ message = exc.full_message(order: :top)
631
+ order = :top
615
632
  end
616
- end
617
- if attr == ATTR_TTY
618
- unless lasts.empty?
619
- puts lasts.reverse
620
- printf "... %d levels...\n", levels if levels > 0
621
- end
622
- puts messages.reverse
623
- end
624
- m = exc.to_s.split(/\n/)
625
- print "#{attr[1]}#{exc.class} (#{attr[4]}#{m.shift}#{attr[0, 1]})#{attr[]}\n"
626
- puts m.map {|s| "#{attr[1]}#{s}#{attr[]}\n"}
627
- if attr == ATTR_PLAIN
628
- puts messages
629
- unless lasts.empty?
630
- puts lasts
631
- printf "... %d levels...\n", levels if levels > 0
632
- end
633
+ message = convert_invalid_byte_sequence(message)
634
+ message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
635
+ case order
636
+ when :top
637
+ lines = m.split("\n")
638
+ when :bottom
639
+ lines = m.split("\n").reverse
640
+ end
641
+ unless irb_bug
642
+ lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact
643
+ if lines.size > @context.back_trace_limit
644
+ omit = lines.size - @context.back_trace_limit
645
+ lines = lines[0..(@context.back_trace_limit - 1)]
646
+ lines << "\t... %d levels..." % omit
647
+ end
648
+ end
649
+ lines = lines.reverse if order == :bottom
650
+ lines.map{ |l| l + "\n" }.join
651
+ }
652
+ puts message
633
653
  end
634
654
  print "Maybe IRB bug!\n" if irb_bug
635
655
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative "nop"
4
+
5
+ # :stopdoc:
6
+ module IRB
7
+ module ExtendCommand
8
+ class Info < Nop
9
+ def execute
10
+ Class.new {
11
+ def inspect
12
+ str = "Ruby version: #{RUBY_VERSION}\n"
13
+ str += "IRB version: #{IRB.version}\n"
14
+ str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
15
+ str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
16
+ str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
17
+ str
18
+ end
19
+ alias_method :to_s, :inspect
20
+ }.new
21
+ end
22
+ end
23
+ end
24
+ end
25
+ # :startdoc:
@@ -0,0 +1,40 @@
1
+ require_relative "nop"
2
+
3
+ # :stopdoc:
4
+ module IRB
5
+ module ExtendCommand
6
+ class Measure < Nop
7
+ def initialize(*args)
8
+ super(*args)
9
+ end
10
+
11
+ def execute(type = nil, arg = nil, &block)
12
+ case type
13
+ when :off
14
+ IRB.conf[:MEASURE] = nil
15
+ IRB.unset_measure_callback(arg)
16
+ when :list
17
+ IRB.conf[:MEASURE_CALLBACKS].each do |type_name, _, arg_val|
18
+ puts "- #{type_name}" + (arg_val ? "(#{arg_val.inspect})" : '')
19
+ end
20
+ when :on
21
+ IRB.conf[:MEASURE] = true
22
+ added = IRB.set_measure_callback(type, arg)
23
+ puts "#{added[0]} is added." if added
24
+ else
25
+ if block_given?
26
+ IRB.conf[:MEASURE] = true
27
+ added = IRB.set_measure_callback(&block)
28
+ puts "#{added[0]} is added." if added
29
+ else
30
+ IRB.conf[:MEASURE] = true
31
+ added = IRB.set_measure_callback(type, arg)
32
+ puts "#{added[0]} is added." if added
33
+ end
34
+ end
35
+ nil
36
+ end
37
+ end
38
+ end
39
+ end
40
+ # :startdoc:
data/lib/irb/cmd/nop.rb CHANGED
@@ -15,9 +15,9 @@ module IRB
15
15
  class Nop
16
16
 
17
17
 
18
- def self.execute(conf, *opts)
18
+ def self.execute(conf, *opts, &block)
19
19
  command = new(conf)
20
- command.execute(*opts)
20
+ command.execute(*opts, &block)
21
21
  end
22
22
 
23
23
  def initialize(conf)
data/lib/irb/color.rb CHANGED
@@ -17,7 +17,7 @@ module IRB # :nodoc:
17
17
  CYAN = 36
18
18
 
19
19
  TOKEN_KEYWORDS = {
20
- on_kw: ['nil', 'self', 'true', 'false', '__FILE__', '__LINE__'],
20
+ on_kw: ['nil', 'self', 'true', 'false', '__FILE__', '__LINE__', '__ENCODING__'],
21
21
  on_const: ['ENV'],
22
22
  }
23
23
  private_constant :TOKEN_KEYWORDS
@@ -60,6 +60,10 @@ module IRB # :nodoc:
60
60
  on_words_beg: [[RED, BOLD], ALL],
61
61
  on_parse_error: [[RED, REVERSE], ALL],
62
62
  compile_error: [[RED, REVERSE], ALL],
63
+ on_assign_error: [[RED, REVERSE], ALL],
64
+ on_alias_error: [[RED, REVERSE], ALL],
65
+ on_class_name_error:[[RED, REVERSE], ALL],
66
+ on_param_error: [[RED, REVERSE], ALL],
63
67
  }
64
68
  rescue NameError
65
69
  # Give up highlighting Ripper-incompatible older Ruby
@@ -67,6 +71,9 @@ module IRB # :nodoc:
67
71
  end
68
72
  private_constant :TOKEN_SEQ_EXPRS
69
73
 
74
+ ERROR_TOKENS = TOKEN_SEQ_EXPRS.keys.select { |k| k.to_s.end_with?('error') }
75
+ private_constant :ERROR_TOKENS
76
+
70
77
  class << self
71
78
  def colorable?
72
79
  $stdout.tty? && supported? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
@@ -107,7 +114,7 @@ module IRB # :nodoc:
107
114
  # If `complete` is false (code is incomplete), this does not warn compile_error.
108
115
  # This option is needed to avoid warning a user when the compile_error is happening
109
116
  # because the input is not wrong but just incomplete.
110
- def colorize_code(code, complete: true)
117
+ def colorize_code(code, complete: true, ignore_error: false)
111
118
  return code unless colorable?
112
119
 
113
120
  symbol_state = SymbolState.new
@@ -115,6 +122,11 @@ module IRB # :nodoc:
115
122
  length = 0
116
123
 
117
124
  scan(code, allow_last_error: !complete) do |token, str, expr|
125
+ # IRB::ColorPrinter skips colorizing fragments with any invalid token
126
+ if ignore_error && ERROR_TOKENS.include?(token)
127
+ return Reline::Unicode.escape_for_print(code)
128
+ end
129
+
118
130
  in_symbol = symbol_state.scan_token(token)
119
131
  str.each_line do |line|
120
132
  line = Reline::Unicode.escape_for_print(line)
@@ -180,11 +192,12 @@ module IRB # :nodoc:
180
192
  end
181
193
  end
182
194
  end
195
+ ensure
183
196
  $VERBOSE = verbose
184
197
  end
185
198
 
186
199
  def dispatch_seq(token, expr, str, in_symbol:)
187
- if token == :on_parse_error or token == :compile_error
200
+ if ERROR_TOKENS.include?(token)
188
201
  TOKEN_SEQ_EXPRS[token][0]
189
202
  elsif in_symbol
190
203
  [YELLOW]
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ require 'pp'
3
+ require 'irb/color'
4
+
5
+ module IRB
6
+ class ColorPrinter < ::PP
7
+ class << self
8
+ def pp(obj, out = $>, width = screen_width)
9
+ q = ColorPrinter.new(out, width)
10
+ q.guard_inspect_key {q.pp obj}
11
+ q.flush
12
+ out << "\n"
13
+ end
14
+
15
+ private
16
+
17
+ def screen_width
18
+ Reline.get_screen_size.last
19
+ rescue Errno::EINVAL # in `winsize': Invalid argument - <STDIN>
20
+ 79
21
+ end
22
+ end
23
+
24
+ def text(str, width = nil)
25
+ unless str.is_a?(String)
26
+ str = str.inspect
27
+ end
28
+ width ||= str.length
29
+
30
+ case str
31
+ when /\A#</, '=', '>'
32
+ super(Color.colorize(str, [:GREEN]), width)
33
+ else
34
+ super(Color.colorize_code(str, ignore_error: true), width)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -47,7 +47,7 @@ module IRB
47
47
  when /^((["'`]).*\2)\.([^.]*)$/
48
48
  # String
49
49
  receiver = $1
50
- message = Regexp.quote($3)
50
+ message = $3
51
51
 
52
52
  candidates = String.instance_methods.collect{|m| m.to_s}
53
53
  if doc_namespace
@@ -59,7 +59,7 @@ module IRB
59
59
  when /^(\/[^\/]*\/)\.([^.]*)$/
60
60
  # Regexp
61
61
  receiver = $1
62
- message = Regexp.quote($2)
62
+ message = $2
63
63
 
64
64
  candidates = Regexp.instance_methods.collect{|m| m.to_s}
65
65
  if doc_namespace
@@ -71,7 +71,7 @@ module IRB
71
71
  when /^([^\]]*\])\.([^.]*)$/
72
72
  # Array
73
73
  receiver = $1
74
- message = Regexp.quote($2)
74
+ message = $2
75
75
 
76
76
  candidates = Array.instance_methods.collect{|m| m.to_s}
77
77
  if doc_namespace
@@ -83,7 +83,7 @@ module IRB
83
83
  when /^([^\}]*\})\.([^.]*)$/
84
84
  # Proc or Hash
85
85
  receiver = $1
86
- message = Regexp.quote($2)
86
+ message = $2
87
87
 
88
88
  proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
89
89
  hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
@@ -117,7 +117,7 @@ module IRB
117
117
  when /^([A-Z].*)::([^:.]*)$/
118
118
  # Constant or class methods
119
119
  receiver = $1
120
- message = Regexp.quote($2)
120
+ message = $2
121
121
  begin
122
122
  candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
123
123
  candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
@@ -134,7 +134,7 @@ module IRB
134
134
  # Symbol
135
135
  receiver = $1
136
136
  sep = $2
137
- message = Regexp.quote($3)
137
+ message = $3
138
138
 
139
139
  candidates = Symbol.instance_methods.collect{|m| m.to_s}
140
140
  if doc_namespace
@@ -147,7 +147,7 @@ module IRB
147
147
  # Numeric
148
148
  receiver = $~[:num]
149
149
  sep = $~[:sep]
150
- message = Regexp.quote($~[:mes])
150
+ message = $~[:mes]
151
151
 
152
152
  begin
153
153
  instance = eval(receiver, bind)
@@ -169,7 +169,7 @@ module IRB
169
169
  # Numeric(0xFFFF)
170
170
  receiver = $1
171
171
  sep = $2
172
- message = Regexp.quote($3)
172
+ message = $3
173
173
 
174
174
  begin
175
175
  instance = eval(receiver, bind)
@@ -201,7 +201,7 @@ module IRB
201
201
  # variable.func or func.func
202
202
  receiver = $1
203
203
  sep = $2
204
- message = Regexp.quote($3)
204
+ message = $3
205
205
 
206
206
  gv = eval("global_variables", bind).collect{|m| m.to_s}.push("true", "false", "nil")
207
207
  lv = eval("local_variables", bind).collect{|m| m.to_s}
@@ -244,7 +244,7 @@ module IRB
244
244
  # unknown(maybe String)
245
245
 
246
246
  receiver = ""
247
- message = Regexp.quote($1)
247
+ message = $1
248
248
 
249
249
  candidates = String.instance_methods(true).collect{|m| m.to_s}
250
250
  if doc_namespace
@@ -294,7 +294,7 @@ module IRB
294
294
  Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
295
295
 
296
296
  def self.select_message(receiver, message, candidates, sep = ".")
297
- candidates.grep(/^#{message}/).collect do |e|
297
+ candidates.grep(/^#{Regexp.quote(message)}/).collect do |e|
298
298
  case e
299
299
  when /^[a-zA-Z_]/
300
300
  receiver + sep + e
@@ -31,8 +31,31 @@ module IRB # :nodoc:
31
31
  load_file(path, priv)
32
32
  end
33
33
 
34
+ if File.respond_to?(:absolute_path?)
35
+ def absolute_path?(path)
36
+ File.absolute_path?(path)
37
+ end
38
+ else
39
+ separator =
40
+ if File::ALT_SEPARATOR
41
+ "[#{Regexp.quote(File::SEPARATOR + File::ALT_SEPARATOR)}]"
42
+ else
43
+ File::SEPARATOR
44
+ end
45
+ ABSOLUTE_PATH_PATTERN = # :nodoc:
46
+ case Dir.pwd
47
+ when /\A\w:/, /\A#{separator}{2}/
48
+ /\A(?:\w:|#{separator})#{separator}/
49
+ else
50
+ /\A#{separator}/
51
+ end
52
+ def absolute_path?(path)
53
+ ABSOLUTE_PATH_PATTERN =~ path
54
+ end
55
+ end
56
+
34
57
  def search_file_from_ruby_path(fn) # :nodoc:
35
- if /^#{Regexp.quote(File::Separator)}/ =~ fn
58
+ if absolute_path?(fn)
36
59
  return fn if File.exist?(fn)
37
60
  return nil
38
61
  end
@@ -50,16 +73,18 @@ module IRB # :nodoc:
50
73
  # See Irb#suspend_input_method for more information.
51
74
  def source_file(path)
52
75
  irb.suspend_name(path, File.basename(path)) do
53
- irb.suspend_input_method(FileInputMethod.new(path)) do
54
- |back_io|
55
- irb.signal_status(:IN_LOAD) do
56
- if back_io.kind_of?(FileInputMethod)
57
- irb.eval_input
58
- else
59
- begin
76
+ FileInputMethod.open(path) do |io|
77
+ irb.suspend_input_method(io) do
78
+ |back_io|
79
+ irb.signal_status(:IN_LOAD) do
80
+ if back_io.kind_of?(FileInputMethod)
60
81
  irb.eval_input
61
- rescue LoadAbort
62
- print "load abort!!\n"
82
+ else
83
+ begin
84
+ irb.eval_input
85
+ rescue LoadAbort
86
+ print "load abort!!\n"
87
+ end
63
88
  end
64
89
  end
65
90
  end
@@ -79,16 +104,18 @@ module IRB # :nodoc:
79
104
  ws = WorkSpace.new
80
105
  end
81
106
  irb.suspend_workspace(ws) do
82
- irb.suspend_input_method(FileInputMethod.new(path)) do
83
- |back_io|
84
- irb.signal_status(:IN_LOAD) do
85
- if back_io.kind_of?(FileInputMethod)
86
- irb.eval_input
87
- else
88
- begin
107
+ FileInputMethod.open(path) do |io|
108
+ irb.suspend_input_method(io) do
109
+ |back_io|
110
+ irb.signal_status(:IN_LOAD) do
111
+ if back_io.kind_of?(FileInputMethod)
89
112
  irb.eval_input
90
- rescue LoadAbort
91
- print "load abort!!\n"
113
+ else
114
+ begin
115
+ irb.eval_input
116
+ rescue LoadAbort
117
+ print "load abort!!\n"
118
+ end
92
119
  end
93
120
  end
94
121
  end
@@ -177,9 +177,9 @@ module IRB # :nodoc:
177
177
  args << "&block"
178
178
  args = args.join(", ")
179
179
  line = __LINE__; eval %[
180
- unless self.class.class_variable_defined?(:@@#{cmd_name}_)
181
- self.class.class_variable_set(:@@#{cmd_name}_, true)
182
- def #{cmd_name}_(\#{args})
180
+ unless singleton_class.class_variable_defined?(:@@#{cmd_name}_)
181
+ singleton_class.class_variable_set(:@@#{cmd_name}_, true)
182
+ def self.#{cmd_name}_(\#{args})
183
183
  ExtendCommand::#{cmd_class}.execute(irb_context, \#{args})
184
184
  end
185
185
  end
data/lib/irb/init.rb CHANGED
@@ -146,7 +146,7 @@ module IRB # :nodoc:
146
146
  @CONF[:AT_EXIT] = []
147
147
  end
148
148
 
149
- def IRB.set_measure_callback(type = nil, arg = nil)
149
+ def IRB.set_measure_callback(type = nil, arg = nil, &block)
150
150
  added = nil
151
151
  if type
152
152
  type_sym = type.upcase.to_sym
@@ -155,11 +155,31 @@ module IRB # :nodoc:
155
155
  end
156
156
  elsif IRB.conf[:MEASURE_PROC][:CUSTOM]
157
157
  added = [:CUSTOM, IRB.conf[:MEASURE_PROC][:CUSTOM], arg]
158
+ elsif block_given?
159
+ added = [:BLOCK, block, arg]
160
+ found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] }
161
+ if found
162
+ found[1] = block
163
+ return added
164
+ else
165
+ IRB.conf[:MEASURE_CALLBACKS] << added
166
+ return added
167
+ end
158
168
  else
159
169
  added = [:TIME, IRB.conf[:MEASURE_PROC][:TIME], arg]
160
170
  end
161
- IRB.conf[:MEASURE_CALLBACKS] << added if added
162
- added
171
+ if added
172
+ found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] }
173
+ if found
174
+ # already added
175
+ nil
176
+ else
177
+ IRB.conf[:MEASURE_CALLBACKS] << added if added
178
+ added
179
+ end
180
+ else
181
+ nil
182
+ end
163
183
  end
164
184
 
165
185
  def IRB.unset_measure_callback(type = nil)
@@ -83,7 +83,15 @@ module IRB
83
83
  #
84
84
  # See IO#eof? for more information.
85
85
  def eof?
86
- @stdin.eof?
86
+ rs, = IO.select([@stdin], [], [], 0.00001)
87
+ if rs and rs[0]
88
+ c = @stdin.getc
89
+ result = c.nil? ? true : false
90
+ @stdin.ungetc(c) unless c.nil?
91
+ result
92
+ else # buffer is empty
93
+ false
94
+ end
87
95
  end
88
96
 
89
97
  # Whether this input method is still readable when there is no more data to
@@ -116,10 +124,22 @@ module IRB
116
124
 
117
125
  # Use a File for IO with irb, see InputMethod
118
126
  class FileInputMethod < InputMethod
127
+ class << self
128
+ def open(file, &block)
129
+ begin
130
+ io = new(file)
131
+ block.call(io)
132
+ ensure
133
+ io&.close
134
+ end
135
+ end
136
+ end
137
+
119
138
  # Creates a new input method object
120
139
  def initialize(file)
121
140
  super
122
141
  @io = IRB::MagicFile.open(file)
142
+ @external_encoding = @io.external_encoding
123
143
  end
124
144
  # The file name of this input method, usually given during initialization.
125
145
  attr_reader :file_name
@@ -129,7 +149,7 @@ module IRB
129
149
  #
130
150
  # See IO#eof? for more information.
131
151
  def eof?
132
- @io.eof?
152
+ @io.closed? || @io.eof?
133
153
  end
134
154
 
135
155
  # Reads the next line from this input method.
@@ -142,13 +162,17 @@ module IRB
142
162
 
143
163
  # The external encoding for standard input.
144
164
  def encoding
145
- @io.external_encoding
165
+ @external_encoding
146
166
  end
147
167
 
148
168
  # For debug message
149
169
  def inspect
150
170
  'FileInputMethod'
151
171
  end
172
+
173
+ def close
174
+ @io.close
175
+ end
152
176
  end
153
177
 
154
178
  begin
data/lib/irb/inspector.rb CHANGED
@@ -100,29 +100,27 @@ module IRB # :nodoc:
100
100
  # Proc to call when the input is evaluated and output in irb.
101
101
  def inspect_value(v)
102
102
  @inspect.call(v)
103
+ rescue
104
+ puts "(Object doesn't support #inspect)"
105
+ ''
103
106
  end
104
107
  end
105
108
 
106
109
  Inspector.def_inspector([false, :to_s, :raw]){|v| v.to_s}
107
- Inspector.def_inspector([true, :p, :inspect]){|v|
108
- begin
109
- result = v.inspect
110
- if IRB.conf[:MAIN_CONTEXT]&.use_colorize? && Color.inspect_colorable?(v)
111
- result = Color.colorize_code(result)
112
- end
113
- result
114
- rescue NoMethodError
115
- puts "(Object doesn't support #inspect)"
116
- ''
117
- end
118
- }
119
- Inspector.def_inspector([:pp, :pretty_inspect], proc{require "pp"}){|v|
120
- result = v.pretty_inspect.chomp
110
+ Inspector.def_inspector([:p, :inspect]){|v|
111
+ result = v.inspect
121
112
  if IRB.conf[:MAIN_CONTEXT]&.use_colorize? && Color.inspect_colorable?(v)
122
113
  result = Color.colorize_code(result)
123
114
  end
124
115
  result
125
116
  }
117
+ Inspector.def_inspector([true, :pp, :pretty_inspect], proc{require "irb/color_printer"}){|v|
118
+ if IRB.conf[:MAIN_CONTEXT]&.use_colorize?
119
+ IRB::ColorPrinter.pp(v, '').chomp
120
+ else
121
+ v.pretty_inspect.chomp
122
+ end
123
+ }
126
124
  Inspector.def_inspector([:yaml, :YAML], proc{require "yaml"}){|v|
127
125
  begin
128
126
  YAML.dump(v)
data/lib/irb/ruby-lex.rb CHANGED
@@ -66,14 +66,19 @@ class RubyLex
66
66
  unprocessed_tokens = []
67
67
  line_num_offset = 0
68
68
  tokens.each do |t|
69
- code << t[2]
70
69
  partial_tokens << t
71
70
  unprocessed_tokens << t
72
71
  if t[2].include?("\n")
73
- ltype, indent, continue, code_block_open = check_state(code, partial_tokens)
74
- result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
75
- line_num_offset += 1
72
+ t_str = t[2]
73
+ t_str.each_line("\n") do |s|
74
+ code << s << "\n"
75
+ ltype, indent, continue, code_block_open = check_state(code, partial_tokens)
76
+ result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
77
+ line_num_offset += 1
78
+ end
76
79
  unprocessed_tokens = []
80
+ else
81
+ code << t[2]
77
82
  end
78
83
  end
79
84
  unless unprocessed_tokens.empty?
@@ -101,24 +106,72 @@ class RubyLex
101
106
  end
102
107
  end
103
108
 
109
+ ERROR_TOKENS = [
110
+ :on_parse_error,
111
+ :compile_error,
112
+ :on_assign_error,
113
+ :on_alias_error,
114
+ :on_class_name_error,
115
+ :on_param_error
116
+ ]
117
+
104
118
  def ripper_lex_without_warning(code)
105
119
  verbose, $VERBOSE = $VERBOSE, nil
106
120
  tokens = nil
107
121
  self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
108
- tokens = Ripper.lex(inner_code, '-', line_no)
122
+ lexer = Ripper::Lexer.new(inner_code, '-', line_no)
123
+ if lexer.respond_to?(:scan) # Ruby 2.7+
124
+ tokens = []
125
+ pos_to_index = {}
126
+ lexer.scan.each do |t|
127
+ if pos_to_index.has_key?(t[0])
128
+ index = pos_to_index[t[0]]
129
+ found_tk = tokens[index]
130
+ if ERROR_TOKENS.include?(found_tk[1]) && !ERROR_TOKENS.include?(t[1])
131
+ tokens[index] = t
132
+ end
133
+ else
134
+ pos_to_index[t[0]] = tokens.size
135
+ tokens << t
136
+ end
137
+ end
138
+ else
139
+ tokens = lexer.parse
140
+ end
109
141
  end
110
- $VERBOSE = verbose
111
142
  tokens
143
+ ensure
144
+ $VERBOSE = verbose
145
+ end
146
+
147
+ def find_prev_spaces(line_index)
148
+ return 0 if @tokens.size == 0
149
+ md = @tokens[0][2].match(/(\A +)/)
150
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
151
+ line_count = 0
152
+ @tokens.each_with_index do |t, i|
153
+ if t[2].include?("\n")
154
+ line_count += t[2].count("\n")
155
+ if line_count >= line_index
156
+ return prev_spaces
157
+ end
158
+ if (@tokens.size - 1) > i
159
+ md = @tokens[i + 1][2].match(/(\A +)/)
160
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
161
+ end
162
+ end
163
+ end
164
+ prev_spaces
112
165
  end
113
166
 
114
167
  def set_auto_indent(context)
115
168
  if @io.respond_to?(:auto_indent) and context.auto_indent_mode
116
169
  @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
117
170
  if is_newline
118
- md = lines[line_index - 1].match(/(\A +)/)
119
- prev_spaces = md.nil? ? 0 : md[1].count(' ')
120
171
  @tokens = ripper_lex_without_warning(lines[0..line_index].join("\n"))
172
+ prev_spaces = find_prev_spaces(line_index)
121
173
  depth_difference = check_newline_depth_difference
174
+ depth_difference = 0 if depth_difference < 0
122
175
  prev_spaces + depth_difference * 2
123
176
  else
124
177
  code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
@@ -170,7 +223,10 @@ class RubyLex
170
223
  throw :TERM_INPUT if @line == ''
171
224
  else
172
225
  @line_no += l.count("\n")
173
- next if l == "\n"
226
+ if l == "\n"
227
+ @exp_line_no += 1
228
+ next
229
+ end
174
230
  @line.concat l
175
231
  if @code_block_open or @ltype or @continue or @indent > 0
176
232
  next
@@ -180,7 +236,7 @@ class RubyLex
180
236
  @line.force_encoding(@io.encoding)
181
237
  yield @line, @exp_line_no
182
238
  end
183
- break if @io.eof?
239
+ raise TerminateLineInput if @io.eof?
184
240
  @line = ''
185
241
  @exp_line_no = @line_no
186
242
 
@@ -355,14 +411,8 @@ class RubyLex
355
411
  next if index > 0 and tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
356
412
  case t[2]
357
413
  when 'do'
358
- if index > 0 and tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG)
359
- # method_with_block do; end
360
- indent += 1
361
- else
362
- # while cond do; end # also "until" or "for"
363
- # This "do" doesn't increment indent because "while" already
364
- # incremented.
365
- end
414
+ syntax_of_do = take_corresponding_syntax_to_kw_do(tokens, index)
415
+ indent += 1 if syntax_of_do == :method_calling
366
416
  when 'def', 'case', 'for', 'begin', 'class', 'module'
367
417
  indent += 1
368
418
  when 'if', 'unless', 'while', 'until'
@@ -377,6 +427,83 @@ class RubyLex
377
427
  indent
378
428
  end
379
429
 
430
+ def is_method_calling?(tokens, index)
431
+ tk = tokens[index]
432
+ if tk[3].anybits?(Ripper::EXPR_CMDARG) and tk[1] == :on_ident
433
+ # The target method call to pass the block with "do".
434
+ return true
435
+ elsif tk[3].anybits?(Ripper::EXPR_ARG) and tk[1] == :on_ident
436
+ non_sp_index = tokens[0..(index - 1)].rindex{ |t| t[1] != :on_sp }
437
+ if non_sp_index
438
+ prev_tk = tokens[non_sp_index]
439
+ if prev_tk[3].anybits?(Ripper::EXPR_DOT) and prev_tk[1] == :on_period
440
+ # The target method call with receiver to pass the block with "do".
441
+ return true
442
+ end
443
+ end
444
+ end
445
+ false
446
+ end
447
+
448
+ def take_corresponding_syntax_to_kw_do(tokens, index)
449
+ syntax_of_do = nil
450
+ # Finding a syntax correnponding to "do".
451
+ index.downto(0) do |i|
452
+ tk = tokens[i]
453
+ # In "continue", the token isn't the corresponding syntax to "do".
454
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t[1] != :on_sp }
455
+ first_in_fomula = false
456
+ if non_sp_index.nil?
457
+ first_in_fomula = true
458
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index][1])
459
+ first_in_fomula = true
460
+ end
461
+ if is_method_calling?(tokens, i)
462
+ syntax_of_do = :method_calling
463
+ break if first_in_fomula
464
+ elsif tk[1] == :on_kw && %w{while until for}.include?(tk[2])
465
+ # A loop syntax in front of "do" found.
466
+ #
467
+ # while cond do # also "until" or "for"
468
+ # end
469
+ #
470
+ # This "do" doesn't increment indent because the loop syntax already
471
+ # incremented.
472
+ syntax_of_do = :loop_syntax
473
+ break if first_in_fomula
474
+ end
475
+ end
476
+ syntax_of_do
477
+ end
478
+
479
+ def is_the_in_correspond_to_a_for(tokens, index)
480
+ syntax_of_in = nil
481
+ # Finding a syntax correnponding to "do".
482
+ index.downto(0) do |i|
483
+ tk = tokens[i]
484
+ # In "continue", the token isn't the corresponding syntax to "do".
485
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t[1] != :on_sp }
486
+ first_in_fomula = false
487
+ if non_sp_index.nil?
488
+ first_in_fomula = true
489
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index][1])
490
+ first_in_fomula = true
491
+ end
492
+ if tk[1] == :on_kw && tk[2] == 'for'
493
+ # A loop syntax in front of "do" found.
494
+ #
495
+ # while cond do # also "until" or "for"
496
+ # end
497
+ #
498
+ # This "do" doesn't increment indent because the loop syntax already
499
+ # incremented.
500
+ syntax_of_in = :for
501
+ end
502
+ break if first_in_fomula
503
+ end
504
+ syntax_of_in
505
+ end
506
+
380
507
  def check_newline_depth_difference
381
508
  depth_difference = 0
382
509
  open_brace_on_line = 0
@@ -405,7 +532,7 @@ class RubyLex
405
532
 
406
533
  case t[1]
407
534
  when :on_ignored_nl, :on_nl, :on_comment
408
- if index != (@tokens.size - 1)
535
+ if index != (@tokens.size - 1) and in_oneliner_def != :BODY
409
536
  depth_difference = 0
410
537
  open_brace_on_line = 0
411
538
  end
@@ -423,14 +550,8 @@ class RubyLex
423
550
  next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
424
551
  case t[2]
425
552
  when 'do'
426
- if index > 0 and @tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG)
427
- # method_with_block do; end
428
- depth_difference += 1
429
- else
430
- # while cond do; end # also "until" or "for"
431
- # This "do" doesn't increment indent because "while" already
432
- # incremented.
433
- end
553
+ syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
554
+ depth_difference += 1 if syntax_of_do == :method_calling
434
555
  when 'def', 'case', 'for', 'begin', 'class', 'module'
435
556
  depth_difference += 1
436
557
  when 'if', 'unless', 'while', 'until', 'rescue'
@@ -438,8 +559,14 @@ class RubyLex
438
559
  unless t[3].allbits?(Ripper::EXPR_LABEL)
439
560
  depth_difference += 1
440
561
  end
441
- when 'else', 'elsif', 'ensure', 'when', 'in'
562
+ when 'else', 'elsif', 'ensure', 'when'
442
563
  depth_difference += 1
564
+ when 'in'
565
+ unless is_the_in_correspond_to_a_for(@tokens, index)
566
+ depth_difference += 1
567
+ end
568
+ when 'end'
569
+ depth_difference -= 1
443
570
  end
444
571
  end
445
572
  end
@@ -483,11 +610,13 @@ class RubyLex
483
610
 
484
611
  case t[1]
485
612
  when :on_ignored_nl, :on_nl, :on_comment
486
- corresponding_token_depth = nil
487
- spaces_at_line_head = 0
488
- is_first_spaces_of_line = true
489
- is_first_printable_of_line = true
490
- open_brace_on_line = 0
613
+ if in_oneliner_def != :BODY
614
+ corresponding_token_depth = nil
615
+ spaces_at_line_head = 0
616
+ is_first_spaces_of_line = true
617
+ is_first_printable_of_line = true
618
+ open_brace_on_line = 0
619
+ end
491
620
  next
492
621
  when :on_sp
493
622
  spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line
@@ -509,7 +638,12 @@ class RubyLex
509
638
  when :on_kw
510
639
  next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
511
640
  case t[2]
512
- when 'def', 'do', 'case', 'for', 'begin', 'class', 'module'
641
+ when 'do'
642
+ syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
643
+ if syntax_of_do == :method_calling
644
+ spaces_of_nest.push(spaces_at_line_head)
645
+ end
646
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
513
647
  spaces_of_nest.push(spaces_at_line_head)
514
648
  when 'rescue'
515
649
  unless t[3].allbits?(Ripper::EXPR_LABEL)
@@ -552,7 +686,7 @@ class RubyLex
552
686
  end_type << :on_regexp_end
553
687
  when :on_symbeg
554
688
  acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw}
555
- if (i + 1) < tokens.size and acceptable_single_tokens.all?{ |t| tokens[i + 1][1] != t }
689
+ if (i + 1) < tokens.size and acceptable_single_tokens.all?{ |st| tokens[i + 1][1] != st }
556
690
  start_token << t
557
691
  end_type << :on_tstring_end
558
692
  end
data/lib/irb/version.rb CHANGED
@@ -11,7 +11,7 @@
11
11
  #
12
12
 
13
13
  module IRB # :nodoc:
14
- VERSION = "1.2.9"
14
+ VERSION = "1.3.4"
15
15
  @RELEASE_VERSION = VERSION
16
- @LAST_UPDATE_DATE = "2020-12-22"
16
+ @LAST_UPDATE_DATE = "2021-02-25"
17
17
  end
data/lib/irb/workspace.rb CHANGED
@@ -128,6 +128,7 @@ EOF
128
128
  def filter_backtrace(bt)
129
129
  return nil if bt =~ /\/irb\/.*\.rb/
130
130
  return nil if bt =~ /\/irb\.rb/
131
+ return nil if bt =~ /tool\/lib\/.*\.rb|runner\.rb/ # for tests in Ruby repository
131
132
  case IRB.conf[:CONTEXT_MODE]
132
133
  when 1
133
134
  return nil if bt =~ %r!/tmp/irb-binding!
@@ -174,7 +175,7 @@ EOF
174
175
  body = (start_pos..end_pos).map do |current_pos|
175
176
  sprintf(fmt, pos == current_pos ? '=>' : '', current_pos + 1, lines[current_pos])
176
177
  end.join("")
177
- "\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n"
178
+ "\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear if use_colorize}\n"
178
179
  end
179
180
 
180
181
  def IRB.delete_caller
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: irb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.9
4
+ version: 1.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keiju ISHITSUKA
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-21 00:00:00.000000000 Z
11
+ date: 2021-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: reline
@@ -75,11 +75,14 @@ files:
75
75
  - lib/irb/cmd/chws.rb
76
76
  - lib/irb/cmd/fork.rb
77
77
  - lib/irb/cmd/help.rb
78
+ - lib/irb/cmd/info.rb
78
79
  - lib/irb/cmd/load.rb
80
+ - lib/irb/cmd/measure.rb
79
81
  - lib/irb/cmd/nop.rb
80
82
  - lib/irb/cmd/pushws.rb
81
83
  - lib/irb/cmd/subirb.rb
82
84
  - lib/irb/color.rb
85
+ - lib/irb/color_printer.rb
83
86
  - lib/irb/completion.rb
84
87
  - lib/irb/context.rb
85
88
  - lib/irb/easter-egg.rb
@@ -134,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
137
  - !ruby/object:Gem::Version
135
138
  version: '0'
136
139
  requirements: []
137
- rubygems_version: 3.1.4
140
+ rubygems_version: 3.0.6
138
141
  signing_key:
139
142
  specification_version: 4
140
143
  summary: Interactive Ruby command-line tool for REPL (Read Eval Print Loop).