method_source 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ method_source
2
+ =============
3
+
4
+ (C) John Mair (banisterfiend) 2010
5
+
6
+ _retrieve the sourcecode for a method_
7
+
8
+ `method_source` is a utility to return a method's sourcecode as a
9
+ Ruby string.
10
+
11
+ It is written in pure Ruby (no C).
12
+
13
+ `method_source` provides the `source` method to the `Method` and
14
+ `UnboundMethod` classes.
15
+
16
+ * Install the [gem](https://rubygems.org/gems/method_source): `gem install method_source`
17
+ * Read the [documentation](http://rdoc.info/github/banister/method_source/master/file/README.markdown)
18
+ * See the [source code](http://github.com/banister/method_source)
19
+
20
+ example:
21
+ ---------
22
+
23
+ Set.instance_method(:merge).source.display
24
+ # =>
25
+ def merge(enum)
26
+ if enum.instance_of?(self.class)
27
+ @hash.update(enum.instance_variable_get(:@hash))
28
+ else
29
+ do_with_enum(enum) { |o| add(o) }
30
+ end
31
+
32
+ self
33
+ end
34
+
35
+ Limitations:
36
+ ------------
37
+
38
+ * Only works with Ruby 1.9+
39
+ * Cannot return source for C methods.
40
+ * Cannot return source for dynamically defined methods.
41
+
42
+ Possible Applications:
43
+ ----------------------
44
+
45
+ * Combine with [RubyParser](https://github.com/seattlerb/ruby_parser)
46
+ for extra fun.
47
+
48
+
@@ -0,0 +1,57 @@
1
+ dlext = Config::CONFIG['DLEXT']
2
+ direc = File.dirname(__FILE__)
3
+
4
+ require 'rake/clean'
5
+ require 'rake/gempackagetask'
6
+ require "#{direc}/lib/method_source/version"
7
+
8
+ CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o")
9
+ CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o",
10
+ "ext/**/*~", "ext/**/*#*", "ext/**/*.obj",
11
+ "ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake")
12
+
13
+ def apply_spec_defaults(s)
14
+ s.name = "method_source"
15
+ s.summary = "retrieve the sourcecode for a method"
16
+ s.version = MethodSource::VERSION
17
+ s.date = Time.now.strftime '%Y-%m-%d'
18
+ s.author = "John Mair (banisterfiend)"
19
+ s.email = 'jrmair@gmail.com'
20
+ s.description = s.summary
21
+ s.require_path = 'lib'
22
+ s.homepage = "http://banisterfiend.wordpress.com"
23
+ s.has_rdoc = 'yard'
24
+ s.files = Dir["ext/**/extconf.rb", "ext/**/*.h", "ext/**/*.c", "lib/**/*.rb",
25
+ "test/*.rb", "CHANGELOG", "README.markdown", "Rakefile"]
26
+ end
27
+
28
+ task :test do
29
+ sh "bacon -k #{direc}/test/test.rb"
30
+ end
31
+
32
+ namespace :ruby do
33
+ spec = Gem::Specification.new do |s|
34
+ apply_spec_defaults(s)
35
+ s.platform = Gem::Platform::RUBY
36
+ end
37
+
38
+ Rake::GemPackageTask.new(spec) do |pkg|
39
+ pkg.need_zip = false
40
+ pkg.need_tar = false
41
+ end
42
+ end
43
+
44
+ desc "build all platform gems at once"
45
+ task :gems => [:rmgems, "ruby:gem"]
46
+
47
+ desc "remove all platform gems"
48
+ task :rmgems => ["ruby:clobber_package"]
49
+
50
+ desc "build and push latest gems"
51
+ task :pushgems => :gems do
52
+ chdir("#{direc}/pkg") do
53
+ Dir["*.gem"].each do |gemfile|
54
+ sh "gem push #{gemfile}"
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,94 @@
1
+ # (C) John Mair (banisterfiend) 2010
2
+ # MIT License
3
+
4
+ direc = File.dirname(__FILE__)
5
+
6
+ require 'stringio'
7
+ require "#{direc}/method_source/version"
8
+
9
+ module MethodSource
10
+
11
+ # Helper method used to find end of method body
12
+ # @param [String] code The string of Ruby code to check for
13
+ # correctness
14
+ # @return [Boolean]
15
+ def self.valid_expression?(code)
16
+ suppress_stderr do
17
+ RubyVM::InstructionSequence.new(code)
18
+ end
19
+ rescue Exception
20
+ false
21
+ else
22
+ true
23
+ end
24
+
25
+ # Helper method used to suppress stderr output by the
26
+ # `RubyVM::InstructionSequence` method
27
+ # @yield The block where stderr is suppressed
28
+ def self.suppress_stderr
29
+ real_stderr, $stderr = $stderr, StringIO.new
30
+ yield
31
+ ensure
32
+ $stderr = real_stderr
33
+ end
34
+
35
+ # Helper method responsible for opening source file and advancing to
36
+ # the correct linenumber. Defined here to avoid polluting `Method`
37
+ # class.
38
+ # @param [Array] source_location The array returned by Method#source_location
39
+ # @return [File] The opened source file
40
+ def self.source_helper(source_location)
41
+ return nil if !source_location.is_a?(Array)
42
+
43
+ file_name, line = source_location
44
+ file = File.open(file_name)
45
+ (line - 1).times { file.readline }
46
+ file
47
+ end
48
+
49
+ # This module is to be included by `Method` and `UnboundMethod` and
50
+ # provides the `#source` functionality
51
+ module MethodExtensions
52
+
53
+ # Return the sourcecode for the method as a string
54
+ # (This functionality is only supported in Ruby 1.9 and above)
55
+ # @return [String] The method sourcecode as a string
56
+ # @example
57
+ # Set.instance_method(:clear).source.display
58
+ # =>
59
+ # def clear
60
+ # @hash.clear
61
+ # self
62
+ # end
63
+ def source
64
+ file = nil
65
+
66
+ if respond_to?(:source_location)
67
+ file = MethodSource.source_helper(source_location)
68
+
69
+ raise "Cannot locate source for this method: #{name}" if !file
70
+ else
71
+ raise "Method#source not supported by this Ruby version (#{RUBY_VERSION})"
72
+ end
73
+
74
+ code = ""
75
+ loop do
76
+ val = file.readline
77
+ code += val
78
+
79
+ return code if MethodSource.valid_expression?(code)
80
+ end
81
+
82
+ ensure
83
+ file.close if file
84
+ end
85
+ end
86
+ end
87
+
88
+ class Method
89
+ include MethodSource::MethodExtensions
90
+ end
91
+
92
+ class UnboundMethod
93
+ include MethodSource::MethodExtensions
94
+ end
@@ -0,0 +1,3 @@
1
+ module MethodSource
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,32 @@
1
+ direc = File.dirname(__FILE__)
2
+
3
+ require 'bacon'
4
+ require "#{direc}/../lib/method_source"
5
+
6
+ hello_source = "def hello; :hello; end\n"
7
+
8
+ def hello; :hello; end
9
+
10
+ describe MethodSource do
11
+
12
+ it 'should define methods on both Method and UnboundMethod' do
13
+ Method.method_defined?(:source).should == true
14
+ UnboundMethod.method_defined?(:source).should == true
15
+ end
16
+
17
+ if RUBY_VERSION =~ /1.9/
18
+ it 'should return source for method' do
19
+ method(:hello).source.should == hello_source
20
+ end
21
+
22
+ it 'should raise for C methods' do
23
+ lambda { method(:puts).source }.should.raise RuntimeError
24
+ end
25
+
26
+ else
27
+ it 'should raise on #source' do
28
+ lambda { method(:hello).source }.should.raise RuntimeError
29
+ end
30
+ end
31
+ end
32
+
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: method_source
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - John Mair (banisterfiend)
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-17 00:00:00 +13:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: retrieve the sourcecode for a method
23
+ email: jrmair@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/method_source/version.rb
32
+ - lib/method_source.rb
33
+ - test/test.rb
34
+ - README.markdown
35
+ - Rakefile
36
+ has_rdoc: yard
37
+ homepage: http://banisterfiend.wordpress.com
38
+ licenses: []
39
+
40
+ post_install_message:
41
+ rdoc_options: []
42
+
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ hash: 3
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.7
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: retrieve the sourcecode for a method
70
+ test_files: []
71
+