在对象初始化时在 ruby 中动态构建访问器
Dynamically building accessors in ruby on object initialization
我围绕 json API 创建了一个 ruby 包装器,将 json 格式的响应转换为 ruby 对象。典型的资源如下所示:
module Learning360
class User
attr_accessor(
:_id,
:mail,
:firstName,
:lastName,
:assignedPrograms,
:paths,
:certifications,
:championAchievements,
:comments,
:completedPrograms,
:groups,
:imageUrl,
:labels,
:lastLoginAt,
:championStatus,
:learnerAchievements,
:managers,
:messages,
:publications,
:reactions,
:skills,
:subordinates,
:toDeactivateAt,
:totalTimeSpentInMinutes,
:custom
)
def initialize(options = {})
options.map { |(k, v)| send("#{k}=", v) }
end
end
end
当我收到 json 有效载荷时,我将它作为选项的散列传递给初始化程序,然后我将每个键的值作为实例变量分配。
只要我维护 attr_accessor
的更新列表,这就很好用。但是,如果 API 决定更改其键的命名或添加新键,这将抛出
undefined method `unexpected_key_from_api=' for #<Learning360::User>
我怎样才能避免这个问题并使我的包装器更健壮。我希望我的包装器对象只从响应中获取任何键,如果不存在则自动构建相应的访问器。
您可以在 initialize
方法中使用 attr_accessor
创建属性。你只需要像下面这样到达它:
module Learning360
class User
def initialize(options = {})
options.each do |(k, v)|
self.class.attr_accessor(k)
send("#{k}=", v)
end
end
end
end
user = Learning360::User.new({ name: "Matz" })
puts user.name # Matz
也可以像User.attr_accessor(k)
一样直接使用class名称。
我围绕 json API 创建了一个 ruby 包装器,将 json 格式的响应转换为 ruby 对象。典型的资源如下所示:
module Learning360
class User
attr_accessor(
:_id,
:mail,
:firstName,
:lastName,
:assignedPrograms,
:paths,
:certifications,
:championAchievements,
:comments,
:completedPrograms,
:groups,
:imageUrl,
:labels,
:lastLoginAt,
:championStatus,
:learnerAchievements,
:managers,
:messages,
:publications,
:reactions,
:skills,
:subordinates,
:toDeactivateAt,
:totalTimeSpentInMinutes,
:custom
)
def initialize(options = {})
options.map { |(k, v)| send("#{k}=", v) }
end
end
end
当我收到 json 有效载荷时,我将它作为选项的散列传递给初始化程序,然后我将每个键的值作为实例变量分配。
只要我维护 attr_accessor
的更新列表,这就很好用。但是,如果 API 决定更改其键的命名或添加新键,这将抛出
undefined method `unexpected_key_from_api=' for #<Learning360::User>
我怎样才能避免这个问题并使我的包装器更健壮。我希望我的包装器对象只从响应中获取任何键,如果不存在则自动构建相应的访问器。
您可以在 initialize
方法中使用 attr_accessor
创建属性。你只需要像下面这样到达它:
module Learning360
class User
def initialize(options = {})
options.each do |(k, v)|
self.class.attr_accessor(k)
send("#{k}=", v)
end
end
end
end
user = Learning360::User.new({ name: "Matz" })
puts user.name # Matz
也可以像User.attr_accessor(k)
一样直接使用class名称。