是否有实施类似的方法的参数列表中指定的实例变量名的CoffeeScript的功能红宝石行为的计划吗? 喜欢
class User
def initialize(@name, age)
# @name is set implicitly, but @age isn't.
# the local variable "age" will be set, just like it currently works.
end
end
我知道这个问题的: 在Ruby中我可以自动初始化方法莫名其妙地填充实例变量? ,但所有的解决方案(包括我自己)似乎并不适合简单的红宝石理念。
而且,会有对有这种行为的任何缺点?
UPDATE
其中的一个原因,这是Ruby社区的DRY(不要重复自己)的理念。 我经常发现自己需要重复的参数变量的名字,因为我希望它被分配到同一个名字的实例变量。
def initialize(name)
# not DRY
@name = name
end
一个缺点我能想到的是,它可能看起来就像一个方法做什么,如果它没有身体。 如果你快速扫描,这可能看起来像一个空操作。 但我认为,给定的时间,我们就可以适应。
另一个缺点:如果你在身体其他设置实例变量,并尝试通过将所有任务在开始读,它可以采取更多的认知“权力”看到有任务也发生在参数列表中。 但我不认为这是任何比说更难,看到一个常量或方法调用,并具有跳转到它的定义。
# notice: instance var assignments are happening in 2 places!
def initialize(@name)
@errors = []
end
经过一番琢磨之后,我不知道是否有可能实际上是从一个红宝石方法得到的参数名。 如果是这样,我可以使用像“iv_”特殊参数的前缀来指示ARGS应设置为实例变量。
它是可能的: 如何使用反射来获取参数的名称 。
是! 所以,我也许可以写一个模块来处理这对我来说。 然后,我卡住了,因为如果我调用模块的helper方法,它不知道的参数值,因为它们是地方给调用者。 啊,但红宝石已经绑定的对象。
这里的模块(仅红宝石1.9):
module InstanceVarsFromArgsSlurper
# arg_prefix must be a valid local variable name, and I strongly suggest
# ending it with an underscore for readability of the slurped args.
def self.enable_for(mod, arg_prefix)
raise ArgumentError, "invalid prefix name" if arg_prefix =~ /[^a-z0-9_]/i
mod.send(:include, self)
mod.instance_variable_set(:@instance_vars_from_args_slurper_prefix, arg_prefix.to_s)
end
def slurp_args(binding)
defined_prefix = self.class.instance_variable_get(:@instance_vars_from_args_slurper_prefix)
method_name = caller[0][/`.*?'/][1..-2]
param_names = method(method_name).parameters.map{|p| p.last.to_s }
param_names.each do |pname|
# starts with and longer than prefix
if pname.start_with?(defined_prefix) and (pname <=> defined_prefix) == 1
ivar_name = pname[defined_prefix.size .. -1]
eval "@#{ivar_name} = #{pname}", binding
end
end
nil
end
end
而这里的用法:
class User
InstanceVarsFromArgsSlurper.enable_for(self, 'iv_')
def initialize(iv_name, age)
slurp_args(binding) # this line does all the heavy lifting
p [:iv_name, iv_name]
p [:age, age]
p [:@name, @name]
p [:@age, @age]
end
end
user = User.new("Methuselah", 969)
p user
输出:
[:iv_name, "Methuselah"]
[:age, 969]
[:@name, "Methuselah"]
[:@age, nil]
#<User:0x00000101089448 @name="Methuselah">
它不会让你有一个空的方法体,但它是干的。 我敢肯定,这可以进一步通过仅仅指定哪些方法应该有这样的行为(通过alias_method实现),而不是调用每个方法slurp_args增强 - 规范必须是在所有的方法虽然定义。
注意模块和辅助方法的名字很可能得到改善。 我只是用浮现在脑海的第一件事。
实际上...
class User
define_method(:initialize) { |@name| }
end
User.new(:name).instance_variable_get :@name
# => :name
工程在1.8.7,但不是在1.9.3。 现在,只要在那里才知道这个...
我想你回答了你自己的问题,它不适合红宝石简单的理念。 这将为参数是如何的方法处理增加额外的复杂性和移动逻辑管理变量成方法的参数。 我可以看到的说法,它使代码的可读性变差一折腾,但它确实让我最不能非常详细。
一些情景@ PARAM将不得不与之抗衡:
def initialize( first, last, @scope, @opts = {} )
def search( @query, condition )
def ratchet( @*arg )
如果所有这些情况下是有效的? 就在initialize
? 该@*arg
似乎在我的脑海特别冒险的。 所有这些规则和排除使Ruby语言更加复杂。 对于自动实例变量的利益,我不认为这将是值得的。