Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(In Ruby) allowing mixed-in class methods access to class constants

I have a class with a constant defined for it. I then have a class method defined that accesses that class constant. This works fine. An example:

#! /usr/bin/env ruby

class NonInstantiableClass
    Const = "hello, world!"
    class << self
        def shout_my_constant
            puts Const.upcase
            end
        end
    end

NonInstantiableClass.shout_my_constant

My problem arises in attempting to move this class method out to an external module, like so:

#! /usr/bin/env ruby

module CommonMethods
    def shout_my_constant
        puts Const.upcase
        end
    end

class NonInstantiableClass
    Const = "hello, world!"
    class << self
        include CommonMethods
        end
    end

NonInstantiableClass.shout_my_constant

Ruby interprets the method as requesting a constant from the module, rather than the class:

line 5:in `shout_my_constant': uninitialized constant CommonMethods::Const (NameError)

So, what magic tricks do you fellows have to let the method access the class constant? Many thanks.

like image 327
jameshfisher Avatar asked Dec 13 '09 20:12

jameshfisher


3 Answers

This seems to work:

#! /usr/bin/env ruby

module CommonMethods
    def shout_my_constant
        puts self::Const.upcase
    end
end

class NonInstantiableClass
    Const = "hello, world!"
    class << self
        include CommonMethods
    end
end

NonInstantiableClass.shout_my_constant

HTH

like image 65
Aidan Cully Avatar answered Oct 23 '22 13:10

Aidan Cully


Its probably worth noting that you don't need to include modules into a metaclass.

class NonInstantiableClass
    Const = "hello, world!"
    class << self
        include CommonMethods
    end
end

Ruby has the extend keyword that effectively adds the modules interface to a class, e.g.

class NonInstantiableClass
    Const = "hello, world!"
    extend CommonMethods
end

You still need to ensure you're referencing the right constant using self::Const or const_get, but extend <module> is the better way to add those methods to the class.

like image 42
Tooky Avatar answered Oct 23 '22 12:10

Tooky


The problem is, if you just write Const it is evaluated on Module creation time. You have to use Module#const_get instead like this: const_get(:Const). This is evaluated at runtime when the method is executed. So this happens in your class and not in your module.

like image 9
johannes Avatar answered Oct 23 '22 12:10

johannes