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 
     | 
    
      # File 'lib/active_support/delegation.rb', line 21
def generate(owner, methods, location: nil, to: nil, prefix: nil, allow_nil: nil, nilable: true, private: nil, as: nil, signature: nil)
  unless to
    raise ArgumentError, "Delegation needs a target. Supply a keyword argument 'to' (e.g. delegate :hello, to: :greeter)."
  end
  if prefix == true && /^[^a-z_]/.match?(to)
    raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
  end
  method_prefix = \
    if prefix
      "#{prefix == true ? to : prefix}_"
    else
      ""
    end
  location ||= caller_locations(1, 1).first
  file, line = location.path, location.lineno
  receiver = if to.is_a?(Module)
    if to.name.nil?
      raise ArgumentError, "Can't delegate to anonymous class or module: #{to}"
    end
    unless Inflector.safe_constantize(to.name).equal?(to)
      raise ArgumentError, "Can't delegate to detached class or module: #{to.name}"
    end
    "::#{to.name}"
  else
    to.to_s
  end
  receiver = "self.#{receiver}" if RESERVED_METHOD_NAMES.include?(receiver)
  explicit_receiver = false
  receiver_class = if as
    explicit_receiver = true
    as
  elsif to.is_a?(Module)
    to.singleton_class
  elsif receiver == "self.class"
    nilable = false     owner.singleton_class
  end
  method_def = []
  method_names = []
  method_def << "self.private" if private
  methods.each do |method|
    method_name = prefix ? "#{method_prefix}#{method}" : method
    method_names << method_name.to_sym
            definition = \
      if signature
        signature
      elsif /[^\]]=\z/.match?(method)
        "arg"
      else
        method_object = if receiver_class
          begin
            receiver_class.public_instance_method(method)
          rescue NameError
            raise if explicit_receiver
                      end
        end
        if method_object
          parameters = method_object.parameters
          if parameters.map(&:first).intersect?([:opt, :rest, :keyreq, :key, :keyrest])
            "..."
          else
            defn = parameters.filter_map { |type, arg| arg if type == :req }
            defn << "&"
            defn.join(", ")
          end
        else
          "..."
        end
      end
                                if nilable == false
      method_def <<
        "def #{method_name}(#{definition})" <<
        "  (#{receiver}).#{method}(#{definition})" <<
        "end"
    elsif allow_nil
      method = method.to_s
      method_def <<
        "def #{method_name}(#{definition})" <<
        "  _ = #{receiver}" <<
        "  if !_.nil? || nil.respond_to?(:#{method})" <<
        "    _.#{method}(#{definition})" <<
        "  end" <<
        "end"
    else
      method = method.to_s
      method_name = method_name.to_s
      method_def <<
        "def #{method_name}(#{definition})" <<
        "  _ = #{receiver}" <<
        "  _.#{method}(#{definition})" <<
        "rescue NoMethodError => e" <<
        "  if _.nil? && e.name == :#{method}" <<
        "    raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
        "  else" <<
        "    raise" <<
        "  end" <<
        "end"
    end
  end
  owner.module_eval(method_def.join(";"), file, line)
  method_names
end
     |