summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorReginald Tan <redge.tan@gmail.com>2012-05-02 22:29:17 -0400
committerReginald Tan <redge.tan@gmail.com>2012-05-23 20:42:16 -0400
commit21553e3dda02ec44d859f402ee72ca00deed0f26 (patch)
tree755d95544b1a24afb3628a85e41ca2a7a1d99b60 /lib
parent7bd1f9b748df78dbc2e7021fa337c1e712068491 (diff)
downloadmethod_source-21553e3dda02ec44d859f402ee72ca00deed0f26.tar.gz
If displaying method source fails for *_evaled methods, retry again.
This time, assume inside eval string and simulate interpolation of #{} by replacing with a placeholder when doing syntax validation Only works if *_eval contains the arguments filename and lineno + 1. Without them, UnboundMethod#source_location would not return the proper filename and lineno needed to display the source.
Diffstat (limited to 'lib')
-rw-r--r--lib/method_source.rb46
1 files changed, 36 insertions, 10 deletions
diff --git a/lib/method_source.rb b/lib/method_source.rb
index 9a3c325..75bbb8e 100644
--- a/lib/method_source.rb
+++ b/lib/method_source.rb
@@ -31,22 +31,48 @@ module MethodSource
# 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
+ # @return [String] The method body
def self.source_helper(source_location)
return nil if !source_location.is_a?(Array)
- file_name, line = source_location
- File.open(file_name) do |file|
- (line - 1).times { file.readline }
+ # 1st try: simple eval
+ code = extract_code(source_location)
+
+ unless code
+ # 2nd try: attempt to re-scan method body, this time, assume we're inside an eval string simulate interpolation of #{} expressions by replacing it with placeholder
+ #
+ # A temporary work around for cases where method body is defined inside a
+ # string (i.e. class_evaled methods), and the resulting valid_expression
+ # doesn't return true due to string not being interpolated.
+ # (see https://github.com/banister/method_source/issues/13)
+ #
+ code = extract_code(source_location) { |code| code.gsub(/\#{.*?}/,"temp") }
+ end
- code = ""
- loop do
- val = file.readline
- code << val
+ code
+ rescue Errno::ENOENT
+ # source_location[0] of evaled methods would return (eval) if __FILE__ and __LINE__ is not given. File.readlines "(eval)" would raise ENOENT
+ nil
+ end
- return code if valid_expression?(code)
- end
+ # @param [Array] source_location The array containing file_name [String], line [Fixnum]
+ # @param [Block] An optional block that can be passed that will be used to modify
+ # the code buffer before its syntax is evaluated
+ # @return [String] The method body
+ def self.extract_code(source_location)
+ file_name, line = source_location
+ code = ""
+ lines_for_file(file_name)[(line - 1)..-1].each do |line|
+ code << line
+ expression = block_given? ? yield(code) : code
+ return code if valid_expression?(expression)
end
+ nil
+ end
+
+ def self.lines_for_file(file_name)
+ @lines_for_file ||= {}
+ @lines_for_file[file_name] ||= File.readlines(file_name)
end
# Helper method responsible for opening source file and buffering up