pry 0.9.8.4-i386-mswin32 → 0.9.9-i386-mswin32
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.
- data/.gitignore +1 -0
- data/CHANGELOG +26 -0
- data/README.markdown +3 -3
- data/lib/pry.rb +9 -1
- data/lib/pry/code.rb +93 -0
- data/lib/pry/command.rb +35 -22
- data/lib/pry/command_set.rb +97 -67
- data/lib/pry/config.rb +63 -10
- data/lib/pry/core_extensions.rb +24 -18
- data/lib/pry/default_commands/context.rb +72 -12
- data/lib/pry/default_commands/easter_eggs.rb +4 -0
- data/lib/pry/default_commands/editing.rb +43 -15
- data/lib/pry/default_commands/find_method.rb +171 -0
- data/lib/pry/default_commands/hist.rb +10 -6
- data/lib/pry/default_commands/introspection.rb +183 -30
- data/lib/pry/default_commands/ls.rb +77 -7
- data/lib/pry/default_commands/misc.rb +1 -0
- data/lib/pry/default_commands/navigating_pry.rb +1 -8
- data/lib/pry/helpers/base_helpers.rb +10 -2
- data/lib/pry/helpers/command_helpers.rb +23 -40
- data/lib/pry/helpers/documentation_helpers.rb +65 -0
- data/lib/pry/indent.rb +17 -4
- data/lib/pry/method.rb +61 -45
- data/lib/pry/pry_class.rb +9 -3
- data/lib/pry/pry_instance.rb +99 -65
- data/lib/pry/rbx_method.rb +2 -9
- data/lib/pry/version.rb +1 -1
- data/lib/pry/wrapped_module.rb +236 -1
- data/pry.gemspec +5 -5
- data/test/helper.rb +22 -0
- data/test/test_command.rb +29 -0
- data/test/test_command_integration.rb +193 -10
- data/test/test_command_set.rb +82 -17
- data/test/test_default_commands/test_cd.rb +16 -0
- data/test/test_default_commands/test_context.rb +61 -0
- data/test/test_default_commands/test_documentation.rb +163 -43
- data/test/test_default_commands/test_find_method.rb +42 -0
- data/test/test_default_commands/test_input.rb +32 -0
- data/test/test_default_commands/test_introspection.rb +50 -197
- data/test/test_default_commands/test_ls.rb +22 -0
- data/test/test_default_commands/test_show_source.rb +306 -0
- data/test/test_pry.rb +3 -3
- data/test/test_pry_defaults.rb +21 -0
- data/test/test_sticky_locals.rb +81 -1
- data/test/test_syntax_checking.rb +7 -6
- metadata +24 -16
data/lib/pry/pry_class.rb
CHANGED
@@ -46,11 +46,14 @@ class Pry
|
|
46
46
|
# @return [Fixnum] The number of active Pry sessions.
|
47
47
|
attr_accessor :active_sessions
|
48
48
|
|
49
|
+
# @return [Boolean] Whether Pry sessions are quiet by default.
|
50
|
+
attr_accessor :quiet
|
51
|
+
|
49
52
|
# plugin forwardables
|
50
53
|
def_delegators :@plugin_manager, :plugins, :load_plugins, :locate_plugins
|
51
54
|
|
52
55
|
delegate_accessors :@config, :input, :output, :commands, :prompt, :print, :exception_handler,
|
53
|
-
:hooks, :color, :pager, :editor, :memory_size, :input_stack
|
56
|
+
:hooks, :color, :pager, :editor, :memory_size, :input_stack, :extra_sticky_locals
|
54
57
|
end
|
55
58
|
|
56
59
|
# Load the rc files given in the `Pry::RC_FILES` array.
|
@@ -261,6 +264,8 @@ class Pry
|
|
261
264
|
|
262
265
|
config.memory_size = 100
|
263
266
|
|
267
|
+
config.extra_sticky_locals = {}
|
268
|
+
|
264
269
|
config.ls ||= OpenStruct.new({
|
265
270
|
:heading_color => :default,
|
266
271
|
|
@@ -279,9 +284,10 @@ class Pry
|
|
279
284
|
:builtin_global_color => :cyan, # e.g. $stdin, $-w, $PID
|
280
285
|
:pseudo_global_color => :cyan, # e.g. $~, $1..$9, $LAST_MATCH_INFO
|
281
286
|
|
282
|
-
:constant_color => :default,
|
287
|
+
:constant_color => :default, # e.g. VERSION, ARGF
|
283
288
|
:class_constant_color => :blue, # e.g. Object, Kernel
|
284
289
|
:exception_constant_color => :magenta, # e.g. Exception, RuntimeError
|
290
|
+
:unloaded_constant_color => :yellow, # Any constant that is still in .autoload? state
|
285
291
|
|
286
292
|
# What should separate items listed by ls? (TODO: we should allow a columnar layout)
|
287
293
|
:separator => " ",
|
@@ -345,7 +351,7 @@ class Pry
|
|
345
351
|
# @param [Object] target The object to get a `Binding` object for.
|
346
352
|
# @return [Binding] The `Binding` object.
|
347
353
|
def self.binding_for(target)
|
348
|
-
if target
|
354
|
+
if Binding === target
|
349
355
|
target
|
350
356
|
else
|
351
357
|
if TOPLEVEL_BINDING.eval('self') == target
|
data/lib/pry/pry_instance.rb
CHANGED
@@ -8,6 +8,8 @@ class Pry
|
|
8
8
|
attr_accessor :print
|
9
9
|
attr_accessor :exception_handler
|
10
10
|
attr_accessor :input_stack
|
11
|
+
attr_accessor :quiet
|
12
|
+
alias :quiet? :quiet
|
11
13
|
|
12
14
|
attr_accessor :custom_completions
|
13
15
|
|
@@ -24,6 +26,8 @@ class Pry
|
|
24
26
|
|
25
27
|
attr_accessor :backtrace
|
26
28
|
|
29
|
+
attr_accessor :extra_sticky_locals
|
30
|
+
|
27
31
|
# Special treatment for hooks as we want to alert people of the
|
28
32
|
# changed API
|
29
33
|
attr_reader :hooks
|
@@ -48,6 +52,7 @@ class Pry
|
|
48
52
|
# @option options [Hash] :hooks The defined hook Procs
|
49
53
|
# @option options [Array<Proc>] :prompt The array of Procs to use for the prompts.
|
50
54
|
# @option options [Proc] :print The Proc to use for the 'print'
|
55
|
+
# @option options [Boolean] :quiet If true, omit the whereami banner when starting.
|
51
56
|
# component of the REPL. (see print.rb)
|
52
57
|
def initialize(options={})
|
53
58
|
refresh(options)
|
@@ -63,9 +68,9 @@ class Pry
|
|
63
68
|
def refresh(options={})
|
64
69
|
defaults = {}
|
65
70
|
attributes = [
|
66
|
-
:input, :output, :commands, :print,
|
71
|
+
:input, :output, :commands, :print, :quiet,
|
67
72
|
:exception_handler, :hooks, :custom_completions,
|
68
|
-
:prompt, :memory_size, :input_stack
|
73
|
+
:prompt, :memory_size, :input_stack, :extra_sticky_locals
|
69
74
|
]
|
70
75
|
|
71
76
|
attributes.each do |attribute|
|
@@ -155,7 +160,7 @@ class Pry
|
|
155
160
|
:_file_ => proc { last_file },
|
156
161
|
:_dir_ => proc { last_dir },
|
157
162
|
:_ => proc { last_result }
|
158
|
-
}
|
163
|
+
}.merge(extra_sticky_locals)
|
159
164
|
end
|
160
165
|
|
161
166
|
# Initialize the repl session.
|
@@ -195,13 +200,19 @@ class Pry
|
|
195
200
|
|
196
201
|
repl_prologue(target)
|
197
202
|
|
198
|
-
break_data =
|
199
|
-
|
200
|
-
|
203
|
+
break_data = nil
|
204
|
+
exception = catch(:raise_up) do
|
205
|
+
break_data = catch(:breakout) do
|
206
|
+
loop do
|
207
|
+
rep(binding_stack.last)
|
208
|
+
end
|
201
209
|
end
|
210
|
+
exception = false
|
202
211
|
end
|
203
212
|
|
204
|
-
|
213
|
+
raise exception if exception
|
214
|
+
|
215
|
+
break_data
|
205
216
|
ensure
|
206
217
|
repl_epilogue(target)
|
207
218
|
end
|
@@ -229,17 +240,6 @@ class Pry
|
|
229
240
|
def re(target=TOPLEVEL_BINDING)
|
230
241
|
target = Pry.binding_for(target)
|
231
242
|
|
232
|
-
compl = Pry::InputCompleter.build_completion_proc(target,
|
233
|
-
instance_eval(&custom_completions))
|
234
|
-
|
235
|
-
if defined? Coolline and input.is_a? Coolline
|
236
|
-
input.completion_proc = proc do |cool|
|
237
|
-
compl.call cool.completed_word
|
238
|
-
end
|
239
|
-
elsif input.respond_to? :completion_proc=
|
240
|
-
input.completion_proc = compl
|
241
|
-
end
|
242
|
-
|
243
243
|
# It's not actually redundant to inject them continually as we may have
|
244
244
|
# moved into the scope of a new Binding (e.g the user typed `cd`)
|
245
245
|
inject_sticky_locals(target)
|
@@ -282,7 +282,7 @@ class Pry
|
|
282
282
|
end
|
283
283
|
|
284
284
|
begin
|
285
|
-
break if complete_expression?(eval_string)
|
285
|
+
break if Pry::Code.complete_expression?(eval_string)
|
286
286
|
rescue SyntaxError => e
|
287
287
|
output.puts "SyntaxError: #{e.message.sub(/.*syntax error, */m, '')}"
|
288
288
|
eval_string = ""
|
@@ -334,9 +334,23 @@ class Pry
|
|
334
334
|
@indent.reset if eval_string.empty?
|
335
335
|
|
336
336
|
current_prompt = select_prompt(eval_string, target)
|
337
|
+
completion_proc = Pry::InputCompleter.build_completion_proc(target,
|
338
|
+
instance_eval(&custom_completions))
|
339
|
+
|
340
|
+
|
337
341
|
indentation = Pry.config.auto_indent ? @indent.indent_level : ''
|
338
342
|
|
339
|
-
|
343
|
+
begin
|
344
|
+
val = readline("#{current_prompt}#{indentation}", completion_proc)
|
345
|
+
|
346
|
+
# Handle <Ctrl+C> like Bash, empty the current input buffer but do not quit.
|
347
|
+
# This is only for ruby-1.9; other versions of ruby do not let you send Interrupt
|
348
|
+
# from within Readline.
|
349
|
+
rescue Interrupt => e
|
350
|
+
output.puts ""
|
351
|
+
eval_string.replace("")
|
352
|
+
return
|
353
|
+
end
|
340
354
|
|
341
355
|
# invoke handler if we receive EOF character (^D)
|
342
356
|
if !val
|
@@ -356,8 +370,8 @@ class Pry
|
|
356
370
|
original_val = "#{indentation}#{val}"
|
357
371
|
indented_val = @indent.indent(val)
|
358
372
|
|
359
|
-
if
|
360
|
-
output.print @indent.correct_indentation(current_prompt
|
373
|
+
if output.tty? && Pry::Helpers::BaseHelpers.use_ansi_codes? && Pry.config.correct_indent
|
374
|
+
output.print @indent.correct_indentation(current_prompt, indented_val, original_val.length - indented_val.length)
|
361
375
|
output.flush
|
362
376
|
end
|
363
377
|
else
|
@@ -514,17 +528,42 @@ class Pry
|
|
514
528
|
self.input = input_stack.pop
|
515
529
|
end
|
516
530
|
retry
|
531
|
+
|
532
|
+
# Interrupts are handled in r() because they need to tweak eval_string
|
533
|
+
# TODO: Refactor this baby.
|
534
|
+
rescue Interrupt
|
535
|
+
raise
|
536
|
+
|
537
|
+
# If we get a random error when trying to read a line we don't want to automatically
|
538
|
+
# retry, as the user will see a lot of error messages scroll past and be unable to do
|
539
|
+
# anything about it.
|
540
|
+
rescue RescuableException => e
|
541
|
+
puts "Error: #{e.message}"
|
542
|
+
puts "FATAL: Pry failed to get user input using `#{input}`."
|
543
|
+
puts "To fix this you may be able to pass input and output file descriptors to pry directly. e.g."
|
544
|
+
puts " Pry.config.input = STDIN"
|
545
|
+
puts " Pry.config.output = STDOUT"
|
546
|
+
puts " binding.pry"
|
547
|
+
throw(:breakout)
|
517
548
|
end
|
518
549
|
end
|
519
|
-
|
520
550
|
private :handle_read_errors
|
521
551
|
|
522
552
|
# Returns the next line of input to be used by the pry instance.
|
523
553
|
# This method should not need to be invoked directly.
|
524
554
|
# @param [String] current_prompt The prompt to use for input.
|
525
555
|
# @return [String] The next line of input.
|
526
|
-
def readline(current_prompt="> ")
|
556
|
+
def readline(current_prompt="> ", completion_proc=nil)
|
527
557
|
handle_read_errors do
|
558
|
+
|
559
|
+
if defined? Coolline and input.is_a? Coolline
|
560
|
+
input.completion_proc = proc do |cool|
|
561
|
+
completion_proc.call cool.completed_word
|
562
|
+
end
|
563
|
+
elsif input.respond_to? :completion_proc=
|
564
|
+
input.completion_proc = completion_proc
|
565
|
+
end
|
566
|
+
|
528
567
|
if input == Readline
|
529
568
|
input.readline(current_prompt, false) # false since we'll add it manually
|
530
569
|
elsif defined? Coolline and input.is_a? Coolline
|
@@ -598,50 +637,45 @@ class Pry
|
|
598
637
|
prompt_stack.size > 1 ? prompt_stack.pop : prompt
|
599
638
|
end
|
600
639
|
|
601
|
-
#
|
602
|
-
# @param [String] code The code to validate.
|
603
|
-
# @return [Boolean] Whether or not the code is a complete Ruby expression.
|
604
|
-
# @raise [SyntaxError] Any SyntaxError that does not represent incompleteness.
|
605
|
-
# @example
|
606
|
-
# complete_expression?("class Hello") #=> false
|
607
|
-
# complete_expression?("class Hello; end") #=> true
|
608
|
-
def complete_expression?(str)
|
609
|
-
if defined?(Rubinius::Melbourne19) && RUBY_VERSION =~ /^1\.9/
|
610
|
-
Rubinius::Melbourne19.parse_string(str, Pry.eval_path)
|
611
|
-
elsif defined?(Rubinius::Melbourne)
|
612
|
-
Rubinius::Melbourne.parse_string(str, Pry.eval_path)
|
613
|
-
else
|
614
|
-
catch(:valid) do
|
615
|
-
Helpers::BaseHelpers.silence_warnings do
|
616
|
-
eval("BEGIN{throw :valid}\n#{str}", binding, Pry.eval_path)
|
617
|
-
end
|
618
|
-
end
|
619
|
-
end
|
620
|
-
|
621
|
-
# Assert that a line which ends with a , is incomplete.
|
622
|
-
str !~ /[,]\z/
|
623
|
-
rescue SyntaxError => e
|
624
|
-
if incomplete_user_input_exception?(e)
|
625
|
-
false
|
626
|
-
else
|
627
|
-
raise e
|
628
|
-
end
|
629
|
-
end
|
630
|
-
|
631
|
-
# Check whether the exception indicates that the user should input more.
|
640
|
+
# Raise an exception out of Pry.
|
632
641
|
#
|
633
|
-
#
|
634
|
-
#
|
635
|
-
# @return [Boolean]
|
642
|
+
# See Kernel#raise for documentation of parameters.
|
643
|
+
# See rb_make_exception for the inbuilt implementation.
|
636
644
|
#
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
645
|
+
# This is necessary so that the raise-up command can tell the
|
646
|
+
# difference between an exception the user has decided to raise,
|
647
|
+
# and a mistake in specifying that exception.
|
648
|
+
#
|
649
|
+
# (i.e. raise-up RunThymeError.new should not be the same as
|
650
|
+
# raise-up NameError, "unititialized constant RunThymeError")
|
651
|
+
#
|
652
|
+
def raise_up_common(force, *args)
|
653
|
+
exception = if args == []
|
654
|
+
last_exception || RuntimeError.new
|
655
|
+
elsif args.length == 1 && args.first.is_a?(String)
|
656
|
+
RuntimeError.new(args.first)
|
657
|
+
elsif args.length > 3
|
658
|
+
raise ArgumentError, "wrong number of arguments"
|
659
|
+
elsif !args.first.respond_to?(:exception)
|
660
|
+
raise TypeError, "exception class/object expected"
|
661
|
+
elsif args.length === 1
|
662
|
+
args.first.exception
|
663
|
+
else
|
664
|
+
args.first.exception(args[1])
|
665
|
+
end
|
666
|
+
|
667
|
+
raise TypeError, "exception object expected" unless exception.is_a? Exception
|
668
|
+
|
669
|
+
exception.set_backtrace(args.length === 3 ? args[2] : caller(1))
|
670
|
+
|
671
|
+
if force || binding_stack.one?
|
672
|
+
binding_stack.clear
|
673
|
+
throw :raise_up, exception
|
643
674
|
else
|
644
|
-
|
675
|
+
binding_stack.pop
|
676
|
+
raise exception
|
645
677
|
end
|
646
678
|
end
|
679
|
+
def raise_up(*args); raise_up_common(false, *args); end
|
680
|
+
def raise_up!(*args); raise_up_common(true, *args); end
|
647
681
|
end
|
data/lib/pry/rbx_method.rb
CHANGED
@@ -1,20 +1,13 @@
|
|
1
1
|
class Pry
|
2
2
|
module RbxMethod
|
3
3
|
private
|
4
|
-
def core?
|
5
|
-
source_file and RbxPath.is_core_path?(source_file)
|
6
|
-
end
|
7
4
|
|
8
5
|
def core_code
|
9
|
-
MethodSource.source_helper(
|
6
|
+
MethodSource.source_helper(source_location)
|
10
7
|
end
|
11
8
|
|
12
9
|
def core_doc
|
13
|
-
MethodSource.comment_helper(
|
14
|
-
end
|
15
|
-
|
16
|
-
def core_path_line
|
17
|
-
[RbxPath.convert_path_to_full(source_file), source_line]
|
10
|
+
MethodSource.comment_helper(source_location)
|
18
11
|
end
|
19
12
|
end
|
20
13
|
end
|
data/lib/pry/version.rb
CHANGED
data/lib/pry/wrapped_module.rb
CHANGED
@@ -1,15 +1,55 @@
|
|
1
|
+
require 'pry/helpers/documentation_helpers'
|
2
|
+
|
1
3
|
class Pry
|
4
|
+
class << self
|
5
|
+
# If the given object is a `Pry::WrappedModule`, return it unaltered. If it's
|
6
|
+
# anything else, return it wrapped in a `Pry::WrappedModule` instance.
|
7
|
+
def WrappedModule(obj)
|
8
|
+
if obj.is_a? Pry::WrappedModule
|
9
|
+
obj
|
10
|
+
else
|
11
|
+
Pry::WrappedModule.new(obj)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
2
16
|
class WrappedModule
|
17
|
+
include Helpers::DocumentationHelpers
|
3
18
|
|
4
19
|
attr_reader :wrapped
|
5
20
|
private :wrapped
|
6
21
|
|
22
|
+
# Convert a string to a module.
|
23
|
+
#
|
24
|
+
# @param [String] mod_name
|
25
|
+
# @param [Binding] target The binding where the lookup takes place.
|
26
|
+
# @return [Module, nil] The module or `nil` (if conversion failed).
|
27
|
+
# @example
|
28
|
+
# Pry::WrappedModule.from_str("Pry::Code")
|
29
|
+
def self.from_str(mod_name, target=TOPLEVEL_BINDING)
|
30
|
+
kind = target.eval("defined?(#{mod_name})")
|
31
|
+
|
32
|
+
# if we dont limit it to constants then from_str could end up
|
33
|
+
# executing methods which is not good, i.e `show-source pry`
|
34
|
+
if (kind == "constant" && target.eval(mod_name).is_a?(Module))
|
35
|
+
Pry::WrappedModule.new(target.eval(mod_name))
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
rescue RescuableException
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
7
43
|
# Create a new WrappedModule
|
8
44
|
# @raise ArgumentError, if the argument is not a Module
|
9
45
|
# @param [Module]
|
10
46
|
def initialize(mod)
|
11
47
|
raise ArgumentError, "Tried to initialize a WrappedModule with a non-module #{mod.inspect}" unless ::Module === mod
|
12
48
|
@wrapped = mod
|
49
|
+
@host_file_lines = nil
|
50
|
+
@source = nil
|
51
|
+
@source_location = nil
|
52
|
+
@doc = nil
|
13
53
|
end
|
14
54
|
|
15
55
|
# The prefix that would appear before methods defined on this class.
|
@@ -67,7 +107,202 @@ class Pry
|
|
67
107
|
end
|
68
108
|
|
69
109
|
def respond_to?(method_name)
|
70
|
-
super || wrapped.
|
110
|
+
super || wrapped.respond_to?(method_name)
|
111
|
+
end
|
112
|
+
|
113
|
+
def yard_docs?
|
114
|
+
!!(defined?(YARD) && YARD::Registry.at(name))
|
115
|
+
end
|
116
|
+
|
117
|
+
def process_doc(doc)
|
118
|
+
process_comment_markup(strip_leading_hash_and_whitespace_from_ruby_comments(doc),
|
119
|
+
:ruby)
|
120
|
+
end
|
121
|
+
|
122
|
+
def doc
|
123
|
+
return @doc if @doc
|
124
|
+
|
125
|
+
file_name, line = source_location
|
126
|
+
|
127
|
+
if yard_docs?
|
128
|
+
from_yard = YARD::Registry.at(name)
|
129
|
+
@doc = from_yard.docstring
|
130
|
+
elsif source_location.nil?
|
131
|
+
raise CommandError, "Can't find module's source location"
|
132
|
+
else
|
133
|
+
@doc = extract_doc_for_candidate(0)
|
134
|
+
end
|
135
|
+
|
136
|
+
raise CommandError, "Can't find docs for module: #{name}." if !@doc
|
137
|
+
|
138
|
+
@doc = process_doc(@doc)
|
139
|
+
end
|
140
|
+
|
141
|
+
def doc_for_candidate(idx)
|
142
|
+
doc = extract_doc_for_candidate(idx)
|
143
|
+
raise CommandError, "Can't find docs for module: #{name}." if !doc
|
144
|
+
|
145
|
+
process_doc(doc)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Retrieve the source for the module.
|
149
|
+
def source
|
150
|
+
@source ||= source_for_candidate(0)
|
71
151
|
end
|
152
|
+
|
153
|
+
def source_for_candidate(idx)
|
154
|
+
file, line = module_source_location_for_candidate(idx)
|
155
|
+
raise CommandError, "Could not locate source for #{wrapped}!" if file.nil?
|
156
|
+
|
157
|
+
strip_leading_whitespace(Pry::Code.retrieve_complete_expression_from(lines_for_file(file)[(line - 1)..-1]))
|
158
|
+
end
|
159
|
+
|
160
|
+
def source_file
|
161
|
+
if yard_docs?
|
162
|
+
from_yard = YARD::Registry.at(name)
|
163
|
+
from_yard.file
|
164
|
+
else
|
165
|
+
source_file_for_candidate(0)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def source_line
|
170
|
+
source_line_for_candidate(0)
|
171
|
+
end
|
172
|
+
|
173
|
+
def source_file_for_candidate(idx)
|
174
|
+
Array(module_source_location_for_candidate(idx)).first
|
175
|
+
end
|
176
|
+
|
177
|
+
def source_line_for_candidate(idx)
|
178
|
+
Array(module_source_location_for_candidate(idx)).last
|
179
|
+
end
|
180
|
+
|
181
|
+
# Retrieve the source location of a module. Return value is in same
|
182
|
+
# format as Method#source_location. If the source location
|
183
|
+
# cannot be found this method returns `nil`.
|
184
|
+
#
|
185
|
+
# @param [Module] mod The module (or class).
|
186
|
+
# @return [Array<String, Fixnum>] The source location of the
|
187
|
+
# module (or class).
|
188
|
+
def source_location
|
189
|
+
@source_location ||= module_source_location_for_candidate(0)
|
190
|
+
rescue Pry::RescuableException
|
191
|
+
nil
|
192
|
+
end
|
193
|
+
|
194
|
+
# memoized lines for file
|
195
|
+
def lines_for_file(file)
|
196
|
+
@lines_for_file ||= {}
|
197
|
+
|
198
|
+
if file == Pry.eval_path
|
199
|
+
@lines_for_file[file] ||= Pry.line_buffer.drop(1)
|
200
|
+
else
|
201
|
+
@lines_for_file[file] ||= File.readlines(file)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def module_source_location_for_candidate(idx)
|
206
|
+
mod_type_string = wrapped.class.to_s.downcase
|
207
|
+
file, line = method_source_location_for_candidate(idx)
|
208
|
+
|
209
|
+
return nil if !file.is_a?(String)
|
210
|
+
|
211
|
+
class_regex1 = /#{mod_type_string}\s*(\w*)(::)?#{wrapped.name.split(/::/).last}/
|
212
|
+
class_regex2 = /(::)?#{wrapped.name.split(/::/).last}\s*?=\s*?#{wrapped.class}/
|
213
|
+
|
214
|
+
host_file_lines = lines_for_file(file)
|
215
|
+
|
216
|
+
search_lines = host_file_lines[0..(line - 2)]
|
217
|
+
idx = search_lines.rindex { |v| class_regex1 =~ v || class_regex2 =~ v }
|
218
|
+
|
219
|
+
source_location = [file, idx + 1]
|
220
|
+
rescue Pry::RescuableException
|
221
|
+
nil
|
222
|
+
end
|
223
|
+
|
224
|
+
def extract_doc
|
225
|
+
extract_doc_for_candidate(0)
|
226
|
+
end
|
227
|
+
|
228
|
+
def extract_doc_for_candidate(idx)
|
229
|
+
file_name, line = module_source_location_for_candidate(idx)
|
230
|
+
|
231
|
+
buffer = ""
|
232
|
+
lines_for_file(source_file_for_candidate(idx))[0..(line - 2)].each do |line|
|
233
|
+
# Add any line that is a valid ruby comment,
|
234
|
+
# but clear as soon as we hit a non comment line.
|
235
|
+
if (line =~ /^\s*#/) || (line =~ /^\s*$/)
|
236
|
+
buffer << line.lstrip
|
237
|
+
else
|
238
|
+
buffer.replace("")
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
buffer
|
243
|
+
end
|
244
|
+
|
245
|
+
# FIXME: this method is also found in Pry::Method
|
246
|
+
def safe_send(obj, method, *args, &block)
|
247
|
+
(Module === obj ? Module : Object).instance_method(method).bind(obj).call(*args, &block)
|
248
|
+
end
|
249
|
+
|
250
|
+
# FIXME: a variant of this method is also found in Pry::Method
|
251
|
+
def all_from_common(mod, method_type)
|
252
|
+
%w(public protected private).map do |visibility|
|
253
|
+
safe_send(mod, :"#{visibility}_#{method_type}s", false).select do |method_name|
|
254
|
+
if method_type == :method
|
255
|
+
safe_send(mod, method_type, method_name).owner == class << mod; self; end
|
256
|
+
else
|
257
|
+
safe_send(mod, method_type, method_name).owner == mod
|
258
|
+
end
|
259
|
+
end.map do |method_name|
|
260
|
+
Pry::Method.new(safe_send(mod, method_type, method_name), :visibility => visibility.to_sym)
|
261
|
+
end
|
262
|
+
end.flatten
|
263
|
+
end
|
264
|
+
|
265
|
+
def all_methods_for(mod)
|
266
|
+
all_from_common(mod, :instance_method) + all_from_common(mod, :method)
|
267
|
+
end
|
268
|
+
|
269
|
+
def all_source_locations_by_popularity
|
270
|
+
return @all_source_locations_by_popularity if @all_source_locations_by_popularity
|
271
|
+
|
272
|
+
ims = all_methods_for(wrapped)
|
273
|
+
|
274
|
+
ims.reject! do |v|
|
275
|
+
begin
|
276
|
+
v.alias? || v.source_location.nil?
|
277
|
+
rescue Pry::RescuableException
|
278
|
+
true
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
@all_source_locations_by_popularity = ims.group_by { |v| Array(v.source_location).first }.
|
283
|
+
sort_by { |k, v| -v.size }
|
284
|
+
end
|
285
|
+
|
286
|
+
def method_candidates
|
287
|
+
@method_candidtates ||= all_source_locations_by_popularity.map do |group|
|
288
|
+
sorted_by_lowest_line_number = group.last.sort_by(&:source_line)
|
289
|
+
best_candidate_for_group = sorted_by_lowest_line_number.first
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def number_of_candidates
|
294
|
+
method_candidates.count
|
295
|
+
end
|
296
|
+
|
297
|
+
def method_source_location_for_candidate(idx)
|
298
|
+
file, line = method_candidates[idx].source_location
|
299
|
+
|
300
|
+
if file && RbxPath.is_core_path?(file)
|
301
|
+
file = RbxPath.convert_path_to_full(file)
|
302
|
+
end
|
303
|
+
|
304
|
+
[file, line]
|
305
|
+
end
|
306
|
+
|
72
307
|
end
|
73
308
|
end
|