irb 1.4.2 → 1.5.1

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