irb 1.4.2 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/irb/ruby-lex.rb CHANGED
@@ -48,7 +48,7 @@ class RubyLex
48
48
  end
49
49
 
50
50
  # io functions
51
- def set_input(io, p = nil, context: nil, &block)
51
+ def set_input(io, p = nil, context:, &block)
52
52
  @io = io
53
53
  if @io.respond_to?(:check_termination)
54
54
  @io.check_termination do |code|
@@ -65,6 +65,12 @@ class RubyLex
65
65
  false
66
66
  end
67
67
  else
68
+ # Accept any single-line input for symbol aliases or commands that transform args
69
+ command = code.split(/\s/, 2).first
70
+ if context.symbol_alias?(command) || context.transform_args?(command)
71
+ next true
72
+ end
73
+
68
74
  code.gsub!(/\s*\z/, '').concat("\n")
69
75
  ltype, indent, continue, code_block_open = check_state(code, context: context)
70
76
  if ltype or indent > 0 or continue or code_block_open
@@ -136,16 +142,18 @@ class RubyLex
136
142
  :on_param_error
137
143
  ]
138
144
 
145
+ def self.generate_local_variables_assign_code(local_variables)
146
+ "#{local_variables.join('=')}=nil;" unless local_variables.empty?
147
+ end
148
+
139
149
  def self.ripper_lex_without_warning(code, context: nil)
140
150
  verbose, $VERBOSE = $VERBOSE, nil
141
- if context
142
- lvars = context.workspace&.binding&.local_variables
143
- if lvars && !lvars.empty?
144
- code = "#{lvars.join('=')}=nil\n#{code}"
145
- line_no = 0
146
- else
147
- line_no = 1
148
- end
151
+ lvars_code = generate_local_variables_assign_code(context&.local_variables || [])
152
+ if lvars_code
153
+ code = "#{lvars_code}\n#{code}"
154
+ line_no = 0
155
+ else
156
+ line_no = 1
149
157
  end
150
158
 
151
159
  compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
@@ -162,7 +170,7 @@ class RubyLex
162
170
  end
163
171
  end
164
172
  else
165
- lexer.parse.reject { |it| it.pos.first == 0 }
173
+ lexer.parse.reject { |it| it.pos.first == 0 }.sort_by(&:pos)
166
174
  end
167
175
  end
168
176
  ensure
@@ -214,6 +222,8 @@ class RubyLex
214
222
  ltype = process_literal_type(tokens)
215
223
  indent = process_nesting_level(tokens)
216
224
  continue = process_continue(tokens)
225
+ lvars_code = self.class.generate_local_variables_assign_code(context.local_variables)
226
+ code = "#{lvars_code}\n#{code}" if lvars_code
217
227
  code_block_open = check_code_block(code, tokens)
218
228
  [ltype, indent, continue, code_block_open]
219
229
  end
@@ -233,13 +243,13 @@ class RubyLex
233
243
  @code_block_open = false
234
244
  end
235
245
 
236
- def each_top_level_statement
246
+ def each_top_level_statement(context)
237
247
  initialize_input
238
248
  catch(:TERM_INPUT) do
239
249
  loop do
240
250
  begin
241
251
  prompt
242
- unless l = lex
252
+ unless l = lex(context)
243
253
  throw :TERM_INPUT if @line == ''
244
254
  else
245
255
  @line_no += l.count("\n")
@@ -269,18 +279,15 @@ class RubyLex
269
279
  end
270
280
  end
271
281
 
272
- def lex
282
+ def lex(context)
273
283
  line = @input.call
274
284
  if @io.respond_to?(:check_termination)
275
285
  return line # multiline
276
286
  end
277
287
  code = @line + (line.nil? ? '' : line)
278
288
  code.gsub!(/\s*\z/, '').concat("\n")
279
- @tokens = self.class.ripper_lex_without_warning(code)
280
- @continue = process_continue
281
- @code_block_open = check_code_block(code)
282
- @indent = process_nesting_level
283
- @ltype = process_literal_type
289
+ @tokens = self.class.ripper_lex_without_warning(code, context: context)
290
+ @ltype, @indent, @continue, @code_block_open = check_state(code, @tokens, context: context)
284
291
  line
285
292
  end
286
293
 
@@ -706,6 +713,7 @@ class RubyLex
706
713
  i = 0
707
714
  start_token = []
708
715
  end_type = []
716
+ pending_heredocs = []
709
717
  while i < tokens.size
710
718
  t = tokens[i]
711
719
  case t.event
@@ -729,18 +737,27 @@ class RubyLex
729
737
  end
730
738
  end
731
739
  when :on_backtick
732
- start_token << t
733
- end_type << :on_tstring_end
740
+ if t.state.allbits?(Ripper::EXPR_BEG)
741
+ start_token << t
742
+ end_type << :on_tstring_end
743
+ end
734
744
  when :on_qwords_beg, :on_words_beg, :on_qsymbols_beg, :on_symbols_beg
735
745
  start_token << t
736
746
  end_type << :on_tstring_end
737
747
  when :on_heredoc_beg
738
- start_token << t
739
- end_type << :on_heredoc_end
748
+ pending_heredocs << t
749
+ end
750
+
751
+ if pending_heredocs.any? && t.tok.include?("\n")
752
+ pending_heredocs.reverse_each do |t|
753
+ start_token << t
754
+ end_type << :on_heredoc_end
755
+ end
756
+ pending_heredocs = []
740
757
  end
741
758
  i += 1
742
759
  end
743
- start_token.last.nil? ? nil : start_token.last
760
+ pending_heredocs.first || start_token.last
744
761
  end
745
762
 
746
763
  def process_literal_type(tokens = @tokens)
data/lib/irb/version.rb CHANGED
@@ -11,7 +11,7 @@
11
11
  #
12
12
 
13
13
  module IRB # :nodoc:
14
- VERSION = "1.4.2"
14
+ VERSION = "1.5.1"
15
15
  @RELEASE_VERSION = VERSION
16
- @LAST_UPDATE_DATE = "2022-10-03"
16
+ @LAST_UPDATE_DATE = "2022-11-28"
17
17
  end
data/lib/irb.rb CHANGED
@@ -53,6 +53,52 @@ require_relative "irb/easter-egg"
53
53
  #
54
54
  # :include: ./irb/lc/help-message
55
55
  #
56
+ # == Commands
57
+ #
58
+ # The following commands are available on IRB.
59
+ #
60
+ # * cwws
61
+ # * Show the current workspace.
62
+ # * cb, cws, chws
63
+ # * Change the current workspace to an object.
64
+ # * bindings, workspaces
65
+ # * Show workspaces.
66
+ # * pushb, pushws
67
+ # * Push an object to the workspace stack.
68
+ # * popb, popws
69
+ # * Pop a workspace from the workspace stack.
70
+ # * load
71
+ # * Load a Ruby file.
72
+ # * require
73
+ # * Require a Ruby file.
74
+ # * source
75
+ # * Loads a given file in the current session.
76
+ # * irb
77
+ # * Start a child IRB.
78
+ # * jobs
79
+ # * List of current sessions.
80
+ # * fg
81
+ # * Switches to the session of the given number.
82
+ # * kill
83
+ # * Kills the session with the given number.
84
+ # * help
85
+ # * Enter the mode to look up RI documents.
86
+ # * irb_info
87
+ # * Show information about IRB.
88
+ # * ls
89
+ # * Show methods, constants, and variables.
90
+ # -g [query] or -G [query] allows you to filter out the output.
91
+ # * measure
92
+ # * measure enables the mode to measure processing time. measure :off disables it.
93
+ # * $, show_source
94
+ # * Show the source code of a given method or constant.
95
+ # * @, whereami
96
+ # * Show the source code around binding.irb again.
97
+ # * debug
98
+ # * Start the debugger of debug.gem.
99
+ # * break, delete, next, step, continue, finish, backtrace, info, catch
100
+ # * Start the debugger of debug.gem and run the command on it.
101
+ #
56
102
  # == Configuration
57
103
  #
58
104
  # IRB reads a personal initialization file when it's invoked.
@@ -93,9 +139,9 @@ require_relative "irb/easter-egg"
93
139
  #
94
140
  # === Autocompletion
95
141
  #
96
- # To enable autocompletion for irb, add the following to your +.irbrc+:
142
+ # To disable autocompletion for irb, add the following to your +.irbrc+:
97
143
  #
98
- # require 'irb/completion'
144
+ # IRB.conf[:USE_AUTOCOMPLETE] = false
99
145
  #
100
146
  # === History
101
147
  #
@@ -430,6 +476,17 @@ module IRB
430
476
  @scanner = RubyLex.new
431
477
  end
432
478
 
479
+ # A hook point for `debug` command's TracePoint after :IRB_EXIT as well as its clean-up
480
+ def debug_break
481
+ # it means the debug command is executed
482
+ if defined?(DEBUGGER__) && DEBUGGER__.respond_to?(:capture_frames_without_irb)
483
+ # after leaving this initial breakpoint, revert the capture_frames patch
484
+ DEBUGGER__.singleton_class.send(:alias_method, :capture_frames, :capture_frames_without_irb)
485
+ # and remove the redundant method
486
+ DEBUGGER__.singleton_class.send(:undef_method, :capture_frames_without_irb)
487
+ end
488
+ end
489
+
433
490
  def run(conf = IRB.conf)
434
491
  conf[:IRB_RC].call(context) if conf[:IRB_RC]
435
492
  conf[:MAIN_CONTEXT] = context
@@ -506,13 +563,15 @@ module IRB
506
563
 
507
564
  @scanner.set_auto_indent(@context) if @context.auto_indent_mode
508
565
 
509
- @scanner.each_top_level_statement do |line, line_no|
566
+ @scanner.each_top_level_statement(@context) do |line, line_no|
510
567
  signal_status(:IN_EVAL) do
511
568
  begin
512
569
  line.untaint if RUBY_VERSION < '2.7'
513
570
  if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
514
571
  IRB.set_measure_callback
515
572
  end
573
+ # Assignment expression check should be done before @context.evaluate to handle code like `a /2#/ if false; a = 1`
574
+ is_assignment = assignment_expression?(line)
516
575
  if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
517
576
  result = nil
518
577
  last_proc = proc{ result = @context.evaluate(line, line_no, exception: exc) }
@@ -529,7 +588,7 @@ module IRB
529
588
  @context.evaluate(line, line_no, exception: exc)
530
589
  end
531
590
  if @context.echo?
532
- if assignment_expression?(line)
591
+ if is_assignment
533
592
  if @context.echo_on_assignment?
534
593
  output_value(@context.echo_on_assignment? == :truncate)
535
594
  end
@@ -592,11 +651,7 @@ module IRB
592
651
 
593
652
  if exc.backtrace
594
653
  order = nil
595
- if '2.5.0' == RUBY_VERSION
596
- # Exception#full_message doesn't have keyword arguments.
597
- message = exc.full_message # the same of (highlight: true, order: bottom)
598
- order = :bottom
599
- elsif '2.5.1' <= RUBY_VERSION && RUBY_VERSION < '3.0.0'
654
+ if RUBY_VERSION < '3.0.0'
600
655
  if STDOUT.tty?
601
656
  message = exc.full_message(order: :bottom)
602
657
  order = :bottom
@@ -827,9 +882,12 @@ module IRB
827
882
  # array of parsed expressions. The first element of each expression is the
828
883
  # expression's type.
829
884
  verbose, $VERBOSE = $VERBOSE, nil
830
- result = ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0))
885
+ code = "#{RubyLex.generate_local_variables_assign_code(@context.local_variables) || 'nil;'}\n#{line}"
886
+ # Get the last node_type of the line. drop(1) is to ignore the local_variables_assign_code part.
887
+ node_type = Ripper.sexp(code)&.dig(1)&.drop(1)&.dig(-1, 0)
888
+ ASSIGNMENT_NODE_TYPES.include?(node_type)
889
+ ensure
831
890
  $VERBOSE = verbose
832
- result
833
891
  end
834
892
 
835
893
  ATTR_TTY = "\e[%sm"
@@ -919,12 +977,13 @@ class Binding
919
977
  #
920
978
  #
921
979
  # See IRB@IRB+Usage for more information.
922
- def irb
980
+ def irb(show_code: true)
923
981
  IRB.setup(source_location[0], argv: [])
924
982
  workspace = IRB::WorkSpace.new(self)
925
- STDOUT.print(workspace.code_around_binding)
983
+ STDOUT.print(workspace.code_around_binding) if show_code
926
984
  binding_irb = IRB::Irb.new(workspace)
927
985
  binding_irb.context.irb_path = File.expand_path(source_location[0])
928
986
  binding_irb.run(IRB.conf)
987
+ binding_irb.debug_break
929
988
  end
930
989
  end
data/man/irb.1 CHANGED
@@ -173,8 +173,19 @@ The default value is 16.
173
173
  .El
174
174
  .Pp
175
175
  .Sh ENVIRONMENT
176
- .Bl -tag -compact
176
+ .Bl -tag -compact -width "XDG_CONFIG_HOME"
177
+ .It Ev IRB_LANG
178
+ The locale used for
179
+ .Nm .
180
+ .Pp
177
181
  .It Ev IRBRC
182
+ The path to the personal initialization file.
183
+ .Pp
184
+ .It Ev XDG_CONFIG_HOME
185
+ .Nm
186
+ respects XDG_CONFIG_HOME. If this is set, load
187
+ .Pa $XDG_CONFIG_HOME/irb/irbrc
188
+ as a personal initialization file.
178
189
  .Pp
179
190
  .El
180
191
  .Pp
@@ -186,7 +197,17 @@ depends on same variables as
186
197
  .Sh FILES
187
198
  .Bl -tag -compact
188
199
  .It Pa ~/.irbrc
189
- Personal irb initialization.
200
+ Personal irb initialization. If
201
+ .Ev IRBRC
202
+ is set, read
203
+ .Pa $IRBRC
204
+ instead. If
205
+ .Ev IRBRC
206
+ is not set and
207
+ .Ev XDG_CONFIG_HOME
208
+ is set,
209
+ .Pa $XDG_CONFIG_HOME/irb/irbrc
210
+ is loaded.
190
211
  .Pp
191
212
  .El
192
213
  .Pp
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.4.2
4
+ version: 1.5.1
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: 2022-10-05 00:00:00.000000000 Z
12
+ date: 2022-11-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: reline
@@ -46,16 +46,27 @@ files:
46
46
  - exe/irb
47
47
  - irb.gemspec
48
48
  - lib/irb.rb
49
+ - lib/irb/cmd/backtrace.rb
50
+ - lib/irb/cmd/break.rb
51
+ - lib/irb/cmd/catch.rb
49
52
  - lib/irb/cmd/chws.rb
53
+ - lib/irb/cmd/continue.rb
54
+ - lib/irb/cmd/debug.rb
55
+ - lib/irb/cmd/delete.rb
56
+ - lib/irb/cmd/edit.rb
57
+ - lib/irb/cmd/finish.rb
50
58
  - lib/irb/cmd/fork.rb
51
59
  - lib/irb/cmd/help.rb
52
60
  - lib/irb/cmd/info.rb
61
+ - lib/irb/cmd/irb_info.rb
53
62
  - lib/irb/cmd/load.rb
54
63
  - lib/irb/cmd/ls.rb
55
64
  - lib/irb/cmd/measure.rb
65
+ - lib/irb/cmd/next.rb
56
66
  - lib/irb/cmd/nop.rb
57
67
  - lib/irb/cmd/pushws.rb
58
68
  - lib/irb/cmd/show_source.rb
69
+ - lib/irb/cmd/step.rb
59
70
  - lib/irb/cmd/subirb.rb
60
71
  - lib/irb/cmd/whereami.rb
61
72
  - lib/irb/color.rb
@@ -107,14 +118,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
118
  requirements:
108
119
  - - ">="
109
120
  - !ruby/object:Gem::Version
110
- version: '2.5'
121
+ version: '2.6'
111
122
  required_rubygems_version: !ruby/object:Gem::Requirement
112
123
  requirements:
113
124
  - - ">="
114
125
  - !ruby/object:Gem::Version
115
126
  version: '0'
116
127
  requirements: []
117
- rubygems_version: 3.4.0.dev
128
+ rubygems_version: 3.3.26
118
129
  signing_key:
119
130
  specification_version: 4
120
131
  summary: Interactive Ruby command-line tool for REPL (Read Eval Print Loop).