有没有办法将模块包含在类中,以便模块可以 方法是否覆盖了类的方法?例如:
module UpcasedName
def name
@name.upcase
end
end
class User
attr_accessor :name
include UpcasedName
end
u = User.new
u.name = 'john'
puts u.name # outputs 'john', not 'JOHN'
在上面的示例中,u.name是'john',而不是'JOHN'。我知道,如果我 扩展用户对象而不是将模块包含到类中 会工作
module UpcasedName
def name
@name.upcase
end
end
class User
attr_accessor :name
end
u = User.new
u.name = 'john'
u.extend UpcasedName
puts u.name # outputs 'JOHN'
但是,我希望将模块包含在类级别,而不是对象级别。
答案 0 :(得分:3)
目前有几种方法可以做到这一点。那么第一个也是最基本的是使用ActiveSupport的alias_method_chain
require 'activesupport'
module UpcasedName
def self.included( base )
base.alias_method_chain :name, :upcase
end
def name_with_upcase
@name.upcase
end
end
class User
attr_accessor :name
include UpcasedName
end
u = User.new
u.name = 'john'
puts u.name
您发布的方法实际上类似于布鲁斯威廉姆斯方法发布的方法:http://www.codefluency.com/articles/2009/01/03/wrapping-a-method-in-ruby
如果你真的对此有所了解,可以按照Yehuda Katz发布的方法进行操作:http://yehudakatz.com/2009/01/18/other-ways-to-wrap-a-method/
答案 1 :(得分:2)
Include类似于从另一个类继承,在某种意义上,包含模块的类的方法优先于包含的方法。您甚至可以在班级中调用super来访问模块中的方法:
class User
attr_accessor :name
def name
super
end
include UpcasedName
end
u = User.new
u.name = 'john'
puts u.name # outputs 'JOHN'
以下是关于它的文章:include vs. extend in Ruby
答案 2 :(得分:0)
根据ucron的回答,可以在没有activesupport的情况下执行此操作,如下所示:
module UpcasedName
def self.included(base)
base.send :alias_method, :name_without_feature, :name
base.send :alias_method, :name, :name_with_upcase
end
def name_with_upcase
@name.upcase
end
end
class User
attr_accessor :name
include UpcasedName
end
u = User.new
u.name = 'john'
puts u.name
答案 3 :(得分:0)
这里的问题是attr_accessor
创建一个覆盖UpcasedName.name方法的User.name方法,因此一个解决方案将使用attr_writer
:
module UpcasedName
def name
@name.upcase
end
end
class User
attr_writer :name
include UpcasedName
end
u = User.new
u.name = 'john'
puts u.name # outputs 'JOHN'
答案 4 :(得分:0)
它可能并不总是一个选项,但我认为如果你只是将类的方法移动到它自己的模块中并将该模块混合回类中会更好。这让我觉得更清洁。