diff options
author | John Mair <jrmair@gmail.com> | 2011-02-28 03:40:47 +1300 |
---|---|---|
committer | John Mair <jrmair@gmail.com> | 2011-02-28 03:40:47 +1300 |
commit | 52ef85631d136a4ff31c0f4c2587b19db3daf512 (patch) | |
tree | fcad597e22e22a576fd6ac74b878e89785012d67 /lib | |
parent | 8f6b36637263a79ae4ac96ec734b1851614a4e19 (diff) | |
download | method_source-dev.tar.gz |
version 0.3.0, some ruby 1.8 supportdev
Diffstat (limited to 'lib')
-rw-r--r-- | lib/method_source.rb | 48 | ||||
-rw-r--r-- | lib/method_source/source_location.rb | 56 | ||||
-rw-r--r-- | lib/method_source/version.rb | 2 |
3 files changed, 93 insertions, 13 deletions
diff --git a/lib/method_source.rb b/lib/method_source.rb index d6a6e29..43651b9 100644 --- a/lib/method_source.rb +++ b/lib/method_source.rb @@ -4,19 +4,41 @@ direc = File.dirname(__FILE__) require "#{direc}/method_source/version" - -if RUBY_VERSION =~ /1.9/ - require 'ripper' -end +require "#{direc}/method_source/source_location" 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 + if RUBY_VERSION =~ /1.9/ + require 'ripper' + + # Determine if a string of code is a valid Ruby expression. + # Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser. + # @param [String] code The code to validate. + # @return [Boolean] Whether or not the code is a valid Ruby expression. + # @example + # valid_expression?("class Hello") #=> false + # valid_expression?("class Hello; end") #=> true + def self.valid_expression?(code) + !!Ripper::SexpBuilder.new(code).parse + end + + else + require 'ruby_parser' + + # Determine if a string of code is a valid Ruby expression. + # Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser. + # @param [String] code The code to validate. + # @return [Boolean] Whether or not the code is a valid Ruby expression. + # @example + # valid_expression?("class Hello") #=> false + # valid_expression?("class Hello; end") #=> true + def self.valid_expression?(code) + RubyParser.new.parse(code) + rescue Racc::ParseError, SyntaxError + false + else + true + end end # Helper method responsible for extracting method body. @@ -86,7 +108,7 @@ module MethodSource raise "Cannot locate source for this method: #{name}" if !source else - raise "Method#source not supported by this Ruby version (#{RUBY_VERSION})" + raise "#{self.class}#source not supported by this Ruby version (#{RUBY_VERSION})" end source @@ -105,7 +127,7 @@ module MethodSource raise "Cannot locate source for this method: #{name}" if !comment else - raise "Method#comment not supported by this Ruby version (#{RUBY_VERSION})" + raise "#{self.class}#comment not supported by this Ruby version (#{RUBY_VERSION})" end comment @@ -114,10 +136,12 @@ module MethodSource end class Method + include MethodSource::SourceLocation::MethodExtensions include MethodSource::MethodExtensions end class UnboundMethod + include MethodSource::SourceLocation::UnboundMethodExtensions include MethodSource::MethodExtensions end diff --git a/lib/method_source/source_location.rb b/lib/method_source/source_location.rb new file mode 100644 index 0000000..1878b18 --- /dev/null +++ b/lib/method_source/source_location.rb @@ -0,0 +1,56 @@ +module MethodSource + module SourceLocation + module MethodExtensions + def trace_func(event, file, line, id, binding, classname) + return unless event == 'call' + set_trace_func nil + + @file, @line = file, line + raise :found + end + + # Return the source location of a method for Ruby 1.8. + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # method definition is found. + def source_location + if @file.nil? + args =[*(1..(arity<-1 ? -arity-1 : arity ))] + + set_trace_func method(:trace_func).to_proc + call *args rescue nil + set_trace_func nil + @file = File.expand_path(@file) if @file && File.exist?(File.expand_path(@file)) + end + return [@file, @line] if File.exist?(@file.to_s) + end + end + + module UnboundMethodExtensions + + # Return the source location of an instance method for Ruby 1.8. + # @return [Array] A two element array. First element is the + # file, second element is the line in the file where the + # method definition is found. + def source_location + klass = case owner + when Class + owner + when Module + Class.new.tap { |v| v.send(:include, owner) } + end + + begin + klass.allocate.method(name).source_location + rescue TypeError + + # Assume we are dealing with a Singleton Class: + # 1. Get the instance object + # 2. Forward the source_location lookup to the instance + instance ||= ObjectSpace.each_object(owner).first + instance.method(name).source_location + end + end + end + end +end diff --git a/lib/method_source/version.rb b/lib/method_source/version.rb index 2ac241c..6a830a9 100644 --- a/lib/method_source/version.rb +++ b/lib/method_source/version.rb @@ -1,3 +1,3 @@ module MethodSource - VERSION = "0.2.0" + VERSION = "0.3.0" end |