degu 0.3.0 → 0.4.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.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +2 -0
- data/COPYING +21 -0
- data/Gemfile +1 -1
- data/README.md +291 -0
- data/Rakefile +4 -4
- data/VERSION +1 -1
- data/degu.gemspec +11 -11
- data/lib/degu/renum/enumerated_value.rb +16 -1
- data/lib/degu/version.rb +1 -1
- data/spec/renum_spec.rb +41 -6
- data/test/test_helper.rb +46 -48
- metadata +28 -38
- data/README.rdoc +0 -150
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4c7ff2eaa04adad080028fead220da2f01df66cf
|
4
|
+
data.tar.gz: 6273045fdce4f22cb41e6d3260af9f6bd801cf07
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ab52b10983dea4a5a8033624b0cffdc74a2fdce9b6af3b0ae6d7e30c1b9ff7de1a63be0b69a0664191112552e86d410be79d5d962de8e52af6c72b548f941bf1
|
7
|
+
data.tar.gz: 0afb37cf14e0700c3407c6da137cb1b454184b6de4b347baac5f214a9c5fba598084245eef6c1405f30aef7ddc53e4acd5b3a425951b39e58229a5c15b809e74
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -6,6 +6,7 @@ rvm:
|
|
6
6
|
- 1.8.7
|
7
7
|
- 1.9.2
|
8
8
|
- 1.9.3
|
9
|
+
- 2.0.0
|
9
10
|
- rbx-18mode
|
10
11
|
- rbx-19mode
|
11
12
|
- ree
|
@@ -18,5 +19,6 @@ matrix:
|
|
18
19
|
- rvm: jruby-19mode
|
19
20
|
- rvm: rbx-18mode
|
20
21
|
- rvm: rbx-19mode
|
22
|
+
- rvm: ruby-head #https://github.com/travis-ci/travis-ci/issues/1195
|
21
23
|
|
22
24
|
script: "bundle exec rake"
|
data/COPYING
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2009-2013 all contributors
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/Gemfile
CHANGED
data/README.md
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
# Degu
|
2
|
+

|
3
|
+
|
4
|
+
Degu bundles the renum Enumeration implementation with the has_enum and has_set
|
5
|
+
rails plugins.
|
6
|
+
|
7
|
+
## Renum
|
8
|
+
|
9
|
+
### Description
|
10
|
+
|
11
|
+
Renum provides a readable but terse enum facility for Ruby. Enums are
|
12
|
+
sometimes called object constants and are analogous to the type-safe enum
|
13
|
+
pattern in Java, though obviously Ruby's flexibility means there's no such
|
14
|
+
thing as type-safety.
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
Renum allows you to do things like this:
|
19
|
+
```ruby
|
20
|
+
enum :Status, %w( NOT_STARTED IN_PROGRESS COMPLETE )
|
21
|
+
|
22
|
+
enum :Size do
|
23
|
+
Small("Really really tiny")
|
24
|
+
Medium("Sort of in the middle")
|
25
|
+
Large("Quite big")
|
26
|
+
|
27
|
+
attr_reader :description
|
28
|
+
|
29
|
+
def init description
|
30
|
+
@description = description
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module MyNamespace
|
35
|
+
enum :FooValue, [ :Bar, :Baz, :Bat ]
|
36
|
+
end
|
37
|
+
```
|
38
|
+
Giving you something that satisfies this spec, plus a bit more:
|
39
|
+
```ruby
|
40
|
+
describe "enum" do
|
41
|
+
|
42
|
+
it "creates a class for the value type" do
|
43
|
+
Status.class.should == Class
|
44
|
+
end
|
45
|
+
|
46
|
+
it "makes each value an instance of the value type" do
|
47
|
+
Status::NOT_STARTED.class.should == Status
|
48
|
+
end
|
49
|
+
|
50
|
+
it "exposes array of values" do
|
51
|
+
Status.values.should == [Status::NOT_STARTED, Status::IN_PROGRESS, Status::COMPLETE]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "provides an alternative means of declaring values where extra information can be provided for initialization" do
|
55
|
+
Size::Small.description.should == "Really really tiny"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "enumerates over values" do
|
59
|
+
Status.map {|s| s.name}.should == %w[NOT_STARTED IN_PROGRESS COMPLETE]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "indexes values" do
|
63
|
+
Status[2].should == Status::COMPLETE
|
64
|
+
end
|
65
|
+
|
66
|
+
it "provides index lookup on values" do
|
67
|
+
Status::IN_PROGRESS.index.should == 1
|
68
|
+
end
|
69
|
+
|
70
|
+
it "provides a reasonable to_s for values" do
|
71
|
+
Status::NOT_STARTED.to_s.should == "Status::NOT_STARTED"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "makes values comparable" do
|
75
|
+
Status::NOT_STARTED.should < Status::COMPLETE
|
76
|
+
end
|
77
|
+
|
78
|
+
it "allows enums to be nested in other modules or classes" do
|
79
|
+
MyNamespace::FooValue::Bar.class.should == MyNamespace::FooValue
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
```
|
84
|
+
If your enumeration holds more than just a couple of attributes, the init method can become messy very quickly.
|
85
|
+
So, we have extended the original renum gem to ease the process of value definition.
|
86
|
+
```ruby
|
87
|
+
enum :Planet do
|
88
|
+
field :mass
|
89
|
+
field :radius
|
90
|
+
field :satelites, default: 0
|
91
|
+
field :human_name do |planet|
|
92
|
+
I18n.translate "enum.planet.#{planet.underscored_name}"
|
93
|
+
end
|
94
|
+
|
95
|
+
Mercury(mass: 3.303e+23, radius: 2.4397e6)
|
96
|
+
Venus(mass: 4.869e+24, radius: 6.0518e6)
|
97
|
+
Earth(mass: 5.976e+24, radius: 6.37814e6, satelites: 1)
|
98
|
+
Mars(mass: 6.421e+23, radius: 3.3972e6, satelites: 2)
|
99
|
+
Jupiter(mass: 1.9e+27, radius: 7.1492e7, satelites: 67)
|
100
|
+
Saturn(mass: 5.688e+26, radius: 6.0268e7, satelites: 62)
|
101
|
+
Uranus(mass: 8.686e+25, radius: 2.5559e7, satelites: 27)
|
102
|
+
Neptune(mass: 1.024e+26, radius: 2.4746e7, satelites: 13)
|
103
|
+
|
104
|
+
def has_satelites?
|
105
|
+
satelites > 0
|
106
|
+
end
|
107
|
+
end
|
108
|
+
```
|
109
|
+
Now, you are able to define your enumeration value attributes using the `field` method, which generates
|
110
|
+
`attribute_reader` for you. You can also specify a default value for this field using either the `:default`-key or
|
111
|
+
a block, if you need some calculation.
|
112
|
+
Now, you have a couple of methods to play with:
|
113
|
+
```ruby
|
114
|
+
# Enums implement Enumerable
|
115
|
+
Planet.map(&:human_name)
|
116
|
+
=> ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
|
117
|
+
|
118
|
+
# access all enum value names
|
119
|
+
Planet.names
|
120
|
+
=> ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
|
121
|
+
|
122
|
+
# use the names as keys
|
123
|
+
Planet.underscored_names
|
124
|
+
=> ["mercury", "venus", "earth", "mars", "jupiter", "saturn", "uranus", "neptune"]
|
125
|
+
|
126
|
+
Planet.field_names
|
127
|
+
=> ["planet_mercury", "planet_venus", "planet_earth", "planet_mars", "planet_jupiter", "planet_saturn", "planet_uranus", "planet_neptune"]
|
128
|
+
|
129
|
+
Planet.values # returns all defined enum values as an array
|
130
|
+
|
131
|
+
# Use [] method to retrieve the values
|
132
|
+
Planet[2]
|
133
|
+
=> #<Planet:0x007ff2aa068bd8 @name="Earth", @index=2, @mass=5.976e+24, @radius=6378140.0, @satelites=1, @human_name="Earth">
|
134
|
+
|
135
|
+
Planet['MARS']
|
136
|
+
=> #<Planet:0x007ff2aa0686d8 @name="Mars", @index=3, @mass=6.421e+23, @radius=3397200.0, @satelites=2, @human_name="Mars">
|
137
|
+
|
138
|
+
Planet[:venus]
|
139
|
+
=> #<Planet:0x007fe4227d9250 @name="Venus", @index=1, @mass=4.869e+24, @radius=6051800.0, @satelites=0, @human_name="Venus">
|
140
|
+
|
141
|
+
# Enums implement JSON load/dump API
|
142
|
+
serialized = Planet::Earth.to_json({})
|
143
|
+
=> "{\"json_class\":\"Planet\",\"name\":\"Earth\"}"
|
144
|
+
|
145
|
+
JSON.load serialized
|
146
|
+
=> #<Planet:0x007fe4227e1d38 @name="Earth", @index=2, @mass=5.976e+24, @radius=6378140.0, @satelites=1, @human_name="Earth">
|
147
|
+
|
148
|
+
# Because enums are static by their nature, it is sufficient to serialize just the name of the enum value.
|
149
|
+
# If you want to serialize the fields also, you can specify the field names to serialize (or just true for all fields)
|
150
|
+
Planet::Earth.to_json fields: [:name, :satelites]
|
151
|
+
=> "{\"json_class\":\"Planet\",\"name\":\"Earth\",\"satelites\":1}"
|
152
|
+
|
153
|
+
Planet::Earth.to_json fields: true
|
154
|
+
=> "{\"json_class\":\"Planet\",\"name\":\"Earth\",\"mass\":5.976e+24,\"radius\":6378140.0,\"satelites\":1,\"human_name\":\"Earth\"}"
|
155
|
+
```
|
156
|
+
|
157
|
+
### Rails integration
|
158
|
+
To use enum values as ActiveRecord attributes we integrated the [has_enum](https://github.com/caroo/has_enum) and
|
159
|
+
[has_set](https://github.com/caroo/has_set) plugins, originally developed by [galaxycats](https://github.com/galaxycats).
|
160
|
+
|
161
|
+
#### has_enum
|
162
|
+
The has_enum extension provides an association with an enumeration class which requires the renum gem.
|
163
|
+
You have to make sure to have a column in your database table to store the string representation
|
164
|
+
of the associated enum instance. The plugin will look by default for a column named like the enum
|
165
|
+
itself plus the "_type" suffix.
|
166
|
+
```ruby
|
167
|
+
|
168
|
+
# Define the Enum-Class
|
169
|
+
enum :CustomerState do
|
170
|
+
field :monthly_due
|
171
|
+
|
172
|
+
Free(montly_due: 0)
|
173
|
+
Basic(monthly_due: 5.95)
|
174
|
+
Premium(monthly_due: 19.95)
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
# Class that has an Enumartion associated
|
179
|
+
class Customer < ActiveRecord::Base
|
180
|
+
has_enum :customer_state # needs customer_state_type column in database
|
181
|
+
end
|
182
|
+
|
183
|
+
customer = Customer.new
|
184
|
+
|
185
|
+
# Before setting any enum
|
186
|
+
customer.customer_state # => nil
|
187
|
+
customer.customer_state_type # => ""
|
188
|
+
|
189
|
+
customer.customer_state = CustomerState::Premium
|
190
|
+
customer.customer_state # => CustomerState::Premium
|
191
|
+
customer.customer_state_type # => "Premium"
|
192
|
+
customer.customer_state_has_changed? # => true
|
193
|
+
```
|
194
|
+
`has_enum` method accepts following attributes:
|
195
|
+
- `column_name` to specify a different column name to store the enum values
|
196
|
+
- `class_name` to specify a different enum class
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
class Customer
|
200
|
+
has_enum :customer_state, class_name: 'UserState', column_name: 'state_type'
|
201
|
+
end
|
202
|
+
```
|
203
|
+
|
204
|
+
#### has_set
|
205
|
+
A simple plugin to enable any `ActiveRecord::Base` object to store a set of
|
206
|
+
attributes in a set like structure represented through a bitfield on the database level.
|
207
|
+
|
208
|
+
You only have to specify the name of the set to hold the attributes in question an the rest
|
209
|
+
is done for you through some fine selected Ruby magic. Here is a simple example of how you could use the plugin:
|
210
|
+
```ruby
|
211
|
+
class Person < ActiveRecord::Base
|
212
|
+
has_set :interests
|
213
|
+
end
|
214
|
+
```
|
215
|
+
|
216
|
+
1. You need an unsigned 8(11)-Byte integer column in your database to store the bitfield.
|
217
|
+
It is expected that the column is named after the name of the set with the suffix `_bitfield`
|
218
|
+
appended (e.g. `interests_bitfield`). You can change that default behavior by providing the option `:column_name`
|
219
|
+
(e.g. `has_set :interests, :column_name => 'my_custom_column'`).
|
220
|
+
2. You need a class that provides the valid values to be stored within the set and map the single bits back
|
221
|
+
to something meaningful. The class should be named after the name of the set (you can change this through
|
222
|
+
the `:enum_class` option). This class could be seen as an enumeration and must implement the following
|
223
|
+
simple interface:
|
224
|
+
* Each enumerator must implement a `name` method to return a literal representation for identification.
|
225
|
+
The literal must be of the type `String`.
|
226
|
+
* Each enumerator must implement a `bitfield_index` method to return the exponent of the number 2 for
|
227
|
+
calculation the position of this enumerator in the bitfield. **Attention** Changing this index afterwards will
|
228
|
+
destroy your data integrity.
|
229
|
+
|
230
|
+
The renum gem is best suited to satisfy this interface.
|
231
|
+
After that you get following methods to work with:
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
enum :Interests do
|
235
|
+
# bitfield_index is just the alias for the index method, but you are free to change it.
|
236
|
+
# Just define a field :bitfield_index and set it for every enum value.
|
237
|
+
Art()
|
238
|
+
Golf()
|
239
|
+
Sleeping()
|
240
|
+
Drinking()
|
241
|
+
Dating()
|
242
|
+
Shopping()
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
person = Person.new
|
247
|
+
|
248
|
+
# Check the interests
|
249
|
+
person.interests
|
250
|
+
=> []
|
251
|
+
|
252
|
+
person.interests = [Interests::Art, Interests::Drinking]
|
253
|
+
=> [Interests::Art, Interests::Drinking]
|
254
|
+
|
255
|
+
person.interest_drinking?
|
256
|
+
=> true
|
257
|
+
|
258
|
+
person.interest_drinking = false
|
259
|
+
=> false
|
260
|
+
|
261
|
+
person.interest_drinking?
|
262
|
+
=> false
|
263
|
+
|
264
|
+
Person.available_interests
|
265
|
+
=> [:interest_art, :interest_golf, :interest_sleeping, :interest_drinking, :interest_dating, :interest_shopping]
|
266
|
+
|
267
|
+
```
|
268
|
+
|
269
|
+
### Copying
|
270
|
+
|
271
|
+
The MIT License (MIT)
|
272
|
+
|
273
|
+
Copyright (c) 2009-2013 all contributors
|
274
|
+
|
275
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
276
|
+
of this software and associated documentation files (the "Software"), to deal
|
277
|
+
in the Software without restriction, including without limitation the rights
|
278
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
279
|
+
copies of the Software, and to permit persons to whom the Software is
|
280
|
+
furnished to do so, subject to the following conditions:
|
281
|
+
|
282
|
+
The above copyright notice and this permission notice shall be included in
|
283
|
+
all copies or substantial portions of the Software.
|
284
|
+
|
285
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
286
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
287
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
288
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
289
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
290
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
291
|
+
THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -7,16 +7,16 @@ GemHadar do
|
|
7
7
|
name 'degu'
|
8
8
|
author 'Florian Frank'
|
9
9
|
email 'dev@pkw.de'
|
10
|
-
homepage "
|
10
|
+
homepage "https://github.com/tuskenraiders/#{name}"
|
11
11
|
summary 'Library for enums and bitfield sets.'
|
12
12
|
description 'Library that includes enums, and rails support for enums and bitfield sets.'
|
13
13
|
test_dir 'test'
|
14
14
|
test_files Dir['test/**/*_test.rb']
|
15
15
|
spec_dir 'spec'
|
16
|
-
ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.rvmrc', 'coverage', '.DS_Store'
|
17
|
-
readme 'README.
|
16
|
+
ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.rvmrc', 'coverage', '.DS_Store', '.ruby-gemset', '.ruby-version'
|
17
|
+
readme 'README.md'
|
18
18
|
|
19
|
-
dependency 'activerecord', '
|
19
|
+
dependency 'activerecord', '>= 3.0', '< 5.0'
|
20
20
|
|
21
21
|
development_dependency 'mocha'
|
22
22
|
development_dependency 'sqlite3'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/degu.gemspec
CHANGED
@@ -2,24 +2,24 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "degu"
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.4.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Florian Frank"]
|
9
|
-
s.date = "2013-
|
9
|
+
s.date = "2013-07-11"
|
10
10
|
s.description = "Library that includes enums, and rails support for enums and bitfield sets."
|
11
11
|
s.email = "dev@pkw.de"
|
12
|
-
s.extra_rdoc_files = ["README.
|
13
|
-
s.files = [".gitignore", ".travis.yml", "Gemfile", "README.
|
14
|
-
s.homepage = "
|
15
|
-
s.rdoc_options = ["--title", "Degu - Library for enums and bitfield sets.", "--main", "README.
|
12
|
+
s.extra_rdoc_files = ["README.md", "lib/degu.rb", "lib/degu/has_enum.rb", "lib/degu/has_set.rb", "lib/degu/polite.rb", "lib/degu/renum.rb", "lib/degu/renum/enumerated_value.rb", "lib/degu/renum/enumerated_value_type_factory.rb", "lib/degu/rude.rb", "lib/degu/version.rb"]
|
13
|
+
s.files = [".gitignore", ".travis.yml", "COPYING", "Gemfile", "README.md", "Rakefile", "VERSION", "degu.gemspec", "lib/degu.rb", "lib/degu/has_enum.rb", "lib/degu/has_set.rb", "lib/degu/polite.rb", "lib/degu/renum.rb", "lib/degu/renum/enumerated_value.rb", "lib/degu/renum/enumerated_value_type_factory.rb", "lib/degu/rude.rb", "lib/degu/version.rb", "spec/renum_spec.rb", "spec/spec_helper.rb", "test/has_enum_test.rb", "test/has_set_test.rb", "test/test_helper.rb", "test_helper.rb"]
|
14
|
+
s.homepage = "https://github.com/tuskenraiders/degu"
|
15
|
+
s.rdoc_options = ["--title", "Degu - Library for enums and bitfield sets.", "--main", "README.md"]
|
16
16
|
s.require_paths = ["lib"]
|
17
|
-
s.rubygems_version = "
|
17
|
+
s.rubygems_version = "2.0.4"
|
18
18
|
s.summary = "Library for enums and bitfield sets."
|
19
19
|
s.test_files = ["test/has_enum_test.rb", "test/has_set_test.rb"]
|
20
20
|
|
21
21
|
if s.respond_to? :specification_version then
|
22
|
-
s.specification_version =
|
22
|
+
s.specification_version = 4
|
23
23
|
|
24
24
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
25
25
|
s.add_development_dependency(%q<gem_hadar>, ["~> 0.1.8"])
|
@@ -27,14 +27,14 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
28
28
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
29
29
|
s.add_development_dependency(%q<utils>, [">= 0"])
|
30
|
-
s.add_runtime_dependency(%q<activerecord>, ["
|
30
|
+
s.add_runtime_dependency(%q<activerecord>, ["< 5.0", ">= 3.0"])
|
31
31
|
else
|
32
32
|
s.add_dependency(%q<gem_hadar>, ["~> 0.1.8"])
|
33
33
|
s.add_dependency(%q<mocha>, [">= 0"])
|
34
34
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
35
35
|
s.add_dependency(%q<rspec>, [">= 0"])
|
36
36
|
s.add_dependency(%q<utils>, [">= 0"])
|
37
|
-
s.add_dependency(%q<activerecord>, ["
|
37
|
+
s.add_dependency(%q<activerecord>, ["< 5.0", ">= 3.0"])
|
38
38
|
end
|
39
39
|
else
|
40
40
|
s.add_dependency(%q<gem_hadar>, ["~> 0.1.8"])
|
@@ -42,6 +42,6 @@ Gem::Specification.new do |s|
|
|
42
42
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
43
43
|
s.add_dependency(%q<rspec>, [">= 0"])
|
44
44
|
s.add_dependency(%q<utils>, [">= 0"])
|
45
|
-
s.add_dependency(%q<activerecord>, ["
|
45
|
+
s.add_dependency(%q<activerecord>, ["< 5.0", ">= 3.0"])
|
46
46
|
end
|
47
47
|
end
|
@@ -16,6 +16,21 @@ module Degu
|
|
16
16
|
include Enumerable
|
17
17
|
extend Forwardable
|
18
18
|
|
19
|
+
##
|
20
|
+
# Adds an enum definition extension method to be able to define methods on newly created enum and use them
|
21
|
+
# inside the definition of enumeration values.
|
22
|
+
# This method accepts both module names and block to extend the enum
|
23
|
+
# Use it as first expression after the `enum :MyEnumName do` enum definition
|
24
|
+
def definition_extension(*names, &block)
|
25
|
+
eigenclass = class << self; self; end
|
26
|
+
unless names.empty?
|
27
|
+
names.each do |name|
|
28
|
+
eigenclass.__send__(:include, name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
eigenclass.send(:class_eval, &block) if block
|
32
|
+
end
|
33
|
+
|
19
34
|
def_delegators :values, :first, :last, :each
|
20
35
|
|
21
36
|
# Returns an array of values in the order they're declared.
|
@@ -237,7 +252,7 @@ module Degu
|
|
237
252
|
obj.as_json(opts)
|
238
253
|
end
|
239
254
|
|
240
|
-
def to_json(opts, *a)
|
255
|
+
def to_json(opts = {}, *a)
|
241
256
|
obj = as_json(opts)
|
242
257
|
opts.respond_to?(:fields) and opts.delete(:fields)
|
243
258
|
obj.to_json(opts, *a)
|
data/lib/degu/version.rb
CHANGED
data/spec/renum_spec.rb
CHANGED
@@ -127,7 +127,7 @@ describe "enum with no values array and values declared in the block" do
|
|
127
127
|
end
|
128
128
|
|
129
129
|
it "responds as expected to arbitrary method calls, in spite of using method_missing for value definition" do
|
130
|
-
|
130
|
+
expect { Size.ExtraLarge() }.to raise_error(NoMethodError)
|
131
131
|
end
|
132
132
|
|
133
133
|
it "supports there being no extra data and no init() method defined, if you don't need them" do
|
@@ -170,12 +170,12 @@ describe "an enum with instance-specific method definitions" do
|
|
170
170
|
end
|
171
171
|
|
172
172
|
it "uses the implementation given at the top level if no alternate definition is given for an instance" do
|
173
|
-
|
173
|
+
expect { Rating::NotRated.description }.to raise_error(NotImplementedError)
|
174
174
|
end
|
175
175
|
|
176
176
|
it "allows definition of a method on just one instance" do
|
177
177
|
Rating::ThumbsUp.thumbs_up_only_method.should == "this method is only defined on ThumbsUp"
|
178
|
-
|
178
|
+
expect { Rating::NotRated.thumbs_up_only_method }.to raise_error(NoMethodError)
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
@@ -196,15 +196,15 @@ modify_frozen_error =
|
|
196
196
|
|
197
197
|
describe "prevention of subtle and annoying bugs" do
|
198
198
|
it "prevents you modifying the values array" do
|
199
|
-
|
199
|
+
expect { Color.values << 'some crazy value' }.to raise_error(modify_frozen_error, /can't modify frozen/)
|
200
200
|
end
|
201
201
|
|
202
202
|
it "prevents you modifying the name hash" do
|
203
|
-
|
203
|
+
expect { Color.values_by_name['MAGENTA'] = 'some crazy value' }.to raise_error(modify_frozen_error, /can't modify frozen/)
|
204
204
|
end
|
205
205
|
|
206
206
|
it "prevents you modifying the name of a value" do
|
207
|
-
|
207
|
+
expect { Color::RED.name << 'dish-Brown' }.to raise_error(modify_frozen_error, /can't modify frozen/)
|
208
208
|
end
|
209
209
|
end
|
210
210
|
|
@@ -279,3 +279,38 @@ if defined?(::JSON)
|
|
279
279
|
end
|
280
280
|
end
|
281
281
|
end
|
282
|
+
|
283
|
+
module ExtensionA
|
284
|
+
def a
|
285
|
+
'a_set_via_extension'
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
module ExtensionB
|
290
|
+
def b
|
291
|
+
'b_set_via_extension'
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
enum :Foo3 do
|
296
|
+
definition_extension ExtensionA, ExtensionB do
|
297
|
+
def c
|
298
|
+
'c_set_via_extension'
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
field :set_per_extension
|
303
|
+
|
304
|
+
Bar(:set_per_extension => a)
|
305
|
+
Baz(:set_per_extension => b)
|
306
|
+
Bang(:set_per_extension => c)
|
307
|
+
end
|
308
|
+
|
309
|
+
describe "definition extensions included as models and block to use inside of the definition" do
|
310
|
+
it "can use methods defined inside of definition extension modules" do
|
311
|
+
expect(Foo3::Bar.set_per_extension).to eq 'a_set_via_extension'
|
312
|
+
expect(Foo3::Baz.set_per_extension).to eq 'b_set_via_extension'
|
313
|
+
expect(Foo3::Bang.set_per_extension).to eq 'c_set_via_extension'
|
314
|
+
end
|
315
|
+
|
316
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,59 +1,57 @@
|
|
1
1
|
require 'degu'
|
2
2
|
require 'test/unit'
|
3
|
-
require 'mocha'
|
3
|
+
require 'mocha/setup'
|
4
4
|
require 'active_record'
|
5
5
|
|
6
6
|
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
7
7
|
ActiveRecord::Migration.verbose = false
|
8
8
|
|
9
9
|
def setup_db
|
10
|
-
ActiveRecord::
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
t.integer :music_bitfield
|
56
|
-
end
|
10
|
+
ActiveRecord::Schema.define(:version => 1) do
|
11
|
+
create_table :class_with_enums do |t|
|
12
|
+
t.column :title, :string
|
13
|
+
t.column :product_type, :string
|
14
|
+
t.column :created_at, :datetime
|
15
|
+
t.column :updated_at, :datetime
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table :class_without_enums do |t|
|
19
|
+
t.column :title, :string
|
20
|
+
t.column :created_at, :datetime
|
21
|
+
t.column :updated_at, :datetime
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table :class_with_interger_columns do |t|
|
25
|
+
t.column :title, :string
|
26
|
+
t.column :product_type, :integer
|
27
|
+
end
|
28
|
+
|
29
|
+
create_table :class_with_custom_name_enums do |t|
|
30
|
+
t.column :title, :string
|
31
|
+
t.column :product_enum, :string
|
32
|
+
t.column :created_at, :datetime
|
33
|
+
t.column :updated_at, :datetime
|
34
|
+
end
|
35
|
+
|
36
|
+
create_table :people do |t|
|
37
|
+
t.string :fullname
|
38
|
+
t.integer :interests_bitfield, :default => 0
|
39
|
+
end
|
40
|
+
|
41
|
+
create_table :punks do |t|
|
42
|
+
t.string :fullname
|
43
|
+
t.string :bad_habits_bitfield
|
44
|
+
end
|
45
|
+
|
46
|
+
create_table :parties do |t|
|
47
|
+
t.string :location
|
48
|
+
t.integer :drinks_set, :default => 0
|
49
|
+
t.integer :music_bitfield, :default => 0
|
50
|
+
end
|
51
|
+
|
52
|
+
create_table :itunes do |t|
|
53
|
+
t.string :location
|
54
|
+
t.integer :music_bitfield
|
57
55
|
end
|
58
56
|
end
|
59
57
|
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: degu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.4.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Florian Frank
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-07-11 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: gem_hadar
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,90 +27,86 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: mocha
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: sqlite3
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: rspec
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: '0'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: '0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: utils
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - '>='
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: '0'
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - '>='
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: '0'
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: activerecord
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
|
-
- -
|
87
|
+
- - '>='
|
100
88
|
- !ruby/object:Gem::Version
|
101
89
|
version: '3.0'
|
90
|
+
- - <
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '5.0'
|
102
93
|
type: :runtime
|
103
94
|
prerelease: false
|
104
95
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
96
|
requirements:
|
107
|
-
- -
|
97
|
+
- - '>='
|
108
98
|
- !ruby/object:Gem::Version
|
109
99
|
version: '3.0'
|
100
|
+
- - <
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '5.0'
|
110
103
|
description: Library that includes enums, and rails support for enums and bitfield
|
111
104
|
sets.
|
112
105
|
email: dev@pkw.de
|
113
106
|
executables: []
|
114
107
|
extensions: []
|
115
108
|
extra_rdoc_files:
|
116
|
-
- README.
|
109
|
+
- README.md
|
117
110
|
- lib/degu.rb
|
118
111
|
- lib/degu/has_enum.rb
|
119
112
|
- lib/degu/has_set.rb
|
@@ -126,8 +119,9 @@ extra_rdoc_files:
|
|
126
119
|
files:
|
127
120
|
- .gitignore
|
128
121
|
- .travis.yml
|
122
|
+
- COPYING
|
129
123
|
- Gemfile
|
130
|
-
- README.
|
124
|
+
- README.md
|
131
125
|
- Rakefile
|
132
126
|
- VERSION
|
133
127
|
- degu.gemspec
|
@@ -146,36 +140,32 @@ files:
|
|
146
140
|
- test/has_set_test.rb
|
147
141
|
- test/test_helper.rb
|
148
142
|
- test_helper.rb
|
149
|
-
homepage:
|
143
|
+
homepage: https://github.com/tuskenraiders/degu
|
150
144
|
licenses: []
|
145
|
+
metadata: {}
|
151
146
|
post_install_message:
|
152
147
|
rdoc_options:
|
153
148
|
- --title
|
154
149
|
- Degu - Library for enums and bitfield sets.
|
155
150
|
- --main
|
156
|
-
- README.
|
151
|
+
- README.md
|
157
152
|
require_paths:
|
158
153
|
- lib
|
159
154
|
required_ruby_version: !ruby/object:Gem::Requirement
|
160
|
-
none: false
|
161
155
|
requirements:
|
162
|
-
- -
|
156
|
+
- - '>='
|
163
157
|
- !ruby/object:Gem::Version
|
164
158
|
version: '0'
|
165
|
-
segments:
|
166
|
-
- 0
|
167
|
-
hash: -3902368099644713264
|
168
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
-
none: false
|
170
160
|
requirements:
|
171
|
-
- -
|
161
|
+
- - '>='
|
172
162
|
- !ruby/object:Gem::Version
|
173
163
|
version: '0'
|
174
164
|
requirements: []
|
175
165
|
rubyforge_project:
|
176
|
-
rubygems_version:
|
166
|
+
rubygems_version: 2.0.4
|
177
167
|
signing_key:
|
178
|
-
specification_version:
|
168
|
+
specification_version: 4
|
179
169
|
summary: Library for enums and bitfield sets.
|
180
170
|
test_files:
|
181
171
|
- test/has_enum_test.rb
|
data/README.rdoc
DELETED
@@ -1,150 +0,0 @@
|
|
1
|
-
= Degu
|
2
|
-
|
3
|
-
Degu bundles the renum Enumeration implementation with the has_enum and has_set
|
4
|
-
rails plugins.
|
5
|
-
|
6
|
-
== Renum
|
7
|
-
|
8
|
-
=== Description
|
9
|
-
|
10
|
-
Renum provides a readable but terse enum facility for Ruby. Enums are
|
11
|
-
sometimes called object constants and are analogous to the type-safe enum
|
12
|
-
pattern in Java, though obviously Ruby's flexibility means there's no such
|
13
|
-
thing as type-safety.
|
14
|
-
|
15
|
-
== Usage
|
16
|
-
|
17
|
-
Renum allows you to do things like this:
|
18
|
-
|
19
|
-
enum :Status, %w( NOT_STARTED IN_PROGRESS COMPLETE )
|
20
|
-
|
21
|
-
enum :Size do
|
22
|
-
Small("Really really tiny")
|
23
|
-
Medium("Sort of in the middle")
|
24
|
-
Large("Quite big")
|
25
|
-
|
26
|
-
attr_reader :description
|
27
|
-
|
28
|
-
def init description
|
29
|
-
@description = description
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
module MyNamespace
|
34
|
-
enum :FooValue, [ :Bar, :Baz, :Bat ]
|
35
|
-
end
|
36
|
-
|
37
|
-
Giving you something that satisfies this spec, plus a bit more:
|
38
|
-
|
39
|
-
describe "enum" do
|
40
|
-
|
41
|
-
it "creates a class for the value type" do
|
42
|
-
Status.class.should == Class
|
43
|
-
end
|
44
|
-
|
45
|
-
it "makes each value an instance of the value type" do
|
46
|
-
Status::NOT_STARTED.class.should == Status
|
47
|
-
end
|
48
|
-
|
49
|
-
it "exposes array of values" do
|
50
|
-
Status.values.should == [Status::NOT_STARTED, Status::IN_PROGRESS, Status::COMPLETE]
|
51
|
-
end
|
52
|
-
|
53
|
-
it "provides an alternative means of declaring values where extra information can be provided for initialization" do
|
54
|
-
Size::Small.description.should == "Really really tiny"
|
55
|
-
end
|
56
|
-
|
57
|
-
it "enumerates over values" do
|
58
|
-
Status.map {|s| s.name}.should == %w[NOT_STARTED IN_PROGRESS COMPLETE]
|
59
|
-
end
|
60
|
-
|
61
|
-
it "indexes values" do
|
62
|
-
Status[2].should == Status::COMPLETE
|
63
|
-
end
|
64
|
-
|
65
|
-
it "provides index lookup on values" do
|
66
|
-
Status::IN_PROGRESS.index.should == 1
|
67
|
-
end
|
68
|
-
|
69
|
-
it "provides a reasonable to_s for values" do
|
70
|
-
Status::NOT_STARTED.to_s.should == "Status::NOT_STARTED"
|
71
|
-
end
|
72
|
-
|
73
|
-
it "makes values comparable" do
|
74
|
-
Status::NOT_STARTED.should < Status::COMPLETE
|
75
|
-
end
|
76
|
-
|
77
|
-
it "allows enums to be nested in other modules or classes" do
|
78
|
-
MyNamespace::FooValue::Bar.class.should == MyNamespace::FooValue
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
=== Rails[http://www.rubyonrails.com/] Integration
|
84
|
-
|
85
|
-
To use enumerated values as ActiveRecord attribute values, use the
|
86
|
-
constantize_attribute plugin
|
87
|
-
(https://github.com/duelinmarkers/constantize_attribute/tree) (also by me).
|
88
|
-
|
89
|
-
class Vehicle < ActiveRecord::Base
|
90
|
-
enum :Status do
|
91
|
-
New()
|
92
|
-
Used()
|
93
|
-
Salvage(true)
|
94
|
-
|
95
|
-
def init(warn = false)
|
96
|
-
@warn = warn
|
97
|
-
end
|
98
|
-
|
99
|
-
def requires_warning_buyer?
|
100
|
-
@warn
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
constantize_attribute :status
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
v = Vehicle.create! :status => Vehicle::Status::New
|
109
|
-
# Now the database has the string "Vehicle::Status::New",
|
110
|
-
# but your record object exposes the Status object:
|
111
|
-
v.status.requires_warning_buyer? # => false
|
112
|
-
|
113
|
-
v.update_attribute :status, Vehicle::Status::Salvage
|
114
|
-
# Now the database has the string "Vehicle::Status::Salvage".
|
115
|
-
v.status.requires_warning_buyer? # => true
|
116
|
-
|
117
|
-
# Since constantize_attribute also accepts strings, it's easy
|
118
|
-
# to use enumerated values with forms.
|
119
|
-
v.status = "Vehicle::Status::Used"
|
120
|
-
v.status.requires_warning_buyer? # => false
|
121
|
-
|
122
|
-
=== License
|
123
|
-
|
124
|
-
This code is free to use under the terms of the MIT license.
|
125
|
-
|
126
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
127
|
-
a copy of this software and associated documentation files (the
|
128
|
-
"Software"), to deal in the Software without restriction, including
|
129
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
130
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
131
|
-
permit persons to whom the Software is furnished to do so, subject to
|
132
|
-
the following conditions:
|
133
|
-
|
134
|
-
The above copyright notice and this permission notice shall be
|
135
|
-
included in all copies or substantial portions of the Software.
|
136
|
-
|
137
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
138
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
139
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
140
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
141
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
142
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
143
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
144
|
-
|
145
|
-
=== Contact
|
146
|
-
|
147
|
-
Renum was created by John D. Hume. Comments are welcome. Send an email to
|
148
|
-
duelin dot markers at gmail or "contact me via my
|
149
|
-
blog[http://elhumidor.blogspot.com/].
|
150
|
-
|