Ruby's double colon (::) operator usage differences

Solution 1:

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

Solution 2:

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.