irb 1.1.0.pre.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +10 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +55 -0
  5. data/Rakefile +10 -0
  6. data/bin/console +6 -0
  7. data/bin/setup +6 -0
  8. data/doc/irb/irb-tools.rd.ja +184 -0
  9. data/doc/irb/irb.rd.ja +411 -0
  10. data/exe/irb +11 -0
  11. data/irb.gemspec +84 -0
  12. data/lib/irb.rb +870 -0
  13. data/lib/irb/cmd/chws.rb +34 -0
  14. data/lib/irb/cmd/fork.rb +39 -0
  15. data/lib/irb/cmd/help.rb +46 -0
  16. data/lib/irb/cmd/load.rb +67 -0
  17. data/lib/irb/cmd/nop.rb +39 -0
  18. data/lib/irb/cmd/pushws.rb +41 -0
  19. data/lib/irb/cmd/subirb.rb +43 -0
  20. data/lib/irb/color.rb +233 -0
  21. data/lib/irb/completion.rb +339 -0
  22. data/lib/irb/context.rb +458 -0
  23. data/lib/irb/ext/change-ws.rb +46 -0
  24. data/lib/irb/ext/history.rb +157 -0
  25. data/lib/irb/ext/loader.rb +129 -0
  26. data/lib/irb/ext/multi-irb.rb +265 -0
  27. data/lib/irb/ext/save-history.rb +117 -0
  28. data/lib/irb/ext/tracer.rb +72 -0
  29. data/lib/irb/ext/use-loader.rb +77 -0
  30. data/lib/irb/ext/workspaces.rb +67 -0
  31. data/lib/irb/extend-command.rb +328 -0
  32. data/lib/irb/frame.rb +81 -0
  33. data/lib/irb/help.rb +37 -0
  34. data/lib/irb/init.rb +312 -0
  35. data/lib/irb/input-method.rb +298 -0
  36. data/lib/irb/inspector.rb +142 -0
  37. data/lib/irb/lc/.document +4 -0
  38. data/lib/irb/lc/error.rb +32 -0
  39. data/lib/irb/lc/help-message +52 -0
  40. data/lib/irb/lc/ja/encoding_aliases.rb +11 -0
  41. data/lib/irb/lc/ja/error.rb +31 -0
  42. data/lib/irb/lc/ja/help-message +55 -0
  43. data/lib/irb/locale.rb +182 -0
  44. data/lib/irb/magic-file.rb +38 -0
  45. data/lib/irb/notifier.rb +232 -0
  46. data/lib/irb/output-method.rb +92 -0
  47. data/lib/irb/ruby-lex.rb +499 -0
  48. data/lib/irb/ruby_logo.aa +38 -0
  49. data/lib/irb/slex.rb +282 -0
  50. data/lib/irb/src_encoding.rb +7 -0
  51. data/lib/irb/version.rb +17 -0
  52. data/lib/irb/workspace.rb +181 -0
  53. data/lib/irb/ws-for-case-2.rb +15 -0
  54. data/lib/irb/xmp.rb +170 -0
  55. data/man/irb.1 +207 -0
  56. metadata +140 -0
data/exe/irb ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # irb.rb - interactive ruby
4
+ # $Release Version: 0.9.6 $
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+
9
+ require "irb"
10
+
11
+ IRB.start(__FILE__)
@@ -0,0 +1,84 @@
1
+ begin
2
+ require_relative "lib/irb/version"
3
+ rescue LoadError
4
+ # for Ruby core repository
5
+ require_relative "version"
6
+ end
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "irb"
10
+ spec.version = IRB::VERSION
11
+ spec.authors = ["Keiju ISHITSUKA"]
12
+ spec.email = ["keiju@ruby-lang.org"]
13
+
14
+ spec.summary = %q{Interactive Ruby command-line tool for REPL (Read Eval Print Loop).}
15
+ spec.description = %q{Interactive Ruby command-line tool for REPL (Read Eval Print Loop).}
16
+ spec.homepage = "https://github.com/ruby/irb"
17
+ spec.license = "BSD-2-Clause"
18
+
19
+ spec.files = [
20
+ "Gemfile",
21
+ "LICENSE.txt",
22
+ "README.md",
23
+ "Rakefile",
24
+ "bin/console",
25
+ "bin/setup",
26
+ "doc/irb/irb-tools.rd.ja",
27
+ "doc/irb/irb.rd.ja",
28
+ "exe/irb",
29
+ "irb.gemspec",
30
+ "lib/irb.rb",
31
+ "lib/irb/cmd/chws.rb",
32
+ "lib/irb/cmd/fork.rb",
33
+ "lib/irb/cmd/help.rb",
34
+ "lib/irb/cmd/load.rb",
35
+ "lib/irb/cmd/nop.rb",
36
+ "lib/irb/cmd/pushws.rb",
37
+ "lib/irb/cmd/subirb.rb",
38
+ "lib/irb/color.rb",
39
+ "lib/irb/completion.rb",
40
+ "lib/irb/context.rb",
41
+ "lib/irb/ext/change-ws.rb",
42
+ "lib/irb/ext/history.rb",
43
+ "lib/irb/ext/loader.rb",
44
+ "lib/irb/ext/multi-irb.rb",
45
+ "lib/irb/ext/save-history.rb",
46
+ "lib/irb/ext/tracer.rb",
47
+ "lib/irb/ext/use-loader.rb",
48
+ "lib/irb/ext/workspaces.rb",
49
+ "lib/irb/extend-command.rb",
50
+ "lib/irb/frame.rb",
51
+ "lib/irb/help.rb",
52
+ "lib/irb/init.rb",
53
+ "lib/irb/input-method.rb",
54
+ "lib/irb/inspector.rb",
55
+ "lib/irb/lc/.document",
56
+ "lib/irb/lc/error.rb",
57
+ "lib/irb/lc/help-message",
58
+ "lib/irb/lc/ja/encoding_aliases.rb",
59
+ "lib/irb/lc/ja/error.rb",
60
+ "lib/irb/lc/ja/help-message",
61
+ "lib/irb/locale.rb",
62
+ "lib/irb/magic-file.rb",
63
+ "lib/irb/notifier.rb",
64
+ "lib/irb/output-method.rb",
65
+ "lib/irb/ruby-lex.rb",
66
+ "lib/irb/ruby_logo.aa",
67
+ "lib/irb/slex.rb",
68
+ "lib/irb/src_encoding.rb",
69
+ "lib/irb/version.rb",
70
+ "lib/irb/workspace.rb",
71
+ "lib/irb/ws-for-case-2.rb",
72
+ "lib/irb/xmp.rb",
73
+ "man/irb.1",
74
+ ]
75
+ spec.bindir = "exe"
76
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
77
+ spec.require_paths = ["lib"]
78
+
79
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4")
80
+
81
+ spec.add_dependency "reline", ">= 0.0.1"
82
+ spec.add_development_dependency "bundler"
83
+ spec.add_development_dependency "rake"
84
+ end
@@ -0,0 +1,870 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # irb.rb - irb main module
4
+ # $Release Version: 0.9.6 $
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+ require "e2mmap"
13
+ require "ripper"
14
+
15
+ require "irb/init"
16
+ require "irb/context"
17
+ require "irb/extend-command"
18
+
19
+ require "irb/ruby-lex"
20
+ require "irb/input-method"
21
+ require "irb/locale"
22
+ require "irb/color"
23
+
24
+ require "irb/version"
25
+
26
+ # IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
27
+ # expressions read from the standard input.
28
+ #
29
+ # The +irb+ command from your shell will start the interpreter.
30
+ #
31
+ # == Usage
32
+ #
33
+ # Use of irb is easy if you know Ruby.
34
+ #
35
+ # When executing irb, prompts are displayed as follows. Then, enter the Ruby
36
+ # expression. An input is executed when it is syntactically complete.
37
+ #
38
+ # $ irb
39
+ # irb(main):001:0> 1+2
40
+ # #=> 3
41
+ # irb(main):002:0> class Foo
42
+ # irb(main):003:1> def foo
43
+ # irb(main):004:2> print 1
44
+ # irb(main):005:2> end
45
+ # irb(main):006:1> end
46
+ # #=> nil
47
+ #
48
+ # The singleline editor module or multiline editor module can be used with irb.
49
+ # Use of multiline editor is default if it's installed.
50
+ #
51
+ # == Command line options
52
+ #
53
+ # Usage: irb.rb [options] [programfile] [arguments]
54
+ # -f Suppress read of ~/.irbrc
55
+ # -d Set $DEBUG to true (same as `ruby -d')
56
+ # -r load-module Same as `ruby -r'
57
+ # -I path Specify $LOAD_PATH directory
58
+ # -U Same as `ruby -U`
59
+ # -E enc Same as `ruby -E`
60
+ # -w Same as `ruby -w`
61
+ # -W[level=2] Same as `ruby -W`
62
+ # --inspect Use `inspect' for output (default except for bc mode)
63
+ # --noinspect Don't use inspect for output
64
+ # --multiline Use multiline editor module
65
+ # --nomultiline Don't use multiline editor module
66
+ # --singleline Use singleline editor module
67
+ # --nosingleline Don't use singleline editor module
68
+ # --colorize Use colorization
69
+ # --nocolorize Don't use colorization
70
+ # --prompt prompt-mode
71
+ # --prompt-mode prompt-mode
72
+ # Switch prompt mode. Pre-defined prompt modes are
73
+ # `default', `simple', `xmp' and `inf-ruby'
74
+ # --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs.
75
+ # Suppresses --multiline and --singleline.
76
+ # --simple-prompt Simple prompt mode
77
+ # --noprompt No prompt mode
78
+ # --tracer Display trace for each execution of commands.
79
+ # --back-trace-limit n
80
+ # Display backtrace top n and tail n. The default
81
+ # value is 16.
82
+ # -v, --version Print the version of irb
83
+ #
84
+ # == Configuration
85
+ #
86
+ # IRB reads from <code>~/.irbrc</code> when it's invoked.
87
+ #
88
+ # If <code>~/.irbrc</code> doesn't exist, +irb+ will try to read in the following order:
89
+ #
90
+ # * +.irbrc+
91
+ # * +irb.rc+
92
+ # * +_irbrc+
93
+ # * <code>$irbrc</code>
94
+ #
95
+ # The following are alternatives to the command line options. To use them type
96
+ # as follows in an +irb+ session:
97
+ #
98
+ # IRB.conf[:IRB_NAME]="irb"
99
+ # IRB.conf[:INSPECT_MODE]=nil
100
+ # IRB.conf[:IRB_RC] = nil
101
+ # IRB.conf[:BACK_TRACE_LIMIT]=16
102
+ # IRB.conf[:USE_LOADER] = false
103
+ # IRB.conf[:USE_MULTILINE] = nil
104
+ # IRB.conf[:USE_SINGLELINE] = nil
105
+ # IRB.conf[:USE_COLORIZE] = true
106
+ # IRB.conf[:USE_TRACER] = false
107
+ # IRB.conf[:IGNORE_SIGINT] = true
108
+ # IRB.conf[:IGNORE_EOF] = false
109
+ # IRB.conf[:PROMPT_MODE] = :DEFAULT
110
+ # IRB.conf[:PROMPT] = {...}
111
+ #
112
+ # === Auto indentation
113
+ #
114
+ # To disable auto-indent mode in irb, add the following to your +.irbrc+:
115
+ #
116
+ # IRB.conf[:AUTO_INDENT] = false
117
+ #
118
+ # === Autocompletion
119
+ #
120
+ # To enable autocompletion for irb, add the following to your +.irbrc+:
121
+ #
122
+ # require 'irb/completion'
123
+ #
124
+ # === History
125
+ #
126
+ # By default, irb will store the last 1000 commands you used in
127
+ # <code>IRB.conf[:HISTORY_FILE]</code> (<code>~/.irb_history</code> by default).
128
+ #
129
+ # If you want to disable history, add the following to your +.irbrc+:
130
+ #
131
+ # IRB.conf[:SAVE_HISTORY] = nil
132
+ #
133
+ # See IRB::Context#save_history= for more information.
134
+ #
135
+ # The history of _resuls_ of commands evaluated is not stored by default,
136
+ # but can be turned on to be stored with this +.irbrc+ setting:
137
+ #
138
+ # IRB.conf[:EVAL_HISTORY] = <number>
139
+ #
140
+ # See IRB::Context#eval_history= and History class. The history of command
141
+ # results is not permanently saved in any file.
142
+ #
143
+ # == Customizing the IRB Prompt
144
+ #
145
+ # In order to customize the prompt, you can change the following Hash:
146
+ #
147
+ # IRB.conf[:PROMPT]
148
+ #
149
+ # This example can be used in your +.irbrc+
150
+ #
151
+ # IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode
152
+ # :AUTO_INDENT => false, # disables auto-indent mode
153
+ # :PROMPT_I => ">> ", # simple prompt
154
+ # :PROMPT_S => nil, # prompt for continuated strings
155
+ # :PROMPT_C => nil, # prompt for continuated statement
156
+ # :RETURN => " ==>%s\n" # format to return value
157
+ # }
158
+ #
159
+ # IRB.conf[:PROMPT_MODE] = :MY_PROMPT
160
+ #
161
+ # Or, invoke irb with the above prompt mode by:
162
+ #
163
+ # irb --prompt my-prompt
164
+ #
165
+ # Constants +PROMPT_I+, +PROMPT_S+ and +PROMPT_C+ specify the format. In the
166
+ # prompt specification, some special strings are available:
167
+ #
168
+ # %N # command name which is running
169
+ # %m # to_s of main object (self)
170
+ # %M # inspect of main object (self)
171
+ # %l # type of string(", ', /, ]), `]' is inner %w[...]
172
+ # %NNi # indent level. NN is digits and means as same as printf("%NNd").
173
+ # # It can be omitted
174
+ # %NNn # line number.
175
+ # %% # %
176
+ #
177
+ # For instance, the default prompt mode is defined as follows:
178
+ #
179
+ # IRB.conf[:PROMPT_MODE][:DEFAULT] = {
180
+ # :PROMPT_I => "%N(%m):%03n:%i> ",
181
+ # :PROMPT_N => "%N(%m):%03n:%i> ",
182
+ # :PROMPT_S => "%N(%m):%03n:%i%l ",
183
+ # :PROMPT_C => "%N(%m):%03n:%i* ",
184
+ # :RETURN => "%s\n" # used to printf
185
+ # }
186
+ #
187
+ # irb comes with a number of available modes:
188
+ #
189
+ # # :NULL:
190
+ # # :PROMPT_I:
191
+ # # :PROMPT_N:
192
+ # # :PROMPT_S:
193
+ # # :PROMPT_C:
194
+ # # :RETURN: |
195
+ # # %s
196
+ # # :DEFAULT:
197
+ # # :PROMPT_I: ! '%N(%m):%03n:%i> '
198
+ # # :PROMPT_N: ! '%N(%m):%03n:%i> '
199
+ # # :PROMPT_S: ! '%N(%m):%03n:%i%l '
200
+ # # :PROMPT_C: ! '%N(%m):%03n:%i* '
201
+ # # :RETURN: |
202
+ # # => %s
203
+ # # :CLASSIC:
204
+ # # :PROMPT_I: ! '%N(%m):%03n:%i> '
205
+ # # :PROMPT_N: ! '%N(%m):%03n:%i> '
206
+ # # :PROMPT_S: ! '%N(%m):%03n:%i%l '
207
+ # # :PROMPT_C: ! '%N(%m):%03n:%i* '
208
+ # # :RETURN: |
209
+ # # %s
210
+ # # :SIMPLE:
211
+ # # :PROMPT_I: ! '>> '
212
+ # # :PROMPT_N: ! '>> '
213
+ # # :PROMPT_S:
214
+ # # :PROMPT_C: ! '?> '
215
+ # # :RETURN: |
216
+ # # => %s
217
+ # # :INF_RUBY:
218
+ # # :PROMPT_I: ! '%N(%m):%03n:%i> '
219
+ # # :PROMPT_N:
220
+ # # :PROMPT_S:
221
+ # # :PROMPT_C:
222
+ # # :RETURN: |
223
+ # # %s
224
+ # # :AUTO_INDENT: true
225
+ # # :XMP:
226
+ # # :PROMPT_I:
227
+ # # :PROMPT_N:
228
+ # # :PROMPT_S:
229
+ # # :PROMPT_C:
230
+ # # :RETURN: |2
231
+ # # ==>%s
232
+ #
233
+ # == Restrictions
234
+ #
235
+ # Because irb evaluates input immediately after it is syntactically complete,
236
+ # the results may be slightly different than directly using Ruby.
237
+ #
238
+ # == IRB Sessions
239
+ #
240
+ # IRB has a special feature, that allows you to manage many sessions at once.
241
+ #
242
+ # You can create new sessions with Irb.irb, and get a list of current sessions
243
+ # with the +jobs+ command in the prompt.
244
+ #
245
+ # === Commands
246
+ #
247
+ # JobManager provides commands to handle the current sessions:
248
+ #
249
+ # jobs # List of current sessions
250
+ # fg # Switches to the session of the given number
251
+ # kill # Kills the session with the given number
252
+ #
253
+ # The +exit+ command, or ::irb_exit, will quit the current session and call any
254
+ # exit hooks with IRB.irb_at_exit.
255
+ #
256
+ # A few commands for loading files within the session are also available:
257
+ #
258
+ # +source+::
259
+ # Loads a given file in the current session and displays the source lines,
260
+ # see IrbLoader#source_file
261
+ # +irb_load+::
262
+ # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
263
+ # +irb_require+::
264
+ # Loads the given file similarly to Kernel#require
265
+ #
266
+ # === Configuration
267
+ #
268
+ # The command line options, or IRB.conf, specify the default behavior of
269
+ # Irb.irb.
270
+ #
271
+ # On the other hand, each conf in IRB@Command+line+options is used to
272
+ # individually configure IRB.irb.
273
+ #
274
+ # If a proc is set for IRB.conf[:IRB_RC], its will be invoked after execution
275
+ # of that proc with the context of the current session as its argument. Each
276
+ # session can be configured using this mechanism.
277
+ #
278
+ # === Session variables
279
+ #
280
+ # There are a few variables in every Irb session that can come in handy:
281
+ #
282
+ # <code>_</code>::
283
+ # The value command executed, as a local variable
284
+ # <code>__</code>::
285
+ # The history of evaluated commands. Available only if
286
+ # <code>IRB.conf[:EVAL_HISTORY]</code> is not +nil+ (which is the default).
287
+ # See also IRB::Context#eval_history= and IRB::History.
288
+ # <code>__[line_no]</code>::
289
+ # Returns the evaluation value at the given line number, +line_no+.
290
+ # If +line_no+ is a negative, the return value +line_no+ many lines before
291
+ # the most recent return value.
292
+ #
293
+ # === Example using IRB Sessions
294
+ #
295
+ # # invoke a new session
296
+ # irb(main):001:0> irb
297
+ # # list open sessions
298
+ # irb.1(main):001:0> jobs
299
+ # #0->irb on main (#<Thread:0x400fb7e4> : stop)
300
+ # #1->irb#1 on main (#<Thread:0x40125d64> : running)
301
+ #
302
+ # # change the active session
303
+ # irb.1(main):002:0> fg 0
304
+ # # define class Foo in top-level session
305
+ # irb(main):002:0> class Foo;end
306
+ # # invoke a new session with the context of Foo
307
+ # irb(main):003:0> irb Foo
308
+ # # define Foo#foo
309
+ # irb.2(Foo):001:0> def foo
310
+ # irb.2(Foo):002:1> print 1
311
+ # irb.2(Foo):003:1> end
312
+ #
313
+ # # change the active session
314
+ # irb.2(Foo):004:0> fg 0
315
+ # # list open sessions
316
+ # irb(main):004:0> jobs
317
+ # #0->irb on main (#<Thread:0x400fb7e4> : running)
318
+ # #1->irb#1 on main (#<Thread:0x40125d64> : stop)
319
+ # #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
320
+ # # check if Foo#foo is available
321
+ # irb(main):005:0> Foo.instance_methods #=> [:foo, ...]
322
+ #
323
+ # # change the active sesssion
324
+ # irb(main):006:0> fg 2
325
+ # # define Foo#bar in the context of Foo
326
+ # irb.2(Foo):005:0> def bar
327
+ # irb.2(Foo):006:1> print "bar"
328
+ # irb.2(Foo):007:1> end
329
+ # irb.2(Foo):010:0> Foo.instance_methods #=> [:bar, :foo, ...]
330
+ #
331
+ # # change the active session
332
+ # irb.2(Foo):011:0> fg 0
333
+ # irb(main):007:0> f = Foo.new #=> #<Foo:0x4010af3c>
334
+ # # invoke a new session with the context of f (instance of Foo)
335
+ # irb(main):008:0> irb f
336
+ # # list open sessions
337
+ # irb.3(<Foo:0x4010af3c>):001:0> jobs
338
+ # #0->irb on main (#<Thread:0x400fb7e4> : stop)
339
+ # #1->irb#1 on main (#<Thread:0x40125d64> : stop)
340
+ # #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
341
+ # #3->irb#3 on #<Foo:0x4010af3c> (#<Thread:0x4010a1e0> : running)
342
+ # # evaluate f.foo
343
+ # irb.3(<Foo:0x4010af3c>):002:0> foo #=> 1 => nil
344
+ # # evaluate f.bar
345
+ # irb.3(<Foo:0x4010af3c>):003:0> bar #=> bar => nil
346
+ # # kill jobs 1, 2, and 3
347
+ # irb.3(<Foo:0x4010af3c>):004:0> kill 1, 2, 3
348
+ # # list open sessions, should only include main session
349
+ # irb(main):009:0> jobs
350
+ # #0->irb on main (#<Thread:0x400fb7e4> : running)
351
+ # # quit irb
352
+ # irb(main):010:0> exit
353
+ module IRB
354
+
355
+ # An exception raised by IRB.irb_abort
356
+ class Abort < Exception;end
357
+
358
+ @CONF = {}
359
+
360
+
361
+ # Displays current configuration.
362
+ #
363
+ # Modifying the configuration is achieved by sending a message to IRB.conf.
364
+ #
365
+ # See IRB@Configuration for more information.
366
+ def IRB.conf
367
+ @CONF
368
+ end
369
+
370
+ # Returns the current version of IRB, including release version and last
371
+ # updated date.
372
+ def IRB.version
373
+ if v = @CONF[:VERSION] then return v end
374
+
375
+ @CONF[:VERSION] = format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE)
376
+ end
377
+
378
+ # The current IRB::Context of the session, see IRB.conf
379
+ #
380
+ # irb
381
+ # irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
382
+ # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
383
+ def IRB.CurrentContext
384
+ IRB.conf[:MAIN_CONTEXT]
385
+ end
386
+
387
+ # Initializes IRB and creates a new Irb.irb object at the +TOPLEVEL_BINDING+
388
+ def IRB.start(ap_path = nil)
389
+ STDOUT.sync = true
390
+ $0 = File::basename(ap_path, ".rb") if ap_path
391
+
392
+ IRB.setup(ap_path)
393
+
394
+ if @CONF[:SCRIPT]
395
+ irb = Irb.new(nil, @CONF[:SCRIPT])
396
+ else
397
+ irb = Irb.new
398
+ end
399
+ irb.run(@CONF)
400
+ end
401
+
402
+ # Calls each event hook of IRB.conf[:AT_EXIT] when the current session quits.
403
+ def IRB.irb_at_exit
404
+ @CONF[:AT_EXIT].each{|hook| hook.call}
405
+ end
406
+
407
+ # Quits irb
408
+ def IRB.irb_exit(irb, ret)
409
+ throw :IRB_EXIT, ret
410
+ end
411
+
412
+ # Aborts then interrupts irb.
413
+ #
414
+ # Will raise an Abort exception, or the given +exception+.
415
+ def IRB.irb_abort(irb, exception = Abort)
416
+ if defined? Thread
417
+ irb.context.thread.raise exception, "abort then interrupt!"
418
+ else
419
+ raise exception, "abort then interrupt!"
420
+ end
421
+ end
422
+
423
+ class Irb
424
+ ASSIGNMENT_NODE_TYPES = [
425
+ # Local, instance, global, class, constant, instance, and index assignment:
426
+ # "foo = bar",
427
+ # "@foo = bar",
428
+ # "$foo = bar",
429
+ # "@@foo = bar",
430
+ # "::Foo = bar",
431
+ # "a::Foo = bar",
432
+ # "Foo = bar"
433
+ # "foo.bar = 1"
434
+ # "foo[1] = bar"
435
+ :assign,
436
+
437
+ # Operation assignment:
438
+ # "foo += bar"
439
+ # "foo -= bar"
440
+ # "foo ||= bar"
441
+ # "foo &&= bar"
442
+ :opassign,
443
+
444
+ # Multiple assignment:
445
+ # "foo, bar = 1, 2
446
+ :massign,
447
+ ]
448
+ # Note: instance and index assignment expressions could also be written like:
449
+ # "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former
450
+ # be parsed as :assign and echo will be suppressed, but the latter is
451
+ # parsed as a :method_add_arg and the output won't be suppressed
452
+
453
+ # Creates a new irb session
454
+ def initialize(workspace = nil, input_method = nil)
455
+ @context = Context.new(self, workspace, input_method)
456
+ @context.main.extend ExtendCommandBundle
457
+ @signal_status = :IN_IRB
458
+ @scanner = RubyLex.new
459
+ end
460
+
461
+ def run(conf = IRB.conf)
462
+ conf[:IRB_RC].call(context) if conf[:IRB_RC]
463
+ conf[:MAIN_CONTEXT] = context
464
+
465
+ trap("SIGINT") do
466
+ signal_handle
467
+ end
468
+
469
+ begin
470
+ catch(:IRB_EXIT) do
471
+ eval_input
472
+ end
473
+ ensure
474
+ conf[:AT_EXIT].each{|hook| hook.call}
475
+ end
476
+ end
477
+
478
+ # Returns the current context of this irb session
479
+ attr_reader :context
480
+ # The lexer used by this irb session
481
+ attr_accessor :scanner
482
+
483
+ # Evaluates input for this session.
484
+ def eval_input
485
+ exc = nil
486
+
487
+ @scanner.set_prompt do
488
+ |ltype, indent, continue, line_no|
489
+ if ltype
490
+ f = @context.prompt_s
491
+ elsif continue
492
+ f = @context.prompt_c
493
+ elsif indent > 0
494
+ f = @context.prompt_n
495
+ else
496
+ f = @context.prompt_i
497
+ end
498
+ f = "" unless f
499
+ if @context.prompting?
500
+ @context.io.prompt = p = prompt(f, ltype, indent, line_no)
501
+ else
502
+ @context.io.prompt = p = ""
503
+ end
504
+ if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
505
+ unless ltype
506
+ prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
507
+ ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
508
+ indent * 2 - p.size
509
+ ind += 2 if continue
510
+ @context.io.prompt = p + " " * ind if ind > 0
511
+ end
512
+ end
513
+ @context.io.prompt
514
+ end
515
+
516
+ @scanner.set_input(@context.io) do
517
+ signal_status(:IN_INPUT) do
518
+ if l = @context.io.gets
519
+ print l if @context.verbose?
520
+ else
521
+ if @context.ignore_eof? and @context.io.readable_after_eof?
522
+ l = "\n"
523
+ if @context.verbose?
524
+ printf "Use \"exit\" to leave %s\n", @context.ap_name
525
+ end
526
+ else
527
+ print "\n"
528
+ end
529
+ end
530
+ l
531
+ end
532
+ end
533
+
534
+ @scanner.set_auto_indent(@context) if @context.auto_indent_mode
535
+
536
+ @scanner.each_top_level_statement do |line, line_no|
537
+ signal_status(:IN_EVAL) do
538
+ begin
539
+ line.untaint if RUBY_VERSION < '2.7'
540
+ @context.evaluate(line, line_no, exception: exc)
541
+ output_value if @context.echo? && (@context.echo_on_assignment? || !assignment_expression?(line))
542
+ rescue Interrupt => exc
543
+ rescue SystemExit, SignalException
544
+ raise
545
+ rescue Exception => exc
546
+ else
547
+ exc = nil
548
+ next
549
+ end
550
+ handle_exception(exc)
551
+ end
552
+ end
553
+ end
554
+
555
+ def handle_exception(exc)
556
+ if exc.backtrace && exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
557
+ !(SyntaxError === exc)
558
+ irb_bug = true
559
+ else
560
+ irb_bug = false
561
+ end
562
+
563
+ if STDOUT.tty?
564
+ attr = ATTR_TTY
565
+ print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n"
566
+ else
567
+ attr = ATTR_PLAIN
568
+ end
569
+ messages = []
570
+ lasts = []
571
+ levels = 0
572
+ if exc.backtrace
573
+ count = 0
574
+ exc.backtrace.each do |m|
575
+ m = @context.workspace.filter_backtrace(m) or next unless irb_bug
576
+ count += 1
577
+ if attr == ATTR_TTY
578
+ m = sprintf("%9d: from %s", count, m)
579
+ else
580
+ m = "\tfrom #{m}"
581
+ end
582
+ if messages.size < @context.back_trace_limit
583
+ messages.push(m)
584
+ elsif lasts.size < @context.back_trace_limit
585
+ lasts.push(m).shift
586
+ levels += 1
587
+ end
588
+ end
589
+ end
590
+ if attr == ATTR_TTY
591
+ unless lasts.empty?
592
+ puts lasts.reverse
593
+ printf "... %d levels...\n", levels if levels > 0
594
+ end
595
+ puts messages.reverse
596
+ end
597
+ m = exc.to_s.split(/\n/)
598
+ print "#{attr[1]}#{exc.class} (#{attr[4]}#{m.shift}#{attr[0, 1]})#{attr[]}\n"
599
+ puts m.map {|s| "#{attr[1]}#{s}#{attr[]}\n"}
600
+ if attr == ATTR_PLAIN
601
+ puts messages
602
+ unless lasts.empty?
603
+ puts lasts
604
+ printf "... %d levels...\n", levels if levels > 0
605
+ end
606
+ end
607
+ print "Maybe IRB bug!\n" if irb_bug
608
+ end
609
+
610
+ # Evaluates the given block using the given +path+ as the Context#irb_path
611
+ # and +name+ as the Context#irb_name.
612
+ #
613
+ # Used by the irb command +source+, see IRB@IRB+Sessions for more
614
+ # information.
615
+ def suspend_name(path = nil, name = nil)
616
+ @context.irb_path, back_path = path, @context.irb_path if path
617
+ @context.irb_name, back_name = name, @context.irb_name if name
618
+ begin
619
+ yield back_path, back_name
620
+ ensure
621
+ @context.irb_path = back_path if path
622
+ @context.irb_name = back_name if name
623
+ end
624
+ end
625
+
626
+ # Evaluates the given block using the given +workspace+ as the
627
+ # Context#workspace.
628
+ #
629
+ # Used by the irb command +irb_load+, see IRB@IRB+Sessions for more
630
+ # information.
631
+ def suspend_workspace(workspace)
632
+ @context.workspace, back_workspace = workspace, @context.workspace
633
+ begin
634
+ yield back_workspace
635
+ ensure
636
+ @context.workspace = back_workspace
637
+ end
638
+ end
639
+
640
+ # Evaluates the given block using the given +input_method+ as the
641
+ # Context#io.
642
+ #
643
+ # Used by the irb commands +source+ and +irb_load+, see IRB@IRB+Sessions
644
+ # for more information.
645
+ def suspend_input_method(input_method)
646
+ back_io = @context.io
647
+ @context.instance_eval{@io = input_method}
648
+ begin
649
+ yield back_io
650
+ ensure
651
+ @context.instance_eval{@io = back_io}
652
+ end
653
+ end
654
+
655
+ # Evaluates the given block using the given +context+ as the Context.
656
+ def suspend_context(context)
657
+ @context, back_context = context, @context
658
+ begin
659
+ yield back_context
660
+ ensure
661
+ @context = back_context
662
+ end
663
+ end
664
+
665
+ # Handler for the signal SIGINT, see Kernel#trap for more information.
666
+ def signal_handle
667
+ unless @context.ignore_sigint?
668
+ print "\nabort!\n" if @context.verbose?
669
+ exit
670
+ end
671
+
672
+ case @signal_status
673
+ when :IN_INPUT
674
+ print "^C\n"
675
+ raise RubyLex::TerminateLineInput
676
+ when :IN_EVAL
677
+ IRB.irb_abort(self)
678
+ when :IN_LOAD
679
+ IRB.irb_abort(self, LoadAbort)
680
+ when :IN_IRB
681
+ # ignore
682
+ else
683
+ # ignore other cases as well
684
+ end
685
+ end
686
+
687
+ # Evaluates the given block using the given +status+.
688
+ def signal_status(status)
689
+ return yield if @signal_status == :IN_LOAD
690
+
691
+ signal_status_back = @signal_status
692
+ @signal_status = status
693
+ begin
694
+ yield
695
+ ensure
696
+ @signal_status = signal_status_back
697
+ end
698
+ end
699
+
700
+ def prompt(prompt, ltype, indent, line_no) # :nodoc:
701
+ p = prompt.dup
702
+ p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
703
+ case $2
704
+ when "N"
705
+ @context.irb_name
706
+ when "m"
707
+ @context.main.to_s
708
+ when "M"
709
+ @context.main.inspect
710
+ when "l"
711
+ ltype
712
+ when "i"
713
+ if indent < 0
714
+ if $1
715
+ "-".rjust($1.to_i)
716
+ else
717
+ "-"
718
+ end
719
+ else
720
+ if $1
721
+ format("%" + $1 + "d", indent)
722
+ else
723
+ indent.to_s
724
+ end
725
+ end
726
+ when "n"
727
+ if $1
728
+ format("%" + $1 + "d", line_no)
729
+ else
730
+ line_no.to_s
731
+ end
732
+ when "%"
733
+ "%"
734
+ end
735
+ end
736
+ p
737
+ end
738
+
739
+ def output_value # :nodoc:
740
+ printf @context.return_format, @context.inspect_last_value
741
+ end
742
+
743
+ # Outputs the local variables to this current session, including
744
+ # #signal_status and #context, using IRB::Locale.
745
+ def inspect
746
+ ary = []
747
+ for iv in instance_variables
748
+ case (iv = iv.to_s)
749
+ when "@signal_status"
750
+ ary.push format("%s=:%s", iv, @signal_status.id2name)
751
+ when "@context"
752
+ ary.push format("%s=%s", iv, eval(iv).__to_s__)
753
+ else
754
+ ary.push format("%s=%s", iv, eval(iv))
755
+ end
756
+ end
757
+ format("#<%s: %s>", self.class, ary.join(", "))
758
+ end
759
+
760
+ def assignment_expression?(line)
761
+ # Try to parse the line and check if the last of possibly multiple
762
+ # expressions is an assignment type.
763
+
764
+ # If the expression is invalid, Ripper.sexp should return nil which will
765
+ # result in false being returned. Any valid expression should return an
766
+ # s-expression where the second selement of the top level array is an
767
+ # array of parsed expressions. The first element of each expression is the
768
+ # expression's type.
769
+ verbose, $VERBOSE = $VERBOSE, nil
770
+ result = ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0))
771
+ $VERBOSE = verbose
772
+ result
773
+ end
774
+
775
+ ATTR_TTY = "\e[%sm"
776
+ def ATTR_TTY.[](*a) self % a.join(";"); end
777
+ ATTR_PLAIN = ""
778
+ def ATTR_PLAIN.[](*) self; end
779
+ end
780
+
781
+ def @CONF.inspect
782
+ IRB.version unless self[:VERSION]
783
+
784
+ array = []
785
+ for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
786
+ case k
787
+ when :MAIN_CONTEXT, :__TMP__EHV__
788
+ array.push format("CONF[:%s]=...myself...", k.id2name)
789
+ when :PROMPT
790
+ s = v.collect{
791
+ |kk, vv|
792
+ ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
793
+ format(":%s=>{%s}", kk.id2name, ss.join(", "))
794
+ }
795
+ array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
796
+ else
797
+ array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
798
+ end
799
+ end
800
+ array.join("\n")
801
+ end
802
+ end
803
+
804
+ class Binding
805
+ # Opens an IRB session where +binding.irb+ is called which allows for
806
+ # interactive debugging. You can call any methods or variables available in
807
+ # the current scope, and mutate state if you need to.
808
+ #
809
+ #
810
+ # Given a Ruby file called +potato.rb+ containing the following code:
811
+ #
812
+ # class Potato
813
+ # def initialize
814
+ # @cooked = false
815
+ # binding.irb
816
+ # puts "Cooked potato: #{@cooked}"
817
+ # end
818
+ # end
819
+ #
820
+ # Potato.new
821
+ #
822
+ # Running <code>ruby potato.rb</code> will open an IRB session where
823
+ # +binding.irb+ is called, and you will see the following:
824
+ #
825
+ # $ ruby potato.rb
826
+ #
827
+ # From: potato.rb @ line 4 :
828
+ #
829
+ # 1: class Potato
830
+ # 2: def initialize
831
+ # 3: @cooked = false
832
+ # => 4: binding.irb
833
+ # 5: puts "Cooked potato: #{@cooked}"
834
+ # 6: end
835
+ # 7: end
836
+ # 8:
837
+ # 9: Potato.new
838
+ #
839
+ # irb(#<Potato:0x00007feea1916670>):001:0>
840
+ #
841
+ # You can type any valid Ruby code and it will be evaluated in the current
842
+ # context. This allows you to debug without having to run your code repeatedly:
843
+ #
844
+ # irb(#<Potato:0x00007feea1916670>):001:0> @cooked
845
+ # => false
846
+ # irb(#<Potato:0x00007feea1916670>):002:0> self.class
847
+ # => Potato
848
+ # irb(#<Potato:0x00007feea1916670>):003:0> caller.first
849
+ # => ".../2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:in `eval'"
850
+ # irb(#<Potato:0x00007feea1916670>):004:0> @cooked = true
851
+ # => true
852
+ #
853
+ # You can exit the IRB session with the +exit+ command. Note that exiting will
854
+ # resume execution where +binding.irb+ had paused it, as you can see from the
855
+ # output printed to standard output in this example:
856
+ #
857
+ # irb(#<Potato:0x00007feea1916670>):005:0> exit
858
+ # Cooked potato: true
859
+ #
860
+ #
861
+ # See IRB@IRB+Usage for more information.
862
+ def irb
863
+ IRB.setup(source_location[0], argv: [])
864
+ workspace = IRB::WorkSpace.new(self)
865
+ STDOUT.print(workspace.code_around_binding)
866
+ binding_irb = IRB::Irb.new(workspace)
867
+ binding_irb.context.irb_path = File.expand_path(source_location[0])
868
+ binding_irb.run(IRB.conf)
869
+ end
870
+ end