File: method_reference.rb

package info (click to toggle)
ruby-contracts 0.17-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 624 kB
  • sloc: ruby: 3,805; makefile: 4; sh: 2
file content (102 lines) | stat: -rw-r--r-- 2,668 bytes parent folder | download | duplicates (2)
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
# frozen_string_literal: true

module Contracts
  # MethodReference represents original method reference that was
  # decorated by contracts.ruby. Used for instance methods.
  class MethodReference
    attr_reader :name

    # name - name of the method
    # method - method object
    def initialize(name, method)
      @name = name
      @method = method
    end

    # Returns method_position, delegates to Support.method_position
    def method_position
      Support.method_position(@method)
    end

    # Makes a method re-definition in proper way
    def make_definition(this, &blk)
      is_private = private?(this)
      is_protected = protected?(this)
      alias_target(this).send(:define_method, name, &blk)
      make_private(this) if is_private
      make_protected(this) if is_protected
    end

    # Aliases original method to a special unique name, which is known
    # only to this class. Usually done right before re-defining the
    # method.
    def make_alias(this)
      _aliased_name = aliased_name
      original_name = name

      alias_target(this).class_eval do
        alias_method _aliased_name, original_name
      end
    end

    # Calls original method on specified `this` argument with
    # specified arguments `args` and block `&blk`.
    def send_to(this, *args, **kargs, &blk)
      this.send(aliased_name, *args, **kargs, &blk)
    end

    private

    # Makes a method private
    def make_private(this)
      original_name = name
      alias_target(this).class_eval { private original_name }
    end

    def private?(this)
      this.private_instance_methods.map(&:to_sym).include?(name)
    end

    def protected?(this)
      this.protected_instance_methods.map(&:to_sym).include?(name)
    end

    # Makes a method protected
    def make_protected(this)
      original_name = name
      alias_target(this).class_eval { protected original_name }
    end

    # Returns alias target for instance methods, subject to be
    # overriden in subclasses.
    def alias_target(this)
      this
    end

    def aliased_name
      @_original_name ||= construct_unique_name
    end

    def construct_unique_name
      :"__contracts_ruby_original_#{name}_#{Support.unique_id}"
    end
  end

  # The same as MethodReference, but used for singleton methods.
  class SingletonMethodReference < MethodReference
    private

    def private?(this)
      this.private_methods.map(&:to_sym).include?(name)
    end

    def protected?(this)
      this.protected_methods.map(&:to_sym).include?(name)
    end

    # Return alias target for singleton methods.
    def alias_target(this)
      Support.eigenclass_of this
    end
  end
end