irb 1.1.0.pre.4

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