Skip to content

Rename attributes when transforming to/from JSON #5

@d-Pixie

Description

@d-Pixie

Hi.

Just wanted to pitch an idea and see what you think: I'm writing an integration gem for a public API. Like many JSON APIs it uses CamelCase for the key names that do not map cleanly to ruby attribute names. For example:

PriceInclVAT should map to price_incl_vat but the gem doesn't do any conversions, leaving you with two choices: roll your own or live with the weird attribute names.

I'd like to add the ability to convert key names when transforming to/from JSON. One way would be to just do a straight map, given at attribute declaration time:

require 'model_attribute'
class User
  extend ModelAttribute
  attribute :id,             :integer, key: 'UserID'
  attribute :paid,           :boolean, key: 'Paid' 
  attribute :name,           :string,  key: 'UserName'
  attribute :created_at,     :time,    key: 'RegistrationTime'
  attribute :vat_schedule,   :json,    key: 'VATSchedule'

  def initialize(attributes = {})
    set_attributes(attributes)
  end
end

or by assigning a conversion method

require 'model_attribute'
class User
  extend ModelAttribute
  attribute :id,             :integer
  attribute :paid,           :boolean
  attribute :name,           :string
  attribute :created_at,     :time
  attribute :vat_schedule,   :json

  def convert( key, export = false )
    map = {
      id: 'UserID',
      paid: 'Paid',
      name: 'UserName',
      created_at: 'RegistrationTime',
      vat_schedule: 'VATSchedule',
    }
    map.reverse! if export
    map[ key ]
  end

  def initialize(attributes = {})
    set_attributes(attributes)
  end
end

Idealy you could do both, use the key directly if it exists and call the method if it doesn't.

require 'model_attribute'
class User
  extend ModelAttribute
  attribute :id,             :integer, key: 'UserID'
  attribute :paid,           :boolean
  attribute :name,           :string,  key: 'UserName'
  attribute :created_at,     :time,    key: 'RegistrationTime'
  attribute :vat_schedule,   :json,    key: 'VATSchedule'

  def convert( key, export = false)
    return key.to_s.capitalize unless export
    'UserID'.gsub(/(.+[a-z])([A-Z])/, '\1_\2' ).downcase.to_sym
  end

  def initialize(attributes = {})
    set_attributes(attributes)
  end
end

Right now I use Virtus with a hand rolled version of the combined approach. I have a map and a generic method. If the key is in the map it's used else the method is run.

Would this be interesting for you? If so I can open a PR when I have something that we can discuss.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions