values 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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,:y)
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,:y)
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
- Value does NOT have all the features of Struct (nor is it meant to).
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.4.0
1
+ 1.5.0
@@ -1,49 +1,43 @@
1
1
  class Value
2
2
  def self.new(*fields)
3
- return Class.new do
3
+ Class.new do
4
4
  attr_reader *fields
5
5
 
6
- define_method(:initialize) do |*input_fields|
7
- raise ArgumentError.new("wrong number of arguments, #{input_fields.size} for #{fields.size}") if fields.size != input_fields.size
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.each_with_index do |field, index|
10
- instance_variable_set('@' + field.to_s, input_fields[index])
9
+ fields.zip(values) do |field, value|
10
+ instance_variable_set(:"@#{field}", value)
11
11
  end
12
- self.freeze
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
- self.new(*args)
23
+
24
+ new(*hash.values_at(*self::VALUE_ATTRS))
28
25
  end
29
26
 
30
27
  def ==(other)
31
- self.eql?(other)
28
+ eql?(other)
32
29
  end
33
30
 
34
31
  def eql?(other)
35
- return false if other.class != self.class
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
- result = 0
43
- self.class::VALUE_ATTRS.each do |field|
44
- result += self.send(field).hash
45
- end
46
- return result + self.class.hash
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
@@ -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
- lambda { Point.new }.should raise_error(ArgumentError, 'wrong number of arguments, 0 for 2')
19
+ expect { Point.new }.to raise_error(ArgumentError, 'wrong number of arguments, 0 for 2')
18
20
  end
19
21
 
20
- it 'can be inherited from to add methods' do
21
- class GraphPoint < Value.new(:x, :y)
22
- def inspect
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
- lambda { p.x = 1}.should raise_error
35
+ expect { p.x = 1 }.to raise_error
34
36
  end
35
37
 
36
- it 'cannot even be mutated inside a sublass with methods' do
37
- class Cow < Value.new(:color)
38
- def change_color(new_color)
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
- lambda {c.change_color("blue")}.should raise_error
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
- lambda {m.instance_variable_set('@amount',2)}.should raise_error
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
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "values"
8
- s.version = "1.4.0"
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-03"
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: 7
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 4
8
+ - 5
9
9
  - 0
10
- version: 1.4.0
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-03 00:00:00 Z
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