Ruby:自定义实现属性访问器验证
问题描述:
我试图执行custom attribute accessors with validation
。Ruby:自定义实现属性访问器验证
比方说attr_validated
。现在这个attr_validated
1:应该有与attr_accessor相同的setter和getter方法。 ##这部分完成。
2:它应该验证给定的块。
attr_validated :num_legs do |v|
v <= 4
end
这个问题可能看起来像任何其他问题,但它不是。 虽然google搜索,我得到
1: IST部分
class Class
def attr_validated(*args)
args.each do |arg|
# getter
self.class_eval("def #{arg};@#{arg};end")
# setter
self.class_eval("def #{arg}=(val);@#{arg}=val;end")
end
end
end
class Dog
attr_validated :num_legs ## Instead of this i need to validate a block also attr_validated :num_legs do |v|
v <= 4
end
dog = Dog.new
p dog.num_legs
p dog.num_legs = 'Stack'
2:我们该如何实施第二部分。
任何帮助将不胜感激!!!
答
怎么是这样的:
class Class
def attr_validated(*args, &validator)
args.each do |name|
define_method("#{name}=") do |value|
if block_given?
raise ArgumentError, "Value '#{value}' is invalid" unless validator.call(value)
end
instance_variable_set("@#{name}", value)
end
define_method(name) do
instance_variable_get("@#{name}")
end
end
end
end
class Person
attr_validated(:name, :occupation) { |name| name.length > 3 }
end
p1 = Person.new
p1.name = "John The Tester"
p1.occupation = "Software developer"
p "#{p1.name} - #{p1.occupation}"
p2 = Person.new
p2.name = "test"
p2.occupation = "Tester"
p "#{p2.name} - #{p2.occupation}"
这会产生这样的输出:
"John The Tester - Software developer"
app.rb:6:in `block (2 levels) in attr_validated': Value 'test' is invalid (ArgumentError)
from app.rb:28:in `<main>'
希望这有帮助!
祝你好运!
UPDATE
您可以添加另一种方法,将应用验证的第一个参数是这样的:
class Class
def attr_validated_first(*args, &validator)
args.each_with_index do |name, index|
define_method("#{name}=") do |value|
if block_given? && index == 0
raise ArgumentError, "Value '#{value}' is invalid" unless validator.call(value)
end
instance_variable_set("@#{name}", value)
end
define_method(name) do
instance_variable_get("@#{name}")
end
end
end
end
但是我不推荐这种方法,这将是混乱!如果你想用不同的验证规则注册几个属性......您可以使用attr_validated
从第一个例子多次,像这样:
class Person
attr_validated(:name) { |name| name.length > 3 }
attr_validated(:occupation) { |occupation| occupation == "Ruby Developer" }
end
答
这很简单。只是raise
在二传手的ArgumentError
如果块说的论据是无效:
class Person
attr_reader :name
def name=(name)
raise ArgumentError, "'#{name}' is not a valid name!" if rejector.(name)
@name = name
end
private
attr_accessor :rejector
def initialize(&rejector)
self.rejector = rejector
end
end
artist = Person.new do |person|
person.length > 6
end
artist.name = 'The Artist Formerly Known As Prince'
# ArgumentError: 'The Artist Formerly Known As Prince' is not a valid name!
artist.name = 'ruby'
# => 'ruby'
许多许多谢谢@PawełDawczak ..它解决了我的问题。仍然我有一件事,块条件将适用于每一个属性..我们可以只为第一参数.. – VKatz
@Vinay - 请检查更新的答案 –
@Vinay通常这样的方法适用于块条件的所有项目,不只是第一个,至少是由Rails的约定来规定的。如果您需要更有选择性地应用它们,请进行多个“attr_validated”调用,其中一个调用块,另一个不调用。您可能还想采用如下模式:'attr_validated:example,with: - > {| v | v.length> 6}'作为lambda传入。 – tadman