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 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