Reputation: 3422
I created a ruby wrapper around a json API that converts json formatted responses into ruby object. A typical resource looks like that :
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
When I receive the json payload, I pass it to the initializer as a hash of options and I then assign each one of the key its value as an instance variable.
This works well as long as I maintain an updated list of attr_accessor
. However if the API decides to change the naming of its keys or add a new key this will throw a
undefined method `unexpected_key_from_api=' for #<Learning360::User>
How can I avoid that problem and make my wrapper more robust. I would like my wrapper object to just take any key from the response and automatically build the corresponding accessor if it doesnt exist.
Upvotes: 1
Views: 385
Reputation: 850
You can create attributes with attr_accessor
inside the initialize
method. You only need to reach to it like below:
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
It is also possible to use class name diectly just like User.attr_accessor(k)
.
Upvotes: 2