good 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/good.rb +16 -8
  2. data/spec/good_spec.rb +31 -23
  3. metadata +3 -3
data/lib/good.rb CHANGED
@@ -1,23 +1,29 @@
1
- class Good
2
- VERSION = "0.1.1"
1
+ class Good
2
+ VERSION = "0.1.3"
3
3
 
4
- class Value
4
+ class Value
5
5
  def self.new(*members, &block)
6
6
  Good.generate(false, *members, &block)
7
- end
7
+ end
8
8
  end
9
9
 
10
- class Record
10
+ class Record
11
11
  def self.new(*members, &block)
12
12
  Good.generate(true, *members, &block)
13
- end
13
+ end
14
+ end
15
+
16
+ def self.validate_constructor_attributes(attributes, allowed)
17
+ if (unrecognized = attributes.keys.map(&:to_sym) - allowed).any?
18
+ raise ArgumentError, "Unrecognized parameter(s): #{unrecognized.join(', ')}"
19
+ end
14
20
  end
15
21
 
16
22
  def self.generate(mutable, *members, &block)
17
23
  Class.new do
18
24
  mutable ? attr_accessor(*members) : attr_reader(*members)
19
25
 
20
- const_set(:MEMBERS, members.dup.freeze)
26
+ const_set(:MEMBERS, members.map(&:to_sym).freeze)
21
27
 
22
28
  def self.coerce(coercable)
23
29
  case coercable
@@ -27,17 +33,19 @@ class Good
27
33
  end
28
34
  end
29
35
 
36
+
30
37
  if mutable
31
38
  def initialize(attributes = {})
39
+ Good.validate_constructor_attributes(attributes, self.class::MEMBERS)
32
40
  attributes.each { |k, v| send("#{k}=", v) }
33
41
  end
34
42
  else
35
43
  def initialize(attributes = {})
44
+ Good.validate_constructor_attributes(attributes, self.class::MEMBERS)
36
45
  attributes.each { |k, v| instance_variable_set(:"@#{k}", v) }
37
46
  end
38
47
  end
39
48
 
40
-
41
49
  def attributes
42
50
  {}.tap { |h| self.class::MEMBERS.each { |m| h[m] = send(m) } }
43
51
  end
data/spec/good_spec.rb CHANGED
@@ -24,27 +24,31 @@ shared_examples :good do
24
24
  it "allows 0 argument construction" do
25
25
  person = Person.new
26
26
  end
27
+
28
+ it "raises an ArgumentError if given an unrecognized parameter" do
29
+ expect { Person.new(:wrong => nil) }.to raise_error(ArgumentError)
30
+ end
27
31
  end
28
32
 
29
33
  describe "#==" do
30
34
  it "is true if all the parameters are ==" do
31
35
  bob_1 = Person.new(:name => "Bob", :age => 50)
32
36
  bob_2 = Person.new(:name => "Bob", :age => 50)
33
-
37
+
34
38
  expect(bob_1).to eq(bob_2)
35
39
  end
36
-
40
+
37
41
  it "is false if any attributes are not #==" do
38
42
  bob = Person.new(:name => "Bob", :age => 50)
39
43
  ted = Person.new(:name => "Ted", :age => 50)
40
-
44
+
41
45
  expect(bob).not_to eq(ted)
42
46
  end
43
-
47
+
44
48
  it "is false if the other object is not of the same class" do
45
49
  bob = Person.new(:name => "Bob", :age => 50)
46
50
  alien_bob = described_class.new(:name, :age).new(:name => "Bob", :age => 50)
47
-
51
+
48
52
  expect(bob).not_to eq(alien_bob)
49
53
  end
50
54
  end
@@ -53,51 +57,56 @@ shared_examples :good do
53
57
  it "is true if all the parameters are ==" do
54
58
  bob_1 = Person.new(:name => "Bob", :age => 50)
55
59
  bob_2 = Person.new(:name => "Bob", :age => 50)
56
-
60
+
57
61
  expect(bob_1).to eql(bob_2)
58
62
  end
59
-
63
+
60
64
  it "is false if any attributes are not #==" do
61
65
  bob = Person.new(:name => "Bob", :age => 50)
62
66
  ted = Person.new(:name => "Ted", :age => 50)
63
-
67
+
64
68
  expect(bob).not_to eql(ted)
65
69
  end
66
-
70
+
67
71
  it "is false if the other object is not of the same class" do
68
72
  bob = Person.new(:name => "Bob", :age => 50)
69
73
  alien_bob = Struct.new(:name, :age).new("Bob", 50)
70
-
74
+
71
75
  expect(bob).not_to eql(alien_bob)
72
76
  end
73
77
  end
74
-
78
+
75
79
  describe "#hash" do
76
80
  it "is stable" do
77
81
  bob_1 = Person.new(:name => "Bob")
78
82
  bob_2 = Person.new(:name => "Bob")
79
-
83
+
80
84
  expect(bob_1.hash).to eq(bob_2.hash)
81
85
  end
82
-
86
+
83
87
  it "varies with the parameters" do
84
88
  bob = Person.new(:name => "Bob", :age => 50)
85
89
  ted = Person.new(:name => "Ted", :age => 50)
86
-
90
+
87
91
  expect(bob.hash).not_to eql(ted.hash)
88
92
  end
89
93
  end
90
-
94
+
91
95
  describe "::MEMBERS" do
92
96
  it "is the list of member variables" do
93
97
  expect(Person::MEMBERS).to eq([:name, :age])
94
98
  end
95
-
99
+
96
100
  it "is frozen" do
97
101
  expect { Person::MEMBERS << :height }.to raise_error(/can't modify frozen/)
98
102
  end
103
+
104
+ it "always contains symbols (even if defined with strings)" do
105
+ klass = described_class.new("a", :b)
106
+ expect(klass::MEMBERS).to eq([:a, :b])
107
+ end
99
108
  end
100
-
109
+
101
110
  describe "#members" do
102
111
  it "is the list of member variables" do
103
112
  person = Person.new
@@ -152,17 +161,17 @@ shared_examples :good do
152
161
  person = Person.new
153
162
  expect(Person.coerce(person)).to be(person)
154
163
  end
155
-
164
+
156
165
  it "initializes a new instance if the input is a hash" do
157
166
  person = Person.coerce({:name => "Bob"})
158
167
  expect(person).to eq(Person.new(:name => "Bob"))
159
168
  end
160
-
169
+
161
170
  it "raises a TypeError otherwise" do
162
171
  expect { Person.coerce("15 lbs of squirrel fur") }.to raise_error(TypeError)
163
172
  end
164
173
  end
165
-
174
+
166
175
  describe "block construction" do
167
176
  let(:car_klass) do
168
177
  described_class.new(:wheels) do
@@ -171,7 +180,7 @@ shared_examples :good do
171
180
  end
172
181
  end
173
182
  end
174
-
183
+
175
184
  it "allows definition of methods" do
176
185
  car = car_klass.new(:wheels => 4)
177
186
  expect(car.drive).to eq("Driving with all 4 wheels!")
@@ -184,7 +193,7 @@ describe Good::Value do
184
193
 
185
194
  it "is immutable" do
186
195
  person = Person.new
187
- expect { person.name = "Bob" }.to raise_error(NoMethodError)
196
+ expect { person.name = "Bob" }.to raise_error(NoMethodError)
188
197
  end
189
198
  end
190
199
 
@@ -196,4 +205,3 @@ describe Good::Record do
196
205
  expect { person.name = "Bob" }.to change { person.name }.to("Bob")
197
206
  end
198
207
  end
199
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-22 00:00:00.000000000 Z
12
+ date: 2015-07-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -95,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
95
  version: '0'
96
96
  requirements: []
97
97
  rubyforge_project:
98
- rubygems_version: 1.8.23
98
+ rubygems_version: 1.8.23.2
99
99
  signing_key:
100
100
  specification_version: 3
101
101
  summary: Good::Value and Good::Record