Module: Ruby3BackwardCompatibility::CallableWithHash

Included in:
I18n::Base, String
Defined in:
lib/ruby3_backward_compatibility/callable_with_hash.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(by) ⇒ Object



23
24
25
26
27
# File 'lib/ruby3_backward_compatibility/callable_with_hash.rb', line 23

def self.extended(by)
  # prepend the anonymous module now, so the user has a chance to control where exactly we will end 
  # up in the prepend chain...
  by.send(:_ruby3_callable_with_hash_module)
end

.find_owned_instance_method(mod, method_name, ignore_missing: false) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/ruby3_backward_compatibility/callable_with_hash.rb', line 3

def self.find_owned_instance_method(mod, method_name, ignore_missing: false)
  method = begin
    mod.send(:instance_method, method_name)
  rescue NameError
    return if ignore_missing
    raise NameError, "method '#{method_name}' is not defined"
  end
  while method.owner > mod
    # we found the method in a prepended module
    super_method = method.super_method
    if super_method.nil?
      warn "Called `callable_with_hash #{method_name.inspect}` on `#{mod}`, which appears not to be the correct owner. Did you mean to call it on `#{method.owner}`?"
      return method
    else
      method = super_method
    end
  end
  method
end

Instance Method Details

#callable_with_hash(*method_names, ignore_missing: false) ⇒ Object



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
# File 'lib/ruby3_backward_compatibility/callable_with_hash.rb', line 29

def callable_with_hash(*method_names, ignore_missing: false)
  method_names.each do |method_name|
    method_is_private = private_instance_methods.include?(method_name)
    method_is_protected = protected_instance_methods.include?(method_name)

    method = CallableWithHash.find_owned_instance_method(self, method_name, ignore_missing: ignore_missing)
    next unless method

    required_param_count = method.parameters.sum { |(kind, _name)| kind == :req ? 1 : 0 }
    _ruby3_callable_with_hash_module.define_method(method_name) do |*args, &block|
      if args.last.respond_to?(:to_hash) && args.size > required_param_count
        keyword_args = args.pop
        super(*args, **keyword_args, &block)
      else
        super(*args, &block)
      end
    end

    if method_is_private
      _ruby3_callable_with_hash_module.send(:private, method_name)
    elsif method_is_protected
      _ruby3_callable_with_hash_module.send(:protected, method_name)
    end
  end

  if method_names.size > 1
    method_names
  else
    method_names.first
  end
end