blob: ecb546eaf7616d82f026089fb2cac582400b96ef (
plain)
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
|
# (C) John Mair (banisterfiend) 2010
# MIT License
direc = File.dirname(__FILE__)
require 'stringio'
require "#{direc}/method_source/version"
if RUBY_VERSION =~ /1.9/
require 'ripper'
end
module MethodSource
# Helper method used to find end of method body
# @param [String] code The string of Ruby code to check for
# correctness
# @return [Boolean]
def self.valid_expression?(code)
!!Ripper::SexpBuilder.new(code).parse
end
# Helper method responsible for extracting method body.
# Defined here to avoid polluting `Method` class.
# @param [Array] source_location The array returned by Method#source_location
# @return [File] The opened source file
def self.source_helper(source_location)
return nil if !source_location.is_a?(Array)
file_name, line = source_location
file = File.open(file_name)
(line - 1).times { file.readline }
code = ""
loop do
val = file.readline
code << val
return code if MethodSource.valid_expression?(code)
end
ensure
file.close if file
end
# Helper method responsible for opening source file and buffering up
# the comments for a specified method. Defined here to avoid polluting
# `Method` class.
# @param [Array] source_location The array returned by Method#source_location
# @return [String] The comments up to the point of the method.
def self.comment_helper(source_location)
return nil if !source_location.is_a?(Array)
file_name, line = source_location
file = File.open(file_name)
buffer = ""
(line - 1).times do
line = file.readline
# Add any line that is a valid ruby comment,
# but clear as soon as we hit a non comment line.
if (line =~ /^\s*#/) || (line =~ /^\s*$/)
buffer << line.lstrip
else
buffer.clear
end
end
buffer
ensure
file.close if file
end
# This module is to be included by `Method` and `UnboundMethod` and
# provides the `#source` functionality
module MethodExtensions
# Return the sourcecode for the method as a string
# (This functionality is only supported in Ruby 1.9 and above)
# @return [String] The method sourcecode as a string
# @example
# Set.instance_method(:clear).source.display
# =>
# def clear
# @hash.clear
# self
# end
def source
if respond_to?(:source_location)
source = MethodSource.source_helper(source_location)
raise "Cannot locate source for this method: #{name}" if !source
else
raise "Method#source not supported by this Ruby version (#{RUBY_VERSION})"
end
source
end
# Return the comments associated with the method as a string.
# (This functionality is only supported in Ruby 1.9 and above)
# @return [String] The method's comments as a string
# @example
# Set.instance_method(:clear).comment.display
# =>
# # Removes all elements and returns self.
def comment
if respond_to?(:source_location)
comment = MethodSource.comment_helper(source_location)
raise "Cannot locate source for this method: #{name}" if !comment
else
raise "Method#comment not supported by this Ruby version (#{RUBY_VERSION})"
end
comment
end
end
end
class Method
include MethodSource::MethodExtensions
end
class UnboundMethod
include MethodSource::MethodExtensions
end
class Proc
include MethodSource::MethodExtensions
end
|