method_source 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,23 +5,25 @@ method_source
5
5
 
6
6
  _retrieve the sourcecode for a method_
7
7
 
8
- *NOTE:* This is nothing fancy; it simply utilizes `Method#source_location`
9
- in Ruby 1.9
8
+ *NOTE:* This simply utilizes `Method#source_location` in Ruby 1.9; it
9
+ does not access the live AST.
10
10
 
11
11
  `method_source` is a utility to return a method's sourcecode as a
12
12
  Ruby string. Also returns `Proc` and `Lambda` sourcecode.
13
13
 
14
+ Method comments can also be extracted using the `comment` method.
15
+
14
16
  It is written in pure Ruby (no C).
15
17
 
16
- `method_source` provides the `source` method to the `Method` and
18
+ `method_source` provides the `source` and `comment` methods to the `Method` and
17
19
  `UnboundMethod` and `Proc` classes.
18
20
 
19
21
  * Install the [gem](https://rubygems.org/gems/method_source): `gem install method_source`
20
22
  * Read the [documentation](http://rdoc.info/github/banister/method_source/master/file/README.markdown)
21
23
  * See the [source code](http://github.com/banister/method_source)
22
24
 
23
- Example: methods
24
- ----------------
25
+ Example: display method source
26
+ ------------------------------
25
27
 
26
28
  Set.instance_method(:merge).source.display
27
29
  # =>
@@ -35,10 +37,18 @@ Example: methods
35
37
  self
36
38
  end
37
39
 
40
+ Example: display method comments
41
+ --------------------------------
42
+
43
+ Set.instance_method(:merge).comment.display
44
+ # =>
45
+ # Merges the elements of the given enumerable object to the set and
46
+ # returns self.
47
+
38
48
  Limitations:
39
49
  ------------
40
50
 
41
- * Only works with Ruby 1.9+ (YARV)
51
+ * Only works with Ruby 1.9+
42
52
  * Cannot return source for C methods.
43
53
  * Cannot return source for dynamically defined methods.
44
54
 
@@ -49,3 +59,8 @@ Possible Applications:
49
59
  for extra fun.
50
60
 
51
61
 
62
+ Special Thanks
63
+ --------------
64
+
65
+ [Adam Sanderson](https://github.com/adamsanderson) for `comment` functionality.
66
+
@@ -20,9 +20,8 @@ module MethodSource
20
20
  !!Ripper::SexpBuilder.new(code).parse
21
21
  end
22
22
 
23
- # Helper method responsible for opening source file and advancing to
24
- # the correct linenumber. Defined here to avoid polluting `Method`
25
- # class.
23
+ # Helper method responsible for extracting method body.
24
+ # Defined here to avoid polluting `Method` class.
26
25
  # @param [Array] source_location The array returned by Method#source_location
27
26
  # @return [File] The opened source file
28
27
  def self.source_helper(source_location)
@@ -31,7 +30,44 @@ module MethodSource
31
30
  file_name, line = source_location
32
31
  file = File.open(file_name)
33
32
  (line - 1).times { file.readline }
34
- file
33
+
34
+ code = ""
35
+ loop do
36
+ val = file.readline
37
+ code << val
38
+
39
+ return code if MethodSource.valid_expression?(code)
40
+ end
41
+
42
+ ensure
43
+ file.close if file
44
+ end
45
+
46
+ # Helper method responsible for opening source file and buffering up
47
+ # the comments for a specified method. Defined here to avoid polluting
48
+ # `Method` class.
49
+ # @param [Array] source_location The array returned by Method#source_location
50
+ # @return [String] The comments up to the point of the method.
51
+ def self.comment_helper(source_location)
52
+ return nil if !source_location.is_a?(Array)
53
+
54
+ file_name, line = source_location
55
+ file = File.open(file_name)
56
+ buffer = ""
57
+ (line - 1).times do
58
+ line = file.readline
59
+ # Add any line that is a valid ruby comment,
60
+ # but clear as soon as we hit a non comment line.
61
+ if (line =~ /^\s*#/) || (line =~ /^\s*$/)
62
+ buffer << line.lstrip
63
+ else
64
+ buffer.clear
65
+ end
66
+ end
67
+
68
+ buffer
69
+ ensure
70
+ file.close if file
35
71
  end
36
72
 
37
73
  # This module is to be included by `Method` and `UnboundMethod` and
@@ -49,26 +85,34 @@ module MethodSource
49
85
  # self
50
86
  # end
51
87
  def source
52
- file = nil
53
-
54
88
  if respond_to?(:source_location)
55
- file = MethodSource.source_helper(source_location)
89
+ source = MethodSource.source_helper(source_location)
56
90
 
57
- raise "Cannot locate source for this method: #{name}" if !file
91
+ raise "Cannot locate source for this method: #{name}" if !source
58
92
  else
59
93
  raise "Method#source not supported by this Ruby version (#{RUBY_VERSION})"
60
94
  end
61
-
62
- code = ""
63
- loop do
64
- val = file.readline
65
- code += val
95
+
96
+ source
97
+ end
98
+
99
+ # Return the comments associated with the method as a string.
100
+ # (This functionality is only supported in Ruby 1.9 and above)
101
+ # @return [String] The method's comments as a string
102
+ # @example
103
+ # Set.instance_method(:clear).comment.display
104
+ # =>
105
+ # # Removes all elements and returns self.
106
+ def comment
107
+ if respond_to?(:source_location)
108
+ comment = MethodSource.comment_helper(source_location)
66
109
 
67
- return code if MethodSource.valid_expression?(code)
110
+ raise "Cannot locate source for this method: #{name}" if !comment
111
+ else
112
+ raise "Method#comment not supported by this Ruby version (#{RUBY_VERSION})"
68
113
  end
69
-
70
- ensure
71
- file.close if file
114
+
115
+ comment
72
116
  end
73
117
  end
74
118
  end
@@ -1,3 +1,3 @@
1
1
  module MethodSource
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -2,17 +2,18 @@ direc = File.dirname(__FILE__)
2
2
 
3
3
  require 'bacon'
4
4
  require "#{direc}/../lib/method_source"
5
-
6
- hello_source = "def hello; :hello; end\n"
7
- lambda_source = "MyLambda = lambda { :lambda }\n"
8
- proc_source = "MyProc = Proc.new { :proc }\n"
9
-
10
- def hello; :hello; end
11
-
12
- MyLambda = lambda { :lambda }
13
- MyProc = Proc.new { :proc }
5
+ require "#{direc}/test_helper"
14
6
 
15
7
  describe MethodSource do
8
+
9
+ before do
10
+ @hello_source = "def hello; :hello; end\n"
11
+ @hello_comment = "# A comment for hello\n# It spans two lines and is indented by 2 spaces\n"
12
+ @lambda_comment = "# This is a comment for MyLambda\n"
13
+ @lambda_source = "MyLambda = lambda { :lambda }\n"
14
+ @proc_source = "MyProc = Proc.new { :proc }\n"
15
+ end
16
+
16
17
  it 'should define methods on Method and UnboundMethod and Proc' do
17
18
  Method.method_defined?(:source).should == true
18
19
  UnboundMethod.method_defined?(:source).should == true
@@ -22,7 +23,11 @@ describe MethodSource do
22
23
  describe "Methods" do
23
24
  if RUBY_VERSION =~ /1.9/
24
25
  it 'should return source for method' do
25
- method(:hello).source.should == hello_source
26
+ method(:hello).source.should == @hello_source
27
+ end
28
+
29
+ it 'should return a comment for method' do
30
+ method(:hello).comment.should == @hello_comment
26
31
  end
27
32
 
28
33
  it 'should raise for C methods' do
@@ -30,7 +35,7 @@ describe MethodSource do
30
35
  end
31
36
 
32
37
  else
33
- it 'should raise on #source' do
38
+ it 'should raise on #source for 1.8' do
34
39
  lambda { method(:hello).source }.should.raise RuntimeError
35
40
  end
36
41
  end
@@ -39,16 +44,56 @@ describe MethodSource do
39
44
  describe "Lambdas and Procs" do
40
45
  if RUBY_VERSION =~ /1.9/
41
46
  it 'should return source for proc' do
42
- MyProc.source.should == proc_source
47
+ MyProc.source.should == @proc_source
43
48
  end
44
-
49
+
50
+ it 'should return an empty string if there is no comment' do
51
+ MyProc.comment.should == ''
52
+ end
53
+
45
54
  it 'should return source for lambda' do
46
- MyLambda.source.should == lambda_source
55
+ MyLambda.source.should == @lambda_source
56
+ end
57
+
58
+ it 'should return comment for lambda' do
59
+ MyLambda.comment.should == @lambda_comment
47
60
  end
48
61
  else
49
- it 'should raise on #source' do
62
+ it 'should raise on #source for 1.8' do
50
63
  lambda { method(:hello).source }.should.raise RuntimeError
51
64
  end
52
65
  end
53
66
  end
67
+
68
+ if RUBY_VERSION =~ /1.9/
69
+ describe "Comment tests" do
70
+ before do
71
+ @comment1 = "# a\n# b\n"
72
+ @comment2 = "# a\n# b\n"
73
+ @comment3 = "# a\n#\n# b\n"
74
+ @comment4 = "# a\n# b\n"
75
+ @comment5 = "# a\n# b\n# c\n# d\n"
76
+ end
77
+
78
+ it "should correctly extract multi-line comments" do
79
+ method(:comment_test1).comment.should == @comment1
80
+ end
81
+
82
+ it "should correctly strip leading whitespace before comments" do
83
+ method(:comment_test2).comment.should == @comment2
84
+ end
85
+
86
+ it "should keep empty comment lines" do
87
+ method(:comment_test3).comment.should == @comment3
88
+ end
89
+
90
+ it "should ignore blank lines between comments" do
91
+ method(:comment_test4).comment.should == @comment4
92
+ end
93
+
94
+ it "should align all comments to same indent level" do
95
+ method(:comment_test5).comment.should == @comment5
96
+ end
97
+ end
98
+ end
54
99
  end
@@ -0,0 +1,34 @@
1
+ # A comment for hello
2
+
3
+ # It spans two lines and is indented by 2 spaces
4
+ def hello; :hello; end
5
+
6
+ # a
7
+ # b
8
+ def comment_test1; end
9
+
10
+ # a
11
+ # b
12
+ def comment_test2; end
13
+
14
+ # a
15
+ #
16
+ # b
17
+ def comment_test3; end
18
+
19
+ # a
20
+
21
+ # b
22
+ def comment_test4; end
23
+
24
+
25
+ # a
26
+ # b
27
+ # c
28
+ # d
29
+ def comment_test5; end
30
+
31
+ # This is a comment for MyLambda
32
+ MyLambda = lambda { :lambda }
33
+ MyProc = Proc.new { :proc }
34
+
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 4
9
- version: 0.1.4
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - John Mair (banisterfiend)
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-17 00:00:00 +13:00
17
+ date: 2010-12-18 00:00:00 +13:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -30,6 +30,7 @@ files:
30
30
  - lib/method_source/version.rb
31
31
  - lib/method_source.rb
32
32
  - test/test.rb
33
+ - test/test_helper.rb
33
34
  - README.markdown
34
35
  - Rakefile
35
36
  has_rdoc: yard