1 | #
|
---|
2 | # irb.rb - irb main module
|
---|
3 | # $Release Version: 0.9.5 $
|
---|
4 | # $Revision: 11708 $
|
---|
5 | # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $
|
---|
6 | # by Keiju ISHITSUKA([email protected])
|
---|
7 | #
|
---|
8 | # --
|
---|
9 | #
|
---|
10 | #
|
---|
11 | #
|
---|
12 | require "e2mmap"
|
---|
13 |
|
---|
14 | require "irb/init"
|
---|
15 | require "irb/context"
|
---|
16 | require "irb/extend-command"
|
---|
17 | #require "irb/workspace"
|
---|
18 |
|
---|
19 | require "irb/ruby-lex"
|
---|
20 | require "irb/input-method"
|
---|
21 | require "irb/locale"
|
---|
22 |
|
---|
23 | STDOUT.sync = true
|
---|
24 |
|
---|
25 | module IRB
|
---|
26 | @RCS_ID='-$Id: irb.rb 11708 2007-02-12 23:01:19Z shyouhei $-'
|
---|
27 |
|
---|
28 | class Abort < Exception;end
|
---|
29 |
|
---|
30 | #
|
---|
31 | @CONF = {}
|
---|
32 |
|
---|
33 | def IRB.conf
|
---|
34 | @CONF
|
---|
35 | end
|
---|
36 |
|
---|
37 | # IRB version method
|
---|
38 | def IRB.version
|
---|
39 | if v = @CONF[:VERSION] then return v end
|
---|
40 |
|
---|
41 | require "irb/version"
|
---|
42 | rv = @RELEASE_VERSION.sub(/\.0/, "")
|
---|
43 | @CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE)
|
---|
44 | end
|
---|
45 |
|
---|
46 | def IRB.CurrentContext
|
---|
47 | IRB.conf[:MAIN_CONTEXT]
|
---|
48 | end
|
---|
49 |
|
---|
50 | # initialize IRB and start TOP_LEVEL irb
|
---|
51 | def IRB.start(ap_path = nil)
|
---|
52 | $0 = File::basename(ap_path, ".rb") if ap_path
|
---|
53 |
|
---|
54 | IRB.setup(ap_path)
|
---|
55 |
|
---|
56 | if @CONF[:SCRIPT]
|
---|
57 | irb = Irb.new(nil, @CONF[:SCRIPT])
|
---|
58 | else
|
---|
59 | irb = Irb.new
|
---|
60 | end
|
---|
61 |
|
---|
62 | @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
---|
63 | @CONF[:MAIN_CONTEXT] = irb.context
|
---|
64 |
|
---|
65 | trap("SIGINT") do
|
---|
66 | irb.signal_handle
|
---|
67 | end
|
---|
68 |
|
---|
69 | catch(:IRB_EXIT) do
|
---|
70 | irb.eval_input
|
---|
71 | end
|
---|
72 | # print "\n"
|
---|
73 | end
|
---|
74 |
|
---|
75 | def IRB.irb_exit(irb, ret)
|
---|
76 | throw :IRB_EXIT, ret
|
---|
77 | end
|
---|
78 |
|
---|
79 | def IRB.irb_abort(irb, exception = Abort)
|
---|
80 | if defined? Thread
|
---|
81 | irb.context.thread.raise exception, "abort then interrupt!!"
|
---|
82 | else
|
---|
83 | raise exception, "abort then interrupt!!"
|
---|
84 | end
|
---|
85 | end
|
---|
86 |
|
---|
87 | #
|
---|
88 | # irb interpriter main routine
|
---|
89 | #
|
---|
90 | class Irb
|
---|
91 | def initialize(workspace = nil, input_method = nil, output_method = nil)
|
---|
92 | @context = Context.new(self, workspace, input_method, output_method)
|
---|
93 | @context.main.extend ExtendCommandBundle
|
---|
94 | @signal_status = :IN_IRB
|
---|
95 |
|
---|
96 | @scanner = RubyLex.new
|
---|
97 | @scanner.exception_on_syntax_error = false
|
---|
98 | end
|
---|
99 | attr_reader :context
|
---|
100 | attr_accessor :scanner
|
---|
101 |
|
---|
102 | def eval_input
|
---|
103 | @scanner.set_prompt do
|
---|
104 | |ltype, indent, continue, line_no|
|
---|
105 | if ltype
|
---|
106 | f = @context.prompt_s
|
---|
107 | elsif continue
|
---|
108 | f = @context.prompt_c
|
---|
109 | elsif indent > 0
|
---|
110 | f = @context.prompt_n
|
---|
111 | else @context.prompt_i
|
---|
112 | f = @context.prompt_i
|
---|
113 | end
|
---|
114 | f = "" unless f
|
---|
115 | if @context.prompting?
|
---|
116 | @context.io.prompt = p = prompt(f, ltype, indent, line_no)
|
---|
117 | else
|
---|
118 | @context.io.prompt = p = ""
|
---|
119 | end
|
---|
120 | if @context.auto_indent_mode
|
---|
121 | unless ltype
|
---|
122 | ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size +
|
---|
123 | indent * 2 - p.size
|
---|
124 | ind += 2 if continue
|
---|
125 | @context.io.prompt = p + " " * ind if ind > 0
|
---|
126 | end
|
---|
127 | end
|
---|
128 | end
|
---|
129 |
|
---|
130 | @scanner.set_input(@context.io) do
|
---|
131 | signal_status(:IN_INPUT) do
|
---|
132 | if l = @context.io.gets
|
---|
133 | print l if @context.verbose?
|
---|
134 | else
|
---|
135 | if @context.ignore_eof? and @context.io.readable_atfer_eof?
|
---|
136 | l = "\n"
|
---|
137 | if @context.verbose?
|
---|
138 | printf "Use \"exit\" to leave %s\n", @context.ap_name
|
---|
139 | end
|
---|
140 | end
|
---|
141 | end
|
---|
142 | l
|
---|
143 | end
|
---|
144 | end
|
---|
145 |
|
---|
146 | @scanner.each_top_level_statement do |line, line_no|
|
---|
147 | signal_status(:IN_EVAL) do
|
---|
148 | begin
|
---|
149 | line.untaint
|
---|
150 | @context.evaluate(line, line_no)
|
---|
151 | output_value if @context.echo?
|
---|
152 | rescue StandardError, ScriptError, Abort
|
---|
153 | $! = RuntimeError.new("unknown exception raised") unless $!
|
---|
154 | print $!.class, ": ", $!, "\n"
|
---|
155 | if $@[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && $!.class.to_s !~ /^IRB/
|
---|
156 | irb_bug = true
|
---|
157 | else
|
---|
158 | irb_bug = false
|
---|
159 | end
|
---|
160 |
|
---|
161 | messages = []
|
---|
162 | lasts = []
|
---|
163 | levels = 0
|
---|
164 | for m in $@
|
---|
165 | m = @context.workspace.filter_backtrace(m) unless irb_bug
|
---|
166 | if m
|
---|
167 | if messages.size < @context.back_trace_limit
|
---|
168 | messages.push "\tfrom "+m
|
---|
169 | else
|
---|
170 | lasts.push "\tfrom "+m
|
---|
171 | if lasts.size > @context.back_trace_limit
|
---|
172 | lasts.shift
|
---|
173 | levels += 1
|
---|
174 | end
|
---|
175 | end
|
---|
176 | end
|
---|
177 | end
|
---|
178 | print messages.join("\n"), "\n"
|
---|
179 | unless lasts.empty?
|
---|
180 | printf "... %d levels...\n", levels if levels > 0
|
---|
181 | print lasts.join("\n")
|
---|
182 | end
|
---|
183 | print "Maybe IRB bug!!\n" if irb_bug
|
---|
184 | end
|
---|
185 | if $SAFE > 2
|
---|
186 | warn "Error: irb does not work for $SAFE level higher than 2"
|
---|
187 | exit 1
|
---|
188 | end
|
---|
189 | end
|
---|
190 | end
|
---|
191 | end
|
---|
192 |
|
---|
193 | def suspend_name(path = nil, name = nil)
|
---|
194 | @context.irb_path, back_path = path, @context.irb_path if path
|
---|
195 | @context.irb_name, back_name = name, @context.irb_name if name
|
---|
196 | begin
|
---|
197 | yield back_path, back_name
|
---|
198 | ensure
|
---|
199 | @context.irb_path = back_path if path
|
---|
200 | @context.irb_name = back_name if name
|
---|
201 | end
|
---|
202 | end
|
---|
203 |
|
---|
204 | def suspend_workspace(workspace)
|
---|
205 | @context.workspace, back_workspace = workspace, @context.workspace
|
---|
206 | begin
|
---|
207 | yield back_workspace
|
---|
208 | ensure
|
---|
209 | @context.workspace = back_workspace
|
---|
210 | end
|
---|
211 | end
|
---|
212 |
|
---|
213 | def suspend_input_method(input_method)
|
---|
214 | back_io = @context.io
|
---|
215 | @context.instance_eval{@io = input_method}
|
---|
216 | begin
|
---|
217 | yield back_io
|
---|
218 | ensure
|
---|
219 | @context.instance_eval{@io = back_io}
|
---|
220 | end
|
---|
221 | end
|
---|
222 |
|
---|
223 | def suspend_context(context)
|
---|
224 | @context, back_context = context, @context
|
---|
225 | begin
|
---|
226 | yield back_context
|
---|
227 | ensure
|
---|
228 | @context = back_context
|
---|
229 | end
|
---|
230 | end
|
---|
231 |
|
---|
232 | def signal_handle
|
---|
233 | unless @context.ignore_sigint?
|
---|
234 | print "\nabort!!\n" if @context.verbose?
|
---|
235 | exit
|
---|
236 | end
|
---|
237 |
|
---|
238 | case @signal_status
|
---|
239 | when :IN_INPUT
|
---|
240 | print "^C\n"
|
---|
241 | raise RubyLex::TerminateLineInput
|
---|
242 | when :IN_EVAL
|
---|
243 | IRB.irb_abort(self)
|
---|
244 | when :IN_LOAD
|
---|
245 | IRB.irb_abort(self, LoadAbort)
|
---|
246 | when :IN_IRB
|
---|
247 | # ignore
|
---|
248 | else
|
---|
249 | # ignore other cases as well
|
---|
250 | end
|
---|
251 | end
|
---|
252 |
|
---|
253 | def signal_status(status)
|
---|
254 | return yield if @signal_status == :IN_LOAD
|
---|
255 |
|
---|
256 | signal_status_back = @signal_status
|
---|
257 | @signal_status = status
|
---|
258 | begin
|
---|
259 | yield
|
---|
260 | ensure
|
---|
261 | @signal_status = signal_status_back
|
---|
262 | end
|
---|
263 | end
|
---|
264 |
|
---|
265 | def prompt(prompt, ltype, indent, line_no)
|
---|
266 | p = prompt.dup
|
---|
267 | p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
|
---|
268 | case $2
|
---|
269 | when "N"
|
---|
270 | @context.irb_name
|
---|
271 | when "m"
|
---|
272 | @context.main.to_s
|
---|
273 | when "M"
|
---|
274 | @context.main.inspect
|
---|
275 | when "l"
|
---|
276 | ltype
|
---|
277 | when "i"
|
---|
278 | if $1
|
---|
279 | format("%" + $1 + "d", indent)
|
---|
280 | else
|
---|
281 | indent.to_s
|
---|
282 | end
|
---|
283 | when "n"
|
---|
284 | if $1
|
---|
285 | format("%" + $1 + "d", line_no)
|
---|
286 | else
|
---|
287 | line_no.to_s
|
---|
288 | end
|
---|
289 | when "%"
|
---|
290 | "%"
|
---|
291 | end
|
---|
292 | end
|
---|
293 | p
|
---|
294 | end
|
---|
295 |
|
---|
296 | def output_value
|
---|
297 | if @context.inspect?
|
---|
298 | printf @context.return_format, @context.last_value.inspect
|
---|
299 | else
|
---|
300 | printf @context.return_format, @context.last_value
|
---|
301 | end
|
---|
302 | end
|
---|
303 |
|
---|
304 | def inspect
|
---|
305 | ary = []
|
---|
306 | for iv in instance_variables
|
---|
307 | case iv
|
---|
308 | when "@signal_status"
|
---|
309 | ary.push format("%s=:%s", iv, @signal_status.id2name)
|
---|
310 | when "@context"
|
---|
311 | ary.push format("%s=%s", iv, eval(iv).__to_s__)
|
---|
312 | else
|
---|
313 | ary.push format("%s=%s", iv, eval(iv))
|
---|
314 | end
|
---|
315 | end
|
---|
316 | format("#<%s: %s>", self.class, ary.join(", "))
|
---|
317 | end
|
---|
318 | end
|
---|
319 |
|
---|
320 | # Singleton method
|
---|
321 | def @CONF.inspect
|
---|
322 | IRB.version unless self[:VERSION]
|
---|
323 |
|
---|
324 | array = []
|
---|
325 | for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
|
---|
326 | case k
|
---|
327 | when :MAIN_CONTEXT, :__TMP__EHV__
|
---|
328 | array.push format("CONF[:%s]=...myself...", k.id2name)
|
---|
329 | when :PROMPT
|
---|
330 | s = v.collect{
|
---|
331 | |kk, vv|
|
---|
332 | ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
|
---|
333 | format(":%s=>{%s}", kk.id2name, ss.join(", "))
|
---|
334 | }
|
---|
335 | array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
|
---|
336 | else
|
---|
337 | array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
|
---|
338 | end
|
---|
339 | end
|
---|
340 | array.join("\n")
|
---|
341 | end
|
---|
342 | end
|
---|