Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does "super" work with modules?

I will ask it on a specific example (in Rails). In the "Destroy without Javascript (revised)" railscast, Ryan Bates overwrites the #resources routing method:

module DeleteResourceRoute
  def resources(*args, &block)
    super(*args) do
      # some code
    end
  end
end

ActionDispatch::Routing::Mapper.send(:include, DeleteResourceRoute)

But doesn't inheritance in Ruby work in a way that the module is the "superclass". How can he be calling #super from the module, then?

If it was possible to overwrite a method like this, then people instead of doing this:

class SomeClass
  alias old_method method
  def method
    # ...
    old_method
    # ...
  end
end

could be doing something this:

class SomeClass
  include Module.new {
    def method
      # ...
      super
      # ...
    end
  }
end

What am I missing?

like image 523
janko-m Avatar asked Oct 14 '12 22:10

janko-m


2 Answers

"super" only lives in "class" context. super could not live in a "pure module" context. so, when you saw a code like:

module DeleteResourceRoute
  def resources(*args, &block)
    super(*args) do
      # some code
    end
  end
end

you should have a class to "include this module", then the "super" take effect, e.g.

class SomeClass extends BaseClass
  include DeleteResourceRoute
end

class BaseClass
  def resources
    puts "called parent!"
  end
end

SomeClass.new.resources  # => called parent!
like image 196
Siwei Avatar answered Oct 13 '22 16:10

Siwei


I figured it out. There is a module that is included into ActionDispatch::Routing::Mapper, and that module holds the #resources method. If #resources was defined directly on ActionDispatch::Routing::Mapper, and not in the module, overwriting it wouldn't work in this way (we would have to use the "alias" method instead).

About modules and classes in general, the module acts like a superclass to the class that included it. By "acting like a superclass" I mean that, if you have a method #foo defined on the module, and you include that module into a class, that class can overwrite the #foo method, and call #super, and that will call the module's #foo method. An example:

module Foo
  def foo
    puts "foo"
  end
end

class Bar
  include Foo

  def foo
    super
    puts "bar"
  end
end

Bar.new.foo
# foo
# bar
# => nil
like image 33
janko-m Avatar answered Oct 13 '22 16:10

janko-m