summaryrefslogtreecommitdiff
path: root/spec/ruby/core/module/method_added_spec.rb
blob: ec92cddc1e4f284536095a144cfa78b0454d2756 (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
require_relative '../../spec_helper'
require_relative 'fixtures/classes'

describe "Module#method_added" do
  before :each do
    ScratchPad.record []
  end

  it "is a private instance method" do
    Module.should have_private_instance_method(:method_added)
  end

  it "returns nil in the default implementation" do
    Module.new do
      method_added(:test).should == nil
    end
  end

  it "is called when a new instance method is defined in self" do
    Module.new do
      def self.method_added(name)
        ScratchPad << name
      end

      def test() end
      def test2() end
      def test() end
      alias_method :aliased_test, :test
      alias aliased_test2 test
    end

    ScratchPad.recorded.should == [:test, :test2, :test, :aliased_test, :aliased_test2]
  end

  it "is not called when a singleton method is added" do
    # obj.singleton_method_added is called instead
    klass = Class.new
    def klass.method_added(name)
      ScratchPad << name
    end

    obj = klass.new
    def obj.new_singleton_method
    end

    ScratchPad.recorded.should == []
  end

  it "is not called when a method is undefined in self" do
    m = Module.new do
      def method_to_undef
      end

      def self.method_added(name)
        fail("method_added called by undef_method")
      end

      undef_method :method_to_undef
    end
    m.should_not have_method(:method_to_undef)
  end

  it "is not called when a method changes visibility" do
    Module.new do
      def public_method
      end

      def private_method
      end

      def self.method_added(name)
        ScratchPad << name
      end

      public :public_method
      private :public_method

      private :private_method
      public :private_method
    end

    ScratchPad.recorded.should == []
  end

  it "is called when using #private in a subclass" do
    parent = Class.new do
      def foo
      end
    end

    Class.new(parent) do
      def self.method_added(name)
        ScratchPad << name
      end

      # Create an instance as that might initialize some method lookup caches, which is interesting to test
      self.new.foo

      private :foo
      public :foo
    end

    ScratchPad.recorded.should == [:foo]
  end

  it "is not called when a method is copied via module_function, rather #singleton_method_added is called" do
    Module.new do
      def mod_function
      end

      def self.method_added(name)
        ScratchPad << [:method_added, name]
      end

      def self.singleton_method_added(name)
        ScratchPad << [:singleton_method_added, name]
      end

      ScratchPad.record []

      module_function :mod_function
    end

    ScratchPad.recorded.should == [[:singleton_method_added, :mod_function]]
  end

  it "is called with a precise caller location with the line of the 'def'" do
    line = nil

    Module.new do
      def self.method_added(name)
        location = caller_locations(1, 1)[0]
        ScratchPad << location.lineno
      end

      line = __LINE__
      def first
      end

      def second
      end
    end

    ScratchPad.recorded.should == [line + 1, line + 4]
  end
end