good 0.1.1 → 0.1.3

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