Skip to content

robertlude/holotype

Repository files navigation

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'

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages