summaryrefslogtreecommitdiff
path: root/spec/method_source_spec.rb
blob: 19276701c9c4a08cb75ac67201316d736288d020 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
require 'spec_helper'

describe MethodSource do

  describe "source_location (testing 1.8 implementation)" do
    it 'should return correct source_location for a method' do
      expect(method(:hello).source_location.first).to match(/spec_helper/)
    end

    it 'should not raise for immediate instance methods' do
      [Symbol, Integer, TrueClass, FalseClass, NilClass].each do |immediate_class|
        expect do
          immediate_class.instance_method(:to_s).source_location
        end.not_to raise_error
      end
    end

    it 'should not raise for immediate methods' do
      [:a, 1, true, false, nil].each do |immediate|
        expect do
          immediate.method(:to_s).source_location
        end.not_to raise_error
      end
    end
  end

  before do
    @hello_module_source = "  def hello; :hello_module; end\n"
    @hello_singleton_source = "def $o.hello; :hello_singleton; end\n"
    @hello_source = "def hello; :hello; end\n"
    @hello_comment = "# A comment for hello\n# It spans two lines and is indented by 2 spaces\n"
    @lambda_comment = "# This is a comment for MyLambda\n"
    @module_comment = "# This is a comment for module\n"
    @class_comment = "# This is a comment for class\n"
    @lambda_source = "MyLambda = lambda { :lambda }\n"
    @proc_source = "MyProc = Proc.new { :proc }\n"
    @hello_instance_evaled_source = "  def hello_\#{name}(*args)\n    send_mesg(:\#{name}, *args)\n  end\n"
    @hello_instance_evaled_source_2 = "  def \#{name}_two()\n    if 40 + 4\n      45\n    end\n  end\n"
    @hello_class_evaled_source = "  def hello_\#{name}(*args)\n    send_mesg(:\#{name}, *args)\n  end\n"
    @hi_module_evaled_source = "  def hi_\#{name}\n    @var = \#{name}\n  end\n"
  end

  it 'should define methods on Method and UnboundMethod and Proc' do
    expect(Method.method_defined?(:source)).to be_truthy
    expect(UnboundMethod.method_defined?(:source)).to be_truthy
    expect(Proc.method_defined?(:source)).to be_truthy
  end

  describe "Methods" do
    it 'should return source for method' do
      expect(method(:hello).source).to eq(@hello_source)
    end

    it 'should return source for a method defined in a module' do
      expect(M.instance_method(:hello).source).to eq(@hello_module_source)
    end

    it 'should return source for a singleton method as an instance method' do
      expect(class << $o
        self
      end.instance_method(:hello).source).to eq(@hello_singleton_source)
    end

    it 'should return source for a singleton method' do
      expect($o.method(:hello).source).to eq(@hello_singleton_source)
    end

    it 'should return a comment for method' do
      expect(method(:hello).comment).to eq(@hello_comment)
    end

    # These tests fail because of http://jira.codehaus.org/browse/JRUBY-4576
    unless defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
      it 'should return source for an *_evaled method' do
        expect(M.method(:hello_name).source).to eq(@hello_instance_evaled_source)
        expect(M.method(:name_two).source).to eq(@hello_instance_evaled_source_2)
        expect(M.instance_method(:hello_name).source).to eq(@hello_class_evaled_source)
        expect(M.instance_method(:hi_name).source).to eq(@hi_module_evaled_source)
      end
    end

    it "should raise error for evaled methods that do not pass __FILE__ and __LINE__ + 1 as its arguments" do
      expect do
        M.instance_method(:name_three).source
      end.to raise_error(MethodSource::SourceNotFoundError)
    end

    if !is_rbx?
      it 'should raise for C methods' do
        expect do
          method(:puts).source
        end.to raise_error(MethodSource::SourceNotFoundError)
      end
    end
  end

  # if RUBY_VERSION =~ /1.9/ || is_rbx?
  describe "Lambdas and Procs" do
    it 'should return source for proc' do
      expect(MyProc.source).to eq(@proc_source)
    end

    it 'should return an empty string if there is no comment' do
      expect(MyProc.comment).to eq('')
    end

    it 'should return source for lambda' do
      expect(MyLambda.source).to eq(@lambda_source)
    end

    it 'should return comment for lambda' do
      expect(MyLambda.comment).to eq(@lambda_comment)
    end

    it 'should return comment for module' do
      expect(M.instance_method(:hello).module_comment).to eq(@module_comment)
    end

    it 'should return comment for class' do
      expect(C.method(:hello).class_comment).to eq(@class_comment)
    end

    it 'should return comment for class instance' do
      expect(C.new.method(:hello).class_comment).to eq(@class_comment)
    end
  end
  # end
  describe "Comment tests" do
    before do
      @comment1 = "# a\n# b\n"
      @comment2 = "# a\n# b\n"
      @comment3 = "# a\n#\n# b\n"
      @comment4 = "# a\n# b\n"
      @comment5 = "# a\n# b\n# c\n# d\n"
    end

    it "should correctly extract multi-line comments" do
      expect(method(:comment_test1).comment).to eq(@comment1)
    end

    it "should correctly strip leading whitespace before comments" do
      expect(method(:comment_test2).comment).to eq(@comment2)
    end

    it "should keep empty comment lines" do
      expect(method(:comment_test3).comment).to eq(@comment3)
    end

    it "should ignore blank lines between comments" do
      expect(method(:comment_test4).comment).to eq(@comment4)
    end

    it "should align all comments to same indent level" do
      expect(method(:comment_test5).comment).to eq(@comment5)
    end
  end
end