在Ruby中,我尝试创建一个类,它基于初始化期间给出的值将继承以下模块之一。我想创建一个基本模块,这些模块继承自包含常用方法的基本模块,这些方法使用继承它的模块中定义的常量。例如:
module BaseMod
def what_am_i
puts OUTPUT
end
end
module Tall
OUTPUT = "I am tall"
include BaseMod
end
module Short
OUTPUT = "I am short"
include BaseMod
end
class Person
def initialize type
if type =~ /short/i
extend Short
else
extend Tall
end
end
end
p = Person.new "short"
p.what_am_i
我的问题是" p.what_am_i"被称为我得到以下错误:
NameError: uninitialized constant BaseMod::OUTPUT
const_missing at org/jruby/RubyModule.java:2642
what_am_i at test_logic2.rb:3
(root) at test_logic2.rb:28
我也想知道是否有更好的方法可以做到这一点。
答案 0 :(得分:4)
module BaseMod
def what_am_i
puts self.class::OUTPUT
end
end
module Tall
OUTPUT = "I am tall"
include BaseMod
end
module Short
OUTPUT = "I am short"
include BaseMod
end
class Person
def initialize(type)
if type =~ /short/i
self.class.send(:include, Short)
else
self.class.send(:include, Tall)
end
end
end
p = Person.new "short"
p.what_am_i
编辑:上述代码实际上无效:
p = Person.new "short"
p.what_am_i
>> I am short
p = Person.new "tall"
p.what_am_i
>> I am tall
p = Person.new "short"
p.what_am_i
>> I am tall
这是另一次尝试:
module BaseMod
def self.included(base)
base.send(:define_method, :what_am_i) do
puts base::OUTPUT
end
end
end
module Tall
OUTPUT = "I am tall"
include BaseMod
end
module Short
OUTPUT = "I am short"
include BaseMod
end
class Person
def initialize type
if type =~ /short/i
extend Short
else
extend Tall
end
end
end
p = Person.new "short"
p.what_am_i
p = Person.new "tall"
p.what_am_i
p = Person.new "short"
p.what_am_i
答案 1 :(得分:2)
要在你的情况下获得常数,你必须写下这样的东西:
module Tall
::OUTPUT = "I am tall"
include BaseMod
end
但请注意,您正在使用模块Short的声明重新定义Constant。为此,你总会得到“我很矮”。
为了正确地做,你应该尝试:
module BaseMod
OUTPUT="Before"
def what_am_i
puts OUTPUT
end
end
module Tall
def self.extended(k)
OUTPUT.replace "I am tall"
end
include BaseMod
end
module Short
def self.extended(k)
OUTPUT.replace "I am short"
end
include BaseMod
end
ķ
答案 2 :(得分:1)
我打算再给桌子带一个选项。我不太确定你的复杂,现实世界的情况是什么,所以这是我的选择:
module BaseMod
def what_am_i
puts output
end
end
module Tall
include BaseMod
def self.extended klass
define_method :output do
"I am tall"
end
end
end
module Short
include BaseMod
def self.extended klass
define_method :output do
"I am short"
end
end
end
class Person
def initialize type
extend (type =~ /short/i ? Short : Tall ) # Because I didn't wanna type all those lines
end
end
p = Person.new "short"
p.what_am_i
请注意,对于这种情况,您可以轻松地执行此操作:
module Tall
include BaseMod
def output
"I am tall"
end
end
但我不知道这对你是否真的有帮助。
答案 3 :(得分:0)
似乎当你用#what_am_i消息向你的人p发消息时,解释器在类祖先中连续查找更高和更高的方法实现,最后在BaseMod中找到它,但是在那个级别,OUTPUT常量没有被定义了。所以我认为Ruby继续在层次结构中寻找向上的OUTPUT常量,但是不考虑向下看,在定义它的Tall和Short模块中。士气是,即使你包含了很多子模块,它们也不会进入一个堆中,每个人都可以访问所有常量,而是按照它们包含的相反顺序保持它们的层次结构(参见Tall.Ancestors)。在任何级别,只能访问相同级别或更高级别的常量。我会用以下方式解决你的问题:
module Personhood
def what_am_i; @output end
end
class Tall
include Personhood
def initialize
@output = "I am tall"
end
end
end
class Short
include Personhood
def initialize
@output = "I am short"
end
end
end
def Person( type )
if type =~ /short/i
Short.new
else
Tall.new
end
end
pete = Person "short"
pete.what_am_i
=> I am short
我处理了一个常数,支持实例变量。在Ruby中,无论如何都没有真正的常量。 Tall和Short是make类,Person是一个构造函数方法,它根据输入返回Tall或Short类。我觉得应该这样做。