RoUS
RoUS

Reputation: 1990

Ruby 1.8.6: How to alias a constant in one class to a class method in another?

Is there any way to create aliases across classes? Specifically, from a constant in one class to a class method in another?

Something like

Object.const_set('Foo', proc { Bar.meth })

except having the proc auto-evaluated at reference-time. (puts Foo for the above displays the proc #inspect value; I need to execute Foo.call to actually invoke bar.meth -- and that's the extra step I'm trying to finesse around.)

Phrased another way, I would like to alias a constant such that when I say puts Foo it is exactly equivalent to puts Bar.meth. If Bar.meth returns different values at different times, so would Foo evaluate to the different values accordingly -- because they're the same.

Can this be done?

Thanks!

Upvotes: 2

Views: 2592

Answers (3)

Guilherme Bernal
Guilherme Bernal

Reputation: 8303

This is what you want?

class A
  def self.bar
    "Test"
  end
end
class B
  def self.Foo
    A.bar
  end
  def self.const_missing(name)
    methods.include?(name.to_s) ? __send__(name) : super
  end
end

A.bar
B.Foo
B::Foo
# all returns "Test"

Upvotes: 1

Danny Hiemstra
Danny Hiemstra

Reputation: 1188

The post above is really great but i was also trying things out in console and got a slightly different solution by not defining a constant in the ruby class "Object".

module Foo
  @output = Time.now # You can use 'Bar.meth' just showing the define at reference time
  def Foo.to_s
    @output
  end
end

Output:

$ puts Time.now
# => Tue Feb 22 22:19:23 +0100 2011
$ puts Foo
# => Tue Feb 22 22:19:19 +0100 2011

Upvotes: 0

Simone Carletti
Simone Carletti

Reputation: 176412

You can create alias between constants

class Foo
  CONST = 3
end

class Bar
  CONST = Foo::CONST
end

p Foo::CONST
# => 3
p Bar::CONST
# => 3

You can also reference a method into an other class. But because the value of the constant is elaborated when the assignment is evaluated, you cannot have it changing depending on an other method.

class Foo
  def self.const
    "value"
  end
end

class Bar
  CONST = Foo.method(:const)
end

p Foo.const
# => "value"
p Bar::CONST
# => #<Method: Foo.const>

You can try to cheat the interpreter by naming the method like a constant

class Foo
  def self.const
    "value"
  end
end

class Bar
  def self.CONST
    Foo.const
  end
end

p Foo.const
# => "value"
p Bar.CONST
# => "value"

but you will only be able to call Bar.CONST, not Bar::CONST.

At this point, I've got a question. Why should you do that? In my opinion, this kind of requirement seems to highlight a design issue.

Upvotes: 1

Related Questions