Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: Syntax for defining a constant inside a Struct

Tags:

ruby

Consider the following (correct) Ruby program:

class Outer

  Inner = Struct.new(:dummy) do
    CONST = 'abce'
    def fun
      puts(dummy)
    end
  end

end

obj = Outer::Inner.new(15)
obj.fun
puts(Outer::CONST)

Why do I have to write Outer::CONST instead of Outer::Inner::CONST?

My understanding of the block passed to Struct::new was that self is bound to Outer::Inner, and indeed, we can see that the method (fun) is attached to the Inner class; but CONST obviously is not.

like image 414
user1934428 Avatar asked Dec 11 '18 14:12

user1934428


2 Answers

This happens because the constant is defined in the current namespace. The class and module keywords define namespaces, but Struct.new (just like Class.new) does not.

In order to define the constant under the Struct's scope, you have to use self::

class Outer
  Inner = Struct.new(:dummy) do
    self::CONST = 'abce'
  end
end

Outer::Inner::CONST
#=> 'abce'

Outer::CONST
#=> NameError uninitialized constant Outer::CONST
like image 171
Stefan Avatar answered Oct 23 '22 18:10

Stefan


After a little digging I was able to figure this out. Here's a quote from a similar question:

Constants belong to classes, therefore constant resolution via the :: operator only works with class objects.

In your above example Inner is a constant not a class, so Outer::Inner::CONST won't work. If we redefine Inner as a class we see the expected results.

class Outer

  class Inner
    CONST = 'abce'
    Deeper = Struct.new(:dummy) do
      def fun
        puts(dummy)
      end
    end
  end

end

obj = Outer::Inner::Deeper.new(15)
obj.fun
puts(Outer::Inner::CONST)
like image 32
Joseph Cho Avatar answered Oct 23 '22 17:10

Joseph Cho