Takes a hash of snake, camel, train, or kabab case and make its attributes accessible with any other case.
The main application is for working with JSON from an API and standardizing to a Ruby-centric underscore/snake case interface.
##Usage
Gemfile
gem "recursive_case_indifferent_ostruct"user = RecursiveCaseIndifferentOstruct.new({
"firstName" => "Tommy",
"first-name" => "Bobby",
"LAST_NAME" => "Johnson",
"Birth-Place" => "Springfield",
"father" => {
"age" 72
},
"siblings" => [
{relation: "brother", age: 12}
]
}, :lower_camel)
# access attributes like so
user.first_name # "Tommy"
user.last_name # "Johnson"
user.father.age # 72
user.siblings[0].age # 12
user.birth_place = "New York" # sets Birth-Place
user.first_name = "Ken" # sets {"firstName" => "Ken", "first-name" => "Ken"}
user.mothers_maiden = "Woods" # Since case is mixed in that hash, use default :lower_camel
user.to_h
# {
# "firstName" => "Ken",
# "first-name" => "Ken",
# "LAST_NAME" => "Johnson",
# "Birth-Place" => "New York",
# "father" => {
# "age" 72
# },
# "siblings" => [
# {relation: "brother", age: 12}
# ],
# "mothersMaiden" => "Woods",
# }# .merge() is case insensitive
user = RecursiveCaseIndifferentOstruct.new(first_name: "Bob")
new_user = user.merge({"FirstName" => "Bobby"})
new_user.first_name # Bobby
user.first_name # Bob
user.merge!({"FirstName" => "Bobby"})
user.first_name # Bobby
Since the key matching is fuzzy, should there be two attributes with
the same name but different case (first-name and firstName), the
library will return first value that it finds. For an assignment it
will assign all matching attributes to the new value.
Should you assign an attribute to the hash that does not already exist
the library will try to figure out which case to use based on other
keys in the hash. If it cannot determine which case is being used
it will fall back to RecursiveCaseIndifferentOstruct::DEFAULT_CASE=:snake
which you could set to override. Another option is to pass the default
case on initialization RecursiveCaseIndifferentOstruct.new(hash, :snake).
Available options:
:snakethis_is_snake:lower_camelthisIsLowerCamel:upper_camelThisIsUpperCamel:kababthis-is-kabab:trainThis-Is-Train
If you need to assign a value to a key that has an odd case you can
use a string with the bracket syntax like so: json["PI:Value"] = 3.14.
The value can still be accessed via json.pi_value.
RecursiveCaseIndifferentOstruct will pass methods along to the hash
if the method is not defined and there is not attribute matching that
name. However, all the hash methods operate on the original hash, so
#has_key?, #each, #fetch, etc, will not be case-indifferent.
Feel free to implement them and submit a PR.
json = RecursiveCaseIndifferentOstruct.new({
ID: 123,
userName: "pax"
})
json.has_key?(:user_name) # false
json.has_key?("userName") # true
json.fetch(:id) # nil
json.keys # [:ID, :userName]rake test