method_source 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+