blob: 57397c76df4d01c037d1cbc581f929e7e19b0adb (
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
|
# (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 opening source file and advancing to
# the correct linenumber. 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 }
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
file = nil
if respond_to?(:source_location)
file = MethodSource.source_helper(source_location)
raise "Cannot locate source for this method: #{name}" if !file
else
raise "Method#source not supported by this Ruby version (#{RUBY_VERSION})"
end
code = ""
loop do
val = file.readline
code += val
return code if MethodSource.valid_expression?(code)
end
ensure
file.close if file
end
end
end
class Method
include MethodSource::MethodExtensions
end
class UnboundMethod
include MethodSource::MethodExtensions
end
class Proc
include MethodSource::MethodExtensions
end
|