values 1.4.0 → 1.5.0
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.
- data/README.md +13 -5
- data/VERSION +1 -1
- data/lib/values.rb +16 -22
- data/spec/values_spec.rb +25 -20
- data/values.gemspec +2 -2
- metadata +4 -4
data/README.md
CHANGED
@@ -4,7 +4,7 @@ These mostly look like classes created using Struct, but fix two problems with t
|
|
4
4
|
Struct constructors can take less than the default number of arguments and set other fields as nil:
|
5
5
|
|
6
6
|
```ruby
|
7
|
-
Point = Struct.new(:x
|
7
|
+
Point = Struct.new(:x, :y)
|
8
8
|
Point.new(1)
|
9
9
|
# => #<struct Point x=1, y=nil>
|
10
10
|
```
|
@@ -12,8 +12,8 @@ Point.new(1)
|
|
12
12
|
Structs are also mutable:
|
13
13
|
|
14
14
|
```ruby
|
15
|
-
Point = Struct.new(:x
|
16
|
-
p = Point.new(1,2)
|
15
|
+
Point = Struct.new(:x, :y)
|
16
|
+
p = Point.new(1, 2)
|
17
17
|
p.x = 2
|
18
18
|
p.x
|
19
19
|
# => 2
|
@@ -30,11 +30,19 @@ Point.new(1)
|
|
30
30
|
# from (irb):5
|
31
31
|
# from /usr/local/bin/irb:12:in `<main>
|
32
32
|
|
33
|
-
p = Point.new(1,2)
|
33
|
+
p = Point.new(1, 2)
|
34
34
|
p.x = 1
|
35
35
|
# => NoMethodError: undefined method x= for #<Point:0x00000100943788 @x=0, @y=1>
|
36
36
|
# from (irb):6
|
37
37
|
# from /usr/local/bin/irb:12:in <main>
|
38
38
|
```
|
39
39
|
|
40
|
-
|
40
|
+
Values also provides an alternative constructor which takes a hash:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
p = Point.with(x: 3, y: 4)
|
44
|
+
p.x
|
45
|
+
# => 3
|
46
|
+
```
|
47
|
+
|
48
|
+
Values does NOT have all the features of Struct (nor is it meant to).
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.5.0
|
data/lib/values.rb
CHANGED
@@ -1,49 +1,43 @@
|
|
1
1
|
class Value
|
2
2
|
def self.new(*fields)
|
3
|
-
|
3
|
+
Class.new do
|
4
4
|
attr_reader *fields
|
5
5
|
|
6
|
-
define_method(:initialize) do |*
|
7
|
-
raise ArgumentError.new("wrong number of arguments, #{
|
6
|
+
define_method(:initialize) do |*values|
|
7
|
+
raise ArgumentError.new("wrong number of arguments, #{values.size} for #{fields.size}") if fields.size != values.size
|
8
8
|
|
9
|
-
fields.
|
10
|
-
instance_variable_set(
|
9
|
+
fields.zip(values) do |field, value|
|
10
|
+
instance_variable_set(:"@#{field}", value)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
|
+
freeze
|
13
14
|
end
|
14
15
|
|
15
16
|
const_set :VALUE_ATTRS, fields
|
16
17
|
|
17
18
|
def self.with(hash)
|
18
|
-
args = []
|
19
|
-
self::VALUE_ATTRS.each do |field|
|
20
|
-
args << hash.fetch(field)
|
21
|
-
end
|
22
|
-
|
23
19
|
unexpected_keys = hash.keys - self::VALUE_ATTRS
|
24
20
|
if unexpected_keys.any?
|
25
21
|
raise ArgumentError.new("Unexpected hash keys: #{unexpected_keys}")
|
26
22
|
end
|
27
|
-
|
23
|
+
|
24
|
+
new(*hash.values_at(*self::VALUE_ATTRS))
|
28
25
|
end
|
29
26
|
|
30
27
|
def ==(other)
|
31
|
-
|
28
|
+
eql?(other)
|
32
29
|
end
|
33
30
|
|
34
31
|
def eql?(other)
|
35
|
-
|
36
|
-
self.class::VALUE_ATTRS.all? do |field|
|
37
|
-
self.send(field) == other.send(field)
|
38
|
-
end
|
32
|
+
self.class == other.class && values == other.values
|
39
33
|
end
|
40
34
|
|
41
35
|
def hash
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
36
|
+
values.map(&:hash).inject(0, :+) + self.class.hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def values
|
40
|
+
self.class::VALUE_ATTRS.map { |field| send(field) }
|
47
41
|
end
|
48
42
|
end
|
49
43
|
end
|
data/spec/values_spec.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../lib/values')
|
2
2
|
describe 'values' do
|
3
|
+
Cell = Value.new(:alive)
|
4
|
+
|
3
5
|
it 'stores a single field' do
|
4
|
-
Cell = Value.new(:alive)
|
5
6
|
c = Cell.new(true)
|
6
7
|
c.alive.should == true
|
7
8
|
end
|
8
9
|
|
9
10
|
Point = Value.new(:x, :y)
|
11
|
+
|
10
12
|
it 'stores multiple values' do
|
11
13
|
p = Point.new(0,1)
|
12
14
|
p.x.should == 0
|
@@ -14,65 +16,62 @@ describe 'values' do
|
|
14
16
|
end
|
15
17
|
|
16
18
|
it 'raises argument errors if not given the right number of arguments' do
|
17
|
-
|
19
|
+
expect { Point.new }.to raise_error(ArgumentError, 'wrong number of arguments, 0 for 2')
|
18
20
|
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
"GraphPoint at #{@x},#{@y}"
|
24
|
-
end
|
22
|
+
class GraphPoint < Value.new(:x, :y)
|
23
|
+
def inspect
|
24
|
+
"GraphPoint at #{@x},#{@y}"
|
25
25
|
end
|
26
|
+
end
|
26
27
|
|
28
|
+
it 'can be inherited from to add methods' do
|
27
29
|
c = GraphPoint.new(0,0)
|
28
30
|
c.inspect.should == 'GraphPoint at 0,0'
|
29
31
|
end
|
30
32
|
|
31
33
|
it 'cannot be mutated' do
|
32
34
|
p = Point.new(0,1)
|
33
|
-
|
35
|
+
expect { p.x = 1 }.to raise_error
|
34
36
|
end
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
@color = new_color
|
40
|
-
end
|
38
|
+
class Cow < Value.new(:color)
|
39
|
+
def change_color(new_color)
|
40
|
+
@color = new_color
|
41
41
|
end
|
42
|
+
end
|
42
43
|
|
44
|
+
it 'cannot even be mutated inside a sublass with methods' do
|
43
45
|
c = Cow.new("red")
|
44
|
-
|
46
|
+
expect { c.change_color("blue") }.to raise_error
|
45
47
|
end
|
46
48
|
|
49
|
+
Money = Value.new(:amount, :denomination)
|
50
|
+
|
47
51
|
it 'cannot be mutated using #instance_variable_set' do
|
48
|
-
Money = Value.new(:amount, :denomination)
|
49
52
|
m = Money.new(1, 'USD')
|
50
|
-
|
53
|
+
expect { m.instance_variable_set('@amount', 2) }.to raise_error
|
51
54
|
end
|
52
55
|
|
53
56
|
it 'can be instantiated with a hash' do
|
54
|
-
Money = Value.new(:amount, :denomination)
|
55
57
|
one_dollar = Money.with(:amount => 1, :denomination => 'USD')
|
56
58
|
one_dollar.amount.should == 1
|
57
59
|
one_dollar.denomination.should == 'USD'
|
58
60
|
end
|
59
61
|
|
60
62
|
it 'errors if you instantiate it from a hash with unrecognised fields' do
|
61
|
-
Money = Value.new(:amount, :denomination)
|
62
63
|
expect do
|
63
64
|
Money.with(:unrecognized_field => 1, :amount => 2, :denomination => 'USD')
|
64
65
|
end.to raise_error
|
65
66
|
end
|
66
67
|
|
67
68
|
it 'errors if you instantiate it from a hash with missing fields' do
|
68
|
-
Money = Value.new(:amount, :denomination)
|
69
69
|
expect do
|
70
70
|
Money.with
|
71
71
|
end.to raise_error
|
72
72
|
end
|
73
73
|
|
74
74
|
it 'does not error when fields are explicitly nil' do
|
75
|
-
Money = Value.new(:amount, :denomination)
|
76
75
|
expect do
|
77
76
|
Money.with(:amount => 1, :denomination => nil)
|
78
77
|
end.not_to raise_error
|
@@ -108,4 +107,10 @@ describe 'values' do
|
|
108
107
|
Point.new(0,0).hash.should_not == Y.new(0,0).hash
|
109
108
|
end
|
110
109
|
end
|
110
|
+
|
111
|
+
describe '#values' do
|
112
|
+
it 'returns an array of field values' do
|
113
|
+
Point.new(10, 13).values.should == [10, 13]
|
114
|
+
end
|
115
|
+
end
|
111
116
|
end
|
data/values.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "values"
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tom Crayford"]
|
12
|
-
s.date = "2013-02-
|
12
|
+
s.date = "2013-02-22"
|
13
13
|
s.description = "Simple immutable value objects for ruby.\n\n Make a new value class: Point = Value.new(:x, :y)\n And use it:\n p = Point.new(1,0)\n p.x\n => 1\n p.y\n => 0\n "
|
14
14
|
s.email = "tcrayford@googlemail.com"
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: values
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
8
|
+
- 5
|
9
9
|
- 0
|
10
|
-
version: 1.
|
10
|
+
version: 1.5.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tom Crayford
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2013-02-
|
18
|
+
date: 2013-02-22 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|