Ruby Read&;使用默认值和验证写入属性
我正在构建一个类来表示自动生成的玩家角色。字符具有性别,可接受的值为Ruby Read&;使用默认值和验证写入属性,ruby,Ruby,我正在构建一个类来表示自动生成的玩家角色。字符具有性别,可接受的值为:male和:female。我需要一个属性读取器和写入器来允许访问和自定义,但也需要一个“默认”值,以防尚未选择某个值,并且用户不想选择某个值。我有以下代码: class Character attr :gender def gender= g g = nil unless g == :male or g == :female @gender = g || [:male, :fe
:male
和:female
。我需要一个属性读取器和写入器来允许访问和自定义,但也需要一个“默认”值,以防尚未选择某个值,并且用户不想选择某个值。我有以下代码:
class Character
attr :gender
def gender= g
g = nil unless g == :male or g == :female
@gender = g || [:male, :female].sample
end
def gender
@gender ||= gender=(nil)
end
end
这样做的目的是始终通过setter来确保值是有效的,并使代码更易于维护,以防我决定在以后的性别列表中添加新值。我面临的问题是a)验证行有多余的值,下面有设置行(在gender=method中),b)从reader方法调用writer方法,传递“nil”看起来很奇怪。有什么想法可以让它更优雅吗?如果在构造函数中设置了有效值,那么在getter中不需要setter。将来,如果要添加新的性别,可以一次性更新现有角色。这可以让你的代码更干净
class Character
attr :gender
def initialize
@gender = valid_genders.sample
end
def gender= g
@gender = g if valid_genders.include? g
end
private
def valid_genders
[:male, :female]
end
end
如果在构造函数中设置了有效值,则不需要getter中的setter。将来,如果要添加新的性别,可以一次性更新现有角色。这可以让你的代码更干净
class Character
attr :gender
def initialize
@gender = valid_genders.sample
end
def gender= g
@gender = g if valid_genders.include? g
end
private
def valid_genders
[:male, :female]
end
end
这真的很幼稚,也许是矫枉过正。如果你真的想以一种干净时尚的方式来做这件事,并且计划拥有不仅仅是性别特征的东西,那么你可能想投资一些东西,比如
module CoolAttributes
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def attribute(name, type, options = {})
get(name, type, options)
set(name, type, options)
end
def get(name, type, options)
define_method(name) do
instance_variable_get(:"@#{name}") || if options[:default].is_a?(Proc)
options[:default].call
else
options[:default]
end
end
end
def set(name, type, options)
define_method("#{name}=") do |value|
instance_variable_set(:"@#{name}", self.class.cast_to(type, value))
end
end
def cast_to(type, value)
if type == :boolean
if ['false', 0, '0', false].include?(value)
false
else
true
end
elsif type == :symbol
value.to_s.to_sym
end
end
end
end
class Character
include CoolAttributes
attribute :gender, :symbol, :default => :male
end
c = Character.new
puts c.gender # male
c.gender = 'male'
puts c.gender.class # Symbol
这与ActiveModel::Attributes
非常相似
编辑:我最终用这个做了一块宝石 这真是太天真了,也许是矫枉过正了。如果你真的想以一种干净时尚的方式来做这件事,并且计划拥有不仅仅是性别特征的东西,那么你可能想投资一些东西,比如
module CoolAttributes
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def attribute(name, type, options = {})
get(name, type, options)
set(name, type, options)
end
def get(name, type, options)
define_method(name) do
instance_variable_get(:"@#{name}") || if options[:default].is_a?(Proc)
options[:default].call
else
options[:default]
end
end
end
def set(name, type, options)
define_method("#{name}=") do |value|
instance_variable_set(:"@#{name}", self.class.cast_to(type, value))
end
end
def cast_to(type, value)
if type == :boolean
if ['false', 0, '0', false].include?(value)
false
else
true
end
elsif type == :symbol
value.to_s.to_sym
end
end
end
end
class Character
include CoolAttributes
attribute :gender, :symbol, :default => :male
end
c = Character.new
puts c.gender # male
c.gender = 'male'
puts c.gender.class # Symbol
这与ActiveModel::Attributes
非常相似
编辑:我最终用这个做了一块宝石 我的版本,您也可以随意初始化:
class Character
attr :gender
def initialize(g = nil)
valid? g ? @gender = g : @gender = random_gender
end
def gender=(g)
@gender = g if valid? g
end
def self.list_genders
new.genders.each_with_index { |gender, idx| puts "#{idx+1} - #{gender}" }
end
def valid?(g)
g && genders.include?(g)
end
def genders
[:male, :female]
end
def random_gender
genders.sample
end
end
Character.list_genders
character = Character.new
p character.gender
character = Character.new(:male)
p character.gender
character.gender = :female
character.gender = :none
p character.gender
我的版本,您也可以随意初始化:
class Character
attr :gender
def initialize(g = nil)
valid? g ? @gender = g : @gender = random_gender
end
def gender=(g)
@gender = g if valid? g
end
def self.list_genders
new.genders.each_with_index { |gender, idx| puts "#{idx+1} - #{gender}" }
end
def valid?(g)
g && genders.include?(g)
end
def genders
[:male, :female]
end
def random_gender
genders.sample
end
end
Character.list_genders
character = Character.new
p character.gender
character = Character.new(:male)
p character.gender
character.gender = :female
character.gender = :none
p character.gender
如果您绝对必须有一个随机选择的“默认”性别,则在初始值设定项中设置该性别,而不是在setter中设置该性别,并简单地拒绝setter中的无效值。这样,您总是有一个有效的性别,因此在getter中不需要额外的逻辑,而setter只需要验证新输入不是:male或:female。如果您绝对必须有一个随机选择的“default”性别,请在初始值设定项中设置,而不是在setter中设置,并简单地拒绝setter中的无效值。这样,你总是有一个有效的性别,所以你永远不需要在getter中有额外的逻辑,你的setter只需要验证新的输入不是:男或:女。