attributable 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8c95938ed6c4f51930505e6e11ec6f210bda51e
4
- data.tar.gz: 338a2ba7e74b833aad96209d33f1a3ea0ee12ade
3
+ metadata.gz: 0ae2deaa3e88ed46bd80f2f96e721c71093f06ca
4
+ data.tar.gz: b0253f219bc607ccb07ac8b9bdedc76a7af16b97
5
5
  SHA512:
6
- metadata.gz: 2a0a0e877474b561c6870b72baa5f10467a819e7dc80f8a28cdfe36cdb84abaa3e6dae836f698010bc6769bfccaec996e66cb4675538db82989e520d12d98b11
7
- data.tar.gz: fb026c2c07406c31dc902af89bad1c81f13a1de92e1d72202a4440e60e8750c657c52af3509c97eeb7871d8a732e56edd77fbffdac37bc486950658d4ae883e8
6
+ metadata.gz: 133f45dda1e6cf016f88811a8d67813743c58e4b4b2873c2aac7c2fedc562576f47be47faeab67860088081847135e709750559d377c65cae9468154fa663ecd
7
+ data.tar.gz: 3b954192277be8bb214c55a953d6fac6475f395295b4eb0bea3b152727cd36773d002cb3af36e5d649d9d49f8e6fe7ca9dd209b14f2a81c2e0aed90a5e964285
data/.rubocop.yml ADDED
@@ -0,0 +1,15 @@
1
+ AllCops:
2
+ Includes:
3
+ - Gemfile
4
+ - Rakefile
5
+ Excludes:
6
+ - vendor/*
7
+
8
+ StringLiterals:
9
+ EnforcedStyle: double_quotes
10
+
11
+ LineLength:
12
+ Max: 99
13
+
14
+ Documentation:
15
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
- ruby '2.0.0'
2
- source 'https://rubygems.org'
1
+ ruby "2.0.0"
2
+ source "https://rubygems.org"
3
3
 
4
4
  # Specify your gem's dependencies in attributable.gemspec
5
5
  gemspec
data/README.md CHANGED
@@ -1,4 +1,4 @@
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)
1
+ # Attributable [![Build Status](https://travis-ci.org/mutiny/attributable.png)](https://travis-ci.org/mutiny/attributable) [![Code Climate](https://codeclimate.com/github/mutiny/attributable.png)](https://codeclimate.com/github/mutiny/attributable) [![Dependency Status](https://gemnasium.com/mutiny/attributable.png)](https://gemnasium.com/mutiny/attributable) [![Coverage Status](https://coveralls.io/repos/mutiny/attributable/badge.png?branch=master)](https://coveralls.io/r/mutiny/attributable?branch=master)
2
2
 
3
3
  A tiny library that makes it easy to create value objects.
4
4
 
@@ -72,6 +72,34 @@ Attributable adds an `inspect` method to your class which display attribute valu
72
72
 
73
73
  john.inspect # => <User forename="John", surname="Doe">
74
74
 
75
+ ## Using with custom initialisation logic
76
+
77
+ Attributable provides the `initialize_attributes` method which can be used if you need to specify your own `initialize` method. For example:
78
+
79
+ require "attributable"
80
+
81
+ class UserWithDerivedAttribute
82
+ extend Attributable
83
+ attributes :forename, :surname
84
+
85
+ attr_accessor :fullname
86
+
87
+ def initialize(attributes = {})
88
+ initialize_attributes(attributes)
89
+ @fullname = "#{forename} #{surname}"
90
+ end
91
+ end
92
+
93
+ john = UserWithDerivedAttribute.new(forename: "John", surname: "Doe")
94
+ john.forename # => "John"
95
+ john.fullname # => "John Doe"
96
+
97
+ Note that, by default, Attributable adds the following `initialize` method:
98
+
99
+ def initialize(attributes = {})
100
+ initialize_attributes(attributes)
101
+ end
102
+
75
103
  ## Specialisation
76
104
 
77
105
  To allow reuse of attribute declarations, Attributable provides the `specialises` class method.
data/Rakefile CHANGED
@@ -1,8 +1,17 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
3
 
4
- task default: "test:unit"
4
+ task default: ["test:unit", "style:check"]
5
5
 
6
6
  namespace :test do
7
7
  RSpec::Core::RakeTask.new(:unit)
8
8
  end
9
+
10
+ namespace :style do
11
+ require "rubocop/rake_task"
12
+
13
+ desc "Run RuboCop on the lib directory"
14
+ Rubocop::RakeTask.new(:check) do |task|
15
+ task.options = ["--auto-correct"]
16
+ end
17
+ end
data/attributable.gemspec CHANGED
@@ -22,4 +22,5 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "rake", "~> 10.1.1"
23
23
  spec.add_development_dependency "rspec", "~> 2.14.1"
24
24
  spec.add_development_dependency "coveralls", "~> 0.7.0"
25
+ spec.add_development_dependency "rubocop", "~> 0.19.1"
25
26
  end
@@ -1,3 +1,3 @@
1
1
  module Attributable
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/attributable.rb CHANGED
@@ -6,19 +6,20 @@ module Attributable
6
6
  @predefined_attributes = @predefined_attributes.merge(from(without_defaults, with_defaults))
7
7
  add_instance_methods(@predefined_attributes)
8
8
  end
9
-
9
+
10
10
  def specialises(clazz)
11
11
  unless clazz.kind_of? Attributable
12
- raise ArgumentError.new("specialisation requires a class that extends Attributable")
12
+ fail ArgumentError, "specialisation requires a class that extends Attributable"
13
13
  end
14
-
14
+
15
15
  super_attributes = clazz.new.instance_variable_get(:@attributes)
16
16
  @predefined_attributes ||= {}
17
17
  @predefined_attributes = super_attributes.merge(@predefined_attributes)
18
18
  add_instance_methods(@predefined_attributes)
19
19
  end
20
20
 
21
- private
21
+ private
22
+
22
23
  # Converts a list of attribute names and a hash of attribute names to default values
23
24
  # to a hash of attribute names to default values
24
25
  def from(without_defaults, with_defaults)
@@ -27,7 +28,7 @@ private
27
28
  with_defaults.each_pair { |name, default| attributes[name] = default }
28
29
  end
29
30
  end
30
-
31
+
31
32
  def add_instance_methods(predefined_attributes)
32
33
  add_constructor(predefined_attributes)
33
34
  add_accessors(predefined_attributes.keys)
@@ -37,6 +38,10 @@ private
37
38
 
38
39
  def add_constructor(predefined_attributes)
39
40
  define_method "initialize" do |attributes = {}|
41
+ initialize_attributes(attributes)
42
+ end
43
+
44
+ define_method "initialize_attributes" do |attributes = {}|
40
45
  @attributes = predefined_attributes.merge(attributes)
41
46
  end
42
47
  end
@@ -52,22 +57,22 @@ private
52
57
  def add_equality_methods(names)
53
58
  define_method "eql?" do |other|
54
59
  other.is_a?(self.class) &&
55
- names.all? { |name| other.send(name.to_sym) == self.send(name.to_sym) }
60
+ names.all? { |name| other.send(name.to_sym) == send(name.to_sym) }
56
61
  end
57
-
62
+
58
63
  alias_method "==", "eql?"
59
-
64
+
60
65
  define_method "hash" do
61
66
  self.class.hash + @attributes.hash
62
67
  end
63
68
  end
64
-
69
+
65
70
  def add_inspect_method(names)
66
71
  define_method "inspect" do
67
72
  values = @attributes.keys
68
- .map { |name| "#{name.to_s}=#{@attributes[name].inspect}" }
73
+ .map { |name| "#{name}=#{@attributes[name].inspect}" }
69
74
  .join(", ")
70
-
75
+
71
76
  "<#{self.class.name} #{values}>"
72
77
  end
73
78
  end
@@ -1,17 +1,20 @@
1
1
  require "attributable"
2
2
 
3
- class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
3
+ class User
4
+ extend Attributable
5
+ attributes :id, :forename, surname: "Bloggs"
6
+ end
4
7
 
5
8
  describe Attributable do
6
9
  describe "accessors" do
7
10
  it "should raise for an unknown attribute" do
8
- i = User.new(id: 1, forename: 'John', surname: 'Doe')
11
+ i = User.new(id: 1, forename: "John", surname: "Doe")
9
12
  expect(i.respond_to?(:address)).to be_false
10
- end
11
-
13
+ end
14
+
12
15
  it "should not have setters" do
13
- i = User.new(forename: 'John')
14
-
16
+ i = User.new(forename: "John")
17
+
15
18
  expect(i.respond_to?(:id=)).to be_false
16
19
  end
17
20
  end
@@ -1,31 +1,56 @@
1
1
  require "attributable"
2
2
 
3
- class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
3
+ class User
4
+ extend Attributable
5
+ attributes :id, :forename, surname: "Bloggs"
6
+ end
7
+
8
+ class UserWithDerivedAttribute
9
+ extend Attributable
10
+ attributes :id, :forename, surname: "Bloggs"
11
+ attr_reader :fullname
12
+
13
+ def initialize(attributes = {})
14
+ initialize_attributes(attributes)
15
+ @fullname = "#{forename} #{surname}"
16
+ end
17
+ end
4
18
 
5
19
  describe Attributable do
6
20
  describe "construction" do
7
21
  it "should accept a hash" do
8
- i = User.new(id: 1, forename: 'John', surname: 'Doe')
9
-
22
+ i = User.new(id: 1, forename: "John", surname: "Doe")
23
+
10
24
  expect(i.id).to eq(1)
11
- expect(i.forename).to eq('John')
12
- expect(i.surname).to eq('Doe')
25
+ expect(i.forename).to eq("John")
26
+ expect(i.surname).to eq("Doe")
13
27
  end
14
28
 
15
29
  it "should set missing attributes to default" do
16
- i = User.new(forename: 'John')
17
-
30
+ i = User.new(forename: "John")
31
+
18
32
  expect(i.id).to be_nil
19
- expect(i.forename).to eq('John')
20
- expect(i.surname).to eq('Bloggs')
33
+ expect(i.forename).to eq("John")
34
+ expect(i.surname).to eq("Bloggs")
21
35
  end
22
-
36
+
23
37
  it "should set missing attributes without defaults to nil" do
24
- i = User.new(surname: 'Doe')
25
-
38
+ i = User.new(surname: "Doe")
39
+
26
40
  expect(i.id).to be_nil
27
41
  expect(i.forename).to be_nil
28
- expect(i.surname).to eq('Doe')
42
+ expect(i.surname).to eq("Doe")
43
+ end
44
+ end
45
+
46
+ describe "constructor" do
47
+ it "should be overridable" do
48
+ i = UserWithDerivedAttribute.new(id: 1, forename: "John", surname: "Doe")
49
+
50
+ expect(i.id).to eq(1)
51
+ expect(i.forename).to eq("John")
52
+ expect(i.surname).to eq("Doe")
53
+ expect(i.fullname).to eq("John Doe")
29
54
  end
30
55
  end
31
56
  end
@@ -1,36 +1,43 @@
1
1
  require "attributable"
2
2
 
3
- class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
4
- class Patient; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
3
+ class User
4
+ extend Attributable
5
+ attributes :id, :forename, surname: "Bloggs"
6
+ end
7
+
8
+ class Patient
9
+ extend Attributable
10
+ attributes :id, :forename, surname: "Bloggs"
11
+ end
5
12
 
6
13
  describe Attributable do
7
14
  describe "equality" do
8
15
  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
-
16
+ i = User.new(id: 1, forename: "John", surname: "Doe")
17
+ j = User.new(id: 1, forename: "John", surname: "Doe")
18
+
12
19
  expect(i).to eql(j)
13
20
  end
14
-
21
+
15
22
  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
-
23
+ i = User.new(id: 1, forename: "John", surname: "Doe")
24
+ j = User.new(id: 1, forename: "John", surname: "Doe")
25
+
19
26
  expect(i).to be == j
20
27
  end
21
-
28
+
22
29
  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
-
30
+ i = User.new(id: 1, forename: "John", surname: "Doe")
31
+ j = User.new(id: 1, forename: "Jane", surname: "Doe")
32
+
26
33
  expect(i).not_to eql(j)
27
34
  expect(i).not_to be == j
28
35
  end
29
-
36
+
30
37
  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
-
38
+ i = User.new(id: 1, forename: "John", surname: "Doe")
39
+ j = Patient.new(id: 1, forename: "John", surname: "Doe")
40
+
34
41
  expect(i).not_to eql(j)
35
42
  expect(i).not_to be == j
36
43
  end
@@ -1,32 +1,39 @@
1
1
  require "attributable"
2
2
 
3
- class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
4
- class Patient; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
3
+ class User
4
+ extend Attributable
5
+ attributes :id, :forename, surname: "Bloggs"
6
+ end
7
+
8
+ class Patient
9
+ extend Attributable
10
+ attributes :id, :forename, surname: "Bloggs"
11
+ end
5
12
 
6
13
  describe Attributable do
7
14
  describe "hash" do
8
15
  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
-
16
+ i = User.new(id: 1, forename: "John", surname: "Doe")
17
+ j = User.new(id: 1, forename: "John", surname: "Doe")
18
+
12
19
  expect(i.hash).to eq(j.hash)
13
20
  end
14
-
21
+
15
22
  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
+ a = User.new(id: 1, forename: "John", surname: "Doe")
24
+ b = User.new(id: nil, forename: "John", surname: "Doe")
25
+ c = User.new(id: 1, forename: nil, surname: "Doe")
26
+ d = User.new(id: 1, forename: "John", surname: nil)
27
+
28
+ hashes = [a, b, c, d].map { |user| user.hash }
29
+
23
30
  expect(hashes.uniq).to eq(hashes)
24
31
  end
25
-
32
+
26
33
  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
-
34
+ u = User.new(id: 1, forename: "John", surname: "Doe")
35
+ p = Patient.new(id: 1, forename: "John", surname: "Doe")
36
+
30
37
  expect(u.hash).not_to eq(p.hash)
31
38
  end
32
39
  end
@@ -1,12 +1,15 @@
1
1
  require "attributable"
2
2
 
3
- class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
3
+ class User
4
+ extend Attributable
5
+ attributes :id, :forename, surname: "Bloggs"
6
+ end
4
7
 
5
8
  describe Attributable do
6
9
  describe "inspect" do
7
10
  it "should emit type and attribute values" do
8
- i = User.new(id: 1, forename: 'John', surname: 'Doe')
9
-
11
+ i = User.new(id: 1, forename: "John", surname: "Doe")
12
+
10
13
  expect(i.inspect).to eq("<User id=1, forename=\"John\", surname=\"Doe\">")
11
14
  end
12
15
  end
@@ -1,6 +1,9 @@
1
1
  require "attributable"
2
2
 
3
- class User; extend Attributable; attributes :id, :forename, surname: "Bloggs" end
3
+ class User
4
+ extend Attributable
5
+ attributes :id, :forename, surname: "Bloggs"
6
+ end
4
7
 
5
8
  describe Attributable do
6
9
  describe "specialisation" do
@@ -11,16 +14,16 @@ describe Attributable do
11
14
  attributes :password, active: true
12
15
  specialises User
13
16
  end
14
-
15
- s = SuperUser.new(id: 1, forename: 'Bob', password: 'secret', active: false)
16
-
17
+
18
+ s = SuperUser.new(id: 1, forename: "Bob", password: "secret", active: false)
19
+
17
20
  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.forename).to eq("Bob")
22
+ expect(s.surname).to eq("Bloggs")
23
+ expect(s.password).to eq("secret")
21
24
  expect(s.active).to be_false
22
25
  end
23
-
26
+
24
27
  it "should be possible to declare specialisation before attributes" do
25
28
  class SuperUser2
26
29
  extend Attributable
@@ -28,49 +31,52 @@ describe Attributable do
28
31
  specialises User
29
32
  attributes :password, active: true
30
33
  end
31
-
32
- s = SuperUser2.new(id: 1, forename: 'Bob', password: 'secret', active: false)
33
-
34
+
35
+ s = SuperUser2.new(id: 1, forename: "Bob", password: "secret", active: false)
36
+
34
37
  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.forename).to eq("Bob")
39
+ expect(s.surname).to eq("Bloggs")
40
+ expect(s.password).to eq("secret")
38
41
  expect(s.active).to be_false
39
42
  end
40
-
41
- it "should ensure that local attributes have greater precedence than specialised attributes" do
43
+
44
+ it "should ensure that local attributes precede specialised attributes" do
42
45
  class SuperUser3
43
46
  extend Attributable
44
47
 
45
48
  specialises User
46
- attributes surname: 'Smith'
49
+ attributes surname: "Smith"
47
50
  end
48
-
51
+
49
52
  s = SuperUser3.new
50
-
51
- expect(s.surname).to eq('Smith')
53
+
54
+ expect(s.surname).to eq("Smith")
52
55
  end
53
-
54
- it "should ensure that local attributes have greater precedence than specialised attributes, even if specialisation is declared after local attributes" do
56
+
57
+ it "should ensure that position of specialises does not affect precedence" do
55
58
  class SuperUser4
56
59
  extend Attributable
57
60
 
58
- attributes surname: 'Smith'
61
+ attributes surname: "Smith"
59
62
  specialises User
60
63
  end
61
-
64
+
62
65
  s = SuperUser4.new
63
-
64
- expect(s.surname).to eq('Smith')
66
+
67
+ expect(s.surname).to eq("Smith")
65
68
  end
66
-
69
+
67
70
  it "should raise if specialising class is not an instance of Attributable" do
68
71
  expect do
69
72
  class SuperUser5
70
73
  extend Attributable
71
74
  specialises String
72
75
  end
73
- end.to raise_error(ArgumentError, "specialisation requires a class that extends Attributable")
76
+ end.to raise_error(
77
+ ArgumentError,
78
+ "specialisation requires a class that extends Attributable"
79
+ )
74
80
  end
75
81
  end
76
82
  end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'coveralls'
1
+ require "coveralls"
2
2
  Coveralls.wear!
3
3
 
4
4
  # This file was generated by the `rspec --init` command. Conventionally, all
@@ -16,12 +16,12 @@ RSpec.configure do |config|
16
16
  # order dependency and want to debug it, you can fix the order by providing
17
17
  # the seed, which is printed after each run.
18
18
  # --seed 1234
19
- config.order = 'random'
20
-
19
+ config.order = "random"
20
+
21
21
  config.expect_with :rspec do |c|
22
22
  # Disable old "should" syntax for expressions
23
23
  c.syntax = :expect
24
24
  end
25
-
25
+
26
26
  config.treat_symbols_as_metadata_keys_with_true_values = true # Prepare for RSpec 3
27
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attributable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Louis Rose
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-24 00:00:00.000000000 Z
11
+ date: 2014-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.7.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.19.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.19.1
69
83
  description: Provides a Ruby module that can be extended by a class in order to provide
70
84
  class methods for defining attributes. Attributable automatically generates accessor,
71
85
  equality, hash and inspect methods.
@@ -77,6 +91,8 @@ extra_rdoc_files: []
77
91
  files:
78
92
  - .gitignore
79
93
  - .rspec
94
+ - .rubocop.yml
95
+ - .travis.yml
80
96
  - Gemfile
81
97
  - LICENSE.txt
82
98
  - README.md
@@ -111,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
127
  version: '0'
112
128
  requirements: []
113
129
  rubyforge_project:
114
- rubygems_version: 2.2.2
130
+ rubygems_version: 2.0.3
115
131
  signing_key:
116
132
  specification_version: 4
117
133
  summary: A tiny library that makes it easy to create value objects