Module: TypeToolkit::DSL
- Defined in:
- lib/type_toolkit/dsl.rb
Overview
@requires_ancestor: MethodDefRecorder
Instance Method Summary collapse
-
#abstract(method_name) ⇒ Object
Mark
method_nameas abstract.
Instance Method Details
#abstract(method_name) ⇒ Object
Mark method_name as abstract.
A real implementation of the method must be provided somewhere in the ancestor chain.
Calls to an unimplemented abstract method will raise AbstractMethodNotImplementedError.
: (Symbol) -> Symbol
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 |
# File 'lib/type_toolkit/dsl.rb', line 13 def abstract(method_name) #: self as (Module[top] & HasAbstractMethods & MethodDefRecorder) recorded_method_name, is_singleton_method = __last_method_def if recorded_method_name != method_name prefix = is_singleton_method ? "." : "#" # Do not rely on this message content! Its content is subject to change. raise <<~MSG.chomp `abstract` expected to see `#{prefix}#{method_name}`, but the last recorded method was called `#{recorded_method_name}`. This can happen when `abstract` is combined with other metaprogramming. If you think this is a bug, please open an issue: https://github.com/Shopify/type_toolkit/issues MSG end # The `method_owner` is the class whose method table stores the abstract method. # # Example: # # class Foo # # is_singleton_method = false, owner is the `Foo` class # abstract def foo; end # # # is_singleton_method = true, owner is `Foo.singleton_class` # abstract def self.foo; end # end method_owner = is_singleton_method ? singleton_class : self #: as Module[top] & HasAbstractMethods # Register the fact that this method is meant to be abstract, # used by APIs like `abstract_method_declared?` and `Method#abstract?` method_owner.__register_abstract_method(method_name) # We never want the empty "stub" method to be called, so we remove it. This has one of 3 effects: # # 1. If the abstract method is implemented by a subclass, then there's no effect. # The subclass' implementation will always be invoked, so this removal does nothing. # # 2. If the abstract method was already implemented by a superclass, # Then this removal ensures that calls to the method will resolve to # the superclass' implementation, and never the empty stub. # # 3. If the abstract method was not implemented anywhere in the ancestor chain, # then this removal ensures we hit `method_missing`, which will then raise # the `AbstractMethodNotImplementedError`. method_owner.remove_method(method_name) # Return the method name, so `abstract` can be chained, e.g. `private abstract def foo; end` method_name end |