irb 1.9.0 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -5
- data/README.md +11 -9
- data/Rakefile +2 -2
- data/lib/irb/cmd/history.rb +47 -0
- data/lib/irb/cmd/show_cmds.rb +6 -0
- data/lib/irb/cmd/show_source.rb +9 -2
- data/lib/irb/completion.rb +25 -4
- data/lib/irb/context.rb +22 -14
- data/lib/irb/debug.rb +18 -0
- data/lib/irb/extend-command.rb +6 -0
- data/lib/irb/history.rb +1 -1
- data/lib/irb/init.rb +4 -5
- data/lib/irb/input-method.rb +3 -0
- data/lib/irb/lc/help-message +1 -0
- data/lib/irb/pager.rb +12 -11
- data/lib/irb/source_finder.rb +26 -6
- data/lib/irb/version.rb +2 -2
- data/lib/irb.rb +48 -40
- metadata +4 -8
- data/lib/irb/type_completion/completor.rb +0 -235
- data/lib/irb/type_completion/methods.rb +0 -13
- data/lib/irb/type_completion/scope.rb +0 -412
- data/lib/irb/type_completion/type_analyzer.rb +0 -1169
- data/lib/irb/type_completion/types.rb +0 -426
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0e7153fbd64c519a7af411d95779821c279a63b786c16df0e5cff4b577a258f
|
4
|
+
data.tar.gz: 86c81569fa9788676c575f64b1010191690b4b3c056330e5f21fb798d724924f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e78e35a1a46ac5b4e62e93f7cac0e1b3657b16cd108851624b3cfd2b6c81662ca6dfa7aff9737d743a625eaa96a47179c95e9af28833dcb9d761ee150923497d
|
7
|
+
data.tar.gz: 562c5e88c5c09adbe4f882d30a34b496599af4f7a45f41d60609ef91148d7271cd97bbfd629ca75da4f3845d7815e51bca3b1969e9bff1c723c18b3c0840517d
|
data/Gemfile
CHANGED
@@ -16,11 +16,9 @@ gem "reline", github: "ruby/reline" if ENV["WITH_LATEST_RELINE"] == "true"
|
|
16
16
|
gem "rake"
|
17
17
|
gem "test-unit"
|
18
18
|
gem "test-unit-ruby-core"
|
19
|
-
gem "debug", github: "ruby/debug"
|
20
19
|
|
21
|
-
gem "
|
20
|
+
gem "debug", github: "ruby/debug", platforms: [:mri, :mswin]
|
22
21
|
|
23
|
-
if RUBY_VERSION >= "3.0.0"
|
24
|
-
gem "
|
25
|
-
gem "prism", ">= 0.17.1"
|
22
|
+
if RUBY_VERSION >= "3.0.0" && !is_truffleruby
|
23
|
+
gem "repl_type_completor"
|
26
24
|
end
|
data/README.md
CHANGED
@@ -119,6 +119,7 @@ IRB
|
|
119
119
|
source Loads a given file in the current session.
|
120
120
|
irb_info Show information about IRB.
|
121
121
|
show_cmds List all available commands and their description.
|
122
|
+
history Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output.
|
122
123
|
|
123
124
|
Multi-irb (DEPRECATED)
|
124
125
|
irb Start a child IRB.
|
@@ -237,11 +238,11 @@ However, there are also some limitations to be aware of:
|
|
237
238
|
|
238
239
|
## Type Based Completion
|
239
240
|
|
240
|
-
IRB's default completion `IRB::RegexpCompletor` uses Regexp. IRB has another experimental completion `IRB::
|
241
|
+
IRB's default completion `IRB::RegexpCompletor` uses Regexp. IRB has another experimental completion `IRB::TypeCompletor` that uses type analysis.
|
241
242
|
|
242
|
-
### How to Enable IRB::
|
243
|
+
### How to Enable IRB::TypeCompletor
|
243
244
|
|
244
|
-
To enable IRB::
|
245
|
+
To enable IRB::TypeCompletor, run IRB with `--type-completor` option
|
245
246
|
```
|
246
247
|
$ irb --type-completor
|
247
248
|
```
|
@@ -249,14 +250,14 @@ Or write the code below to IRB's rc-file.
|
|
249
250
|
```ruby
|
250
251
|
IRB.conf[:COMPLETOR] = :type # default is :regexp
|
251
252
|
```
|
252
|
-
You also need `gem
|
253
|
+
You also need `gem repl_type_completor` to use this feature.
|
253
254
|
|
254
255
|
To check if it's enabled, type `irb_info` into IRB and see the `Completion` section.
|
255
256
|
```
|
256
257
|
irb(main):001> irb_info
|
257
258
|
...
|
258
259
|
# Enabled
|
259
|
-
Completion: Autocomplete,
|
260
|
+
Completion: Autocomplete, ReplTypeCompletor: 0.1.0, Prism: 0.18.0, RBS: 3.3.0
|
260
261
|
# Not enabled
|
261
262
|
Completion: Autocomplete, RegexpCompletor
|
262
263
|
...
|
@@ -265,7 +266,7 @@ If you have `sig/` directory or `rbs_collection.lock.yaml` in current directory,
|
|
265
266
|
|
266
267
|
### Advantage over Default IRB::RegexpCompletor
|
267
268
|
|
268
|
-
IRB::
|
269
|
+
IRB::TypeCompletor can autocomplete chained methods, block parameters and more if type information is available.
|
269
270
|
These are some examples IRB::RegexpCompletor cannot complete.
|
270
271
|
|
271
272
|
```ruby
|
@@ -287,11 +288,11 @@ As a trade-off, completion calculation takes more time than IRB::RegexpCompletor
|
|
287
288
|
|
288
289
|
### Difference between Steep's Completion
|
289
290
|
|
290
|
-
Compared with Steep, IRB::
|
291
|
+
Compared with Steep, IRB::TypeCompletor has some difference and limitations.
|
291
292
|
```ruby
|
292
293
|
[0, 'a'].sample.
|
293
294
|
# Steep completes intersection of Integer methods and String methods
|
294
|
-
# IRB::
|
295
|
+
# IRB::TypeCompletor completes both Integer and String methods
|
295
296
|
```
|
296
297
|
|
297
298
|
Some features like type narrowing is not implemented.
|
@@ -301,7 +302,7 @@ def f(arg = [0, 'a'].sample)
|
|
301
302
|
arg. # Completes both Integer and String methods
|
302
303
|
```
|
303
304
|
|
304
|
-
Unlike other static type checker, IRB::
|
305
|
+
Unlike other static type checker, IRB::TypeCompletor uses runtime information to provide better completion.
|
305
306
|
```ruby
|
306
307
|
irb(main):001> a = [1]
|
307
308
|
=> [1]
|
@@ -314,6 +315,7 @@ irb(main):002> a.first. # Completes Integer methods
|
|
314
315
|
|
315
316
|
- `NO_COLOR`: Assigning a value to it disables IRB's colorization.
|
316
317
|
- `IRB_USE_AUTOCOMPLETE`: Setting it to `false` disables IRB's autocompletion.
|
318
|
+
- `IRB_COMPLETOR`: Configures IRB's auto-completion behavior, allowing settings for either `regexp` or `type`.
|
317
319
|
- `VISUAL`: Its value would be used to open files by the `edit` command.
|
318
320
|
- `EDITOR`: Its value would be used to open files by the `edit` command if `VISUAL` is unset.
|
319
321
|
- `IRBRC`: The file specified would be evaluated as IRB's rc-file.
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ Rake::TestTask.new(:test) do |t|
|
|
5
5
|
t.libs << "test" << "test/lib"
|
6
6
|
t.libs << "lib"
|
7
7
|
t.ruby_opts << "-rhelper"
|
8
|
-
t.test_files = FileList["test/irb
|
8
|
+
t.test_files = FileList["test/irb/**/test_*.rb"]
|
9
9
|
end
|
10
10
|
|
11
11
|
# To make sure they have been correctly setup for Ruby CI.
|
@@ -13,7 +13,7 @@ desc "Run each irb test file in isolation."
|
|
13
13
|
task :test_in_isolation do
|
14
14
|
failed = false
|
15
15
|
|
16
|
-
FileList["test/irb
|
16
|
+
FileList["test/irb/**/test_*.rb"].each do |test_file|
|
17
17
|
ENV["TEST"] = test_file
|
18
18
|
begin
|
19
19
|
Rake::Task["test"].execute
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
require_relative "nop"
|
5
|
+
require_relative "../pager"
|
6
|
+
|
7
|
+
module IRB
|
8
|
+
# :stopdoc:
|
9
|
+
|
10
|
+
module ExtendCommand
|
11
|
+
class History < Nop
|
12
|
+
category "IRB"
|
13
|
+
description "Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output."
|
14
|
+
|
15
|
+
def self.transform_args(args)
|
16
|
+
match = args&.match(/(-g|-G)\s+(?<grep>.+)\s*\n\z/)
|
17
|
+
return unless match
|
18
|
+
|
19
|
+
"grep: #{Regexp.new(match[:grep]).inspect}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute(grep: nil)
|
23
|
+
formatted_inputs = irb_context.io.class::HISTORY.each_with_index.reverse_each.filter_map do |input, index|
|
24
|
+
next if grep && !input.match?(grep)
|
25
|
+
|
26
|
+
header = "#{index}: "
|
27
|
+
|
28
|
+
first_line, *other_lines = input.split("\n")
|
29
|
+
first_line = "#{header}#{first_line}"
|
30
|
+
|
31
|
+
truncated_lines = other_lines.slice!(1..) # Show 1 additional line (2 total)
|
32
|
+
other_lines << "..." if truncated_lines&.any?
|
33
|
+
|
34
|
+
other_lines.map! do |line|
|
35
|
+
" " * header.length + line
|
36
|
+
end
|
37
|
+
|
38
|
+
[first_line, *other_lines].join("\n") + "\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
Pager.page_content(formatted_inputs.join)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# :startdoc:
|
47
|
+
end
|
data/lib/irb/cmd/show_cmds.rb
CHANGED
@@ -16,6 +16,12 @@ module IRB
|
|
16
16
|
commands_info = IRB::ExtendCommandBundle.all_commands_info
|
17
17
|
commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
|
18
18
|
|
19
|
+
user_aliases = irb_context.instance_variable_get(:@user_aliases)
|
20
|
+
|
21
|
+
commands_grouped_by_categories["Aliases"] = user_aliases.map do |alias_name, target|
|
22
|
+
{ display_name: alias_name, description: "Alias for `#{target}`" }
|
23
|
+
end
|
24
|
+
|
19
25
|
if irb_context.with_debugger
|
20
26
|
# Remove the original "Debugging" category
|
21
27
|
commands_grouped_by_categories.delete("Debugging")
|
data/lib/irb/cmd/show_source.rb
CHANGED
@@ -27,11 +27,18 @@ module IRB
|
|
27
27
|
puts "Error: Expected a string but got #{str.inspect}"
|
28
28
|
return
|
29
29
|
end
|
30
|
-
|
31
|
-
|
30
|
+
if str.include? " -s"
|
31
|
+
str, esses = str.split(" -")
|
32
|
+
s_count = esses.count("^s").zero? ? esses.size : 1
|
33
|
+
source = SourceFinder.new(@irb_context).find_source(str, s_count)
|
34
|
+
else
|
35
|
+
source = SourceFinder.new(@irb_context).find_source(str)
|
36
|
+
end
|
32
37
|
|
33
38
|
if source
|
34
39
|
show_source(source)
|
40
|
+
elsif s_count
|
41
|
+
puts "Error: Couldn't locate a super definition for #{str}"
|
35
42
|
else
|
36
43
|
puts "Error: Couldn't locate a definition for #{str}"
|
37
44
|
end
|
data/lib/irb/completion.rb
CHANGED
@@ -93,6 +93,27 @@ module IRB
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
class TypeCompletor < BaseCompletor # :nodoc:
|
97
|
+
def initialize(context)
|
98
|
+
@context = context
|
99
|
+
end
|
100
|
+
|
101
|
+
def inspect
|
102
|
+
ReplTypeCompletor.info
|
103
|
+
end
|
104
|
+
|
105
|
+
def completion_candidates(preposing, target, _postposing, bind:)
|
106
|
+
result = ReplTypeCompletor.analyze(preposing + target, binding: bind, filename: @context.irb_path)
|
107
|
+
return [] unless result
|
108
|
+
result.completion_candidates.map { target + _1 }
|
109
|
+
end
|
110
|
+
|
111
|
+
def doc_namespace(preposing, matched, _postposing, bind:)
|
112
|
+
result = ReplTypeCompletor.analyze(preposing + matched, binding: bind, filename: @context.irb_path)
|
113
|
+
result&.doc_namespace('')
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
96
117
|
class RegexpCompletor < BaseCompletor # :nodoc:
|
97
118
|
using Module.new {
|
98
119
|
refine ::Binding do
|
@@ -210,16 +231,16 @@ module IRB
|
|
210
231
|
end
|
211
232
|
|
212
233
|
when /^([^\}]*\})\.([^.]*)$/
|
213
|
-
#
|
234
|
+
# Hash or Proc
|
214
235
|
receiver = $1
|
215
236
|
message = $2
|
216
237
|
|
217
238
|
if doc_namespace
|
218
|
-
["
|
239
|
+
["Hash.#{message}", "Proc.#{message}"]
|
219
240
|
else
|
220
|
-
proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
|
221
241
|
hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
|
222
|
-
|
242
|
+
proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
|
243
|
+
select_message(receiver, message, hash_candidates | proc_candidates)
|
223
244
|
end
|
224
245
|
|
225
246
|
when /^(:[^:.]+)$/
|
data/lib/irb/context.rb
CHANGED
@@ -146,9 +146,21 @@ module IRB
|
|
146
146
|
@newline_before_multiline_output = true
|
147
147
|
end
|
148
148
|
|
149
|
-
@
|
149
|
+
@user_aliases = IRB.conf[:COMMAND_ALIASES].dup
|
150
|
+
@command_aliases = @user_aliases.merge(KEYWORD_ALIASES)
|
150
151
|
end
|
151
152
|
|
153
|
+
# because all input will eventually be evaluated as Ruby code,
|
154
|
+
# command names that conflict with Ruby keywords need special workaround
|
155
|
+
# we can remove them once we implemented a better command system for IRB
|
156
|
+
KEYWORD_ALIASES = {
|
157
|
+
:break => :irb_break,
|
158
|
+
:catch => :irb_catch,
|
159
|
+
:next => :irb_next,
|
160
|
+
}.freeze
|
161
|
+
|
162
|
+
private_constant :KEYWORD_ALIASES
|
163
|
+
|
152
164
|
private def build_completor
|
153
165
|
completor_type = IRB.conf[:COMPLETOR]
|
154
166
|
case completor_type
|
@@ -164,26 +176,22 @@ module IRB
|
|
164
176
|
RegexpCompletor.new
|
165
177
|
end
|
166
178
|
|
167
|
-
TYPE_COMPLETION_REQUIRED_PRISM_VERSION = '0.17.1'
|
168
|
-
|
169
179
|
private def build_type_completor
|
170
|
-
|
171
|
-
|
180
|
+
if RUBY_ENGINE == 'truffleruby'
|
181
|
+
# Avoid SynatxError. truffleruby does not support endless method definition yet.
|
182
|
+
warn 'TypeCompletor is not supported on TruffleRuby yet'
|
172
183
|
return
|
173
184
|
end
|
185
|
+
|
174
186
|
begin
|
175
|
-
require '
|
187
|
+
require 'repl_type_completor'
|
176
188
|
rescue LoadError => e
|
177
|
-
warn "
|
189
|
+
warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}"
|
178
190
|
return
|
179
191
|
end
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
end
|
184
|
-
require 'irb/type_completion/completor'
|
185
|
-
TypeCompletion::Types.preload_in_thread
|
186
|
-
TypeCompletion::Completor.new
|
192
|
+
|
193
|
+
ReplTypeCompletor.preload_rbs
|
194
|
+
TypeCompletor.new(self)
|
187
195
|
end
|
188
196
|
|
189
197
|
def save_history=(val)
|
data/lib/irb/debug.rb
CHANGED
@@ -57,6 +57,24 @@ module IRB
|
|
57
57
|
DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
|
58
58
|
end
|
59
59
|
|
60
|
+
if !@output_modifier_defined && !DEBUGGER__::CONFIG[:no_hint]
|
61
|
+
irb_output_modifier_proc = Reline.output_modifier_proc
|
62
|
+
|
63
|
+
Reline.output_modifier_proc = proc do |output, complete:|
|
64
|
+
unless output.strip.empty?
|
65
|
+
cmd = output.split(/\s/, 2).first
|
66
|
+
|
67
|
+
if !complete && DEBUGGER__.commands.key?(cmd)
|
68
|
+
output = output.sub(/\n$/, " # debug command\n")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
irb_output_modifier_proc.call(output, complete: complete)
|
73
|
+
end
|
74
|
+
|
75
|
+
@output_modifier_defined = true
|
76
|
+
end
|
77
|
+
|
60
78
|
true
|
61
79
|
end
|
62
80
|
|
data/lib/irb/extend-command.rb
CHANGED
data/lib/irb/history.rb
CHANGED
@@ -60,7 +60,7 @@ module IRB
|
|
60
60
|
end
|
61
61
|
|
62
62
|
File.open(history_file, (append_history ? 'a' : 'w'), 0o600, encoding: IRB.conf[:LC_MESSAGES]&.encoding) do |f|
|
63
|
-
hist = history.map{ |l| l.split("\n").join("\\\n") }
|
63
|
+
hist = history.map{ |l| l.scrub.split("\n").join("\\\n") }
|
64
64
|
unless append_history
|
65
65
|
begin
|
66
66
|
hist = hist.last(num) if hist.size > num and num > 0
|
data/lib/irb/init.rb
CHANGED
@@ -76,12 +76,13 @@ module IRB # :nodoc:
|
|
76
76
|
@CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod)
|
77
77
|
@CONF[:USE_COLORIZE] = (nc = ENV['NO_COLOR']).nil? || nc.empty?
|
78
78
|
@CONF[:USE_AUTOCOMPLETE] = ENV.fetch("IRB_USE_AUTOCOMPLETE", "true") != "false"
|
79
|
-
@CONF[:COMPLETOR] =
|
79
|
+
@CONF[:COMPLETOR] = ENV.fetch("IRB_COMPLETOR", "regexp").to_sym
|
80
80
|
@CONF[:INSPECT_MODE] = true
|
81
81
|
@CONF[:USE_TRACER] = false
|
82
82
|
@CONF[:USE_LOADER] = false
|
83
83
|
@CONF[:IGNORE_SIGINT] = true
|
84
84
|
@CONF[:IGNORE_EOF] = false
|
85
|
+
@CONF[:USE_PAGER] = true
|
85
86
|
@CONF[:EXTRA_DOC_DIRS] = []
|
86
87
|
@CONF[:ECHO] = nil
|
87
88
|
@CONF[:ECHO_ON_ASSIGNMENT] = nil
|
@@ -188,10 +189,6 @@ module IRB # :nodoc:
|
|
188
189
|
# Symbol aliases
|
189
190
|
:'$' => :show_source,
|
190
191
|
:'@' => :whereami,
|
191
|
-
# Keyword aliases
|
192
|
-
:break => :irb_break,
|
193
|
-
:catch => :irb_catch,
|
194
|
-
:next => :irb_next,
|
195
192
|
}
|
196
193
|
end
|
197
194
|
|
@@ -285,6 +282,8 @@ module IRB # :nodoc:
|
|
285
282
|
end
|
286
283
|
when "--noinspect"
|
287
284
|
@CONF[:INSPECT_MODE] = false
|
285
|
+
when "--no-pager"
|
286
|
+
@CONF[:USE_PAGER] = false
|
288
287
|
when "--singleline", "--readline", "--legacy"
|
289
288
|
@CONF[:USE_SINGLELINE] = true
|
290
289
|
when "--nosingleline", "--noreadline"
|
data/lib/irb/input-method.rb
CHANGED
@@ -312,6 +312,9 @@ module IRB
|
|
312
312
|
return nil if result.nil? or pointer.nil? or pointer < 0
|
313
313
|
|
314
314
|
name = doc_namespace.call(result[pointer])
|
315
|
+
# Use first one because document dialog does not support multiple namespaces.
|
316
|
+
name = name.first if name.is_a?(Array)
|
317
|
+
|
315
318
|
show_easter_egg = name&.match?(/\ARubyVM/) && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
|
316
319
|
|
317
320
|
options = {}
|
data/lib/irb/lc/help-message
CHANGED
@@ -22,6 +22,7 @@ Usage: irb.rb [options] [programfile] [arguments]
|
|
22
22
|
Show truncated result on assignment (default).
|
23
23
|
--inspect Use 'inspect' for output.
|
24
24
|
--noinspect Don't use 'inspect' for output.
|
25
|
+
--no-pager Don't use pager.
|
25
26
|
--multiline Use multiline editor module (default).
|
26
27
|
--nomultiline Don't use multiline editor module.
|
27
28
|
--singleline Use single line editor module.
|
data/lib/irb/pager.rb
CHANGED
@@ -7,9 +7,9 @@ module IRB
|
|
7
7
|
PAGE_COMMANDS = [ENV['RI_PAGER'], ENV['PAGER'], 'less', 'more'].compact.uniq
|
8
8
|
|
9
9
|
class << self
|
10
|
-
def page_content(content)
|
10
|
+
def page_content(content, **options)
|
11
11
|
if content_exceeds_screen_height?(content)
|
12
|
-
page do |io|
|
12
|
+
page(**options) do |io|
|
13
13
|
io.puts content
|
14
14
|
end
|
15
15
|
else
|
@@ -17,8 +17,8 @@ module IRB
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def page
|
21
|
-
if STDIN.tty? && pager = setup_pager
|
20
|
+
def page(retain_content: false)
|
21
|
+
if IRB.conf[:USE_PAGER] && STDIN.tty? && pager = setup_pager(retain_content: retain_content)
|
22
22
|
begin
|
23
23
|
pid = pager.pid
|
24
24
|
yield pager
|
@@ -55,19 +55,20 @@ module IRB
|
|
55
55
|
pageable_height * screen_width < Reline::Unicode.calculate_width(content, true)
|
56
56
|
end
|
57
57
|
|
58
|
-
def setup_pager
|
58
|
+
def setup_pager(retain_content:)
|
59
59
|
require 'shellwords'
|
60
60
|
|
61
|
-
PAGE_COMMANDS.each do |
|
62
|
-
|
63
|
-
next if
|
61
|
+
PAGE_COMMANDS.each do |pager_cmd|
|
62
|
+
cmd = Shellwords.split(pager_cmd)
|
63
|
+
next if cmd.empty?
|
64
64
|
|
65
|
-
if
|
66
|
-
|
65
|
+
if cmd.first == 'less'
|
66
|
+
cmd << '-R' unless cmd.include?('-R')
|
67
|
+
cmd << '-X' if retain_content && !cmd.include?('-X')
|
67
68
|
end
|
68
69
|
|
69
70
|
begin
|
70
|
-
io = IO.popen(
|
71
|
+
io = IO.popen(cmd, 'w')
|
71
72
|
rescue
|
72
73
|
next
|
73
74
|
end
|
data/lib/irb/source_finder.rb
CHANGED
@@ -16,7 +16,7 @@ module IRB
|
|
16
16
|
@irb_context = irb_context
|
17
17
|
end
|
18
18
|
|
19
|
-
def find_source(signature)
|
19
|
+
def find_source(signature, s_count = nil)
|
20
20
|
context_binding = @irb_context.workspace.binding
|
21
21
|
case signature
|
22
22
|
when /\A[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
|
@@ -26,14 +26,13 @@ module IRB
|
|
26
26
|
when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
|
27
27
|
owner = eval(Regexp.last_match[:owner], context_binding)
|
28
28
|
method = Regexp.last_match[:method]
|
29
|
-
|
30
|
-
|
31
|
-
file, line = owner.instance_method(method).source_location if methods.include?(method.to_sym)
|
32
|
-
end
|
29
|
+
return unless owner.respond_to?(:instance_method)
|
30
|
+
file, line = method_target(owner, s_count, method, "owner")
|
33
31
|
when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
|
34
32
|
receiver = eval(Regexp.last_match[:receiver] || 'self', context_binding)
|
35
33
|
method = Regexp.last_match[:method]
|
36
|
-
|
34
|
+
return unless receiver.respond_to?(method, true)
|
35
|
+
file, line = method_target(receiver, s_count, method, "receiver")
|
37
36
|
end
|
38
37
|
if file && line && File.exist?(file)
|
39
38
|
Source.new(file: file, first_line: line, last_line: find_end(file, line))
|
@@ -60,5 +59,26 @@ module IRB
|
|
60
59
|
end
|
61
60
|
first_line
|
62
61
|
end
|
62
|
+
|
63
|
+
def method_target(owner_receiver, s_count, method, type)
|
64
|
+
case type
|
65
|
+
when "owner"
|
66
|
+
target_method = owner_receiver.instance_method(method)
|
67
|
+
return target_method.source_location unless s_count
|
68
|
+
when "receiver"
|
69
|
+
if s_count
|
70
|
+
target_method = owner_receiver.class.instance_method(method)
|
71
|
+
else
|
72
|
+
target_method = method
|
73
|
+
return owner_receiver.method(method).source_location
|
74
|
+
end
|
75
|
+
end
|
76
|
+
s_count.times do |s|
|
77
|
+
target_method = target_method.super_method if target_method
|
78
|
+
end
|
79
|
+
target_method.nil? ? nil : target_method.source_location
|
80
|
+
rescue NameError
|
81
|
+
nil
|
82
|
+
end
|
63
83
|
end
|
64
84
|
end
|