yammer / model_attribute Goto Github PK
View Code? Open in Web Editor NEWModelAttribute gem - attributes for non-ActiveRecord models
License: Other
ModelAttribute gem - attributes for non-ActiveRecord models
License: Other
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.
class Foo
attribute :metadata, :json
end
instance = Foo.new
If you give a Hash with string keys, all is well:
instance.metadata = {"master" => "chief"}
#=> {"master" => "chief"}
However, if you provide a Hash with symbol keys (which might have happened depending on how your JSON was generated or if it came from elsewhere e.g. Yaml):
instance.metadata = {:master => "chief"}
#=> ArgumentError: JSON only supports nil, numeric, string, boolean and arrays and hashes of those.
I think this is a bug because it's non-obvious behaviour, especially in Ruby where hashes can have ambiguous key semantics. There's probably three solutions:
metadata=
) methodHello I'm facing the issue with inheritance, attributes are not being copied.
Ruby 2.3.1
model_attribute (3.1.1)
require 'model_attribute'
class Person
extend ModelAttribute
attribute :name, :string
attribute :last_name, :string
def initialize(attributes = {})
set_attributes(attributes)
end
end
class User < Person
def initialize(attributes = {})
super(attributes)
self.name = "This is an error"
end
end
User.attributes # nil
User.new({})
# /Users/soto/.rvm/gems/ruby-2.3.1/gems/model_attribute-3.1.1/lib/model_attribute.rb:87:in `read_attribute': undefined method `include?' for nil:NilClass (NoMethodError)
# from /Users/soto/.rvm/gems/ruby-2.3.1/gems/model_attribute-3.1.1/lib/model_attribute.rb:66:in `write_attribute'
# from /Users/soto/.rvm/gems/ruby-2.3.1/gems/model_attribute-3.1.1/lib/model_attribute.rb:27:in `name='
# from script.rb:17:in `initialize'
# from script.rb:22:in `new'
# from script.rb:22:in `<main>'
I suggest to make it clear in the README that if you want to use this Models in your Rails form you will need to add:
include ActiveModel::Conversion
extend ActiveModel::Naming
def persisted?
false
end
To your model
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.