good 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.md +33 -17
  2. data/lib/good.rb +11 -9
  3. metadata +2 -2
data/README.md CHANGED
@@ -2,11 +2,13 @@
2
2
 
3
3
  2 little things that make writing good Ruby programs a little easier.
4
4
 
5
- 1. `Good::Value` is a class generator for simple, pleasant [Value objects](http://en.wikipedia.org/wiki/Value_object).
5
+ 1. `Good::Value` is a class generator for simple, pleasant, immutable [Value objects](http://en.wikipedia.org/wiki/Value_object).
6
6
 
7
- 2. `Good::Record` is a class generator for simple, pleasant [Record objects](http://en.wikipedia.org/wiki/Record_(computer_science) "Record Objects"). They're a lot like `Struct`.
7
+ 2. `Good::Record` is a class generator for simple, pleasant, mutable [Record objects](http://en.wikipedia.org/wiki/Record_(computer_science) "Record Objects"). They're a lot like `Struct`.
8
8
 
9
- Both are used the same way same way, like this:
9
+ ## Usage
10
+
11
+ Both are used the same way, like this:
10
12
 
11
13
  ```ruby
12
14
  class Person < Good::Value.new(:name, :age)
@@ -17,7 +19,6 @@ or like this if you prefer:
17
19
 
18
20
  ```ruby
19
21
  Person = Good::Value.new(:name, :age)
20
- end
21
22
  ```
22
23
 
23
24
  Now, we can create a `Person`:
@@ -64,11 +65,21 @@ person.age # => 30
64
65
 
65
66
  Except for mutability `Good::Value` and `Good::Record` have the same interface.
66
67
 
67
- Don't forget, `Good::Value` and `Good::Record` are just regular Ruby objects,
68
- so they get to have methods just like everybody else:
68
+ Don't forget, `Good::Value` and `Good::Record` create regular Ruby classes so
69
+ they get to have methods just like everybody else:
69
70
 
70
71
  ```ruby
71
- Person < Good::Value.new(:name, :age)
72
+ class Person < Good::Value.new(:name, :age)
73
+ def introduction
74
+ "My name is #{name} and I'm #{age} years old"
75
+ end
76
+ end
77
+ ```
78
+
79
+ or, via block:
80
+
81
+ ```ruby
82
+ Person = Good::Value.new(:name, :age) do
72
83
  def introduction
73
84
  "My name is #{name} and I'm #{age} years old"
74
85
  end
@@ -76,14 +87,15 @@ end
76
87
  ```
77
88
 
78
89
  Also, classes created with `Good::Value` and `Good::Record` have reasonable
79
- implmentations of `#==`, `#eql?` and `#hash`.
90
+ implementations of `#==`, `#eql?` and `#hash`.
80
91
 
81
92
  ## Bonus Features
82
93
 
83
- You can ask `Good::Value` and `Good::Record` a little about their structure:
94
+ You can ask `Good::Value` and `Good::Record` instances about their structure
95
+ and contents:
84
96
 
85
97
  ```ruby
86
- person.new(:name => "Miss Brahms", :age => 30)
98
+ person = Person.new(:name => "Miss Brahms", :age => 30)
87
99
 
88
100
  Person::MEMBERS # => [:name, :age]
89
101
  person.members # => [:name, :age]
@@ -91,7 +103,7 @@ person.values # => ["Miss Brahms", 30]
91
103
  person.attributes # => {:name => "Miss Mrahms", :age => 30}
92
104
  ```
93
105
 
94
- You can call `Person.coerce` to coerce input to a `Person` in the follwoing
106
+ You can call `Person.coerce` to coerce input to a `Person` in the following
95
107
  ways:
96
108
 
97
109
  ```ruby
@@ -134,7 +146,7 @@ a number of these classes, the boilerplate code gets heavy pretty quickly. Plus
134
146
  you'll probably do it wrong the first time (I certainly did).
135
147
 
136
148
  It's worth noting that `Good` in no way seeks to become the foundation of your
137
- domain model. The second a class outgrows it's `Good::Value` or `Good::Record`
149
+ domain model. The second a class outgrows its `Good::Value` or `Good::Record`
138
150
  roots, by all means you should remove `Good` from the picture and rely on pure
139
151
  Ruby classes instead. `Good` helps you get started quickly by making a
140
152
  particular pattern easy, but when your classes get more mature, it's time for
@@ -166,7 +178,7 @@ class Authenticator
166
178
  end
167
179
 
168
180
  def authentic?
169
- ...
181
+ # ...
170
182
  end
171
183
  end
172
184
  ```
@@ -194,22 +206,22 @@ class Authenticator
194
206
  end
195
207
 
196
208
  def authentic?
197
- ...
209
+ # ...
198
210
  end
199
211
  end
200
212
  ```
201
213
 
202
- Say now that the the Authenticator needs to pass the user's credentials to
214
+ Say now that the Authenticator needs to pass the user's credentials to
203
215
  another component (to log the attempt, for example), we are now in the enviable
204
216
  position of having an object, with a well defined interface to pass around -
205
217
  not a hash with implicit assumptions about its contents. Further, because of
206
218
  the `.coerce` method we can now accept a hash at the boundary or a fully formed
207
219
  `Credentials` object, it makes no difference to the `Authenticator`.
208
220
 
209
- This evolulution seems fairly common. To solve an immediate problem, a new
221
+ This evolution seems fairly common. To solve an immediate problem, a new
210
222
  `Good::Value` class is created inside the namespace of an existing class, which
211
223
  is at first desirable because it does not inflict this abstraction externally.
212
- Then, as the class begins to interact with other compontents in the system,
224
+ Then, as the class begins to interact with other components in the system,
213
225
  this previously internal class can be made external and evolved into it's own
214
226
  fully fledged domain object (perhaps shedding `Good` in the process). When you
215
227
  start with a hash, it can be harder to spot the "missing" class.
@@ -232,3 +244,7 @@ Or install it yourself as:
232
244
 
233
245
  bundle && bundle exec rake
234
246
 
247
+ ## Credits
248
+
249
+ * Borrowed heavily from https://github.com/tcrayford/Values
250
+
data/lib/good.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class Good
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
 
4
4
  class Value
5
5
  def self.new(*members, &block)
@@ -15,7 +15,6 @@ class Good
15
15
 
16
16
  def self.generate(mutable, *members, &block)
17
17
  Class.new do
18
-
19
18
  mutable ? attr_accessor(*members) : attr_reader(*members)
20
19
 
21
20
  const_set(:MEMBERS, members.dup.freeze)
@@ -27,16 +26,19 @@ class Good
27
26
  else raise TypeError, "Unable to coerce #{coercable.class} into #{self}"
28
27
  end
29
28
  end
30
-
31
- define_method(:initialize) do |attributes={}|
32
- if mutable
29
+
30
+ if mutable
31
+ def initialize(attributes = {})
33
32
  attributes.each { |k, v| send("#{k}=", v) }
34
- else
35
- attributes.each { |k, v| instance_variable_set(:"@#{k}", v) }
33
+ end
34
+ else
35
+ def initialize(attributes = {})
36
+ attributes.each { |k, v| instance_variable_set(:"@#{k}", v) }
36
37
  end
37
38
  end
38
39
 
39
- def attributes
40
+
41
+ def attributes
40
42
  {}.tap { |h| self.class::MEMBERS.each { |m| h[m] = send(m) } }
41
43
  end
42
44
 
@@ -59,7 +61,7 @@ class Good
59
61
  def eql?(other)
60
62
  self == other
61
63
  end
62
-
64
+
63
65
  def hash
64
66
  attributes.hash
65
67
  end
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.0
4
+ version: 0.1.1
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-15 00:00:00.000000000 Z
12
+ date: 2014-05-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec