blob: bdb00ed5e7105c907285cf32726b66cc5651932b (
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
|
# (C) John Mair (banisterfiend) 2010
# MIT License
direc = File.dirname(__FILE__)
require 'stringio'
require "#{direc}/method_source/version"
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)
suppress_stderr do
RubyVM::InstructionSequence.new(code)
end
rescue Exception
false
else
true
end
# Helper method used to suppress stderr output by the
# `RubyVM::InstructionSequence` method
# @yield The block where stderr is suppressed
def self.suppress_stderr
real_stderr, $stderr = $stderr, StringIO.new
yield
ensure
$stderr = real_stderr
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
|