Hello!
Playing with Null Object Pattern, I discovered that it can be handy to use method_missing
macro:
class Dog
def walk(direction)
"step #{direction}"
end
end
dog = Dog.new
dog.walk "forward" # => "step forward"
class NilDog
macro method_missing(call)
end
end
dog = NilDog.new
dog.bark 1, 2, 3 { :foo } # => nil
But if Dog has to inherit from some abstract Animal, it doesn’t work anymore:
abstract class Animal
abstract def walk(direction)
end
class Dog < Animal
def walk(direction)
"step #{direction}"
end
end
class NilDog < Animal
macro method_missing(call)
end
end
Error: abstract `def Animal#walk(direction)` must be implemented by NilDog
Apparently, abstract def
has a precedence over method_missing
here, so the question is, is it possible to trick abstract def
into believing that the corresponding method was implemented by NilDog
?
Probably method_missing
should count as everything being implemented.
That said, I think method_missing
was a mistake and I’d like to remove it from the language.
Ok, let’s put method_missing
away and try something else.
It seems, one has to mirror all the methods (and preserve arity) of Dog
, into NillDog
, or is it possible to make NilDog
responsive to any method call without that tedious mirroring?
abstract class Animal
abstract def walk(direction)
end
class Dog < Animal
def walk(direction)
"step #{direction}"
end
def some_other_method(..., ...)
...
end
def and_other_method(..., ...)
...
end
end
class NilDog < Animal
def walk(direction) # need to mirror all the public methods of `Dog`,
end # to keep the API consistent
# ↓ ↓ ↓ ↓ ↓ ↓ ↓
def some_other_method(..., ...)
...
end
def and_other_method(..., ...)
...
end
end
At least, is it possible to accept and throw away all the arguments passed to a method? Something like Ruby does with:
def foo(*)
end
I think best you will get is def some_other_method(*args, **kwargs)
to catch all arguments. But the methods involve blocks/yield you will need two defs for each method.
Unless all the params of methods have type restrictions is impossible to have 100% the same API.
If there they are restricted probably con macros you are able to generate the NilDog
on the fly.
But I would go with *args, **kwargs
first.
I see, thank you for help!
Throw away method_missing from the language? Is it a real plan? In other (dynamic languages), it’s possible to do pretty cool things with it (used in ORMs, XML/JSON parsers, proxying is easy with it)…