31

Is there any difference between

module Foo
  class Engine < Rails::Engine
  end
end

and

module Foo
  class Engine < ::Rails::Engine
  end
end
Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
CuriousMind
  • 33,537
  • 28
  • 98
  • 137

2 Answers2

52

Constants in Ruby are nested like files and directories in filesystem. So, constants are uniquely identified by their paths.

To draw an analogy with the file system:

::Rails::Engine #is an absolute path to the constant.
# like /Rails/Engine in FS.

Rails::Engine #is a path relative to the current tree level.
# like ./Rails/Engine in FS.

Here is the illustration of possible error:

module Foo

  # We may not know about this in real big apps
  module Rails
    class Engine 
    end
  end

  class Engine1 < Rails::Engine
  end

  class Engine2 < ::Rails::Engine
  end
end

Foo::Engine1.superclass
 => Foo::Rails::Engine # not what we want

Foo::Engine2.superclass
 => Rails::Engine # correct
Flexoid
  • 4,155
  • 21
  • 20
  • Right. So if you were to call Rails::Engine from a module using the name `Module Foo`, it may interpret it as `Foo::Rails::Engine`. I've seen errors like this at times and had to add the additional `::` in front of an include. – Kevin Bedell May 07 '12 at 13:34
  • 5
    It was taken from the book "Metaprogramming Ruby" by Paolo Perrotta. Very useful book to deepen the knowledge of the Ruby. – Flexoid May 07 '12 at 13:39
  • Nice analogy. This becomes problematic when one has modules with the same name in different scopes, since Ruby seems to use the first/nearest one it can find. – Matheus Moreira May 07 '12 at 13:40
  • 3
    A subtle point: if `Rails::Engine` is defined outside of `Foo` and it is also **not** defined inside `Foo` then `Foo::Engine1.superclass` will be `Rails::Engine` as desired. – Aaron K Jul 30 '12 at 15:07
5
Rails::Engine #is a path relative to the current tree level.
# like ./Rails/Engine in FS.

This is not quite true!

Let's have an example:

module M
  Y = 1
  class M
    Y = 2
    class M
      Y = 3
    end
    class C
      Y = 4
      puts M::Y
    end
  end
end

# => 3

module M
  Y = 1
  class M
    Y = 2
    class C
      Y = 4
      puts M::Y
    end
  end
end

# => 2

module M
  Y = 1
  class M
    Y = 2
    class M
      Y = 4
      puts M::Y
    end
  end
end

# => 4

So when you say M::Y ruby looks up for the closest defintion no matter if it is inside the current scope or outer scope or outer outer scope etc.

Viorel
  • 1,420
  • 1
  • 17
  • 27