我正在构建一个类来表示自动生成的玩家角色。角色具有性别,可接受的值为: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 =方法中)和b)从阅读器方法调用writer方法看起来非常奇怪&#34 ;零"通过。有什么想法让这更优雅吗?
答案 0 :(得分:3)
如果在构造函数中设置了有效值,则在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
答案 1 :(得分:1)
这真的天真,也许是矫枉过正。如果您真的认真地以干净时尚的方式做到这一点,并且计划不仅仅具有性别属性,那么您可能希望投资类似......
skip
这几乎就是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
。
编辑:我最终制作了一个宝石。 https://github.com/joshmn/attributary
答案 2 :(得分:0)
我的版本,您也可以随意初始化:
pred1