Cot is a gem designed to help convert rest based resources into ruby objects. Currently it only handles converting the responses into objects and doesn't deal with the requests themselves, there are plenty of gems for that out there.
Example
class NestedClass < Cot::Frame
property :parent_id
property :foo, from: :bar
end
class ExampleObject < Cot::Frame
property :id
property :name, :searchable => true, primary: true
property :company_name, :from => :companyName
property :item do
from :place
value do |params|
NestedClass.new params.merge parent_id: id
end
end
property :blank do
missing do
"Item #{id}"
end
end
enum :types do
entry :first
entry :third, value: 3
entry :fourth
end
search_property :created_at, :from => :createdOn
end
class ExampleCollection < Cot::Collection
def initialize(objects, options = {})
super ExampleObject, objects, options
end
end
# No initialize required, just pass in the objects
class ExampleDSLCollection < Cot::Collection
collected_class ExampleObject
sub_key :key
default_attributes default: :attributes
end
thingy = ExampleObject.new(id: :my_id, name: 'awesome name', createdOn: Time.now, place: {bar: 'this is nested.foo'})
thingy.id # 5
thingy.name # awesome name
ExampleObject.types.first # 1
ExampleObject.types[:third] # 3
thingy.types.fourth # 4
thingy.item # NestedClass instance
thingy.item.foo # 'this is nested.foo'
thingy.created_at # what time it is now
thingy.defined_properties # [:id, :name, :created_at]
thingy.blank # 'Item 5'
thingy.exists? # 'awesome name'
collection = ExampleCollection.new [{ id: :my_id, name: 'awesome name', createdOn: Time.now }, { id: :my_id, name: 'awesome name', createdOn: Time.now }], { default_attributes: { default: :attribute }
collection.first.name # 'awesome name'
collection.first.default # :attribute
collection.exists? # Do all of the entries exist?
collection.update_members [{ id: 1, name: 'new awesome name', createdOn: Time.now }, { id: 2, name: 'new awesome name', createdOn: Time.now }]
collection.first.name # 'new awesome name'
Details
Using cot is pretty simple. There are two main classes: Collection and Frame. Collections are basically big arrays that contain objects (presumably Frame objects). Collection provides some helper methods to manage the collection, but also delegates to Array, so each, map and all that good stuff are there as well. Frame allows you to declare how the object will convert a json payload into an object.
Frame provides some helpful methods:
- Class Methods
- property
- The first parameter is the name of the property and it is added as a method to the object.
- You can pass additional options in two ways, first you can pass a hash of options to property and secondly you can pass a block to property.
- There are five optional arguments, value, from, missing, primary and searchable.
- From indicates that the property has an alternate key in the incoming/outgoing data.
- Searchable adds the property to the search mappings.
- Primary indicates that this is the primary key. Currently this only determines what exists? looks at.
- Missing takes a block and will execute the block if nothing was passed to the object on initialize. This block is evaluated in the context of the object. So you can for example have a string that says "Object #{id}"
- Value takes a block and overwrites the value of the property to be the result of the block
- This is useful for nested objects.
- The block is executed as part of the instance of the object, so you have access to other properties.
- The block takes one parameter, which is the value of the hash for that key (what the value would have been if there was no value block).
- search_property adds the parameter to the search mapping. It takes an optional from argument which inidates the property has an alternate key in the incoming/outgoing data.
- enum takes a name and a block
- Enums are defined on the instances and the class
- Enum defines a method for each entry and also allows readonly hash access
- The block expects a series of entries to be declared
- enum starts counting at 1 by default
- Each entry will have the value of 1 higher than the previous by default
- An optional value parameter can be passed which sets the entries value to that number. This lets you skip a numer, start higher or lower or even be non-sequential.
- property
- Instance Methods
- defined_properties returns a list of the defined properties
- properties_mapping returns a hash containing all of the renamed properties. The keys are the values of the from argument and the values are the property name.
- inverted_properties_mapping returns an inverted hash containing all of the renamed properties. This is the same as properties_mapping but the property names are the keys and the froms are the values
- search_mappings returns a hash containing the search properties. If a from was provided then that is the key otherwise the key and the value will be the property name.
- inverted_search_mappings returns an inverted search_mappings hash.
- serializable_hash returns hash with the correct keys to post back. AKA, it reverts the keys to what the from arguments (if any) were.
- to_json returns a json encoded version of serializable_hash.
- valid? true if errors is empty
- errors used to store any errors associated with the object
Collection provides the following methods:
- DSL
- If you don't need any special behavior in your initialize, you can use the DSL to declare the class, sub_key and default_attributes
- Initialization
- You can pass options to the collection when you initialize
- sub_key: Uses the contents inside the sub_key
- default_attributes: Will add the keys/values to the object
- Instance Methods
- The following methods collate the results from members
- serializable_hash
- to_json
- errors (pulls into a hash with member.id as the key)
- exists? returns true if all the members exist
- changed? returns true if any of the members have changed
- update_members updates the members of the collection to based on the payload (this can add or remove members)
- The following methods collate the results from members