irb 1.1.0.pre.3

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 (49) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +55 -0
  4. data/exe/irb +11 -0
  5. data/irb.gemspec +29 -0
  6. data/lib/irb.rb +855 -0
  7. data/lib/irb/cmd/chws.rb +34 -0
  8. data/lib/irb/cmd/fork.rb +39 -0
  9. data/lib/irb/cmd/help.rb +46 -0
  10. data/lib/irb/cmd/load.rb +67 -0
  11. data/lib/irb/cmd/nop.rb +39 -0
  12. data/lib/irb/cmd/pushws.rb +41 -0
  13. data/lib/irb/cmd/subirb.rb +43 -0
  14. data/lib/irb/color.rb +218 -0
  15. data/lib/irb/completion.rb +339 -0
  16. data/lib/irb/context.rb +459 -0
  17. data/lib/irb/ext/change-ws.rb +46 -0
  18. data/lib/irb/ext/history.rb +120 -0
  19. data/lib/irb/ext/loader.rb +129 -0
  20. data/lib/irb/ext/multi-irb.rb +265 -0
  21. data/lib/irb/ext/save-history.rb +117 -0
  22. data/lib/irb/ext/tracer.rb +72 -0
  23. data/lib/irb/ext/use-loader.rb +77 -0
  24. data/lib/irb/ext/workspaces.rb +67 -0
  25. data/lib/irb/extend-command.rb +328 -0
  26. data/lib/irb/frame.rb +81 -0
  27. data/lib/irb/help.rb +37 -0
  28. data/lib/irb/init.rb +312 -0
  29. data/lib/irb/input-method.rb +298 -0
  30. data/lib/irb/inspector.rb +142 -0
  31. data/lib/irb/lc/.document +4 -0
  32. data/lib/irb/lc/error.rb +32 -0
  33. data/lib/irb/lc/help-message +50 -0
  34. data/lib/irb/lc/ja/encoding_aliases.rb +11 -0
  35. data/lib/irb/lc/ja/error.rb +31 -0
  36. data/lib/irb/lc/ja/help-message +52 -0
  37. data/lib/irb/locale.rb +182 -0
  38. data/lib/irb/magic-file.rb +38 -0
  39. data/lib/irb/notifier.rb +232 -0
  40. data/lib/irb/output-method.rb +92 -0
  41. data/lib/irb/ruby-lex.rb +492 -0
  42. data/lib/irb/ruby-token.rb +267 -0
  43. data/lib/irb/slex.rb +282 -0
  44. data/lib/irb/src_encoding.rb +7 -0
  45. data/lib/irb/version.rb +17 -0
  46. data/lib/irb/workspace.rb +190 -0
  47. data/lib/irb/ws-for-case-2.rb +15 -0
  48. data/lib/irb/xmp.rb +170 -0
  49. metadata +133 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 71eba1b800fb1d93376272f2f222979ae70d21f19a129b9c06a148784a2e178b
4
+ data.tar.gz: 02e1cb9a9d88a5e582467975edf596e848e7076066ada250798c43ccbafdfe0b
5
+ SHA512:
6
+ metadata.gz: a4acfeb73e0b972fb9ca65b89e1e74f8c9523c26b3d9021af148214f7991d4eb9d633b58a6dbd7b7da7b1c800efc7dd814ddee9bd31c0680ee6e59c0c7b4e5b4
7
+ data.tar.gz: c0cf5a8bf14b9d1fc037021cff5cd6ad94834595b4c21f933367111114a241279c7643db6e1e0ac408746c448ff9f9b37acf65923600e1437a4a77aca07d5f49
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,55 @@
1
+ # IRB
2
+
3
+ IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby expressions read from the standard input.
4
+
5
+ The `irb` command from your shell will start the interpreter.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'irb'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install irb
22
+
23
+ ## Usage
24
+
25
+ Use of irb is easy if you know Ruby.
26
+
27
+ When executing irb, prompts are displayed as follows. Then, enter the Ruby expression. An input is executed when it is syntactically complete.
28
+
29
+ ```
30
+ $ irb
31
+ irb(main):001:0> 1+2
32
+ #=> 3
33
+ irb(main):002:0> class Foo
34
+ irb(main):003:1> def foo
35
+ irb(main):004:2> print 1
36
+ irb(main):005:2> end
37
+ irb(main):006:1> end
38
+ #=> nil
39
+ ```
40
+
41
+ The Readline extension module can be used with irb. Use of Readline is default if it's installed.
42
+
43
+ ## Development
44
+
45
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
46
+
47
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
48
+
49
+ ## Contributing
50
+
51
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/irb.
52
+
53
+ ## License
54
+
55
+ The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
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,29 @@
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 = ["LICENSE.txt", "README.md", "exe/irb", "irb.gemspec", "lib/irb.rb", "lib/irb/cmd/chws.rb", "lib/irb/cmd/fork.rb", "lib/irb/cmd/help.rb", "lib/irb/cmd/load.rb", "lib/irb/cmd/nop.rb", "lib/irb/cmd/pushws.rb", "lib/irb/cmd/subirb.rb", "lib/irb/completion.rb", "lib/irb/context.rb", "lib/irb/color.rb", "lib/irb/ext/change-ws.rb", "lib/irb/ext/history.rb", "lib/irb/ext/loader.rb", "lib/irb/ext/multi-irb.rb", "lib/irb/ext/save-history.rb", "lib/irb/ext/tracer.rb", "lib/irb/ext/use-loader.rb", "lib/irb/ext/workspaces.rb", "lib/irb/extend-command.rb", "lib/irb/frame.rb", "lib/irb/help.rb", "lib/irb/init.rb", "lib/irb/input-method.rb", "lib/irb/inspector.rb", "lib/irb/lc/.document", "lib/irb/lc/error.rb", "lib/irb/lc/help-message", "lib/irb/lc/ja/encoding_aliases.rb", "lib/irb/lc/ja/error.rb", "lib/irb/lc/ja/help-message", "lib/irb/locale.rb", "lib/irb/magic-file.rb", "lib/irb/notifier.rb", "lib/irb/output-method.rb", "lib/irb/ruby-lex.rb", "lib/irb/ruby-token.rb", "lib/irb/slex.rb", "lib/irb/src_encoding.rb", "lib/irb/version.rb", "lib/irb/workspace.rb", "lib/irb/ws-for-case-2.rb", "lib/irb/xmp.rb"]
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4")
25
+
26
+ spec.add_dependency "reline", ">= 0.0.1"
27
+ spec.add_development_dependency "bundler"
28
+ spec.add_development_dependency "rake"
29
+ end
@@ -0,0 +1,855 @@
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 Readline extension module can be used with irb. Use of Readline is
49
+ # 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
+ # --reidline Use Reidline extension module
65
+ # --noreidline Don't use Reidline extension module
66
+ # --readline Use Readline extension module
67
+ # --noreadline Don't use Readline extension 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 --reidline and --readline.
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_REIDLINE] = nil
104
+ # IRB.conf[:USE_READLINE] = 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_history</code>.
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
+ # == Customizing the IRB Prompt
136
+ #
137
+ # In order to customize the prompt, you can change the following Hash:
138
+ #
139
+ # IRB.conf[:PROMPT]
140
+ #
141
+ # This example can be used in your +.irbrc+
142
+ #
143
+ # IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode
144
+ # :AUTO_INDENT => false, # disables auto-indent mode
145
+ # :PROMPT_I => ">> ", # simple prompt
146
+ # :PROMPT_S => nil, # prompt for continuated strings
147
+ # :PROMPT_C => nil, # prompt for continuated statement
148
+ # :RETURN => " ==>%s\n" # format to return value
149
+ # }
150
+ #
151
+ # IRB.conf[:PROMPT_MODE] = :MY_PROMPT
152
+ #
153
+ # Or, invoke irb with the above prompt mode by:
154
+ #
155
+ # irb --prompt my-prompt
156
+ #
157
+ # Constants +PROMPT_I+, +PROMPT_S+ and +PROMPT_C+ specify the format. In the
158
+ # prompt specification, some special strings are available:
159
+ #
160
+ # %N # command name which is running
161
+ # %m # to_s of main object (self)
162
+ # %M # inspect of main object (self)
163
+ # %l # type of string(", ', /, ]), `]' is inner %w[...]
164
+ # %NNi # indent level. NN is digits and means as same as printf("%NNd").
165
+ # # It can be omitted
166
+ # %NNn # line number.
167
+ # %% # %
168
+ #
169
+ # For instance, the default prompt mode is defined as follows:
170
+ #
171
+ # IRB.conf[:PROMPT_MODE][:DEFAULT] = {
172
+ # :PROMPT_I => "%N(%m):%03n:%i> ",
173
+ # :PROMPT_N => "%N(%m):%03n:%i> ",
174
+ # :PROMPT_S => "%N(%m):%03n:%i%l ",
175
+ # :PROMPT_C => "%N(%m):%03n:%i* ",
176
+ # :RETURN => "%s\n" # used to printf
177
+ # }
178
+ #
179
+ # irb comes with a number of available modes:
180
+ #
181
+ # # :NULL:
182
+ # # :PROMPT_I:
183
+ # # :PROMPT_N:
184
+ # # :PROMPT_S:
185
+ # # :PROMPT_C:
186
+ # # :RETURN: |
187
+ # # %s
188
+ # # :DEFAULT:
189
+ # # :PROMPT_I: ! '%N(%m):%03n:%i> '
190
+ # # :PROMPT_N: ! '%N(%m):%03n:%i> '
191
+ # # :PROMPT_S: ! '%N(%m):%03n:%i%l '
192
+ # # :PROMPT_C: ! '%N(%m):%03n:%i* '
193
+ # # :RETURN: |
194
+ # # => %s
195
+ # # :CLASSIC:
196
+ # # :PROMPT_I: ! '%N(%m):%03n:%i> '
197
+ # # :PROMPT_N: ! '%N(%m):%03n:%i> '
198
+ # # :PROMPT_S: ! '%N(%m):%03n:%i%l '
199
+ # # :PROMPT_C: ! '%N(%m):%03n:%i* '
200
+ # # :RETURN: |
201
+ # # %s
202
+ # # :SIMPLE:
203
+ # # :PROMPT_I: ! '>> '
204
+ # # :PROMPT_N: ! '>> '
205
+ # # :PROMPT_S:
206
+ # # :PROMPT_C: ! '?> '
207
+ # # :RETURN: |
208
+ # # => %s
209
+ # # :INF_RUBY:
210
+ # # :PROMPT_I: ! '%N(%m):%03n:%i> '
211
+ # # :PROMPT_N:
212
+ # # :PROMPT_S:
213
+ # # :PROMPT_C:
214
+ # # :RETURN: |
215
+ # # %s
216
+ # # :AUTO_INDENT: true
217
+ # # :XMP:
218
+ # # :PROMPT_I:
219
+ # # :PROMPT_N:
220
+ # # :PROMPT_S:
221
+ # # :PROMPT_C:
222
+ # # :RETURN: |2
223
+ # # ==>%s
224
+ #
225
+ # == Restrictions
226
+ #
227
+ # Because irb evaluates input immediately after it is syntactically complete,
228
+ # the results may be slightly different than directly using Ruby.
229
+ #
230
+ # == IRB Sessions
231
+ #
232
+ # IRB has a special feature, that allows you to manage many sessions at once.
233
+ #
234
+ # You can create new sessions with Irb.irb, and get a list of current sessions
235
+ # with the +jobs+ command in the prompt.
236
+ #
237
+ # === Commands
238
+ #
239
+ # JobManager provides commands to handle the current sessions:
240
+ #
241
+ # jobs # List of current sessions
242
+ # fg # Switches to the session of the given number
243
+ # kill # Kills the session with the given number
244
+ #
245
+ # The +exit+ command, or ::irb_exit, will quit the current session and call any
246
+ # exit hooks with IRB.irb_at_exit.
247
+ #
248
+ # A few commands for loading files within the session are also available:
249
+ #
250
+ # +source+::
251
+ # Loads a given file in the current session and displays the source lines,
252
+ # see IrbLoader#source_file
253
+ # +irb_load+::
254
+ # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
255
+ # +irb_require+::
256
+ # Loads the given file similarly to Kernel#require
257
+ #
258
+ # === Configuration
259
+ #
260
+ # The command line options, or IRB.conf, specify the default behavior of
261
+ # Irb.irb.
262
+ #
263
+ # On the other hand, each conf in IRB@Command+line+options is used to
264
+ # individually configure IRB.irb.
265
+ #
266
+ # If a proc is set for IRB.conf[:IRB_RC], its will be invoked after execution
267
+ # of that proc with the context of the current session as its argument. Each
268
+ # session can be configured using this mechanism.
269
+ #
270
+ # === Session variables
271
+ #
272
+ # There are a few variables in every Irb session that can come in handy:
273
+ #
274
+ # <code>_</code>::
275
+ # The value command executed, as a local variable
276
+ # <code>__</code>::
277
+ # The history of evaluated commands
278
+ # <code>__[line_no]</code>::
279
+ # Returns the evaluation value at the given line number, +line_no+.
280
+ # If +line_no+ is a negative, the return value +line_no+ many lines before
281
+ # the most recent return value.
282
+ #
283
+ # === Example using IRB Sessions
284
+ #
285
+ # # invoke a new session
286
+ # irb(main):001:0> irb
287
+ # # list open sessions
288
+ # irb.1(main):001:0> jobs
289
+ # #0->irb on main (#<Thread:0x400fb7e4> : stop)
290
+ # #1->irb#1 on main (#<Thread:0x40125d64> : running)
291
+ #
292
+ # # change the active session
293
+ # irb.1(main):002:0> fg 0
294
+ # # define class Foo in top-level session
295
+ # irb(main):002:0> class Foo;end
296
+ # # invoke a new session with the context of Foo
297
+ # irb(main):003:0> irb Foo
298
+ # # define Foo#foo
299
+ # irb.2(Foo):001:0> def foo
300
+ # irb.2(Foo):002:1> print 1
301
+ # irb.2(Foo):003:1> end
302
+ #
303
+ # # change the active session
304
+ # irb.2(Foo):004:0> fg 0
305
+ # # list open sessions
306
+ # irb(main):004:0> jobs
307
+ # #0->irb on main (#<Thread:0x400fb7e4> : running)
308
+ # #1->irb#1 on main (#<Thread:0x40125d64> : stop)
309
+ # #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
310
+ # # check if Foo#foo is available
311
+ # irb(main):005:0> Foo.instance_methods #=> [:foo, ...]
312
+ #
313
+ # # change the active sesssion
314
+ # irb(main):006:0> fg 2
315
+ # # define Foo#bar in the context of Foo
316
+ # irb.2(Foo):005:0> def bar
317
+ # irb.2(Foo):006:1> print "bar"
318
+ # irb.2(Foo):007:1> end
319
+ # irb.2(Foo):010:0> Foo.instance_methods #=> [:bar, :foo, ...]
320
+ #
321
+ # # change the active session
322
+ # irb.2(Foo):011:0> fg 0
323
+ # irb(main):007:0> f = Foo.new #=> #<Foo:0x4010af3c>
324
+ # # invoke a new session with the context of f (instance of Foo)
325
+ # irb(main):008:0> irb f
326
+ # # list open sessions
327
+ # irb.3(<Foo:0x4010af3c>):001:0> jobs
328
+ # #0->irb on main (#<Thread:0x400fb7e4> : stop)
329
+ # #1->irb#1 on main (#<Thread:0x40125d64> : stop)
330
+ # #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
331
+ # #3->irb#3 on #<Foo:0x4010af3c> (#<Thread:0x4010a1e0> : running)
332
+ # # evaluate f.foo
333
+ # irb.3(<Foo:0x4010af3c>):002:0> foo #=> 1 => nil
334
+ # # evaluate f.bar
335
+ # irb.3(<Foo:0x4010af3c>):003:0> bar #=> bar => nil
336
+ # # kill jobs 1, 2, and 3
337
+ # irb.3(<Foo:0x4010af3c>):004:0> kill 1, 2, 3
338
+ # # list open sessions, should only include main session
339
+ # irb(main):009:0> jobs
340
+ # #0->irb on main (#<Thread:0x400fb7e4> : running)
341
+ # # quit irb
342
+ # irb(main):010:0> exit
343
+ module IRB
344
+
345
+ # An exception raised by IRB.irb_abort
346
+ class Abort < Exception;end
347
+
348
+ @CONF = {}
349
+
350
+
351
+ # Displays current configuration.
352
+ #
353
+ # Modifying the configuration is achieved by sending a message to IRB.conf.
354
+ #
355
+ # See IRB@Configuration for more information.
356
+ def IRB.conf
357
+ @CONF
358
+ end
359
+
360
+ # Returns the current version of IRB, including release version and last
361
+ # updated date.
362
+ def IRB.version
363
+ if v = @CONF[:VERSION] then return v end
364
+
365
+ @CONF[:VERSION] = format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE)
366
+ end
367
+
368
+ # The current IRB::Context of the session, see IRB.conf
369
+ #
370
+ # irb
371
+ # irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
372
+ # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
373
+ def IRB.CurrentContext
374
+ IRB.conf[:MAIN_CONTEXT]
375
+ end
376
+
377
+ # Initializes IRB and creates a new Irb.irb object at the +TOPLEVEL_BINDING+
378
+ def IRB.start(ap_path = nil)
379
+ STDOUT.sync = true
380
+ $0 = File::basename(ap_path, ".rb") if ap_path
381
+
382
+ IRB.setup(ap_path)
383
+
384
+ if @CONF[:SCRIPT]
385
+ irb = Irb.new(nil, @CONF[:SCRIPT])
386
+ else
387
+ irb = Irb.new
388
+ end
389
+ irb.run(@CONF)
390
+ end
391
+
392
+ # Calls each event hook of IRB.conf[:AT_EXIT] when the current session quits.
393
+ def IRB.irb_at_exit
394
+ @CONF[:AT_EXIT].each{|hook| hook.call}
395
+ end
396
+
397
+ # Quits irb
398
+ def IRB.irb_exit(irb, ret)
399
+ throw :IRB_EXIT, ret
400
+ end
401
+
402
+ # Aborts then interrupts irb.
403
+ #
404
+ # Will raise an Abort exception, or the given +exception+.
405
+ def IRB.irb_abort(irb, exception = Abort)
406
+ if defined? Thread
407
+ irb.context.thread.raise exception, "abort then interrupt!"
408
+ else
409
+ raise exception, "abort then interrupt!"
410
+ end
411
+ end
412
+
413
+ class Irb
414
+ ASSIGNMENT_NODE_TYPES = [
415
+ # Local, instance, global, class, constant, instance, and index assignment:
416
+ # "foo = bar",
417
+ # "@foo = bar",
418
+ # "$foo = bar",
419
+ # "@@foo = bar",
420
+ # "::Foo = bar",
421
+ # "a::Foo = bar",
422
+ # "Foo = bar"
423
+ # "foo.bar = 1"
424
+ # "foo[1] = bar"
425
+ :assign,
426
+
427
+ # Operation assignment:
428
+ # "foo += bar"
429
+ # "foo -= bar"
430
+ # "foo ||= bar"
431
+ # "foo &&= bar"
432
+ :opassign,
433
+
434
+ # Multiple assignment:
435
+ # "foo, bar = 1, 2
436
+ :massign,
437
+ ]
438
+ # Note: instance and index assignment expressions could also be written like:
439
+ # "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former
440
+ # be parsed as :assign and echo will be suppressed, but the latter is
441
+ # parsed as a :method_add_arg and the output won't be suppressed
442
+
443
+ # Creates a new irb session
444
+ def initialize(workspace = nil, input_method = nil, output_method = nil)
445
+ @context = Context.new(self, workspace, input_method, output_method)
446
+ @context.main.extend ExtendCommandBundle
447
+ @signal_status = :IN_IRB
448
+ @scanner = RubyLex.new
449
+ end
450
+
451
+ def run(conf = IRB.conf)
452
+ conf[:IRB_RC].call(context) if conf[:IRB_RC]
453
+ conf[:MAIN_CONTEXT] = context
454
+
455
+ trap("SIGINT") do
456
+ signal_handle
457
+ end
458
+
459
+ begin
460
+ catch(:IRB_EXIT) do
461
+ eval_input
462
+ end
463
+ ensure
464
+ conf[:AT_EXIT].each{|hook| hook.call}
465
+ end
466
+ end
467
+
468
+ # Returns the current context of this irb session
469
+ attr_reader :context
470
+ # The lexer used by this irb session
471
+ attr_accessor :scanner
472
+
473
+ # Evaluates input for this session.
474
+ def eval_input
475
+ exc = nil
476
+
477
+ @scanner.set_prompt do
478
+ |ltype, indent, continue, line_no|
479
+ if ltype
480
+ f = @context.prompt_s
481
+ elsif continue
482
+ f = @context.prompt_c
483
+ elsif indent > 0
484
+ f = @context.prompt_n
485
+ else
486
+ f = @context.prompt_i
487
+ end
488
+ f = "" unless f
489
+ if @context.prompting?
490
+ @context.io.prompt = p = prompt(f, ltype, indent, line_no)
491
+ else
492
+ @context.io.prompt = p = ""
493
+ end
494
+ if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
495
+ unless ltype
496
+ prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
497
+ ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
498
+ indent * 2 - p.size
499
+ ind += 2 if continue
500
+ @context.io.prompt = p + " " * ind if ind > 0
501
+ end
502
+ end
503
+ @context.io.prompt
504
+ end
505
+
506
+ @scanner.set_input(@context.io) do
507
+ signal_status(:IN_INPUT) do
508
+ if l = @context.io.gets
509
+ print l if @context.verbose?
510
+ else
511
+ if @context.ignore_eof? and @context.io.readable_after_eof?
512
+ l = "\n"
513
+ if @context.verbose?
514
+ printf "Use \"exit\" to leave %s\n", @context.ap_name
515
+ end
516
+ else
517
+ print "\n"
518
+ end
519
+ end
520
+ l
521
+ end
522
+ end
523
+
524
+ @scanner.set_auto_indent(@context) if @context.auto_indent_mode
525
+
526
+ @scanner.each_top_level_statement do |line, line_no|
527
+ signal_status(:IN_EVAL) do
528
+ begin
529
+ line.untaint
530
+ @context.evaluate(line, line_no, exception: exc)
531
+ output_value if @context.echo? && (@context.echo_on_assignment? || !assignment_expression?(line))
532
+ rescue Interrupt => exc
533
+ rescue SystemExit, SignalException
534
+ raise
535
+ rescue Exception => exc
536
+ else
537
+ exc = nil
538
+ next
539
+ end
540
+ handle_exception(exc)
541
+ end
542
+ end
543
+ end
544
+
545
+ def handle_exception(exc)
546
+ if exc.backtrace && exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
547
+ !(SyntaxError === exc)
548
+ irb_bug = true
549
+ else
550
+ irb_bug = false
551
+ end
552
+
553
+ if STDOUT.tty?
554
+ attr = ATTR_TTY
555
+ print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n"
556
+ else
557
+ attr = ATTR_PLAIN
558
+ end
559
+ messages = []
560
+ lasts = []
561
+ levels = 0
562
+ if exc.backtrace
563
+ count = 0
564
+ exc.backtrace.each do |m|
565
+ m = @context.workspace.filter_backtrace(m) or next unless irb_bug
566
+ count += 1
567
+ if attr == ATTR_TTY
568
+ m = sprintf("%9d: from %s", count, m)
569
+ else
570
+ m = "\tfrom #{m}"
571
+ end
572
+ if messages.size < @context.back_trace_limit
573
+ messages.push(m)
574
+ elsif lasts.size < @context.back_trace_limit
575
+ lasts.push(m).shift
576
+ levels += 1
577
+ end
578
+ end
579
+ end
580
+ if attr == ATTR_TTY
581
+ unless lasts.empty?
582
+ puts lasts.reverse
583
+ printf "... %d levels...\n", levels if levels > 0
584
+ end
585
+ puts messages.reverse
586
+ end
587
+ m = exc.to_s.split(/\n/)
588
+ print "#{attr[1]}#{exc.class} (#{attr[4]}#{m.shift}#{attr[0, 1]})#{attr[]}\n"
589
+ puts m.map {|s| "#{attr[1]}#{s}#{attr[]}\n"}
590
+ if attr == ATTR_PLAIN
591
+ puts messages
592
+ unless lasts.empty?
593
+ puts lasts
594
+ printf "... %d levels...\n", levels if levels > 0
595
+ end
596
+ end
597
+ print "Maybe IRB bug!\n" if irb_bug
598
+ end
599
+
600
+ # Evaluates the given block using the given +path+ as the Context#irb_path
601
+ # and +name+ as the Context#irb_name.
602
+ #
603
+ # Used by the irb command +source+, see IRB@IRB+Sessions for more
604
+ # information.
605
+ def suspend_name(path = nil, name = nil)
606
+ @context.irb_path, back_path = path, @context.irb_path if path
607
+ @context.irb_name, back_name = name, @context.irb_name if name
608
+ begin
609
+ yield back_path, back_name
610
+ ensure
611
+ @context.irb_path = back_path if path
612
+ @context.irb_name = back_name if name
613
+ end
614
+ end
615
+
616
+ # Evaluates the given block using the given +workspace+ as the
617
+ # Context#workspace.
618
+ #
619
+ # Used by the irb command +irb_load+, see IRB@IRB+Sessions for more
620
+ # information.
621
+ def suspend_workspace(workspace)
622
+ @context.workspace, back_workspace = workspace, @context.workspace
623
+ begin
624
+ yield back_workspace
625
+ ensure
626
+ @context.workspace = back_workspace
627
+ end
628
+ end
629
+
630
+ # Evaluates the given block using the given +input_method+ as the
631
+ # Context#io.
632
+ #
633
+ # Used by the irb commands +source+ and +irb_load+, see IRB@IRB+Sessions
634
+ # for more information.
635
+ def suspend_input_method(input_method)
636
+ back_io = @context.io
637
+ @context.instance_eval{@io = input_method}
638
+ begin
639
+ yield back_io
640
+ ensure
641
+ @context.instance_eval{@io = back_io}
642
+ end
643
+ end
644
+
645
+ # Evaluates the given block using the given +context+ as the Context.
646
+ def suspend_context(context)
647
+ @context, back_context = context, @context
648
+ begin
649
+ yield back_context
650
+ ensure
651
+ @context = back_context
652
+ end
653
+ end
654
+
655
+ # Handler for the signal SIGINT, see Kernel#trap for more information.
656
+ def signal_handle
657
+ unless @context.ignore_sigint?
658
+ print "\nabort!\n" if @context.verbose?
659
+ exit
660
+ end
661
+
662
+ case @signal_status
663
+ when :IN_INPUT
664
+ print "^C\n"
665
+ raise RubyLex::TerminateLineInput
666
+ when :IN_EVAL
667
+ IRB.irb_abort(self)
668
+ when :IN_LOAD
669
+ IRB.irb_abort(self, LoadAbort)
670
+ when :IN_IRB
671
+ # ignore
672
+ else
673
+ # ignore other cases as well
674
+ end
675
+ end
676
+
677
+ # Evaluates the given block using the given +status+.
678
+ def signal_status(status)
679
+ return yield if @signal_status == :IN_LOAD
680
+
681
+ signal_status_back = @signal_status
682
+ @signal_status = status
683
+ begin
684
+ yield
685
+ ensure
686
+ @signal_status = signal_status_back
687
+ end
688
+ end
689
+
690
+ def prompt(prompt, ltype, indent, line_no) # :nodoc:
691
+ p = prompt.dup
692
+ p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
693
+ case $2
694
+ when "N"
695
+ @context.irb_name
696
+ when "m"
697
+ @context.main.to_s
698
+ when "M"
699
+ @context.main.inspect
700
+ when "l"
701
+ ltype
702
+ when "i"
703
+ if indent < 0
704
+ if $1
705
+ "-".rjust($1.to_i)
706
+ else
707
+ "-"
708
+ end
709
+ else
710
+ if $1
711
+ format("%" + $1 + "d", indent)
712
+ else
713
+ indent.to_s
714
+ end
715
+ end
716
+ when "n"
717
+ if $1
718
+ format("%" + $1 + "d", line_no)
719
+ else
720
+ line_no.to_s
721
+ end
722
+ when "%"
723
+ "%"
724
+ end
725
+ end
726
+ p
727
+ end
728
+
729
+ def output_value # :nodoc:
730
+ printf @context.return_format, @context.inspect_last_value
731
+ end
732
+
733
+ # Outputs the local variables to this current session, including
734
+ # #signal_status and #context, using IRB::Locale.
735
+ def inspect
736
+ ary = []
737
+ for iv in instance_variables
738
+ case (iv = iv.to_s)
739
+ when "@signal_status"
740
+ ary.push format("%s=:%s", iv, @signal_status.id2name)
741
+ when "@context"
742
+ ary.push format("%s=%s", iv, eval(iv).__to_s__)
743
+ else
744
+ ary.push format("%s=%s", iv, eval(iv))
745
+ end
746
+ end
747
+ format("#<%s: %s>", self.class, ary.join(", "))
748
+ end
749
+
750
+ def assignment_expression?(line)
751
+ # Try to parse the line and check if the last of possibly multiple
752
+ # expressions is an assignment type.
753
+
754
+ # If the expression is invalid, Ripper.sexp should return nil which will
755
+ # result in false being returned. Any valid expression should return an
756
+ # s-expression where the second selement of the top level array is an
757
+ # array of parsed expressions. The first element of each expression is the
758
+ # expression's type.
759
+ ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0))
760
+ end
761
+
762
+ ATTR_TTY = "\e[%sm"
763
+ def ATTR_TTY.[](*a) self % a.join(";"); end
764
+ ATTR_PLAIN = ""
765
+ def ATTR_PLAIN.[](*) self; end
766
+ end
767
+
768
+ def @CONF.inspect
769
+ IRB.version unless self[:VERSION]
770
+
771
+ array = []
772
+ for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
773
+ case k
774
+ when :MAIN_CONTEXT, :__TMP__EHV__
775
+ array.push format("CONF[:%s]=...myself...", k.id2name)
776
+ when :PROMPT
777
+ s = v.collect{
778
+ |kk, vv|
779
+ ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
780
+ format(":%s=>{%s}", kk.id2name, ss.join(", "))
781
+ }
782
+ array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
783
+ else
784
+ array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
785
+ end
786
+ end
787
+ array.join("\n")
788
+ end
789
+ end
790
+
791
+ class Binding
792
+ # Opens an IRB session where +binding.irb+ is called which allows for
793
+ # interactive debugging. You can call any methods or variables available in
794
+ # the current scope, and mutate state if you need to.
795
+ #
796
+ #
797
+ # Given a Ruby file called +potato.rb+ containing the following code:
798
+ #
799
+ # class Potato
800
+ # def initialize
801
+ # @cooked = false
802
+ # binding.irb
803
+ # puts "Cooked potato: #{@cooked}"
804
+ # end
805
+ # end
806
+ #
807
+ # Potato.new
808
+ #
809
+ # Running <code>ruby potato.rb</code> will open an IRB session where
810
+ # +binding.irb+ is called, and you will see the following:
811
+ #
812
+ # $ ruby potato.rb
813
+ #
814
+ # From: potato.rb @ line 4 :
815
+ #
816
+ # 1: class Potato
817
+ # 2: def initialize
818
+ # 3: @cooked = false
819
+ # => 4: binding.irb
820
+ # 5: puts "Cooked potato: #{@cooked}"
821
+ # 6: end
822
+ # 7: end
823
+ # 8:
824
+ # 9: Potato.new
825
+ #
826
+ # irb(#<Potato:0x00007feea1916670>):001:0>
827
+ #
828
+ # You can type any valid Ruby code and it will be evaluated in the current
829
+ # context. This allows you to debug without having to run your code repeatedly:
830
+ #
831
+ # irb(#<Potato:0x00007feea1916670>):001:0> @cooked
832
+ # => false
833
+ # irb(#<Potato:0x00007feea1916670>):002:0> self.class
834
+ # => Potato
835
+ # irb(#<Potato:0x00007feea1916670>):003:0> caller.first
836
+ # => ".../2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:in `eval'"
837
+ # irb(#<Potato:0x00007feea1916670>):004:0> @cooked = true
838
+ # => true
839
+ #
840
+ # You can exit the IRB session with the +exit+ command. Note that exiting will
841
+ # resume execution where +binding.irb+ had paused it, as you can see from the
842
+ # output printed to standard output in this example:
843
+ #
844
+ # irb(#<Potato:0x00007feea1916670>):005:0> exit
845
+ # Cooked potato: true
846
+ #
847
+ #
848
+ # See IRB@IRB+Usage for more information.
849
+ def irb
850
+ IRB.setup(source_location[0], argv: [])
851
+ workspace = IRB::WorkSpace.new(self)
852
+ STDOUT.print(workspace.code_around_binding)
853
+ IRB::Irb.new(workspace).run(IRB.conf)
854
+ end
855
+ end