Skip to content

Instantly share code, notes, and snippets.

@saturnflyer
Forked from zdennis/the_world_of_foos.rb
Last active July 16, 2019 16:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save saturnflyer/201506ee3f1aa74fa7642d35ede732aa to your computer and use it in GitHub Desktop.
Save saturnflyer/201506ee3f1aa74fa7642d35ede732aa to your computer and use it in GitHub Desktop.
Given the below hierarchy how many ways can you think of to wrap the `Parent#foo` implementation so that `Grandchild1` and `Grandchild2` can have their own unique logic that executes after all of the mixin `foo`(s) but before the `Parent#foo` executes?
module N
def foo
puts "N: foo"
super
end
end
module O
def foo
puts "O: foo"
super
end
end
class Parent
def foo
puts "foo"
end
end
class Child < Parent
include N
end
module FooChecker
def self.from(klass)
special_foo_name = "#{klass.name}SpecialFoo"
mod = Module.new
self.const_set(special_foo_name, mod)
mod.class_eval %{
def foo
if self.is_a?(#{klass.name})
puts %{#\{self.class.name\} special foo}
end
super
end
}
# Altenatively this. But super must be called
# with explicit arguments when used in define_method
# mod.class_eval do
# define_method :foo do
# if self.is_a?(klass)
# puts %{#{self.class.name} special foo}
# end
# super()
# end
# end
mod
end
end
class Grandchild1 < Child
Parent.prepend(FooChecker.from(self))
include O
end
class Grandchild2 < Child
Parent.prepend(FooChecker.from(self))
include O
end
# Say we want this to wrap the this to output:
# O: foo
# N: foo
# Grandchild1 special foo
# foo
Grandchild1.new.foo
# And we wanted this to output:
# O: foo
# N: foo
# Grandchild2 special foo
# foo
Grandchild2.new.foo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment