irb 1.14.0 → 1.18.0
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/.rdoc_options +5 -0
- data/CONTRIBUTING.md +52 -0
- data/EXTEND_IRB.md +3 -0
- data/Gemfile +11 -1
- data/README.md +13 -293
- data/doc/COMMAND_LINE_OPTIONS.md +69 -0
- data/doc/COMPARED_WITH_PRY.md +22 -0
- data/doc/Configurations.md +274 -0
- data/doc/EXTEND_IRB.md +122 -0
- data/doc/Index.md +705 -0
- data/doc/irb/irb.rd.ja +1 -1
- data/lib/irb/color.rb +251 -162
- data/lib/irb/color_printer.rb +10 -9
- data/lib/irb/command/base.rb +46 -13
- data/lib/irb/command/copy.rb +83 -0
- data/lib/irb/command/debug.rb +8 -6
- data/lib/irb/command/help.rb +1 -1
- data/lib/irb/command/history.rb +1 -1
- data/lib/irb/command/internal_helpers.rb +7 -4
- data/lib/irb/command/ls.rb +29 -15
- data/lib/irb/completion.rb +81 -57
- data/lib/irb/context.rb +132 -53
- data/lib/irb/debug/ui.rb +2 -4
- data/lib/irb/debug.rb +9 -12
- data/lib/irb/default_commands.rb +19 -8
- data/lib/irb/easter-egg.rb +13 -7
- data/lib/irb/ext/multi-irb.rb +2 -0
- data/lib/irb/history.rb +84 -55
- data/lib/irb/init.rb +7 -2
- data/lib/irb/input-method.rb +167 -130
- data/lib/irb/inspector.rb +42 -36
- data/lib/irb/lc/help-message +2 -2
- data/lib/irb/lc/ja/help-message +4 -4
- data/lib/irb/nesting_parser.rb +364 -213
- data/lib/irb/pager.rb +137 -7
- data/lib/irb/ruby-lex.rb +230 -302
- data/lib/irb/ruby_logo.aa +79 -37
- data/lib/irb/source_finder.rb +15 -22
- data/lib/irb/startup_message.rb +83 -0
- data/lib/irb/statement.rb +21 -0
- data/lib/irb/version.rb +2 -2
- data/lib/irb/workspace.rb +22 -31
- data/lib/irb.rb +148 -986
- data/man/irb.1 +37 -2
- metadata +42 -12
- data/.document +0 -4
- data/Rakefile +0 -54
- data/bin/console +0 -6
- data/bin/setup +0 -6
- data/irb.gemspec +0 -46
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IRB
|
|
4
|
+
module Command
|
|
5
|
+
class Copy < Base
|
|
6
|
+
category "Misc"
|
|
7
|
+
description "Copy expression output to clipboard"
|
|
8
|
+
|
|
9
|
+
help_message(<<~HELP)
|
|
10
|
+
Usage: copy ([expression])
|
|
11
|
+
|
|
12
|
+
When given:
|
|
13
|
+
- an expression, copy the inspect result of the expression to the clipboard.
|
|
14
|
+
- no arguments, copy the last evaluated result (`_`) to the clipboard.
|
|
15
|
+
|
|
16
|
+
Examples:
|
|
17
|
+
|
|
18
|
+
copy Foo.new
|
|
19
|
+
copy User.all.to_a
|
|
20
|
+
copy
|
|
21
|
+
HELP
|
|
22
|
+
|
|
23
|
+
def execute(arg)
|
|
24
|
+
# Copy last value if no expression was supplied
|
|
25
|
+
arg = '_' if arg.to_s.strip.empty?
|
|
26
|
+
|
|
27
|
+
value = irb_context.workspace.binding.eval(arg)
|
|
28
|
+
output = irb_context.inspect_method.inspect_value(value, +'', colorize: false).chomp
|
|
29
|
+
|
|
30
|
+
if clipboard_available?
|
|
31
|
+
copy_to_clipboard(output)
|
|
32
|
+
else
|
|
33
|
+
warn "System clipboard not found"
|
|
34
|
+
end
|
|
35
|
+
rescue StandardError => e
|
|
36
|
+
warn "Error: #{e}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def copy_to_clipboard(text)
|
|
42
|
+
IO.popen(clipboard_program, 'w') do |io|
|
|
43
|
+
io.write(text)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
raise IOError.new("Copying to clipboard failed") unless $? == 0
|
|
47
|
+
|
|
48
|
+
puts "Copied to system clipboard"
|
|
49
|
+
rescue Errno::ENOENT => e
|
|
50
|
+
warn e.message
|
|
51
|
+
warn "Is IRB.conf[:COPY_COMMAND] set to a bad value?"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def clipboard_program
|
|
55
|
+
@clipboard_program ||= if IRB.conf[:COPY_COMMAND]
|
|
56
|
+
IRB.conf[:COPY_COMMAND]
|
|
57
|
+
elsif executable?("clip.exe")
|
|
58
|
+
"clip.exe"
|
|
59
|
+
elsif executable?("pbcopy")
|
|
60
|
+
"pbcopy"
|
|
61
|
+
elsif executable?("xclip")
|
|
62
|
+
"xclip -selection clipboard"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def executable?(command)
|
|
67
|
+
if windows?
|
|
68
|
+
system("where #{command} > NUL 2>&1")
|
|
69
|
+
else
|
|
70
|
+
system("which #{command} > /dev/null 2>&1")
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def clipboard_available?
|
|
75
|
+
!!clipboard_program
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def windows?
|
|
79
|
+
/mingw|mswin/.match?(RUBY_PLATFORM)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
data/lib/irb/command/debug.rb
CHANGED
|
@@ -58,13 +58,15 @@ module IRB
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
class DebugCommand < Debug
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
class << self
|
|
62
|
+
def category
|
|
63
|
+
"Debugging"
|
|
64
|
+
end
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
def description
|
|
67
|
+
command_name = self.name.split("::").last.downcase
|
|
68
|
+
"Start the debugger of debug.gem and run its `#{command_name}` command."
|
|
69
|
+
end
|
|
68
70
|
end
|
|
69
71
|
end
|
|
70
72
|
end
|
data/lib/irb/command/help.rb
CHANGED
|
@@ -39,7 +39,7 @@ module IRB
|
|
|
39
39
|
|
|
40
40
|
help_cmds = commands_grouped_by_categories.delete("Help")
|
|
41
41
|
no_category_cmds = commands_grouped_by_categories.delete("No category")
|
|
42
|
-
aliases = irb_context.instance_variable_get(:@
|
|
42
|
+
aliases = irb_context.instance_variable_get(:@command_aliases).map do |alias_name, target|
|
|
43
43
|
{ display_name: alias_name, description: "Alias for `#{target}`" }
|
|
44
44
|
end
|
|
45
45
|
|
data/lib/irb/command/history.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'prism'
|
|
4
|
+
|
|
3
5
|
module IRB
|
|
4
6
|
module Command
|
|
5
7
|
# Internal use only, for default command's backward compatibility.
|
|
@@ -7,9 +9,10 @@ module IRB
|
|
|
7
9
|
def unwrap_string_literal(str)
|
|
8
10
|
return if str.empty?
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
result = Prism.parse(str)
|
|
13
|
+
body = result.value.statements.body
|
|
14
|
+
if result.success? && body.size == 1 && body.first.is_a?(Prism::StringNode)
|
|
15
|
+
body.first.unescaped
|
|
13
16
|
else
|
|
14
17
|
str
|
|
15
18
|
end
|
|
@@ -19,7 +22,7 @@ module IRB
|
|
|
19
22
|
# Use throw and catch to handle arg that includes `;`
|
|
20
23
|
# For example: "1, kw: (2; 3); 4" will be parsed to [[1], { kw: 3 }]
|
|
21
24
|
catch(:EXTRACT_RUBY_ARGS) do
|
|
22
|
-
@irb_context.workspace.binding.eval "IRB::Command.extract_ruby_args #{arg}"
|
|
25
|
+
@irb_context.workspace.binding.eval "::IRB::Command.extract_ruby_args #{arg}"
|
|
23
26
|
end || [[], {}]
|
|
24
27
|
end
|
|
25
28
|
end
|
data/lib/irb/command/ls.rb
CHANGED
|
@@ -11,7 +11,7 @@ module IRB
|
|
|
11
11
|
|
|
12
12
|
module Command
|
|
13
13
|
class Ls < Base
|
|
14
|
-
|
|
14
|
+
class EvaluationError < StandardError; end
|
|
15
15
|
|
|
16
16
|
category "Context"
|
|
17
17
|
description "Show methods, constants, and variables."
|
|
@@ -22,40 +22,54 @@ module IRB
|
|
|
22
22
|
-g [query] Filter the output with a query.
|
|
23
23
|
HELP_MESSAGE
|
|
24
24
|
|
|
25
|
+
def evaluate(code)
|
|
26
|
+
@irb_context.workspace.binding.eval(code)
|
|
27
|
+
rescue Exception => e
|
|
28
|
+
puts "#{e.class}: #{e.message}"
|
|
29
|
+
raise EvaluationError
|
|
30
|
+
end
|
|
31
|
+
|
|
25
32
|
def execute(arg)
|
|
26
33
|
if match = arg.match(/\A(?<target>.+\s|)(-g|-G)\s+(?<grep>.+)$/)
|
|
27
|
-
|
|
28
|
-
use_main = true
|
|
29
|
-
else
|
|
30
|
-
obj = @irb_context.workspace.binding.eval(match[:target])
|
|
31
|
-
end
|
|
34
|
+
target = match[:target]
|
|
32
35
|
grep = Regexp.new(match[:grep])
|
|
36
|
+
elsif match = arg.match(/\A((?<target>.+),|)\s*grep:(?<grep>.+)/)
|
|
37
|
+
# Legacy style `ls obj, grep: /regexp/`
|
|
38
|
+
# Evaluation order should be eval(target) then eval(grep)
|
|
39
|
+
target = match[:target] || ''
|
|
40
|
+
grep_regexp_code = match[:grep]
|
|
33
41
|
else
|
|
34
|
-
|
|
35
|
-
use_main = args.empty?
|
|
36
|
-
obj = args.first
|
|
37
|
-
grep = kwargs[:grep]
|
|
42
|
+
target = arg.strip
|
|
38
43
|
end
|
|
39
44
|
|
|
40
|
-
if
|
|
45
|
+
if target.empty?
|
|
41
46
|
obj = irb_context.workspace.main
|
|
42
47
|
locals = irb_context.workspace.binding.local_variables
|
|
48
|
+
else
|
|
49
|
+
obj = evaluate(target)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if grep_regexp_code
|
|
53
|
+
grep = evaluate(grep_regexp_code)
|
|
43
54
|
end
|
|
44
55
|
|
|
45
56
|
o = Output.new(grep: grep)
|
|
46
57
|
|
|
47
|
-
klass
|
|
58
|
+
klass = Kernel.instance_method(:class).bind(obj).call
|
|
59
|
+
obj_is_class_or_module = Module === obj
|
|
60
|
+
klass = obj_is_class_or_module ? obj : klass
|
|
48
61
|
|
|
49
|
-
o.dump("constants", obj.constants) if
|
|
62
|
+
o.dump("constants", obj.constants) if obj_is_class_or_module
|
|
50
63
|
dump_methods(o, klass, obj)
|
|
51
|
-
o.dump("instance variables",
|
|
64
|
+
o.dump("instance variables", Kernel.instance_method(:instance_variables).bind(obj).call)
|
|
52
65
|
o.dump("class variables", klass.class_variables)
|
|
53
66
|
o.dump("locals", locals) if locals
|
|
54
67
|
o.print_result
|
|
68
|
+
rescue EvaluationError
|
|
55
69
|
end
|
|
56
70
|
|
|
57
71
|
def dump_methods(o, klass, obj)
|
|
58
|
-
singleton_class = begin obj.
|
|
72
|
+
singleton_class = begin Kernel.instance_method(:singleton_class).bind(obj).call; rescue TypeError; nil end
|
|
59
73
|
dumped_mods = Array.new
|
|
60
74
|
ancestors = klass.ancestors
|
|
61
75
|
ancestors = ancestors.reject { |c| c >= Object } if klass < Object
|
data/lib/irb/completion.rb
CHANGED
|
@@ -8,30 +8,33 @@
|
|
|
8
8
|
require_relative 'ruby-lex'
|
|
9
9
|
|
|
10
10
|
module IRB
|
|
11
|
+
class DocumentTarget # :nodoc:
|
|
12
|
+
attr_reader :name
|
|
13
|
+
|
|
14
|
+
def initialize(name)
|
|
15
|
+
@name = name
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class CommandDocument < DocumentTarget # :nodoc:
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Represents a method/class documentation target. May hold multiple names
|
|
23
|
+
# when the receiver is ambiguous (e.g. `{}.any?` could be Hash#any? or Proc#any?).
|
|
24
|
+
# The dialog popup uses only the first name; the full-screen display renders all.
|
|
25
|
+
class MethodDocument < DocumentTarget # :nodoc:
|
|
26
|
+
attr_reader :names
|
|
27
|
+
|
|
28
|
+
def initialize(*names)
|
|
29
|
+
super(names.first)
|
|
30
|
+
@names = names
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
11
34
|
class BaseCompletor # :nodoc:
|
|
12
35
|
|
|
13
36
|
# Set of reserved words used by Ruby, you should not use these for
|
|
14
37
|
# constants or variables
|
|
15
|
-
ReservedWords = %w[
|
|
16
|
-
__ENCODING__ __LINE__ __FILE__
|
|
17
|
-
BEGIN END
|
|
18
|
-
alias and
|
|
19
|
-
begin break
|
|
20
|
-
case class
|
|
21
|
-
def defined? do
|
|
22
|
-
else elsif end ensure
|
|
23
|
-
false for
|
|
24
|
-
if in
|
|
25
|
-
module
|
|
26
|
-
next nil not
|
|
27
|
-
or
|
|
28
|
-
redo rescue retry return
|
|
29
|
-
self super
|
|
30
|
-
then true
|
|
31
|
-
undef unless until
|
|
32
|
-
when while
|
|
33
|
-
yield
|
|
34
|
-
]
|
|
35
38
|
|
|
36
39
|
HELP_COMMAND_PREPOSING = /\Ahelp\s+/
|
|
37
40
|
|
|
@@ -60,13 +63,13 @@ module IRB
|
|
|
60
63
|
|
|
61
64
|
def retrieve_gem_and_system_load_path
|
|
62
65
|
candidates = (GEM_PATHS | $LOAD_PATH)
|
|
63
|
-
candidates.
|
|
66
|
+
candidates.filter_map do |p|
|
|
64
67
|
if p.respond_to?(:to_path)
|
|
65
68
|
p.to_path
|
|
66
69
|
else
|
|
67
70
|
String(p) rescue nil
|
|
68
71
|
end
|
|
69
|
-
end.
|
|
72
|
+
end.sort
|
|
70
73
|
end
|
|
71
74
|
|
|
72
75
|
def retrieve_files_to_require_from_load_path
|
|
@@ -96,6 +99,12 @@ module IRB
|
|
|
96
99
|
end
|
|
97
100
|
end
|
|
98
101
|
|
|
102
|
+
def command_document_target(preposing, matched)
|
|
103
|
+
if preposing.empty? && IRB::Command.command_names.include?(matched)
|
|
104
|
+
CommandDocument.new(matched)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
99
108
|
def retrieve_files_to_require_relative_from_current_dir
|
|
100
109
|
@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
|
|
101
110
|
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
|
|
@@ -127,36 +136,52 @@ module IRB
|
|
|
127
136
|
|
|
128
137
|
return commands unless result
|
|
129
138
|
|
|
130
|
-
|
|
139
|
+
encoded_candidates = result.completion_candidates.filter_map do |i|
|
|
140
|
+
encoded = i.encode(Encoding.default_external)
|
|
141
|
+
target + encoded
|
|
142
|
+
rescue Encoding::UndefinedConversionError
|
|
143
|
+
# If the string cannot be converted, we just ignore it
|
|
144
|
+
nil
|
|
145
|
+
end
|
|
146
|
+
commands | encoded_candidates
|
|
131
147
|
end
|
|
132
148
|
|
|
133
149
|
def doc_namespace(preposing, matched, _postposing, bind:)
|
|
134
|
-
|
|
135
|
-
|
|
150
|
+
command_document_target(preposing, matched) || begin
|
|
151
|
+
result = ReplTypeCompletor.analyze(preposing + matched, binding: bind, filename: @context.irb_path)
|
|
152
|
+
result&.doc_namespace('')
|
|
153
|
+
end
|
|
136
154
|
end
|
|
137
155
|
end
|
|
138
156
|
|
|
139
157
|
class RegexpCompletor < BaseCompletor # :nodoc:
|
|
158
|
+
KERNEL_METHODS = ::Kernel.instance_method(:methods)
|
|
159
|
+
KERNEL_PRIVATE_METHODS = ::Kernel.instance_method(:private_methods)
|
|
160
|
+
KERNEL_INSTANCE_VARIABLES = ::Kernel.instance_method(:instance_variables)
|
|
161
|
+
OBJECT_CLASS_INSTANCE_METHOD = ::Object.instance_method(:class)
|
|
162
|
+
MODULE_CONSTANTS_INSTANCE_METHOD = ::Module.instance_method(:constants)
|
|
163
|
+
|
|
140
164
|
using Module.new {
|
|
141
165
|
refine ::Binding do
|
|
142
166
|
def eval_methods
|
|
143
|
-
|
|
167
|
+
KERNEL_METHODS.bind_call(receiver)
|
|
144
168
|
end
|
|
145
169
|
|
|
146
170
|
def eval_private_methods
|
|
147
|
-
|
|
171
|
+
KERNEL_PRIVATE_METHODS.bind_call(receiver)
|
|
148
172
|
end
|
|
149
173
|
|
|
150
174
|
def eval_instance_variables
|
|
151
|
-
|
|
175
|
+
KERNEL_INSTANCE_VARIABLES.bind_call(receiver)
|
|
152
176
|
end
|
|
153
177
|
|
|
154
178
|
def eval_global_variables
|
|
155
|
-
::Kernel.
|
|
179
|
+
::Kernel.global_variables
|
|
156
180
|
end
|
|
157
181
|
|
|
158
182
|
def eval_class_constants
|
|
159
|
-
|
|
183
|
+
klass = OBJECT_CLASS_INSTANCE_METHOD.bind_call(receiver)
|
|
184
|
+
MODULE_CONSTANTS_INSTANCE_METHOD.bind_call(klass)
|
|
160
185
|
end
|
|
161
186
|
end
|
|
162
187
|
}
|
|
@@ -172,28 +197,15 @@ module IRB
|
|
|
172
197
|
else
|
|
173
198
|
return nil # It's not String literal
|
|
174
199
|
end
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
break
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
return unless tok&.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
|
|
184
|
-
|
|
185
|
-
case tok.tok
|
|
186
|
-
when 'require'
|
|
187
|
-
retrieve_files_to_require_from_load_path.select { |path|
|
|
188
|
-
path.start_with?(actual_target)
|
|
189
|
-
}.map { |path|
|
|
190
|
-
quote + path
|
|
200
|
+
|
|
201
|
+
case preposing
|
|
202
|
+
when /(^|[^\w])require\(? *\z/
|
|
203
|
+
retrieve_files_to_require_from_load_path.filter_map { |path|
|
|
204
|
+
quote + path if path.start_with?(actual_target)
|
|
191
205
|
}
|
|
192
|
-
when
|
|
193
|
-
retrieve_files_to_require_relative_from_current_dir.
|
|
194
|
-
path.start_with?(actual_target)
|
|
195
|
-
}.map { |path|
|
|
196
|
-
quote + path
|
|
206
|
+
when /(^|[^\w])require_relative\(? *\z/
|
|
207
|
+
retrieve_files_to_require_relative_from_current_dir.filter_map { |path|
|
|
208
|
+
quote + path if path.start_with?(actual_target)
|
|
197
209
|
}
|
|
198
210
|
end
|
|
199
211
|
end
|
|
@@ -211,12 +223,17 @@ module IRB
|
|
|
211
223
|
# It doesn't make sense to propose commands with other preposing
|
|
212
224
|
commands = [] unless preposing.empty?
|
|
213
225
|
|
|
214
|
-
completion_data = retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.
|
|
226
|
+
completion_data = retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.filter_map do |i|
|
|
227
|
+
i.encode(Encoding.default_external)
|
|
228
|
+
rescue Encoding::UndefinedConversionError
|
|
229
|
+
# If the string cannot be converted, we just ignore it
|
|
230
|
+
nil
|
|
231
|
+
end
|
|
215
232
|
commands | completion_data
|
|
216
233
|
end
|
|
217
234
|
|
|
218
|
-
def doc_namespace(
|
|
219
|
-
retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
|
235
|
+
def doc_namespace(preposing, matched, _postposing, bind:)
|
|
236
|
+
command_document_target(preposing, matched) || retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
|
220
237
|
end
|
|
221
238
|
|
|
222
239
|
def retrieve_completion_data(input, bind:, doc_namespace:)
|
|
@@ -280,7 +297,7 @@ module IRB
|
|
|
280
297
|
nil
|
|
281
298
|
else
|
|
282
299
|
sym = $1
|
|
283
|
-
candidates = Symbol.all_symbols.
|
|
300
|
+
candidates = Symbol.all_symbols.filter_map do |s|
|
|
284
301
|
s.inspect
|
|
285
302
|
rescue EncodingError
|
|
286
303
|
# ignore
|
|
@@ -452,12 +469,19 @@ module IRB
|
|
|
452
469
|
eval("#{perfect_match_var}.class.name", bind) rescue nil
|
|
453
470
|
else
|
|
454
471
|
candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
|
|
455
|
-
candidates |=
|
|
472
|
+
candidates |= RubyLex::RESERVED_WORDS.map(&:to_s)
|
|
456
473
|
candidates.find{ |i| i == input }
|
|
457
474
|
end
|
|
458
475
|
else
|
|
459
476
|
candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
|
|
460
|
-
candidates |=
|
|
477
|
+
candidates |= RubyLex::RESERVED_WORDS.map(&:to_s)
|
|
478
|
+
|
|
479
|
+
target_encoding = Encoding.default_external
|
|
480
|
+
candidates = candidates.compact.filter_map do |candidate|
|
|
481
|
+
candidate.encoding == target_encoding ? candidate : candidate.encode(target_encoding)
|
|
482
|
+
rescue EncodingError
|
|
483
|
+
nil
|
|
484
|
+
end
|
|
461
485
|
candidates.grep(/^#{Regexp.quote(input)}/).sort
|
|
462
486
|
end
|
|
463
487
|
end
|