Project

holotype

0.0
No release in over 3 years
Low commit activity in last 3 years
Simple models
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 3.0
~> 11.0
~> 3.9.0

Runtime

 Project Readme

Holotype

Build Status

hol·o·type

noun (BOTANY ZOOLOGY)

a single type specimen upon which the description and name of a new species is based.

Simply simple models

This is a pre-release version!

It should work as advertised generally. There are a couple small issues left to tackle as I move toward v1.0.0:

  • Finishing the documentation
  • Fixing a small bug where an incorrect-but-related error is raised instead of the intended error which is more descriptive
  • Finish verifying the readme examples
  • Final scan for TODOs

If you encounter anything unrelated to the above, please file an issue.

Usage

Extend Holotype to create a model.

class Example
  extend Holotype

  attribute :my_first_attribute
end

example = Example.new my_first_attribute: 'some value'

puts "My first attribute's value: #{example.my_first_attribute}"

Output:

My first attribute's value: some value

Attribute Options

Option Description Default
collection_class Specifies the class to use for the collection Array Examples
collection Specifies whether or not the attribute is a collection false Examples
default Specifies a static value to use as a default for the value none Examples
read_only Specifies whether or not the attribute is read only false Examples
required Specifies whether or not the attribute is required during initialization false Examples
value_class Specifies the class to use for the value none Examples
(given block) Specifies a block to use for dynamic default assignment none Examples

Collections

Use options collection and collection_class to control how collections are handled. Note that providing a collection_class automatically sets collection: true.

class CollectionExample
  extend Holotype

  attribute :an_array_collection,
            collection: true

  attribute :a_set_collection,
            collection_class: Set

  attribute :a_hash_collection,
            collection_class: Hash
end

no_initial_value_example = CollectionExample.new
initial_value_example    = CollectionExample.new(
                             an_array_collection: [1, 2, 2, 3, 3, 3],
                           )
set_value_example        = CollectionExample.new(
                             a_set_collection: [1, 2, 2, 3, 3, 3],
                           )
hash_value_example       = CollectionExample.new(
                             a_hash_collection: Hash[a: 1, b: 2, c: 3],
                           )

puts "no_initial_value_example.an_array_collection.inspect:"
puts "  #{no_initial_value_example.an_array_collection.inspect}"
puts
puts "initial_value_example.an_array_collection.inspect:"
puts "  #{initial_value_example.an_array_collection.inspect}"
puts
puts "set_value_example.a_set_collection.inspect:"
puts "  #{set_value_example.a_set_collection.inspect}"
puts
puts "hash_value_example.a_hash_collection.inspect:"
puts "  #{hash_value_example.a_hash_collection.inspect}"

Output:

no_initial_value_example.an_array_collection.inspect:
  []

initial_value_example.an_array_collection.inspect:
  [1, 2, 2, 3, 3, 3]

set_value_example.a_set_collection.inspect:
  #<Set: {1, 2, 3}>

hash_value_example.a_hash_collection.inspect:
  {:a=>1, :b=>2, :c=>3}

Defaults

Use option default or provide a block to create default values. There is a difference between default and providing a block, however.

Providing option default will use the same instance of that value for the default of each object. This is handy for static values. It should be noted, however, that because it is the same instance for every object, that modifications to the value object itself will apply to every object using that default.

Providing a block will defer until the first time the option is accessed or serialized, and will run in the context of the object itself. This is handy for calculating values based on other attributes or even simply creating unique instances of default values. These default blocks are run only once.

Providing both a default option and a block will result in an error.

Providing either type of default and a required option also result in an error.

class DefaultExample
  extend Holotype

  attribute :static_default,
            default: 1234

  attribute(:dynamic_default) { static_default * 2 }
end

example = DefaultExample.new

puts "example.static_default  = #{example.static_default}"
puts "example.dynamic_default = #{example.dynamic_default}"

Output:

example.static_default  = 1234
example.dynamic_default = 2468

Read Only Attributes

Use option read_only: true to prevent changing the value of an attribute.

class ReadOnlyExample
  extend Holotype

  attribute :read_only_attribute,
            read_only: true
end

write_error_example = ReadOnlyExample.new read_only_attribute: 123

begin
  write_error_example.read_only_attribute = 456
rescue Holotype::Attribute::ReadOnlyError => error
  puts "Read only error: #{error.message}"
end

Immutable Objects

class ImmutableExampleChild
  extend Holotype

  attribute :some_attribute
end

class ImmutableExample
  extend Holotype

  make_immutable

  attribute :basic_attribute

  attribute :collection_attribute,
            collection: true

  attribute :child_attribute,
            value_class: ImmutableExampleChild
end

immutable_example = ImmutableExample.new(
                      basic_attribute:      123,
                      child_attribute:      Hash[some_attribute: 'hello'],
                      collection_attribute: %i[x y z]
                    )

immutable_example.basic_attribute = 456

immutable_example.collection_attribute << :w

immutable_example.child_attribute.some_attribute = 'goodbye'