1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
# frozen_string_literal: true
require 'tempfile'
class Pry
module Helpers
module CommandHelpers
include OptionsHelpers
extend self
# Open a temp file and yield it to the block, closing it after
# @return [String] The path of the temp file
def temp_file(ext = '.rb')
file = Tempfile.new(['pry', ext])
yield(file)
ensure
file.close(true)
end
def internal_binding?(context)
method_name = context.eval("::Kernel.__method__").to_s
# class_eval is here because of http://jira.codehaus.org/browse/JRUBY-6753
%w[__binding__ __pry__ class_eval].include?(method_name)
# TODO: codehaus is dead, there was no test for this and the
# description for the commit doesn't exist. Probably a candidate for
# removal so we have a chance to introduce a regression and document it
# properly.
end
def get_method_or_raise(method_name, context, opts = {})
method = Pry::Method.from_str(method_name, context, opts)
if !method && method_name
raise Pry::MethodNotFound, "method '#{method_name}' could not be found."
end
(opts[:super] || 0).times do
if method.super
method = method.super
else
raise Pry::MethodNotFound,
"'#{method.name_with_owner}' has no super method"
end
end
if !method || (!method_name && internal_binding?(context))
raise Pry::MethodNotFound,
'no method name given, and context is not a method'
end
set_file_and_dir_locals(method.source_file)
method
end
# Remove any common leading whitespace from every line in `text`. This
# can be used to make a HEREDOC line up with the left margin, without
# sacrificing the indentation level of the source code.
#
# @example
# opt.banner(unindent(<<-USAGE))
# Lorem ipsum dolor sit amet, consectetur adipisicing elit,
# sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
# "Ut enim ad minim veniam."
# USAGE
#
# @param [String] dirty_text The text from which to remove indentation
# @return [String] the text with indentation stripped
def unindent(dirty_text, left_padding = 0)
text = dirty_text.sub(/\A[ \t]+\z/, '') # Empty blank lines.
# Find the longest common whitespace to all indented lines. Ignore lines
# containing just -- or ++ as these seem to be used by comment authors
# as delimeters.
scanned_text = text.scan(/^[ \t]*(?!--\n|\+\+\n)(?=[^ \t\n])/)
margin = scanned_text.inject do |current_margin, next_indent|
if next_indent.start_with?(current_margin)
current_margin
elsif current_margin.start_with?(next_indent)
next_indent
else
''
end
end
text.gsub(/^#{margin}/, ' ' * left_padding)
end
# Restrict a string to the given range of lines (1-indexed)
# @param [String] content The string.
# @param [Range, Integer] lines The line(s) to restrict it to.
# @return [String] The resulting string.
def restrict_to_lines(content, lines)
line_range = one_index_range_or_number(lines)
Array(content.lines.to_a[line_range]).join
end
def one_index_number(line_number)
line_number > 0 ? line_number - 1 : line_number
end
# convert a 1-index range to a 0-indexed one
def one_index_range(range)
Range.new(one_index_number(range.begin), one_index_number(range.end))
end
def one_index_range_or_number(range_or_number)
case range_or_number
when Range
one_index_range(range_or_number)
else
one_index_number(range_or_number)
end
end
def absolute_index_number(line_number, array_length)
if line_number >= 0
line_number
else
[array_length + line_number, 0].max
end
end
def absolute_index_range(range_or_number, array_length)
case range_or_number
when Range
a = absolute_index_number(range_or_number.begin, array_length)
b = absolute_index_number(range_or_number.end, array_length)
else
a = b = absolute_index_number(range_or_number, array_length)
end
Range.new(a, b)
end
def set_file_and_dir_locals(file_name, pry = pry_instance, ctx = target)
return if !ctx || !file_name
pry.last_file = File.expand_path(file_name)
pry.inject_local("_file_", pry.last_file, ctx)
pry.last_dir = File.dirname(pry.last_file)
pry.inject_local("_dir_", pry.last_dir, ctx)
end
end
end
end
|