irb 1.0.0 → 1.4.1
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.
- checksums.yaml +4 -4
- data/.document +4 -0
- data/Gemfile +10 -2
- data/LICENSE.txt +3 -3
- data/README.md +3 -3
- data/Rakefile +17 -1
- data/doc/irb/irb-tools.rd.ja +184 -0
- data/doc/irb/irb.rd.ja +427 -0
- data/irb.gemspec +18 -4
- data/lib/irb/cmd/fork.rb +2 -4
- data/lib/irb/cmd/help.rb +10 -5
- data/lib/irb/cmd/info.rb +32 -0
- data/lib/irb/cmd/ls.rb +101 -0
- data/lib/irb/cmd/measure.rb +43 -0
- data/lib/irb/cmd/nop.rb +10 -4
- data/lib/irb/cmd/pushws.rb +0 -1
- data/lib/irb/cmd/show_source.rb +93 -0
- data/lib/irb/cmd/whereami.rb +20 -0
- data/lib/irb/color.rb +246 -0
- data/lib/irb/color_printer.rb +47 -0
- data/lib/irb/completion.rb +254 -55
- data/lib/irb/context.rb +165 -72
- data/lib/irb/easter-egg.rb +138 -0
- data/lib/irb/ext/change-ws.rb +0 -1
- data/lib/irb/ext/history.rb +47 -11
- data/lib/irb/ext/loader.rb +46 -20
- data/lib/irb/ext/multi-irb.rb +7 -7
- data/lib/irb/ext/save-history.rb +36 -11
- data/lib/irb/ext/tracer.rb +14 -2
- data/lib/irb/ext/use-loader.rb +4 -3
- data/lib/irb/ext/workspaces.rb +0 -1
- data/lib/irb/extend-command.rb +113 -63
- data/lib/irb/frame.rb +12 -7
- data/lib/irb/help.rb +0 -1
- data/lib/irb/init.rb +146 -26
- data/lib/irb/input-method.rb +287 -9
- data/lib/irb/inspector.rb +15 -11
- data/lib/irb/lc/error.rb +55 -16
- data/lib/irb/lc/help-message +25 -13
- data/lib/irb/lc/ja/error.rb +55 -14
- data/lib/irb/lc/ja/help-message +11 -6
- data/lib/irb/locale.rb +13 -4
- data/lib/irb/notifier.rb +12 -8
- data/lib/irb/output-method.rb +6 -6
- data/lib/irb/ruby-lex.rb +673 -992
- data/lib/irb/ruby_logo.aa +37 -0
- data/lib/irb/version.rb +2 -2
- data/lib/irb/workspace.rb +65 -21
- data/lib/irb/xmp.rb +1 -1
- data/lib/irb.rb +276 -96
- data/man/irb.1 +229 -0
- metadata +25 -31
- data/.gitignore +0 -9
- data/.travis.yml +0 -6
- data/lib/irb/lc/.document +0 -4
- data/lib/irb/ruby-token.rb +0 -267
- data/lib/irb/slex.rb +0 -282
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'pp'
|
3
|
+
require 'irb/color'
|
4
|
+
|
5
|
+
module IRB
|
6
|
+
class ColorPrinter < ::PP
|
7
|
+
class << self
|
8
|
+
def pp(obj, out = $>, width = screen_width)
|
9
|
+
q = ColorPrinter.new(out, width)
|
10
|
+
q.guard_inspect_key {q.pp obj}
|
11
|
+
q.flush
|
12
|
+
out << "\n"
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def screen_width
|
18
|
+
Reline.get_screen_size.last
|
19
|
+
rescue Errno::EINVAL # in `winsize': Invalid argument - <STDIN>
|
20
|
+
79
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def pp(obj)
|
25
|
+
if obj.is_a?(String)
|
26
|
+
# Avoid calling Ruby 2.4+ String#pretty_print that splits a string by "\n"
|
27
|
+
text(obj.inspect)
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def text(str, width = nil)
|
34
|
+
unless str.is_a?(String)
|
35
|
+
str = str.inspect
|
36
|
+
end
|
37
|
+
width ||= str.length
|
38
|
+
|
39
|
+
case str
|
40
|
+
when /\A#</, '=', '>'
|
41
|
+
super(Color.colorize(str, [:GREEN]), width)
|
42
|
+
else
|
43
|
+
super(Color.colorize_code(str, ignore_error: true), width)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/irb/completion.rb
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
# From Original Idea of shugo@ruby-lang.org
|
8
8
|
#
|
9
9
|
|
10
|
-
|
10
|
+
require_relative 'ruby-lex'
|
11
11
|
|
12
12
|
module IRB
|
13
13
|
module InputCompletor # :nodoc:
|
@@ -16,11 +16,12 @@ module IRB
|
|
16
16
|
# Set of reserved words used by Ruby, you should not use these for
|
17
17
|
# constants or variables
|
18
18
|
ReservedWords = %w[
|
19
|
+
__ENCODING__ __LINE__ __FILE__
|
19
20
|
BEGIN END
|
20
21
|
alias and
|
21
22
|
begin break
|
22
23
|
case class
|
23
|
-
def defined do
|
24
|
+
def defined? do
|
24
25
|
else elsif end ensure
|
25
26
|
false for
|
26
27
|
if in
|
@@ -35,118 +36,267 @@ module IRB
|
|
35
36
|
yield
|
36
37
|
]
|
37
38
|
|
38
|
-
|
39
|
-
bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
|
39
|
+
BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
|
40
40
|
|
41
|
+
def self.absolute_path?(p) # TODO Remove this method after 2.6 EOL.
|
42
|
+
if File.respond_to?(:absolute_path?)
|
43
|
+
File.absolute_path?(p)
|
44
|
+
else
|
45
|
+
if File.absolute_path(p) == p
|
46
|
+
true
|
47
|
+
else
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.retrieve_gem_and_system_load_path
|
54
|
+
gem_paths = Gem::Specification.latest_specs(true).map { |s|
|
55
|
+
s.require_paths.map { |p|
|
56
|
+
if absolute_path?(p)
|
57
|
+
p
|
58
|
+
else
|
59
|
+
File.join(s.full_gem_path, p)
|
60
|
+
end
|
61
|
+
}
|
62
|
+
}.flatten if defined?(Gem::Specification)
|
63
|
+
(gem_paths.to_a | $LOAD_PATH).sort
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.retrieve_files_to_require_from_load_path
|
67
|
+
@@files_from_load_path ||=
|
68
|
+
(
|
69
|
+
shortest = []
|
70
|
+
rest = retrieve_gem_and_system_load_path.each_with_object([]) { |path, result|
|
71
|
+
begin
|
72
|
+
names = Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: path)
|
73
|
+
rescue Errno::ENOENT
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
next if names.empty?
|
77
|
+
names.map! { |n| n.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '') }.sort!
|
78
|
+
shortest << names.shift
|
79
|
+
result.concat(names)
|
80
|
+
}
|
81
|
+
shortest.sort! | rest
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.retrieve_files_to_require_relative_from_current_dir
|
86
|
+
@@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
|
87
|
+
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
CompletionRequireProc = lambda { |target, preposing = nil, postposing = nil|
|
92
|
+
if target =~ /\A(['"])([^'"]+)\Z/
|
93
|
+
quote = $1
|
94
|
+
actual_target = $2
|
95
|
+
else
|
96
|
+
return nil # It's not String literal
|
97
|
+
end
|
98
|
+
tokens = RubyLex.ripper_lex_without_warning(preposing.gsub(/\s*\z/, ''))
|
99
|
+
tok = nil
|
100
|
+
tokens.reverse_each do |t|
|
101
|
+
unless [:on_lparen, :on_sp, :on_ignored_sp, :on_nl, :on_ignored_nl, :on_comment].include?(t.event)
|
102
|
+
tok = t
|
103
|
+
break
|
104
|
+
end
|
105
|
+
end
|
106
|
+
result = []
|
107
|
+
if tok && tok.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
|
108
|
+
case tok.tok
|
109
|
+
when 'require'
|
110
|
+
result = retrieve_files_to_require_from_load_path.select { |path|
|
111
|
+
path.start_with?(actual_target)
|
112
|
+
}.map { |path|
|
113
|
+
quote + path
|
114
|
+
}
|
115
|
+
when 'require_relative'
|
116
|
+
result = retrieve_files_to_require_relative_from_current_dir.select { |path|
|
117
|
+
path.start_with?(actual_target)
|
118
|
+
}.map { |path|
|
119
|
+
quote + path
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
result
|
124
|
+
}
|
125
|
+
|
126
|
+
CompletionProc = lambda { |target, preposing = nil, postposing = nil|
|
127
|
+
if preposing && postposing
|
128
|
+
result = CompletionRequireProc.(target, preposing, postposing)
|
129
|
+
unless result
|
130
|
+
result = retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
|
131
|
+
end
|
132
|
+
result
|
133
|
+
else
|
134
|
+
retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
|
135
|
+
end
|
136
|
+
}
|
137
|
+
|
138
|
+
def self.retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
|
41
139
|
case input
|
42
140
|
when /^((["'`]).*\2)\.([^.]*)$/
|
43
141
|
# String
|
44
142
|
receiver = $1
|
45
|
-
message =
|
143
|
+
message = $3
|
46
144
|
|
47
145
|
candidates = String.instance_methods.collect{|m| m.to_s}
|
48
|
-
|
146
|
+
if doc_namespace
|
147
|
+
"String.#{message}"
|
148
|
+
else
|
149
|
+
select_message(receiver, message, candidates)
|
150
|
+
end
|
49
151
|
|
50
152
|
when /^(\/[^\/]*\/)\.([^.]*)$/
|
51
153
|
# Regexp
|
52
154
|
receiver = $1
|
53
|
-
message =
|
155
|
+
message = $2
|
54
156
|
|
55
157
|
candidates = Regexp.instance_methods.collect{|m| m.to_s}
|
56
|
-
|
158
|
+
if doc_namespace
|
159
|
+
"Regexp.#{message}"
|
160
|
+
else
|
161
|
+
select_message(receiver, message, candidates)
|
162
|
+
end
|
57
163
|
|
58
164
|
when /^([^\]]*\])\.([^.]*)$/
|
59
165
|
# Array
|
60
166
|
receiver = $1
|
61
|
-
message =
|
167
|
+
message = $2
|
62
168
|
|
63
169
|
candidates = Array.instance_methods.collect{|m| m.to_s}
|
64
|
-
|
170
|
+
if doc_namespace
|
171
|
+
"Array.#{message}"
|
172
|
+
else
|
173
|
+
select_message(receiver, message, candidates)
|
174
|
+
end
|
65
175
|
|
66
176
|
when /^([^\}]*\})\.([^.]*)$/
|
67
177
|
# Proc or Hash
|
68
178
|
receiver = $1
|
69
|
-
message =
|
179
|
+
message = $2
|
70
180
|
|
71
|
-
|
72
|
-
|
73
|
-
|
181
|
+
proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
|
182
|
+
hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
|
183
|
+
if doc_namespace
|
184
|
+
["Proc.#{message}", "Hash.#{message}"]
|
185
|
+
else
|
186
|
+
select_message(receiver, message, proc_candidates | hash_candidates)
|
187
|
+
end
|
74
188
|
|
75
189
|
when /^(:[^:.]*)$/
|
76
190
|
# Symbol
|
77
|
-
if
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
191
|
+
return nil if doc_namespace
|
192
|
+
sym = $1
|
193
|
+
candidates = Symbol.all_symbols.collect do |s|
|
194
|
+
":" + s.id2name.encode(Encoding.default_external)
|
195
|
+
rescue EncodingError
|
196
|
+
# ignore
|
83
197
|
end
|
198
|
+
candidates.grep(/^#{Regexp.quote(sym)}/)
|
84
199
|
|
85
|
-
when /^::([A-Z][^:\.\(]*)$/
|
200
|
+
when /^::([A-Z][^:\.\(\)]*)$/
|
86
201
|
# Absolute Constant or class methods
|
87
202
|
receiver = $1
|
88
203
|
candidates = Object.constants.collect{|m| m.to_s}
|
89
|
-
|
204
|
+
if doc_namespace
|
205
|
+
candidates.find { |i| i == receiver }
|
206
|
+
else
|
207
|
+
candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
|
208
|
+
end
|
90
209
|
|
91
210
|
when /^([A-Z].*)::([^:.]*)$/
|
92
211
|
# Constant or class methods
|
93
212
|
receiver = $1
|
94
|
-
message =
|
213
|
+
message = $2
|
95
214
|
begin
|
96
215
|
candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
|
97
216
|
candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
|
98
217
|
rescue Exception
|
99
218
|
candidates = []
|
100
219
|
end
|
101
|
-
|
220
|
+
if doc_namespace
|
221
|
+
"#{receiver}::#{message}"
|
222
|
+
else
|
223
|
+
select_message(receiver, message, candidates, "::")
|
224
|
+
end
|
102
225
|
|
103
226
|
when /^(:[^:.]+)(\.|::)([^.]*)$/
|
104
227
|
# Symbol
|
105
228
|
receiver = $1
|
106
229
|
sep = $2
|
107
|
-
message =
|
230
|
+
message = $3
|
108
231
|
|
109
232
|
candidates = Symbol.instance_methods.collect{|m| m.to_s}
|
110
|
-
|
233
|
+
if doc_namespace
|
234
|
+
"Symbol.#{message}"
|
235
|
+
else
|
236
|
+
select_message(receiver, message, candidates, sep)
|
237
|
+
end
|
111
238
|
|
112
|
-
when /^(
|
239
|
+
when /^(?<num>-?(?:0[dbo])?[0-9_]+(?:\.[0-9_]+)?(?:(?:[eE][+-]?[0-9]+)?i?|r)?)(?<sep>\.|::)(?<mes>[^.]*)$/
|
113
240
|
# Numeric
|
114
|
-
receiver =
|
115
|
-
sep =
|
116
|
-
message =
|
241
|
+
receiver = $~[:num]
|
242
|
+
sep = $~[:sep]
|
243
|
+
message = $~[:mes]
|
117
244
|
|
118
245
|
begin
|
119
|
-
|
246
|
+
instance = eval(receiver, bind)
|
247
|
+
if doc_namespace
|
248
|
+
"#{instance.class.name}.#{message}"
|
249
|
+
else
|
250
|
+
candidates = instance.methods.collect{|m| m.to_s}
|
251
|
+
select_message(receiver, message, candidates, sep)
|
252
|
+
end
|
120
253
|
rescue Exception
|
121
|
-
|
254
|
+
if doc_namespace
|
255
|
+
nil
|
256
|
+
else
|
257
|
+
candidates = []
|
258
|
+
end
|
122
259
|
end
|
123
|
-
select_message(receiver, message, candidates, sep)
|
124
260
|
|
125
261
|
when /^(-?0x[0-9a-fA-F_]+)(\.|::)([^.]*)$/
|
126
262
|
# Numeric(0xFFFF)
|
127
263
|
receiver = $1
|
128
264
|
sep = $2
|
129
|
-
message =
|
265
|
+
message = $3
|
130
266
|
|
131
267
|
begin
|
132
|
-
|
268
|
+
instance = eval(receiver, bind)
|
269
|
+
if doc_namespace
|
270
|
+
"#{instance.class.name}.#{message}"
|
271
|
+
else
|
272
|
+
candidates = instance.methods.collect{|m| m.to_s}
|
273
|
+
select_message(receiver, message, candidates, sep)
|
274
|
+
end
|
133
275
|
rescue Exception
|
134
|
-
|
276
|
+
if doc_namespace
|
277
|
+
nil
|
278
|
+
else
|
279
|
+
candidates = []
|
280
|
+
end
|
135
281
|
end
|
136
|
-
select_message(receiver, message, candidates, sep)
|
137
282
|
|
138
283
|
when /^(\$[^.]*)$/
|
139
284
|
# global var
|
140
|
-
|
141
|
-
|
285
|
+
gvar = $1
|
286
|
+
all_gvars = global_variables.collect{|m| m.to_s}
|
287
|
+
if doc_namespace
|
288
|
+
all_gvars.find{ |i| i == gvar }
|
289
|
+
else
|
290
|
+
all_gvars.grep(Regexp.new(Regexp.quote(gvar)))
|
291
|
+
end
|
142
292
|
|
143
|
-
when /^([
|
293
|
+
when /^([^.:"].*)(\.|::)([^.]*)$/
|
144
294
|
# variable.func or func.func
|
145
295
|
receiver = $1
|
146
296
|
sep = $2
|
147
|
-
message =
|
297
|
+
message = $3
|
148
298
|
|
149
|
-
gv = eval("global_variables", bind).collect{|m| m.to_s}
|
299
|
+
gv = eval("global_variables", bind).collect{|m| m.to_s}.push("true", "false", "nil")
|
150
300
|
lv = eval("local_variables", bind).collect{|m| m.to_s}
|
151
301
|
iv = eval("instance_variables", bind).collect{|m| m.to_s}
|
152
302
|
cv = eval("self.class.constants", bind).collect{|m| m.to_s}
|
@@ -177,21 +327,76 @@ module IRB
|
|
177
327
|
candidates.sort!
|
178
328
|
candidates.uniq!
|
179
329
|
end
|
180
|
-
|
330
|
+
if doc_namespace
|
331
|
+
rec_class = rec.is_a?(Module) ? rec : rec.class
|
332
|
+
"#{rec_class.name}#{sep}#{candidates.find{ |i| i == message }}"
|
333
|
+
else
|
334
|
+
select_message(receiver, message, candidates, sep)
|
335
|
+
end
|
181
336
|
|
182
337
|
when /^\.([^.]*)$/
|
183
338
|
# unknown(maybe String)
|
184
339
|
|
185
340
|
receiver = ""
|
186
|
-
message =
|
341
|
+
message = $1
|
187
342
|
|
188
343
|
candidates = String.instance_methods(true).collect{|m| m.to_s}
|
189
|
-
|
344
|
+
if doc_namespace
|
345
|
+
"String.#{candidates.find{ |i| i == message }}"
|
346
|
+
else
|
347
|
+
select_message(receiver, message, candidates)
|
348
|
+
end
|
190
349
|
|
191
350
|
else
|
192
|
-
|
351
|
+
if doc_namespace
|
352
|
+
vars = eval("local_variables | instance_variables", bind).collect{|m| m.to_s}
|
353
|
+
perfect_match_var = vars.find{|m| m.to_s == input}
|
354
|
+
if perfect_match_var
|
355
|
+
eval("#{perfect_match_var}.class.name", bind)
|
356
|
+
else
|
357
|
+
candidates = eval("methods | private_methods | local_variables | instance_variables | self.class.constants", bind).collect{|m| m.to_s}
|
358
|
+
candidates |= ReservedWords
|
359
|
+
candidates.find{ |i| i == input }
|
360
|
+
end
|
361
|
+
else
|
362
|
+
candidates = eval("methods | private_methods | local_variables | instance_variables | self.class.constants", bind).collect{|m| m.to_s}
|
363
|
+
candidates |= ReservedWords
|
364
|
+
candidates.grep(/^#{Regexp.quote(input)}/)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
193
368
|
|
194
|
-
|
369
|
+
PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) {
|
370
|
+
begin
|
371
|
+
require 'rdoc'
|
372
|
+
rescue LoadError
|
373
|
+
return
|
374
|
+
end
|
375
|
+
|
376
|
+
RDocRIDriver ||= RDoc::RI::Driver.new
|
377
|
+
|
378
|
+
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
|
379
|
+
IRB.__send__(:easter_egg)
|
380
|
+
return
|
381
|
+
end
|
382
|
+
|
383
|
+
namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
384
|
+
return unless namespace
|
385
|
+
|
386
|
+
if namespace.is_a?(Array)
|
387
|
+
out = RDoc::Markup::Document.new
|
388
|
+
namespace.each do |m|
|
389
|
+
begin
|
390
|
+
RDocRIDriver.add_method(out, m)
|
391
|
+
rescue RDoc::RI::Driver::NotFoundError
|
392
|
+
end
|
393
|
+
end
|
394
|
+
RDocRIDriver.display(out)
|
395
|
+
else
|
396
|
+
begin
|
397
|
+
RDocRIDriver.display_names([namespace])
|
398
|
+
rescue RDoc::RI::Driver::NotFoundError
|
399
|
+
end
|
195
400
|
end
|
196
401
|
}
|
197
402
|
|
@@ -199,7 +404,7 @@ module IRB
|
|
199
404
|
Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
|
200
405
|
|
201
406
|
def self.select_message(receiver, message, candidates, sep = ".")
|
202
|
-
candidates.grep(/^#{message}/).collect do |e|
|
407
|
+
candidates.grep(/^#{Regexp.quote(message)}/).collect do |e|
|
203
408
|
case e
|
204
409
|
when /^[a-zA-Z_]/
|
205
410
|
receiver + sep + e
|
@@ -225,7 +430,7 @@ module IRB
|
|
225
430
|
end
|
226
431
|
end
|
227
432
|
|
228
|
-
%i(IRB
|
433
|
+
%i(IRB RubyLex).each do |sym|
|
229
434
|
next unless Object.const_defined?(sym)
|
230
435
|
scanner.call(Object.const_get(sym))
|
231
436
|
end
|
@@ -236,9 +441,3 @@ module IRB
|
|
236
441
|
end
|
237
442
|
end
|
238
443
|
end
|
239
|
-
|
240
|
-
if Readline.respond_to?("basic_word_break_characters=")
|
241
|
-
Readline.basic_word_break_characters= " \t\n`><=;|&{("
|
242
|
-
end
|
243
|
-
Readline.completion_append_character = nil
|
244
|
-
Readline.completion_proc = IRB::InputCompletor::CompletionProc
|