Is there a way to use arguments when including a ruby module? I have a module Assetable which is included across many classes. I want to be able to generate attr_accessor's on the fly.
在包含ruby模块时有没有办法使用参数?我有一个模块Assetable,它包含在许多类中。我希望能够动态生成attr_accessor。
module Assetable
extend ActiveSupport::Concern
included do
(argument).times do |i|
attr_accessor "asset_#{i}".to_sym
attr_accessible "asset_#{i}".to_sym
end
end
end
4 个解决方案
#1
13
There is no way of passing arguments when including the module. The best next thing would be to define a class method that lets you create what you need afterwards:
包含模块时无法传递参数。接下来最好的事情是定义一个类方法,让您在之后创建所需的内容:
module Assetable
extend ActiveSupport::Concern
module ClassMethods
def total_assets(number)
number.times do |i|
attr_accessor "asset_#{i}"
attr_accessible "asset_#{i}"
end
end
end
end
class C
include Assetable
total_assets 3
end
o = C.new
o.asset_2 = "Some value."
o.asset_2 #=> "Some value."
Also be careful when overriding the included
method within a concern because it's also used by ActiveSupport::Concern
. You should call super
within the overriden method in order to ensure proper initialization.
在覆盖问题时覆盖包含的方法时也要小心,因为它也被ActiveSupport :: Concern使用。您应该在overriden方法中调用super,以确保正确初始化。
#2
17
There is a trick: making a class that's inheriting from a module so that you could pass any arguments to the module like class.
有一个技巧:创建一个继承自模块的类,以便您可以将任何参数传递给模块,如类。
class Assetable < Module
def initialize(num)
@num = num
end
def included(base)
num = @num
base.class_eval do
num.times do |i|
attr_accessor "asset_#{i}"
end
end
end
end
class A
include Assetable.new(3)
end
a = A.new
a.asset_0 = 123
a.asset_0 # => 123
The details are blogged at http://kinopyo.com/en/blog/ruby-include-module-with-arguments, hope you'll find it useful.
详细信息请访问http://kinopyo.com/en/blog/ruby-include-module-with-arguments,希望您会发现它很有用。
#3
4
You can't pass arguments to a module. In fact, you can't pass arguments to anything except a message send.
您无法将参数传递给模块。实际上,除了发送消息之外,您不能将参数传递给任何内容。
So, you have to use a message send:
所以,你必须使用一条消息发送:
module Kernel
private def Assetable(num)
@__assetable_cache__ ||= []
@__assetable_cache__[num] ||= Module.new do
num.times do |i|
attr_accessor :"asset_#{i}"
attr_accessible :"asset_#{i}"
end
end
end
end
class Foo
include Assetable 3
end
Note: I didn't see why you would need ActiveSupport::Concern
here at all, but it's easy to add back in.
注意:我根本不明白你为什么需要ActiveSupport :: Concern,但很容易重新加入。
#4
0
You can generate and include an anonymous module without polluting global namespaces:
您可以生成并包含匿名模块,而不会污染全局名称空间:
module Assetable
def self.[](argument)
Module.new do
extend ActiveSupport::Concern
included do
(argument).times do |i|
attr_accessor :"asset_#{i}"
attr_accessible :"asset_#{i}"
end
end
end
end
end
class Foo
include Assetable[5]
end
#1
13
There is no way of passing arguments when including the module. The best next thing would be to define a class method that lets you create what you need afterwards:
包含模块时无法传递参数。接下来最好的事情是定义一个类方法,让您在之后创建所需的内容:
module Assetable
extend ActiveSupport::Concern
module ClassMethods
def total_assets(number)
number.times do |i|
attr_accessor "asset_#{i}"
attr_accessible "asset_#{i}"
end
end
end
end
class C
include Assetable
total_assets 3
end
o = C.new
o.asset_2 = "Some value."
o.asset_2 #=> "Some value."
Also be careful when overriding the included
method within a concern because it's also used by ActiveSupport::Concern
. You should call super
within the overriden method in order to ensure proper initialization.
在覆盖问题时覆盖包含的方法时也要小心,因为它也被ActiveSupport :: Concern使用。您应该在overriden方法中调用super,以确保正确初始化。
#2
17
There is a trick: making a class that's inheriting from a module so that you could pass any arguments to the module like class.
有一个技巧:创建一个继承自模块的类,以便您可以将任何参数传递给模块,如类。
class Assetable < Module
def initialize(num)
@num = num
end
def included(base)
num = @num
base.class_eval do
num.times do |i|
attr_accessor "asset_#{i}"
end
end
end
end
class A
include Assetable.new(3)
end
a = A.new
a.asset_0 = 123
a.asset_0 # => 123
The details are blogged at http://kinopyo.com/en/blog/ruby-include-module-with-arguments, hope you'll find it useful.
详细信息请访问http://kinopyo.com/en/blog/ruby-include-module-with-arguments,希望您会发现它很有用。
#3
4
You can't pass arguments to a module. In fact, you can't pass arguments to anything except a message send.
您无法将参数传递给模块。实际上,除了发送消息之外,您不能将参数传递给任何内容。
So, you have to use a message send:
所以,你必须使用一条消息发送:
module Kernel
private def Assetable(num)
@__assetable_cache__ ||= []
@__assetable_cache__[num] ||= Module.new do
num.times do |i|
attr_accessor :"asset_#{i}"
attr_accessible :"asset_#{i}"
end
end
end
end
class Foo
include Assetable 3
end
Note: I didn't see why you would need ActiveSupport::Concern
here at all, but it's easy to add back in.
注意:我根本不明白你为什么需要ActiveSupport :: Concern,但很容易重新加入。
#4
0
You can generate and include an anonymous module without polluting global namespaces:
您可以生成并包含匿名模块,而不会污染全局名称空间:
module Assetable
def self.[](argument)
Module.new do
extend ActiveSupport::Concern
included do
(argument).times do |i|
attr_accessor :"asset_#{i}"
attr_accessible :"asset_#{i}"
end
end
end
end
end
class Foo
include Assetable[5]
end