Module: Mortymer::Sigil::ClassMethods
- Defined in:
- lib/mortymer/sigil.rb
Overview
Class methods to be included as part of the dsl
Instance Method Summary collapse
-
#method_added(method_name) ⇒ Object
Hook called when a method is defined.
-
#sign(*positional_types, returns: nil, **keyword_types) ⇒ Object
Store type signatures for methods before they are defined.
Instance Method Details
#method_added(method_name) ⇒ Object
Hook called when a method is defined
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 |
# File 'lib/mortymer/sigil.rb', line 23 def method_added(method_name) super return if @pending_type_signature.nil? return if @processing_type_check signature = @pending_type_signature @pending_type_signature = nil # Get the original method original_method = instance_method(method_name) @processing_type_check = true # Redefine the method with type checking define_method(method_name) do |*args, **kwargs| # Validate positional arguments procced_args = [] procced_kwargs = {} args.each_with_index do |arg, idx| unless (type = signature[:positional_types][idx]) procced_args << arg next end begin procced_args << if type.respond_to?(:structify) type.structify(arg) elsif type.respond_to?(:call) type.call(arg) elsif arg.is_a?(type) arg else raise TypeError, "Invalid type for argument #{idx}: expected #{type}, got #{arg.class}" end rescue Dry::Types::CoercionError => e raise TypeError, "Invalid type for argument #{idx}: expected #{type}, got #{arg.class} - #{e.}" end end # Validate keyword arguments kwargs.each do |key, value| unless (type = signature[:keyword_types][key]) procced_kwargs[key] = value next end begin procced_kwargs[key] = (type.respond_to?(:structify) ? type.structify(value) : type.call(value)) rescue Dry::Types::CoercionError => e raise TypeError, "Invalid type for keyword argument #{key}: expected #{type}, got #{value.class} - #{e.}" end end # Call the original method result = original_method.bind(self).call(*procced_args, **procced_kwargs) # Validate return type if specified if (return_type = signature[:returns]) begin # A mortymer model or contract if return_type.respond_to?(:structify) return return_type.structify(result) # A dry type elsif return_type.respond_to?(:call) return return_type.call(result) # A custom object elsif result.is_a?(return_type) return result else raise TypeError, "Invalid return type: expected #{return_type}, got #{result.class}" end rescue Dry::Types::CoercionError => e raise TypeError, "Invalid return type: expected #{return_type}, got #{result.class} - #{e.}" end end result end @processing_type_check = false # Call super to maintain compatibility with other method hooks end |
#sign(*positional_types, returns: nil, **keyword_types) ⇒ Object
Store type signatures for methods before they are defined
14 15 16 17 18 19 20 |
# File 'lib/mortymer/sigil.rb', line 14 def sign(*positional_types, returns: nil, **keyword_types) @pending_type_signature = { positional_types: positional_types, keyword_types: keyword_types, returns: returns } end |