irb 1.13.2 → 1.14.1

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: 243737997cdd6abe7e129eb7e7945dca379f1af38ed4254dfe094f2a611918cc
4
- data.tar.gz: 5a1cbbdf5ab88a61278afe32a5497f38efa1342e123734ae3ede6135aae9b91f
3
+ metadata.gz: 7b71e88a4dbaabac4d4a40667f3bd763bd05dfda12832919e44072f04f85ceb4
4
+ data.tar.gz: 213f59cc1bc59c61ea2013e81a098d0cb1c95f9972233cb8886bb7b353884fe8
5
5
  SHA512:
6
- metadata.gz: 0b4e5d658e1eba4a0503ffd3776c3baffabb0782eb43a993aac593b6dc4383e9e209ca3c1f077c78225f612a1ac7607f951bc11a2ff8fd78a93e12029fbf1954
7
- data.tar.gz: c9e978f318f22d322934b77b8c431830e67a9cb7cf365923041f77123ee5e7d39ffa814a4e7bdd9af759f4671d0b24bd2ae68a9d20beb54b4a0e4248e32ee85f
6
+ metadata.gz: 2ed2dd4b075b7e54ca58bf206c9dca68163564f5bbdbd8bacb24479af62a2b0bbef9d612ae0af0075bda787e189c6020b953c1858e5faecfbab7e9e441d83952
7
+ data.tar.gz: 6a81b55c3f04253913c0c1adcc118d61c03cb0b7a5a64410bbfe5495b2fc6d08e0a451eb21302327454f73ef83ed54d74c23ef065139fedbd3a685b1c5562c63
data/Gemfile CHANGED
@@ -7,7 +7,7 @@ is_truffleruby = RUBY_DESCRIPTION =~ /truffleruby/
7
7
 
8
8
  if is_unix && ENV['WITH_VTERM']
9
9
  gem "vterm", github: "ruby/vterm-gem"
10
- gem "yamatanooroti", github: "ruby/yamatanooroti"
10
+ gem "yamatanooroti", github: "ruby/yamatanooroti", ref: "f6e47192100d6089f70cf64c1de540dcaadf005a"
11
11
  end
12
12
 
13
13
  gem "stackprof" if is_unix && !is_truffleruby
data/README.md CHANGED
@@ -114,6 +114,7 @@ Help
114
114
  help List all available commands. Use `help <command>` to get information about a specific command.
115
115
 
116
116
  IRB
117
+ context Displays current configuration.
117
118
  exit Exit the current irb session.
118
119
  exit! Exit the current process.
119
120
  irb_load Load a Ruby file.
@@ -121,6 +122,7 @@ IRB
121
122
  source Loads a given file in the current session.
122
123
  irb_info Show information about IRB.
123
124
  history Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output.
125
+ disable_irb Disable binding.irb.
124
126
 
125
127
  Workspace
126
128
  cwws Show the current workspace.
@@ -128,6 +130,7 @@ Workspace
128
130
  workspaces Show workspaces.
129
131
  pushws Push an object to the workspace stack.
130
132
  popws Pop a workspace from the workspace stack.
133
+ cd Move into the given object or leave the current context.
131
134
 
132
135
  Multi-irb (DEPRECATED)
133
136
  irb Start a child IRB.
@@ -152,11 +155,14 @@ Misc
152
155
  measure `measure` enables the mode to measure processing time. `measure :off` disables it.
153
156
 
154
157
  Context
155
- show_doc Enter the mode to look up RI documents.
158
+ show_doc Look up documentation with RI.
156
159
  ls Show methods, constants, and variables.
157
- show_source Show the source code of a given method or constant.
160
+ show_source Show the source code of a given method, class/module, or constant.
158
161
  whereami Show the source code around binding.irb again.
159
162
 
163
+ Helper methods
164
+ conf Returns the current IRB context.
165
+
160
166
  Aliases
161
167
  $ Alias for `show_source`
162
168
  @ Alias for `whereami`
@@ -10,8 +10,10 @@ module IRB
10
10
  module Command
11
11
  class CommandArgumentError < StandardError; end
12
12
 
13
- def self.extract_ruby_args(*args, **kwargs)
14
- throw :EXTRACT_RUBY_ARGS, [args, kwargs]
13
+ class << self
14
+ def extract_ruby_args(*args, **kwargs)
15
+ throw :EXTRACT_RUBY_ARGS, [args, kwargs]
16
+ end
15
17
  end
16
18
 
17
19
  class Base
@@ -31,6 +33,12 @@ module IRB
31
33
  @help_message
32
34
  end
33
35
 
36
+ def execute(irb_context, arg)
37
+ new(irb_context).execute(arg)
38
+ rescue CommandArgumentError => e
39
+ puts e.message
40
+ end
41
+
34
42
  private
35
43
 
36
44
  def highlight(text)
@@ -38,12 +46,6 @@ module IRB
38
46
  end
39
47
  end
40
48
 
41
- def self.execute(irb_context, arg)
42
- new(irb_context).execute(arg)
43
- rescue CommandArgumentError => e
44
- puts e.message
45
- end
46
-
47
49
  def initialize(irb_context)
48
50
  @irb_context = irb_context
49
51
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRB
4
+ module Command
5
+ class CD < Base
6
+ category "Workspace"
7
+ description "Move into the given object or leave the current context."
8
+
9
+ help_message(<<~HELP)
10
+ Usage: cd ([target]|..)
11
+
12
+ IRB uses a stack of workspaces to keep track of context(s), with `pushws` and `popws` commands to manipulate the stack.
13
+ The `cd` command is an attempt to simplify the operation and will be subject to change.
14
+
15
+ When given:
16
+ - an object, cd will use that object as the new context by pushing it onto the workspace stack.
17
+ - "..", cd will leave the current context by popping the top workspace off the stack.
18
+ - no arguments, cd will move to the top workspace on the stack by popping off all workspaces.
19
+
20
+ Examples:
21
+
22
+ cd Foo
23
+ cd Foo.new
24
+ cd @ivar
25
+ cd ..
26
+ cd
27
+ HELP
28
+
29
+ def execute(arg)
30
+ case arg
31
+ when ".."
32
+ irb_context.pop_workspace
33
+ when ""
34
+ # TODO: decide what workspace commands should be kept, and underlying APIs should look like,
35
+ # and perhaps add a new API to clear the workspace stack.
36
+ prev_workspace = irb_context.pop_workspace
37
+ while prev_workspace
38
+ prev_workspace = irb_context.pop_workspace
39
+ end
40
+ else
41
+ begin
42
+ obj = eval(arg, irb_context.workspace.binding)
43
+ irb_context.push_workspace(obj)
44
+ rescue StandardError => e
45
+ warn "Error: #{e}"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -58,13 +58,15 @@ module IRB
58
58
  end
59
59
 
60
60
  class DebugCommand < Debug
61
- def self.category
62
- "Debugging"
63
- end
61
+ class << self
62
+ def category
63
+ "Debugging"
64
+ end
64
65
 
65
- def self.description
66
- command_name = self.name.split("::").last.downcase
67
- "Start the debugger of debug.gem and run its `#{command_name}` command."
66
+ def description
67
+ command_name = self.name.split("::").last.downcase
68
+ "Start the debugger of debug.gem and run its `#{command_name}` command."
69
+ end
68
70
  end
69
71
  end
70
72
  end
@@ -39,7 +39,7 @@ module IRB
39
39
 
40
40
  help_cmds = commands_grouped_by_categories.delete("Help")
41
41
  no_category_cmds = commands_grouped_by_categories.delete("No category")
42
- aliases = irb_context.instance_variable_get(:@user_aliases).map do |alias_name, target|
42
+ aliases = irb_context.instance_variable_get(:@command_aliases).map do |alias_name, target|
43
43
  { display_name: alias_name, description: "Alias for `#{target}`" }
44
44
  end
45
45
 
@@ -33,6 +33,8 @@ module IRB
33
33
  yield
34
34
  ]
35
35
 
36
+ HELP_COMMAND_PREPOSING = /\Ahelp\s+/
37
+
36
38
  def completion_candidates(preposing, target, postposing, bind:)
37
39
  raise NotImplementedError
38
40
  end
@@ -86,8 +88,8 @@ module IRB
86
88
  )
87
89
  end
88
90
 
89
- def command_completions(preposing, target)
90
- if preposing.empty? && !target.empty?
91
+ def command_candidates(target)
92
+ if !target.empty?
91
93
  IRB::Command.command_names.select { _1.start_with?(target) }
92
94
  else
93
95
  []
@@ -111,8 +113,18 @@ module IRB
111
113
  end
112
114
 
113
115
  def completion_candidates(preposing, target, _postposing, bind:)
114
- commands = command_completions(preposing, target)
116
+ # When completing the argument of `help` command, only commands should be candidates
117
+ return command_candidates(target) if preposing.match?(HELP_COMMAND_PREPOSING)
118
+
119
+ commands = if preposing.empty?
120
+ command_candidates(target)
121
+ # It doesn't make sense to propose commands with other preposing
122
+ else
123
+ []
124
+ end
125
+
115
126
  result = ReplTypeCompletor.analyze(preposing + target, binding: bind, filename: @context.irb_path)
127
+
116
128
  return commands unless result
117
129
 
118
130
  commands | result.completion_candidates.map { target + _1 }
@@ -187,12 +199,20 @@ module IRB
187
199
  end
188
200
 
189
201
  def completion_candidates(preposing, target, postposing, bind:)
190
- if preposing && postposing
191
- result = complete_require_path(target, preposing, postposing)
192
- return result if result
202
+ if result = complete_require_path(target, preposing, postposing)
203
+ return result
193
204
  end
194
- commands = command_completions(preposing || '', target)
195
- commands | retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
205
+
206
+ commands = command_candidates(target)
207
+
208
+ # When completing the argument of `help` command, only commands should be candidates
209
+ return commands if preposing.match?(HELP_COMMAND_PREPOSING)
210
+
211
+ # It doesn't make sense to propose commands with other preposing
212
+ commands = [] unless preposing.empty?
213
+
214
+ completion_data = retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
215
+ commands | completion_data
196
216
  end
197
217
 
198
218
  def doc_namespace(_preposing, matched, _postposing, bind:)
@@ -470,7 +490,7 @@ module IRB
470
490
  end
471
491
  end
472
492
  CompletionProc = ->(target, preposing = nil, postposing = nil) {
473
- regexp_completor.completion_candidates(preposing, target, postposing, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding)
493
+ regexp_completor.completion_candidates(preposing || '', target, postposing || '', bind: IRB.conf[:MAIN_CONTEXT].workspace.binding)
474
494
  }
475
495
  end
476
496
  deprecate_constant :InputCompletor
data/lib/irb/context.rb CHANGED
@@ -13,6 +13,7 @@ module IRB
13
13
  # A class that wraps the current state of the irb session, including the
14
14
  # configuration of IRB.conf.
15
15
  class Context
16
+ ASSIGN_OPERATORS_REGEXP = Regexp.union(%w[= += -= *= /= %= **= &= |= &&= ||= ^= <<= >>=])
16
17
  # Creates a new IRB context.
17
18
  #
18
19
  # The optional +input_method+ argument:
@@ -148,8 +149,7 @@ module IRB
148
149
  @newline_before_multiline_output = true
149
150
  end
150
151
 
151
- @user_aliases = IRB.conf[:COMMAND_ALIASES].dup
152
- @command_aliases = @user_aliases.merge(KEYWORD_ALIASES)
152
+ @command_aliases = IRB.conf[:COMMAND_ALIASES].dup
153
153
  end
154
154
 
155
155
  private def term_interactive?
@@ -157,17 +157,6 @@ module IRB
157
157
  STDIN.tty? && ENV['TERM'] != 'dumb'
158
158
  end
159
159
 
160
- # because all input will eventually be evaluated as Ruby code,
161
- # command names that conflict with Ruby keywords need special workaround
162
- # we can remove them once we implemented a better command system for IRB
163
- KEYWORD_ALIASES = {
164
- :break => :irb_break,
165
- :catch => :irb_catch,
166
- :next => :irb_next,
167
- }.freeze
168
-
169
- private_constant :KEYWORD_ALIASES
170
-
171
160
  def use_tracer=(val)
172
161
  require_relative "ext/tracer" if val
173
162
  IRB.conf[:USE_TRACER] = val
@@ -602,7 +591,6 @@ module IRB
602
591
  set_last_value(result)
603
592
  when Statement::Command
604
593
  statement.command_class.execute(self, statement.arg)
605
- set_last_value(nil)
606
594
  end
607
595
 
608
596
  nil
@@ -636,6 +624,46 @@ module IRB
636
624
  result
637
625
  end
638
626
 
627
+ def parse_command(code)
628
+ command_name, arg = code.strip.split(/\s+/, 2)
629
+ return unless code.lines.size == 1 && command_name
630
+
631
+ arg ||= ''
632
+ command = command_name.to_sym
633
+ # Command aliases are always command. example: $, @
634
+ if (alias_name = command_aliases[command])
635
+ return [alias_name, arg]
636
+ end
637
+
638
+ # Assignment-like expression is not a command
639
+ return if arg.start_with?(ASSIGN_OPERATORS_REGEXP) && !arg.start_with?(/==|=~/)
640
+
641
+ # Local variable have precedence over command
642
+ return if local_variables.include?(command)
643
+
644
+ # Check visibility
645
+ public_method = !!Kernel.instance_method(:public_method).bind_call(main, command) rescue false
646
+ private_method = !public_method && !!Kernel.instance_method(:method).bind_call(main, command) rescue false
647
+ if Command.execute_as_command?(command, public_method: public_method, private_method: private_method)
648
+ [command, arg]
649
+ end
650
+ end
651
+
652
+ def colorize_input(input, complete:)
653
+ if IRB.conf[:USE_COLORIZE] && IRB::Color.colorable?
654
+ lvars = local_variables || []
655
+ if parse_command(input)
656
+ name, sep, arg = input.split(/(\s+)/, 2)
657
+ arg = IRB::Color.colorize_code(arg, complete: complete, local_variables: lvars)
658
+ "#{IRB::Color.colorize(name, [:BOLD])}\e[m#{sep}#{arg}"
659
+ else
660
+ IRB::Color.colorize_code(input, complete: complete, local_variables: lvars)
661
+ end
662
+ else
663
+ Reline::Unicode.escape_for_print(input)
664
+ end
665
+ end
666
+
639
667
  def inspect_last_value # :nodoc:
640
668
  @inspect_method.inspect_value(@last_value)
641
669
  end
data/lib/irb/debug.rb CHANGED
@@ -57,22 +57,18 @@ module IRB
57
57
  DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
58
58
  end
59
59
 
60
- if !@output_modifier_defined && !DEBUGGER__::CONFIG[:no_hint]
61
- irb_output_modifier_proc = Reline.output_modifier_proc
62
-
63
- Reline.output_modifier_proc = proc do |output, complete:|
64
- unless output.strip.empty?
65
- cmd = output.split(/\s/, 2).first
60
+ if !DEBUGGER__::CONFIG[:no_hint] && irb.context.io.is_a?(RelineInputMethod)
61
+ Reline.output_modifier_proc = proc do |input, complete:|
62
+ unless input.strip.empty?
63
+ cmd = input.split(/\s/, 2).first
66
64
 
67
65
  if !complete && DEBUGGER__.commands.key?(cmd)
68
- output = output.sub(/\n$/, " # debug command\n")
66
+ input = input.sub(/\n$/, " # debug command\n")
69
67
  end
70
68
  end
71
69
 
72
- irb_output_modifier_proc.call(output, complete: complete)
70
+ irb.context.colorize_input(input, complete: complete)
73
71
  end
74
-
75
- @output_modifier_defined = true
76
72
  end
77
73
 
78
74
  true
@@ -5,6 +5,7 @@ require_relative "command/internal_helpers"
5
5
  require_relative "command/backtrace"
6
6
  require_relative "command/break"
7
7
  require_relative "command/catch"
8
+ require_relative "command/cd"
8
9
  require_relative "command/chws"
9
10
  require_relative "command/context"
10
11
  require_relative "command/continue"
@@ -180,9 +181,15 @@ module IRB
180
181
  [:edit, NO_OVERRIDE]
181
182
  )
182
183
 
183
- _register_with_aliases(:irb_break, Command::Break)
184
- _register_with_aliases(:irb_catch, Command::Catch)
185
- _register_with_aliases(:irb_next, Command::Next)
184
+ _register_with_aliases(:irb_break, Command::Break,
185
+ [:break, OVERRIDE_ALL]
186
+ )
187
+ _register_with_aliases(:irb_catch, Command::Catch,
188
+ [:catch, OVERRIDE_PRIVATE_ONLY]
189
+ )
190
+ _register_with_aliases(:irb_next, Command::Next,
191
+ [:next, OVERRIDE_ALL]
192
+ )
186
193
  _register_with_aliases(:irb_delete, Command::Delete,
187
194
  [:delete, NO_OVERRIDE]
188
195
  )
@@ -240,6 +247,8 @@ module IRB
240
247
  _register_with_aliases(:irb_disable_irb, Command::DisableIrb,
241
248
  [:disable_irb, NO_OVERRIDE]
242
249
  )
250
+
251
+ register(:cd, Command::CD)
243
252
  end
244
253
 
245
254
  ExtendCommand = Command
@@ -256,10 +265,12 @@ module IRB
256
265
  # Deprecated. Doesn't have any effect.
257
266
  @EXTEND_COMMANDS = []
258
267
 
259
- # Drepcated. Use Command.regiser instead.
260
- def self.def_extend_command(cmd_name, cmd_class, _, *aliases)
261
- Command._register_with_aliases(cmd_name, cmd_class, *aliases)
262
- Command.class_variable_set(:@@command_override_policies, nil)
268
+ class << self
269
+ # Drepcated. Use Command.regiser instead.
270
+ def def_extend_command(cmd_name, cmd_class, _, *aliases)
271
+ Command._register_with_aliases(cmd_name, cmd_class, *aliases)
272
+ Command.class_variable_set(:@@command_override_policies, nil)
273
+ end
263
274
  end
264
275
  end
265
276
  end
@@ -100,19 +100,21 @@ module IRB
100
100
 
101
101
  private def easter_egg_logo(type)
102
102
  @easter_egg_logos ||= File.read(File.join(__dir__, 'ruby_logo.aa'), encoding: 'UTF-8:UTF-8')
103
- .split(/TYPE: ([A-Z]+)\n/)[1..]
103
+ .split(/TYPE: ([A-Z_]+)\n/)[1..]
104
104
  .each_slice(2)
105
105
  .to_h
106
106
  @easter_egg_logos[type.to_s.upcase]
107
107
  end
108
108
 
109
109
  private def easter_egg(type = nil)
110
+ print "\e[?1049h"
110
111
  type ||= [:logo, :dancing].sample
111
112
  case type
112
113
  when :logo
113
- require "rdoc"
114
- RDoc::RI::Driver.new.page do |io|
115
- io.write easter_egg_logo(:large)
114
+ Pager.page do |io|
115
+ logo_type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode_large : :ascii_large
116
+ io.write easter_egg_logo(logo_type)
117
+ STDIN.raw { STDIN.getc } if io == STDOUT
116
118
  end
117
119
  when :dancing
118
120
  STDOUT.cooked do
@@ -137,10 +139,11 @@ module IRB
137
139
  end
138
140
  rescue Interrupt
139
141
  ensure
140
- print "\e[0m\e[?1049l"
141
142
  trap("SIGINT", prev_trap)
142
143
  end
143
144
  end
145
+ ensure
146
+ print "\e[0m\e[?1049l"
144
147
  end
145
148
  end
146
149
  end
@@ -171,11 +171,13 @@ module IRB
171
171
  end
172
172
 
173
173
  class ReadlineInputMethod < StdioInputMethod
174
- def self.initialize_readline
175
- require "readline"
176
- rescue LoadError
177
- else
178
- include ::Readline
174
+ class << self
175
+ def initialize_readline
176
+ require "readline"
177
+ rescue LoadError
178
+ else
179
+ include ::Readline
180
+ end
179
181
  end
180
182
 
181
183
  include HistorySavingAbility
@@ -263,18 +265,9 @@ module IRB
263
265
  @completion_params = [preposing, target, postposing, bind]
264
266
  @completor.completion_candidates(preposing, target, postposing, bind: bind)
265
267
  }
266
- Reline.output_modifier_proc =
267
- if IRB.conf[:USE_COLORIZE]
268
- proc do |output, complete: |
269
- next unless IRB::Color.colorable?
270
- lvars = IRB.CurrentContext&.local_variables || []
271
- IRB::Color.colorize_code(output, complete: complete, local_variables: lvars)
272
- end
273
- else
274
- proc do |output|
275
- Reline::Unicode.escape_for_print(output)
276
- end
277
- end
268
+ Reline.output_modifier_proc = proc do |input, complete:|
269
+ IRB.CurrentContext.colorize_input(input, complete: complete)
270
+ end
278
271
  Reline.dig_perfect_match_proc = ->(matched) { display_document(matched) }
279
272
  Reline.autocompletion = IRB.conf[:USE_AUTOCOMPLETE]
280
273
 
data/lib/irb/inspector.rb CHANGED
@@ -6,7 +6,6 @@
6
6
 
7
7
  module IRB # :nodoc:
8
8
 
9
-
10
9
  # Convenience method to create a new Inspector, using the given +inspect+
11
10
  # proc, and optional +init+ proc and passes them to Inspector.new
12
11
  #
@@ -43,38 +42,40 @@ module IRB # :nodoc:
43
42
  # +:marshal+:: Using Marshal.dump
44
43
  INSPECTORS = {}
45
44
 
46
- # Determines the inspector to use where +inspector+ is one of the keys passed
47
- # during inspector definition.
48
- def self.keys_with_inspector(inspector)
49
- INSPECTORS.select{|k, v| v == inspector}.collect{|k, v| k}
50
- end
51
-
52
- # Example
53
- #
54
- # Inspector.def_inspector(key, init_p=nil){|v| v.inspect}
55
- # Inspector.def_inspector([key1,..], init_p=nil){|v| v.inspect}
56
- # Inspector.def_inspector(key, inspector)
57
- # Inspector.def_inspector([key1,...], inspector)
58
- def self.def_inspector(key, arg=nil, &block)
59
- if block_given?
60
- inspector = IRB::Inspector(block, arg)
61
- else
62
- inspector = arg
45
+ class << self
46
+ # Determines the inspector to use where +inspector+ is one of the keys passed
47
+ # during inspector definition.
48
+ def keys_with_inspector(inspector)
49
+ INSPECTORS.select{|k, v| v == inspector}.collect{|k, v| k}
63
50
  end
64
51
 
65
- case key
66
- when Array
67
- for k in key
68
- def_inspector(k, inspector)
52
+ # Example
53
+ #
54
+ # Inspector.def_inspector(key, init_p=nil){|v| v.inspect}
55
+ # Inspector.def_inspector([key1,..], init_p=nil){|v| v.inspect}
56
+ # Inspector.def_inspector(key, inspector)
57
+ # Inspector.def_inspector([key1,...], inspector)
58
+ def def_inspector(key, arg=nil, &block)
59
+ if block_given?
60
+ inspector = IRB::Inspector(block, arg)
61
+ else
62
+ inspector = arg
63
+ end
64
+
65
+ case key
66
+ when Array
67
+ for k in key
68
+ def_inspector(k, inspector)
69
+ end
70
+ when Symbol
71
+ INSPECTORS[key] = inspector
72
+ INSPECTORS[key.to_s] = inspector
73
+ when String
74
+ INSPECTORS[key] = inspector
75
+ INSPECTORS[key.intern] = inspector
76
+ else
77
+ INSPECTORS[key] = inspector
69
78
  end
70
- when Symbol
71
- INSPECTORS[key] = inspector
72
- INSPECTORS[key.to_s] = inspector
73
- when String
74
- INSPECTORS[key] = inspector
75
- INSPECTORS[key.intern] = inspector
76
- else
77
- INSPECTORS[key] = inspector
78
79
  end
79
80
  end
80
81