猴子修补 Virtus 的Attribute
课程当然是一种选择。
但是,进入库的内部会使您容易受到该库源代码私有部分的重构的影响。
相反,您可以使用封装此功能的辅助模块。这里有一个建议:
require 'virtus'
# Put this helper module somewhere on your load path (e.g. your project's lib directory)
module ApiThing
def self.included(base)
base.include Virtus.model
base.extend ApiThing::ClassMethods
end
module ClassMethods
@@identifiers = {}
def api_attribute(attr_name, *virtus_args, identifier:, **virtus_options)
attribute attr_name, *virtus_args, **virtus_options
@@identifiers[attr_name.to_sym] = identifier
end
def identifier_for(attr_name)
@@identifiers.fetch(attr_name.to_sym){ raise ArgumentError, "unknown API attribute #{attr_name.inspect}" }
end
end
def identifier_for(attr_name)
self.class.identifier_for(attr_name)
end
end
# And include it in your API classes
class Balls
include ApiThing
api_attribute :color, String, identifier: 'SOME__fancy_identifier'
api_attribute :number, Integer, identifier: 'SOME__other_identifier'
api_attribute :size, BigDecimal, identifier: 'THAT__third_identifier'
end
# The attributes will be registered with Virtus – as usual
puts Balls.attribute_set[:color].type #=> Axiom::Types::String
puts Balls.attribute_set[:number].type #=> Axiom::Types::Integer
puts Balls.attribute_set[:size].type #=> Axiom::Types::Decimal
# You can use the handy Virtus constructor that takes a hash – as usual
b = Balls.new(color: 'red', number: 2, size: 42)
# You can access the attribute values – as usual
puts b.color #=> "red"
puts b.number #=> 2
puts b.size #=> 0.42e2
puts b.durability #=> undefined method `durability' [...]
# You can ask the instance about identifiers
puts b.identifier_for :color #=> "SOME__fancy_identifier"
puts b.identifier_for :durability #=> unknown API attribute :durability (ArgumentError)
# And you can ask the class about identifiers
puts Balls.identifier_for :color #=> "SOME__fancy_identifier"
puts Balls.identifier_for :durability #=> unknown API attribute :durability (ArgumentError)
你不需要 Virtus 来实现你的 API 标识符。类似的帮助模块可以只注册attr_accessor
s 而不是 Virtus 属性。
但是,Virtus 还具有其他方便的功能,例如散列构造函数和属性强制转换。如果您不介意没有这些功能或寻找替代品,那么放弃 Virtus 应该不是问题。
!:)