attributable 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e8c95938ed6c4f51930505e6e11ec6f210bda51e
4
+ data.tar.gz: 338a2ba7e74b833aad96209d33f1a3ea0ee12ade
5
+ SHA512:
6
+ metadata.gz: 2a0a0e877474b561c6870b72baa5f10467a819e7dc80f8a28cdfe36cdb84abaa3e6dae836f698010bc6769bfccaec996e66cb4675538db82989e520d12d98b11
7
+ data.tar.gz: fb026c2c07406c31dc902af89bad1c81f13a1de92e1d72202a4440e60e8750c657c52af3509c97eeb7871d8a732e56edd77fbffdac37bc486950658d4ae883e8
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format progress
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ ruby '2.0.0'
2
+ source 'https://rubygems.org'
3
+
4
+ # Specify your gem's dependencies in attributable.gemspec
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Louis Rose
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # Attributable [![Build Status](https://travis-ci.org/louismrose/mutiny.png?branch=master)](https://travis-ci.org/louismrose/mutiny) [![Code Climate](https://codeclimate.com/github/louismrose/mutiny.png)](https://codeclimate.com/github/louismrose/mutiny) [![Dependency Status](https://gemnasium.com/louismrose/mutiny.png)](https://gemnasium.com/louismrose/mutiny) [![Coverage Status](https://coveralls.io/repos/louismrose/mutiny/badge.png?branch=master)](https://coveralls.io/r/louismrose/mutiny?branch=master)
2
+
3
+ A tiny library that makes it easy to create value objects.
4
+
5
+ ## Basic usage
6
+
7
+ require "attributable"
8
+
9
+ class User
10
+ extend Attributable
11
+
12
+ attributes :forename, :surname
13
+ end
14
+
15
+ john = User.new(forename: "John", surname: "Doe")
16
+ john.forename # => "John"
17
+ john.surname # => "Doe"
18
+
19
+ All attributes are read-only:
20
+
21
+ john.forename = "Jonathan" # => NoMethodError: undefined method `forename='
22
+
23
+ Default values for attributes can be set via a hash argument to `attributes`:
24
+
25
+ class UserWithDefaults
26
+ extend Attributable
27
+
28
+ attributes :forename, :surname, active: true
29
+ end
30
+
31
+ anon = UserWithDefaults.new
32
+ anon.active # => true
33
+ anon.forename # => nil
34
+
35
+ ## Equality
36
+
37
+ Attributable adds `eql?` and `==` methods to your class which compare attribute values and types.
38
+
39
+ john = User.new(forename: "John", surname: "Doe")
40
+ second_john = User.new(forename: "John", surname: "Doe")
41
+
42
+ john.eql? second_john # => true
43
+ john == second_john # => true
44
+
45
+ The equality methods return false when compared to an object of the same type with different attribute values:
46
+
47
+ jane = User.new(forename: "Jane", surname: "Doe")
48
+ john.eql? jane # => false
49
+ john == jane # => false
50
+
51
+ The equality methods return false when compared to an object of a different type, even if the attribute values are equal.
52
+
53
+ class Admin
54
+ extend Attributable
55
+
56
+ attributes :forename, :surname
57
+ end
58
+
59
+ admin_john = Admin.new(forename: "Jane", surname: "Doe")
60
+ john.eql? admin_john # => false
61
+ john == admin_john # => false
62
+
63
+ Because Attributable overrides `eql?` and `==`, it also overrides `hash`:
64
+
65
+ john.hash == second_john.hash # => true
66
+ john.hash == jane.hash # => false
67
+ john.hash == admin_john.hash # => false
68
+
69
+ ## Pretty printing
70
+
71
+ Attributable adds an `inspect` method to your class which display attribute values.
72
+
73
+ john.inspect # => <User forename="John", surname="Doe">
74
+
75
+ ## Specialisation
76
+
77
+ To allow reuse of attribute declarations, Attributable provides the `specialises` class method.
78
+
79
+ class Author
80
+ extend Attributable
81
+
82
+ specialises User
83
+ attributes blogs: []
84
+ end
85
+
86
+ ronson = Author.new(forename: "Jon", surname: "Ronson")
87
+ ronson.inspect # => <Author forename="Jon", surname="Ronson", blogs=[]>
88
+
89
+ Specialising classes can override the defaults set in specialised classes.
90
+
91
+ class Ronson
92
+ extend Attributable
93
+
94
+ specialises User
95
+ attributes surname: "Ronson"
96
+ end
97
+
98
+ Ronson.new(forename: "Jon").inspect # <Ronson forename="Jon", surname="Ronson">
99
+ Ronson.new(forename: "Mark").inspect # <Ronson forename="Mark", surname="Ronson">
100
+
101
+ ## Installation
102
+
103
+ Add this line to your application's Gemfile:
104
+
105
+ gem 'attributable'
106
+
107
+ And then execute:
108
+
109
+ $ bundle
110
+
111
+ Or install it yourself as:
112
+
113
+ $ gem install attributable
114
+
115
+ ## Contributing
116
+
117
+ 1. Fork it
118
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
119
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
120
+ 4. Push to the branch (`git push origin my-new-feature`)
121
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ task default: "test:unit"
5
+
6
+ namespace :test do
7
+ RSpec::Core::RakeTask.new(:unit)
8
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'attributable/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "attributable"
8
+ spec.version = Attributable::VERSION
9
+ spec.authors = ["Louis Rose"]
10
+ spec.email = ["louis.rose@york.ac.uk"]
11
+ spec.description = %q{Provides a Ruby module that can be extended by a class in order to provide class methods for defining attributes. Attributable automatically generates accessor, equality, hash and inspect methods.}
12
+ spec.summary = %q{A tiny library that makes it easy to create value objects}
13
+ spec.homepage = "https://github.com/mutiny/attributable"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake", "~> 10.1.1"
23
+ spec.add_development_dependency "rspec", "~> 2.14.1"
24
+ spec.add_development_dependency "coveralls", "~> 0.7.0"
25
+ end
@@ -0,0 +1,74 @@
1
+ require "attributable/version"
2
+
3
+ module Attributable
4
+ def attributes(*without_defaults, **with_defaults)
5
+ @predefined_attributes ||= {}
6
+ @predefined_attributes = @predefined_attributes.merge(from(without_defaults, with_defaults))
7
+ add_instance_methods(@predefined_attributes)
8
+ end
9
+
10
+ def specialises(clazz)
11
+ unless clazz.kind_of? Attributable
12
+ raise ArgumentError.new("specialisation requires a class that extends Attributable")
13
+ end
14
+
15
+ super_attributes = clazz.new.instance_variable_get(:@attributes)
16
+ @predefined_attributes ||= {}
17
+ @predefined_attributes = super_attributes.merge(@predefined_attributes)
18
+ add_instance_methods(@predefined_attributes)
19
+ end
20
+
21
+ private
22
+ # Converts a list of attribute names and a hash of attribute names to default values
23
+ # to a hash of attribute names to default values
24
+ def from(without_defaults, with_defaults)
25
+ {}.tap do |attributes|
26
+ without_defaults.each { |name| attributes[name] = nil }
27
+ with_defaults.each_pair { |name, default| attributes[name] = default }
28
+ end
29
+ end
30
+
31
+ def add_instance_methods(predefined_attributes)
32
+ add_constructor(predefined_attributes)
33
+ add_accessors(predefined_attributes.keys)
34
+ add_equality_methods(predefined_attributes.keys)
35
+ add_inspect_method(predefined_attributes.keys)
36
+ end
37
+
38
+ def add_constructor(predefined_attributes)
39
+ define_method "initialize" do |attributes = {}|
40
+ @attributes = predefined_attributes.merge(attributes)
41
+ end
42
+ end
43
+
44
+ def add_accessors(names)
45
+ names.each do |name|
46
+ define_method "#{name}" do
47
+ @attributes[name.to_sym]
48
+ end
49
+ end
50
+ end
51
+
52
+ def add_equality_methods(names)
53
+ define_method "eql?" do |other|
54
+ other.is_a?(self.class) &&
55
+ names.all? { |name| other.send(name.to_sym) == self.send(name.to_sym) }
56
+ end
57
+
58
+ alias_method "==", "eql?"
59
+
60
+ define_method "hash" do
61
+ self.class.hash + @attributes.hash
62
+ end
63
+ end
64
+
65
+ def add_inspect_method(names)
66
+ define_method "inspect" do
67
+ values = @attributes.keys
68
+ .map { |name| "#{name.to_s}=#{@attributes[name].inspect}" }
69
+ .join(", ")
70
+
71
+ "<#{self.class.name} #{values}>"
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,3 @@
1
+ module Attributable
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,18 @@
1
+ require "attributable"
2
+
3
+ class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
4
+
5
+ describe Attributable do
6
+ describe "accessors" do
7
+ it "should raise for an unknown attribute" do
8
+ i = User.new(id: 1, forename: 'John', surname: 'Doe')
9
+ expect(i.respond_to?(:address)).to be_false
10
+ end
11
+
12
+ it "should not have setters" do
13
+ i = User.new(forename: 'John')
14
+
15
+ expect(i.respond_to?(:id=)).to be_false
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ require "attributable"
2
+
3
+ class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
4
+
5
+ describe Attributable do
6
+ describe "construction" do
7
+ it "should accept a hash" do
8
+ i = User.new(id: 1, forename: 'John', surname: 'Doe')
9
+
10
+ expect(i.id).to eq(1)
11
+ expect(i.forename).to eq('John')
12
+ expect(i.surname).to eq('Doe')
13
+ end
14
+
15
+ it "should set missing attributes to default" do
16
+ i = User.new(forename: 'John')
17
+
18
+ expect(i.id).to be_nil
19
+ expect(i.forename).to eq('John')
20
+ expect(i.surname).to eq('Bloggs')
21
+ end
22
+
23
+ it "should set missing attributes without defaults to nil" do
24
+ i = User.new(surname: 'Doe')
25
+
26
+ expect(i.id).to be_nil
27
+ expect(i.forename).to be_nil
28
+ expect(i.surname).to eq('Doe')
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ require "attributable"
2
+
3
+ class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
4
+ class Patient; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
5
+
6
+ describe Attributable do
7
+ describe "equality" do
8
+ it "should provide a working eql? method" do
9
+ i = User.new(id: 1, forename: 'John', surname: 'Doe')
10
+ j = User.new(id: 1, forename: 'John', surname: 'Doe')
11
+
12
+ expect(i).to eql(j)
13
+ end
14
+
15
+ it "should provide a working == method" do
16
+ i = User.new(id: 1, forename: 'John', surname: 'Doe')
17
+ j = User.new(id: 1, forename: 'John', surname: 'Doe')
18
+
19
+ expect(i).to be == j
20
+ end
21
+
22
+ it "should distinguish between objects with different attribute values" do
23
+ i = User.new(id: 1, forename: 'John', surname: 'Doe')
24
+ j = User.new(id: 1, forename: 'Jane', surname: 'Doe')
25
+
26
+ expect(i).not_to eql(j)
27
+ expect(i).not_to be == j
28
+ end
29
+
30
+ it "should distinguish between objects with different types and same attribute values" do
31
+ i = User.new(id: 1, forename: 'John', surname: 'Doe')
32
+ j = Patient.new(id: 1, forename: 'John', surname: 'Doe')
33
+
34
+ expect(i).not_to eql(j)
35
+ expect(i).not_to be == j
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,33 @@
1
+ require "attributable"
2
+
3
+ class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
4
+ class Patient; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
5
+
6
+ describe Attributable do
7
+ describe "hash" do
8
+ it "should ensure that objects with the same attribute values have the same hash" do
9
+ i = User.new(id: 1, forename: 'John', surname: 'Doe')
10
+ j = User.new(id: 1, forename: 'John', surname: 'Doe')
11
+
12
+ expect(i.hash).to eq(j.hash)
13
+ end
14
+
15
+ it "should ensure that objects with different attribute values have different hashes" do
16
+ a = User.new(id: 1, forename: 'John', surname: 'Doe')
17
+ b = User.new(id: nil, forename: 'John', surname: 'Doe')
18
+ c = User.new(id: 1, forename: nil, surname: 'Doe')
19
+ d = User.new(id: 1, forename: 'John', surname: nil)
20
+
21
+ hashes = [a,b,c,d].map { |user| user.hash }
22
+
23
+ expect(hashes.uniq).to eq(hashes)
24
+ end
25
+
26
+ it "should ensure that objects of different types different hashes" do
27
+ u = User.new(id: 1, forename: 'John', surname: 'Doe')
28
+ p = Patient.new(id: 1, forename: 'John', surname: 'Doe')
29
+
30
+ expect(u.hash).not_to eq(p.hash)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ require "attributable"
2
+
3
+ class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
4
+
5
+ describe Attributable do
6
+ describe "inspect" do
7
+ it "should emit type and attribute values" do
8
+ i = User.new(id: 1, forename: 'John', surname: 'Doe')
9
+
10
+ expect(i.inspect).to eq("<User id=1, forename=\"John\", surname=\"Doe\">")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,76 @@
1
+ require "attributable"
2
+
3
+ class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
4
+
5
+ describe Attributable do
6
+ describe "specialisation" do
7
+ it "should pull in attributes from specified class" do
8
+ class SuperUser
9
+ extend Attributable
10
+
11
+ attributes :password, active: true
12
+ specialises User
13
+ end
14
+
15
+ s = SuperUser.new(id: 1, forename: 'Bob', password: 'secret', active: false)
16
+
17
+ expect(s.id).to eq(1)
18
+ expect(s.forename).to eq('Bob')
19
+ expect(s.surname).to eq('Bloggs')
20
+ expect(s.password).to eq('secret')
21
+ expect(s.active).to be_false
22
+ end
23
+
24
+ it "should be possible to declare specialisation before attributes" do
25
+ class SuperUser2
26
+ extend Attributable
27
+
28
+ specialises User
29
+ attributes :password, active: true
30
+ end
31
+
32
+ s = SuperUser2.new(id: 1, forename: 'Bob', password: 'secret', active: false)
33
+
34
+ expect(s.id).to eq(1)
35
+ expect(s.forename).to eq('Bob')
36
+ expect(s.surname).to eq('Bloggs')
37
+ expect(s.password).to eq('secret')
38
+ expect(s.active).to be_false
39
+ end
40
+
41
+ it "should ensure that local attributes have greater precedence than specialised attributes" do
42
+ class SuperUser3
43
+ extend Attributable
44
+
45
+ specialises User
46
+ attributes surname: 'Smith'
47
+ end
48
+
49
+ s = SuperUser3.new
50
+
51
+ expect(s.surname).to eq('Smith')
52
+ end
53
+
54
+ it "should ensure that local attributes have greater precedence than specialised attributes, even if specialisation is declared after local attributes" do
55
+ class SuperUser4
56
+ extend Attributable
57
+
58
+ attributes surname: 'Smith'
59
+ specialises User
60
+ end
61
+
62
+ s = SuperUser4.new
63
+
64
+ expect(s.surname).to eq('Smith')
65
+ end
66
+
67
+ it "should raise if specialising class is not an instance of Attributable" do
68
+ expect do
69
+ class SuperUser5
70
+ extend Attributable
71
+ specialises String
72
+ end
73
+ end.to raise_error(ArgumentError, "specialisation requires a class that extends Attributable")
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,27 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ # This file was generated by the `rspec --init` command. Conventionally, all
5
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
6
+ # Require this file using `require "spec_helper"` to ensure that it is only
7
+ # loaded once.
8
+ #
9
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+
15
+ # Run specs in random order to surface order dependencies. If you find an
16
+ # order dependency and want to debug it, you can fix the order by providing
17
+ # the seed, which is printed after each run.
18
+ # --seed 1234
19
+ config.order = 'random'
20
+
21
+ config.expect_with :rspec do |c|
22
+ # Disable old "should" syntax for expressions
23
+ c.syntax = :expect
24
+ end
25
+
26
+ config.treat_symbols_as_metadata_keys_with_true_values = true # Prepare for RSpec 3
27
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attributable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Louis Rose
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 10.1.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 10.1.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 2.14.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.14.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: coveralls
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.7.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.7.0
69
+ description: Provides a Ruby module that can be extended by a class in order to provide
70
+ class methods for defining attributes. Attributable automatically generates accessor,
71
+ equality, hash and inspect methods.
72
+ email:
73
+ - louis.rose@york.ac.uk
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - .gitignore
79
+ - .rspec
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - attributable.gemspec
85
+ - lib/attributable.rb
86
+ - lib/attributable/version.rb
87
+ - spec/attributable/accessors_spec.rb
88
+ - spec/attributable/construction_spec.rb
89
+ - spec/attributable/equality_spec.rb
90
+ - spec/attributable/hash_spec.rb
91
+ - spec/attributable/inspect_spec.rb
92
+ - spec/attributable/specialisation_spec.rb
93
+ - spec/spec_helper.rb
94
+ homepage: https://github.com/mutiny/attributable
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.2.2
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: A tiny library that makes it easy to create value objects
118
+ test_files:
119
+ - spec/attributable/accessors_spec.rb
120
+ - spec/attributable/construction_spec.rb
121
+ - spec/attributable/equality_spec.rb
122
+ - spec/attributable/hash_spec.rb
123
+ - spec/attributable/inspect_spec.rb
124
+ - spec/attributable/specialisation_spec.rb
125
+ - spec/spec_helper.rb