This is a small library that helps increase the pliability of object constructor signatures. Instead of instantiating via the constructor, this library can install helper factory class-level methods that you can use with hashes:
- make(): create a single instance of a class
- array(): create an array of instances of a class
One caveat to this library is that it is not meant to be a complete modeling solution but rather just a tool that helps model a domain or complete a modeling framework. The main missing element to this library is that you still have to manage and implement constructors. The two class-level factory methods are just meant to create a syntactic hash-like interface.
To install through Rubygems:
gem install acts_as_hashable
You can also add this to your Gemfile:
bundle add acts_as_hashable
Consider the following example:
class Person
acts_as_hashable
attr_reader :name, :age
def initialize(name:, age:)
@name = name
@age = age
end
end
class HeadOfHousehold
acts_as_hashable
attr_reader :person, :partner
def initialize(person:, partner: nil)
@person = Person.make(person)
@partner = Person.make(partner)
end
end
class Family
acts_as_hashable
attr_reader :head_of_household, :children
def initialize(head_of_household:, children: [])
@head_of_household = HeadOfHousehold.make(head_of_household)
@children = Person.array(children)
end
end
Simply placing:
acts_as_hashable
on a class means it will have the two main factory methods available for you to use. Then, you can leverage these for instantiation:
family = {
head_of_household: {
person: {
name: 'Matt',
age: 109,
},
partner: {
name: 'Katie',
age: 110,
}
},
children: [
{ name: 'Martin', age: 29 },
{ name: 'Short', age: 99 },
]
}
family_obj = Family.make(family)
The family_obj will then be a fully hydrated Family instance. The family instance attributes will also be fully hydrated since its constructor also uses acts_as_hashable.
Note that this works nicely with either keyword arguments or a hash-based argument constructor like so:
class Toy
acts_as_hashable
attr_reader :squishy
def initialize(opts = {})
@squishy = opts[:squishy] || false
end
end
class Pet
acts_as_hashable
attr_reader :name, :toy
def initialize(opts = {})
@name = opts[:name]
@toy = Toy.make(opts[:toy])
end
end
More complex relationships may contain objects with disparate types. In this case we can use the included factory pattern to help us build these. Based on our examples above:
class ExampleFactory
acts_as_hashable_factory
register 'Pet', Pet
register 'HeadOfHousehold', HeadOfHousehold
end
Now we can dynamically build these using:
objects = [
{
type: 'Pet',
name: 'Doug the dog',
toy: { squishy: true }
},
{
type: 'HeadOfHousehold',
person: {
name: 'Matt',
age: 109
},
partner: {
name: 'Katie',
age: 110
}
}
]
hydrated_objects = ExampleFactory.array(objects)
If the type key does not happen to be type
then you can explicitly set this as:
class ExampleFactory
acts_as_hashable_factory
type_key 'object_type'
register 'Pet', Pet
register 'HeadOfHousehold', HeadOfHousehold
end
You can also choose to pass in a proc/lambda instead of a class constant:
class ExampleFactory
acts_as_hashable_factory
type_key 'object_type'
register 'Pet', Pet
register 'HeadOfHousehold', ->(_key) { HeadOfHousehold }
end
In case you need full control of the registry you can also choose to simply override the class-level registry
method which will simply return a hash of keys (names) and values (class constants).
Factories can also be resolved using Ruby's Object#const_get and Object#const_missing. Simply register a string representing the class in order to use these mechanics, such as:
class ExampleFactory
acts_as_hashable_factory
type_key 'object_type'
register 'Pet', 'Pet'
register 'HeadOfHousehold', ->(_key) { HeadOfHousehold }
end
Basic steps to take to get this repository compiling:
- I 78F4 nstall Ruby (check acts_as_hashable.gemspec for versions supported)
- Install bundler (gem install bundler)
- Clone the repository (git clone git@github.com:bluemarblepayroll/acts_as_hashable.git)
- Navigate to the root folder (cd acts_as_hashable)
- Install dependencies (bundle)
To execute the test suite run:
bundle exec rspec spec --format documentation
Alternatively, you can have Guard watch for changes:
bundle exec guard
Also, do not forget to run Rubocop:
bundle exec rubocop
Note: ensure you have proper authorization before trying to publish new versions.
After code changes have successfully gone through the Pull Request review process then the following steps should be followed for publishing new versions:
- Merge Pull Request into master
- Update
lib/acts_as_hashable/version.rb
using semantic versioning - Install dependencies:
bundle
- Update
CHANGELOG.md
with release notes - Commit & push master to remote and ensure CI builds master successfully
- Run
bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the.gem
file to rubygems.org.
Everyone interacting in this codebase, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
This project is MIT Licensed.