yinum 1.8.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 91dd035ae18c028a192338197d8a66f85446f230
4
- data.tar.gz: f2f97cb348e34639a03775b4e7106b05f455bf2e
3
+ metadata.gz: 1e8081295eac8fc84fd85a1d3be91ab25a0c38ea
4
+ data.tar.gz: b3e09fe7ab057e6d5376c7ff340604e5b1dd96a9
5
5
  SHA512:
6
- metadata.gz: 8ff43e20151586d1eb18e8b59b4619aebe1038e3813515bd24c4ff3ca374800e3b92d1e5e93dbde62925aaa13a16c81df027dc9895179ba6c74d44480958b424
7
- data.tar.gz: b19b884b6c0e0e87b795fcfd16aa3662ca80eef65ab1c1095d7f1df3f00f1de12592e1c89d305fa29407e250cc0ee6af1988578e712f55465722d6abd8741127
6
+ metadata.gz: dba6fa59647819652cabe411f0af9354abe87b9b522cc4dd03f3ebbfa0837a91e602e6dc195cf91f09cce17d718647037a93e027b3df4da159cfb2450f22d509
7
+ data.tar.gz: a0e2d4eabcdfdc21557f785db1e0c5b33e9e9f2e0f32f84c2aa59c0cb663993745eaaaa88a14371f808a65be0d3d162932c850120487426a9ea6e6eea5bb5d58
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ **2.0.0**
2
+ * Use `#alias_attr` instead of calling super in `Enum::Helpers::EnumAttribute`.
3
+ * Allow valueless enums (given with `Array` instead of `Hash`), that map to the
4
+ string of the key.
5
+
1
6
  **1.8.1**
2
7
  * Oops, merge 1.7.5 into 1.8.
3
8
 
data/Gemfile.lock CHANGED
@@ -1,12 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yinum (1.8.1)
4
+ yinum (2.0.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.2.5)
10
+ nil_or (2.0.0)
10
11
  rspec (2.14.1)
11
12
  rspec-core (~> 2.14.0)
12
13
  rspec-expectations (~> 2.14.0)
@@ -20,5 +21,6 @@ PLATFORMS
20
21
  ruby
21
22
 
22
23
  DEPENDENCIES
23
- rspec
24
+ nil_or (~> 2.0)
25
+ rspec (~> 2.0)
24
26
  yinum!
data/README.md CHANGED
@@ -1,215 +1,288 @@
1
- # yinum
1
+ # yinum [![Gem Version](https://badge.fury.io/rb/yinum.svg)](http://badge.fury.io/rb/yinum)
2
2
 
3
3
  A yummy straightforward implementation of an enum for Ruby (on Rails).
4
4
 
5
5
  The straightforward usage looks like this:
6
6
 
7
- COLORS = Enum.new(:COLORS, :red => 1, :green => 2, :blue => 3)
8
- COLORS.red
9
- => COLORS.red
10
- COLORS.red == 1 && COLORS.red == :red
11
- => true
7
+ ```ruby
8
+ COLORS = Enum.new(:COLORS, :red => 1, :green => 2, :blue => 3)
9
+ COLORS.red
10
+ => COLORS.red
11
+ COLORS.red == 1 && COLORS.red == :red
12
+ => true
13
+ ```
12
14
 
13
- ## Getting started
15
+ ## Installation
14
16
 
15
- $ gem install yinum
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'yinum'
21
+ ```
22
+
23
+ And then execute:
16
24
 
17
- Or in your Gemfile:
25
+ $ bundle
18
26
 
19
- gem "yinum"
27
+ Or install it yourself as:
28
+
29
+ $ gem install yinum
20
30
 
21
31
  ## Usage
22
32
 
23
33
  Creating an enum:
24
34
 
25
- FRUITS = Enum.new(:FRUITS, :apple => 1, :orange => 2)
26
- => FRUITS(:apple => 1, :orange => 2)
35
+ ```ruby
36
+ FRUITS = Enum.new(:FRUITS, :apple => 1, :orange => 2)
37
+ => FRUITS(:apple => 1, :orange => 2)
38
+ ```
27
39
 
28
40
  Creating an enum with a parent class:
29
41
 
30
- class Car
31
- COLORS = Enum.new(:COLORS, Car, :red => 1, :black => 2)
32
- end
33
- => Car::COLORS(:red => 1, :black => 2)
42
+ ```ruby
43
+ class Car
44
+ COLORS = Enum.new(:COLORS, Car, :red => 1, :black => 2)
45
+ end
46
+ => Car::COLORS(:red => 1, :black => 2)
47
+ ```
34
48
 
35
49
  Another way, with the helper method:
36
50
 
37
- class Car
38
- enum :COLORS, 1 => :red, 2 => :black
39
- end
40
- => Car::COLORS(:red => 1, :black => 2)
51
+ ```ruby
52
+ class Car
53
+ enum :COLORS, 1 => :red, 2 => :black
54
+ end
55
+ => Car::COLORS(:red => 1, :black => 2)
56
+ ```
41
57
 
42
58
  (Can go either KEY => VALUE or VALUE => KEY as long as the key is a Symbol or the value is a Numeric).
43
59
 
44
60
  Getting enum values:
45
61
 
46
- FRUITS.apple
47
- => FRUITS.apple
48
- FRUITS[:apple]
49
- => FRUITS.apple
50
- FRUITS[1]
51
- => FRUITS.apple
52
- FRUITS['orange']
53
- => FRUITS.orange
54
- FRUITS['2']
55
- => FRUITS.orange
56
- FRUITS['orange', '1']
57
- => [FRUITS.orange, FRUITS.apple]
62
+ ```ruby
63
+ FRUITS.apple
64
+ => FRUITS.apple
65
+ FRUITS[:apple]
66
+ => FRUITS.apple
67
+ FRUITS[1]
68
+ => FRUITS.apple
69
+ FRUITS['orange']
70
+ => FRUITS.orange
71
+ FRUITS['2']
72
+ => FRUITS.orange
73
+ FRUITS['orange', '1']
74
+ => [FRUITS.orange, FRUITS.apple]
75
+ ```
58
76
 
59
77
  Comparing enum values:
60
78
 
61
- fruit = FRUITS.orange
62
- => FRUITS.orange
63
- fruit == 2
64
- => true
65
- fruit == :orange
66
- => true
67
- fruit.apple?
68
- => false
79
+ ```ruby
80
+ fruit = FRUITS.orange
81
+ => FRUITS.orange
82
+ fruit == 2
83
+ => true
84
+ fruit == :orange
85
+ => true
86
+ fruit.apple?
87
+ => false
88
+ ```
69
89
 
70
90
  The enum value is actually a delegate to the value with a special inspect and comparison:
71
91
 
72
- fruit = FRUITS.orange
73
- => FRUITS.orange
74
- fruit.to_i
75
- => 2
76
- fruit + 1
77
- => 3
78
- fruit > FRUITS.apple
79
- => true
92
+ ```ruby
93
+ fruit = FRUITS.orange
94
+ => FRUITS.orange
95
+ fruit.to_i
96
+ => 2
97
+ fruit + 1
98
+ => 3
99
+ fruit > FRUITS.apple
100
+ => true
101
+ ```
80
102
 
81
103
  Generating enum attribute methods for your class:
82
104
 
83
- class Car
84
- attr_accessor :color
85
- attr_enum :color, :COLORS, :red => 1, :black => 2
86
- end
87
- car = Car.new
88
- car.color = :red
89
- car.color
90
- => Car::COLORS.red
91
- car.color = "2"
92
- car.color
93
- => Car::COLORS.black
94
- car.color.black?
95
- => false
105
+ ```ruby
106
+ class Car
107
+ attr_accessor :color
108
+ attr_enum :color, :COLORS, :red => 1, :black => 2
109
+ end
110
+ car = Car.new
111
+ car.color = :red
112
+ car.color
113
+ => Car::COLORS.red
114
+ car.color = "2"
115
+ car.color
116
+ => Car::COLORS.black
117
+ car.color_without_enum
118
+ => "2"
119
+ car.color.black?
120
+ => false
121
+ ```
96
122
 
97
123
  If this is a defining attribute for the class, add `:qualifier => true` to generate question methods like so:
98
124
 
99
- class Car
100
- attr_accessor :color
101
- attr_enum :color, :COLORS, { :qualifier => true }, :red => 1, :black => 2
102
- end
103
- car = Car.new
104
- car.color = :red
105
- car.red?
106
- => true
125
+ ```ruby
126
+ class Car
127
+ attr_accessor :color
128
+ attr_enum :color, :COLORS, { :qualifier => true }, :red => 1, :black => 2
129
+ end
130
+ car = Car.new
131
+ car.color = :red
132
+ car.red?
133
+ => true
134
+ ```
107
135
 
108
136
  How the enum gets along with Rails, assuming the following model:
109
137
 
110
- # == Schema Info
111
- #
112
- # Table name: cars
113
- #
114
- # id :integer(11) not null, primary key
115
- # color :integer(11)
116
- #
138
+ ```ruby
139
+ # == Schema Info
140
+ #
141
+ # Table name: cars
142
+ #
143
+ # id :integer(11) not null, primary key
144
+ # color :integer(11)
145
+ #
117
146
 
118
- class Car < ActiveRecord::Base
119
- enum_column :color, :COLORS, :red => 1, :black => 2
120
- end
147
+ class Car < ActiveRecord::Base
148
+ enum_column :color, :COLORS, :red => 1, :black => 2
149
+ end
150
+ ```
121
151
 
122
152
  Now the `color` column is always read and written using the enum value feature:
123
153
 
124
- Car.create! :color => :red
125
- => #<Car id: 1, color: 1>
126
- Car.last.color.red?
127
- => true
154
+ ```ruby
155
+ Car.create! :color => :red
156
+ => #<Car id: 1, color: 1>
157
+ Car.last.color.red?
158
+ => true
159
+ ```
128
160
 
129
161
  This also creates a `validates_inclusion_of` with `allow_nil => true` to prevent having bad values.
130
162
 
131
163
  Adding a `:scoped => true` option before the enum values allows automatic generation of scopes and question
132
164
  methods on the model as follows:
133
165
 
134
- class Car < ActiveRecord::Base
135
- enum_column :color, :COLORS, { :scoped => true }, :red => 1, :black => 2
136
- end
137
- Car.red.to_sql
138
- => "SELECT `cars`.* FROM `cars` WHERE `cars`.`color` = 1"
139
- Car.last.red?
140
- => true
166
+ ```ruby
167
+ class Car < ActiveRecord::Base
168
+ enum_column :color, :COLORS, { :scoped => true }, :red => 1, :black => 2
169
+ end
170
+ Car.red.to_sql
171
+ => "SELECT `cars`.* FROM `cars` WHERE `cars`.`color` = 1"
172
+ Car.last.red?
173
+ => true
174
+ ```
141
175
 
142
176
  You can also use another class's enum for your class with enum\_column and attr\_enum (including generated methods) like so:
143
177
 
144
- class Motorcycle < ActiveRecord::Base
145
- enum_column :color, Car::COLORS, { :scoped => true }
146
- end
147
- Motorcycle.black.to_sql
148
- => "SELECT `motorcycles`.* FROM `motorcycles` WHERE `motorcycles`.`color` = 2"
149
- Motorcycle.black
150
- => Car::COLORS.black
178
+ ```ruby
179
+ class Motorcycle < ActiveRecord::Base
180
+ enum_column :color, Car::COLORS, { :scoped => true }
181
+ end
182
+ Motorcycle.black.to_sql
183
+ => "SELECT `motorcycles`.* FROM `motorcycles` WHERE `motorcycles`.`color` = 2"
184
+ Motorcycle.black
185
+ => Car::COLORS.black
186
+ ```
151
187
 
152
188
  Last but not least, automatic translation lookup.
153
189
  Given the following `config/locales/en.yml`:
154
190
 
155
- en:
156
- enums:
157
- fruits:
158
- apple: Green Apple
159
- orange: Orange Color
160
- colors:
161
- red: Shiny Red
162
- black: Blackest Black
163
- car:
164
- colors:
165
- black: Actually, white
191
+ ```yaml
192
+ en:
193
+ enums:
194
+ fruits:
195
+ apple: Green Apple
196
+ orange: Orange Color
197
+ colors:
198
+ red: Shiny Red
199
+ black: Blackest Black
200
+ car:
201
+ colors:
202
+ black: Actually, white
203
+ ```
166
204
 
167
205
  The following will occur:
168
206
 
169
- FRUITS.apple.t
170
- => "Green Apple"
171
- FRUITS[2].t
172
- => "Orange Color"
173
- Car::COLORS.red.t
174
- => "Shiny Red"
175
- Car::COLORS.black.t
176
- => "Actually, white"
177
- Car::COLORS.options # nice for options_for_select
178
- => { "Shiny Red" => :red, "Actually, white" => :black }
207
+ ```ruby
208
+ FRUITS.apple.t
209
+ => "Green Apple"
210
+ FRUITS[2].t
211
+ => "Orange Color"
212
+ Car::COLORS.red.t
213
+ => "Shiny Red"
214
+ Car::COLORS.black.t
215
+ => "Actually, white"
216
+ Car::COLORS.options # nice for options_for_select
217
+ => { "Shiny Red" => :red, "Actually, white" => :black }
218
+ ```
179
219
 
180
220
  When the enum is given a parent, the class's name is used in the translation.
181
221
  If the translation is missing, it fallbacks to the translation without the class's name.
182
222
 
183
223
  All enum names (usually CONSTANT\_LIKE) and parent class names are converted to snakecase.
184
224
 
225
+ ### Valueless Enums
226
+
227
+ You can also define an enum without giving values, by giving an `Array` instead
228
+ of a `Hash`.
229
+
230
+ ```ruby
231
+ FRUITS = Enum.new(:FRUITS, [:apple, :orange])
232
+ FRUITES.apple.value
233
+ => "apple"
234
+ ```
235
+
236
+ This will give you validations on attributes and columns, without forcing you
237
+ to keep track of an incremental value for the keys.
238
+
239
+ Keep in mind that with columns it means that you'll need a string column type
240
+ instead of an integer.
241
+
185
242
  ## Limitations
186
243
 
187
244
  Since the `===` operator is called on the when value, this syntax cannot be used:
188
245
 
189
- case fruit
190
- when :apple then "This will never happen!"
191
- end
246
+ ```ruby
247
+ case fruit
248
+ when :apple then "This will never happen!"
249
+ end
250
+ ```
192
251
 
193
252
  The following should be used instead:
194
253
 
195
- case fruit
196
- when FRUITS.apple then "This is better..."
197
- end
254
+ ```ruby
255
+ case fruit
256
+ when FRUITS.apple then "This is better..."
257
+ end
258
+ ```
198
259
 
199
260
  This is because I had trouble overriding the `===` operator of the Symbol class.
200
261
 
201
262
  Another limitation is the following:
202
263
 
203
- Car.where(:color => :red) # bad
204
- Car.where(:color => Car::COLORS.red) # good
264
+ ```ruby
265
+ Car.where(:color => :red) # bad
266
+ Car.where(:color => Car::COLORS.red) # good
267
+ ```
205
268
 
206
269
  You may use the EnumValue object for anything, but don't get smart using the key.
207
270
  If the EnumValue doesn't work in a spot, use #name (in `options_for_select`) or #value (in `update_all`).
208
271
 
209
272
  ## Also
210
273
 
211
- EnumValue also works well with [nil_or](https://github.com/toplex/nil_or):
274
+ EnumValue also works well with [nil_or](https://github.com/odedniv/nil_or):
275
+
276
+ ```ruby
277
+ fruit = FRUITS.apple
278
+ fruit.nil_or.t
279
+ => "Green Apple"
280
+ ```
281
+
282
+ ## Contributing
212
283
 
213
- fruit = FRUITS.apple
214
- fruit.nil_or.t
215
- => "Green Apple"
284
+ 1. Fork it ( https://github.com/odedniv/enum/fork )
285
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
286
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
287
+ 4. Push to the branch (`git push origin my-new-feature`)
288
+ 5. Create a new Pull Request
data/lib/enum.rb CHANGED
@@ -5,7 +5,7 @@ class Enum
5
5
  attr_reader :klass, :name, :by_name, :by_value
6
6
 
7
7
  def initialize(name, klass=nil, hash={})
8
- klass, hash = nil, klass if klass.is_a?(Hash)
8
+ klass, hash = nil, klass unless klass.is_a?(Class)
9
9
  @name, @klass = name, klass
10
10
  map_hash(hash)
11
11
  generate_methods
@@ -48,12 +48,13 @@ class Enum
48
48
 
49
49
  private
50
50
  def map_hash(hash)
51
+ hash = Hash[hash.map { |n| [n, n.to_s] }] if hash.is_a?(Array)
51
52
  @by_name = {}
52
53
  @by_value = {}
53
54
  @by_name_s = {}
54
55
  @by_value_s = {}
55
56
  hash.each do |n, v|
56
- n, v = v, n if v.is_a?(Symbol) or n.is_a?(Numeric)
57
+ n, v = v, n if v.is_a?(Symbol) and not n.is_a?(Symbol)
57
58
  raise "duplicate enum name #{n} for #{to_s}" if @by_name.has_key?(n)
58
59
  raise "duplicate enum value #{v} for #{to_s}.#{n}" if @by_value.has_key?(v)
59
60
  raise "value can't be nil for #{to_s}.#{n}" if v.nil?
@@ -104,6 +104,6 @@ class Enum::EnumValue < BasicObject
104
104
  require 'nil_or'
105
105
  rescue ::LoadError
106
106
  else
107
- include ::NilOr
107
+ include ::NilOr::Methods
108
108
  end
109
109
  end
@@ -19,19 +19,31 @@ module Enum::Helpers::EnumAttribute
19
19
  e = const_get(name_or_enum)
20
20
  end
21
21
  # attribute reader
22
- define_method(attr) do
23
- v = super()
24
- (ev = e.get(v)).nil? ? Enum::EnumValue.new(e, v) : ev
22
+ reader, reader_without_enum = attr, :"#{attr}_without_enum"
23
+ begin
24
+ alias_method reader_without_enum, reader
25
+ rescue NameError # reader does not exist
26
+ else
27
+ define_method(reader) do
28
+ v = send(reader_without_enum)
29
+ (ev = e.get(v)).nil? ? Enum::EnumValue.new(e, v) : ev
30
+ end
25
31
  end
26
32
  # attribute writer
27
- define_method("#{attr}=") do |v|
28
- case
29
- when v.enum_value?
30
- super(v.value)
31
- when v.nil?, v == "" # might be received from forms
32
- super(v)
33
- else
34
- super(e[v].value)
33
+ writer, writer_without_enum = :"#{attr}=", :"#{attr}_without_enum="
34
+ begin
35
+ alias_method writer_without_enum, writer
36
+ rescue NameError # writer does not exist
37
+ else
38
+ define_method(writer) do |v|
39
+ case
40
+ when v.enum_value?
41
+ send(writer_without_enum, v.value)
42
+ when v.nil?, v == "" # might be received from forms
43
+ send(writer_without_enum, v)
44
+ else
45
+ send(writer_without_enum, e[v].value)
46
+ end
35
47
  end
36
48
  end
37
49
 
data/lib/enum/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Enum
2
- VERSION = '1.8.1'
2
+ VERSION = '2.0.0'
3
3
  end
@@ -7,26 +7,24 @@ class I18n
7
7
  end
8
8
 
9
9
  describe Enum::EnumValue do
10
- subject { @enum }
11
-
12
10
  context "no parent" do
13
- before { @enum = Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
14
- # can't use subject @enum.red as it turns into a Fixnum
11
+ subject(:enum) { Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
12
+ # can't use EnumValue in subject for some reason
15
13
 
16
- specify { @enum.red.inspect.should == "MY_COLORS.red" }
17
- specify { @enum.red.t.should == "enums.my_colors.red" }
18
- end # context "no parent"
14
+ specify { enum.red.inspect.should == "MY_COLORS.red" }
15
+ specify { enum.red.t.should == "enums.my_colors.red" }
16
+ end
19
17
 
20
18
  context "with parent" do
21
- before { @enum = Enum.new(:MY_COLORS, Object, :red => 1, :blue => 2) }
22
- # can't use subject @enum.red as it turns into a Fixnum
19
+ subject(:enum) { Enum.new(:MY_COLORS, Object, :red => 1, :blue => 2) }
20
+ # can't use EnumValue in subject for some reason
23
21
 
24
- specify { @enum.red.inspect.should == "Object::MY_COLORS.red" }
25
- specify { @enum.red.t.should == "enums.object.my_colors.red" }
26
- end # context "with parent"
22
+ specify { enum.red.inspect.should == "Object::MY_COLORS.red" }
23
+ specify { enum.red.t.should == "enums.object.my_colors.red" }
24
+ end
27
25
 
28
26
  context "comparison" do
29
- before { @enum = Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
27
+ subject(:enum) { Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
30
28
 
31
29
  its(:red) { should == 1 }
32
30
  its(:blue) { should_not == 1 }
@@ -38,12 +36,21 @@ describe Enum::EnumValue do
38
36
  its(:blue) { should_not === :red }
39
37
  its(:red) { should be_red }
40
38
  its(:blue) { should_not be_red }
41
- specify { @enum.red.object_id.should == @enum[:red].object_id }
42
- specify { @enum.red.object_id.should == @enum[1].object_id }
43
- end # context "comparison"
39
+ specify { enum.red.object_id.should == enum[:red].object_id }
40
+ specify { enum.red.object_id.should == enum[1].object_id }
41
+ end
44
42
 
45
43
  context "invalid" do
46
- specify { expect { @enum[:green] }.to raise_error(StandardError) }
47
- specify { expect { @enum[3] }.to raise_error(StandardError) }
48
- end # context "invalid"
49
- end # describe EnumValue
44
+ subject(:enum) { Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
45
+
46
+ specify { expect { enum[:green] }.to raise_error(StandardError) }
47
+ specify { expect { enum[3] }.to raise_error(StandardError) }
48
+ end
49
+
50
+ describe "#nil_or" do
51
+ subject(:enum) { Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
52
+ # can't use EnumValue in subject for some reason
53
+
54
+ specify { enum.red.nil_or.should be_enum_value }
55
+ end
56
+ end
@@ -0,0 +1,68 @@
1
+ class EnumUserBase
2
+ attr_accessor :color
3
+
4
+ class << self
5
+ def create_class(name = self.name)
6
+ klass_name = :"Anonymous#{name}"
7
+ send(:remove_const, klass_name) if const_defined?(klass_name)
8
+ const_set(klass_name, Class.new(self)) # gives a name
9
+ end
10
+ end
11
+ end
12
+
13
+ shared_examples_for Enum::Helpers::EnumGenerator do
14
+ subject { klass::COLORS }
15
+
16
+ its(:name) { should == :COLORS }
17
+ its(:klass) { should == klass }
18
+ its(:by_name) { should == { :red => 1, :blue => 2 } }
19
+ end
20
+
21
+ shared_examples_for Enum::Helpers::EnumAttribute do
22
+ subject(:record) { klass.new }
23
+ before { record.instance_eval { @color = :unknown } }
24
+
25
+ describe "setter" do
26
+ context "nil" do
27
+ before { record.color = nil }
28
+ specify { record.instance_eval { @color }.should be_nil }
29
+ specify { record.instance_eval { @color }.should_not be_enum_value }
30
+ end
31
+
32
+ context "name" do
33
+ before { record.color = :red }
34
+ specify { record.instance_eval { @color }.should == 1 }
35
+ specify { record.instance_eval { @color }.should_not be_enum_value }
36
+ end
37
+
38
+ context "value" do
39
+ before { record.color = 2 }
40
+ specify { record.instance_eval { @color }.should == 2 }
41
+ specify { record.instance_eval { @color }.should_not be_enum_value }
42
+ end
43
+
44
+ specify "invalid" do
45
+ expect { @record.color = 3 }.to raise_error(StandardError)
46
+ end
47
+ end
48
+
49
+ describe "getter" do
50
+ context "nil" do
51
+ before { record.instance_eval { @color = nil } }
52
+ specify { record.color.should be_nil }
53
+ specify { record.color.should be_enum_value }
54
+ end
55
+
56
+ context "value" do
57
+ before { record.instance_eval { @color = 2 } }
58
+ specify { record.color.should be_blue }
59
+ specify { record.color.should be_enum_value }
60
+ end
61
+
62
+ context "invalid" do
63
+ before { record.instance_eval { @color = 3 } }
64
+ specify { record.color.should == 3 }
65
+ specify { record.color.should be_enum_value }
66
+ end
67
+ end
68
+ end
@@ -1,152 +1,43 @@
1
1
  require 'spec_helper'
2
+ require 'lib/enum/helpers/common_specs'
2
3
 
3
- class UsesEnumAttribute < Hash # to allow setting 'attributes'
4
+ class EnumAttributeUser < EnumUserBase
4
5
  extend Enum::Helpers::EnumAttribute
5
-
6
- class << self
7
- # enum definition
8
- def define_enum(attr, name_or_enum, options = {}, hash = nil)
9
- @enum_name = name_or_enum.is_a?(Enum) ? name_or_enum.name : name_or_enum
10
- attr_enum attr, name_or_enum, options, hash
11
- end
12
- def undefine_enum
13
- remove_const :COLORS
14
- end
15
- end
16
-
17
- # mocking setters
18
- def method_missing(method, *args, &block)
19
- if method.to_s.end_with?('=') and args.length == 1
20
- self[method.to_s.chop.to_sym] = args.first
21
- elsif method =~ /^[a-z_]*$/ and args.length == 0
22
- self[method]
23
- else
24
- super
25
- end
26
- end
27
- end
28
-
29
- class UsesAnoterEnumAttribute < UsesEnumAttribute
30
- end
31
-
32
- def enum_generator_specs
33
- describe Enum::Helpers::EnumGenerator do
34
- subject { UsesEnumAttribute::COLORS }
35
-
36
- its(:name) { should == :COLORS }
37
- its(:klass) { should == UsesEnumAttribute }
38
- its(:by_name) { should == { :red => 1, :blue => 2 } }
39
- end # describe Enum::Helpers::EnumGenerator
40
- end
41
-
42
- def enum_attribute_specs
43
- context "attributes" do
44
- before do
45
- @record = UsesEnumAttribute.new
46
- @record[:color] = :unknown
47
- end
48
- subject { @record }
49
-
50
- context "setter" do
51
- specify "nil" do
52
- @record.color = nil
53
- @record[:color].should be_nil
54
- @record[:color].should_not be_enum_value
55
- end
56
-
57
- specify "empty string" do
58
- @record.color = ""
59
- @record[:color].should == ""
60
- @record[:color].should_not be_enum_value
61
- end
62
-
63
- specify "symbol name" do
64
- @record.color = :red
65
- @record[:color].should == 1
66
- @record[:color].should_not be_enum_value
67
- end
68
-
69
- specify "string name" do
70
- @record.color = 'red'
71
- @record[:color].should == 1
72
- @record[:color].should_not be_enum_value
73
- end
74
-
75
- specify "value" do
76
- @record.color = 2
77
- @record[:color].should == 2
78
- @record[:color].should_not be_enum_value
79
- end
80
-
81
- specify "invalid" do
82
- expect { @record.color = 3 }.to raise_error(StandardError)
83
- end
84
- end # context "setter"
85
-
86
- context "getter" do
87
- specify "nil" do
88
- @record[:color] = nil
89
- @record.color.should be_nil
90
- @record.color.should be_enum_value
91
- end
92
-
93
- specify "value" do
94
- @record[:color] = 2
95
- @record.color.should be_blue
96
- @record.color.should be_enum_value
97
- end
98
-
99
- specify "invalid" do
100
- @record[:color] = 3
101
- @record.color.should == 3
102
- @record.color.should be_enum_value
103
- end
104
-
105
- specify "invalid empty string" do
106
- @record[:color] = ""
107
- @record.color.should == ""
108
- @record.color.should be_enum_value
109
- end
110
- end # context "getter"
111
- end # context "attribute"
112
6
  end
113
7
 
114
8
  describe Enum::Helpers::EnumAttribute do
115
- after { UsesEnumAttribute.undefine_enum }
116
- subject { UsesEnumAttribute }
9
+ subject(:klass) { EnumAttributeUser.create_class }
117
10
 
118
11
  context "not qualifier" do
119
- before { UsesEnumAttribute.define_enum(:color, :COLORS, :red => 1, :blue => 2) }
12
+ before { klass.attr_enum(:color, :COLORS, :red => 1, :blue => 2) }
120
13
 
121
- enum_generator_specs
122
- enum_attribute_specs
123
- end # context "not qualifier"
14
+ it_behaves_like Enum::Helpers::EnumGenerator
15
+ it_behaves_like Enum::Helpers::EnumAttribute
16
+ end
124
17
 
125
18
  context "qualifier" do
126
- before { UsesEnumAttribute.define_enum(:color, :COLORS, { :qualifier => true }, :red => 1, :blue => 2) }
19
+ before { klass.attr_enum(:color, :COLORS, { :qualifier => true }, :red => 1, :blue => 2) }
127
20
 
128
- enum_generator_specs
129
- enum_attribute_specs
21
+ it_behaves_like Enum::Helpers::EnumGenerator
22
+ it_behaves_like Enum::Helpers::EnumAttribute
130
23
 
131
24
  context "questions" do
132
- before do
133
- @record = UsesEnumAttribute.new
134
- @record.color = :red
135
- end
136
- subject { @record }
25
+ subject(:record) { klass.new }
26
+ before { record.color = :red }
137
27
 
138
28
  it { should be_red }
139
29
  it { should_not be_blue }
140
- end # context "questions"
141
- end # context "qualifier"
30
+ end
31
+ end
142
32
 
143
33
  context "use another enum" do
144
34
  before do
145
- UsesEnumAttribute.define_enum(:color, :COLORS, { :qualifier => true }, :red => 1, :blue => 2)
146
- UsesAnoterEnumAttribute.define_enum(:color, UsesEnumAttribute::COLORS)
35
+ klass.attr_enum(:color, :COLORS, { :qualifier => true }, :red => 1, :blue => 2)
36
+ another_klass = EnumAttributeUser.create_class(:AnotherEnumAttributeUser)
37
+ another_klass.attr_enum(:color, klass::COLORS)
147
38
  end
148
39
 
149
- enum_generator_specs
150
- enum_attribute_specs
40
+ it_behaves_like Enum::Helpers::EnumGenerator
41
+ it_behaves_like Enum::Helpers::EnumAttribute
151
42
  end
152
- end # describe Enum::Helpers::EnumAttribute
43
+ end
@@ -1,27 +1,13 @@
1
1
  require 'spec_helper'
2
+ require 'lib/enum/helpers/common_specs'
2
3
 
3
- class UsesEnumColumn < Hash # to allow setting 'attributes'
4
+ class EnumColumnUser < EnumUserBase
4
5
  extend Enum::Helpers::EnumColumn
5
-
6
6
  class << self
7
- # enum definition
8
- def define_enum(attr, name_or_enum, options={}, hash=nil)
9
- @enum_name = name_or_enum.is_a?(Enum) ? name_or_enum.name : name_or_enum
10
- reset_mocks
11
- enum_column attr, name_or_enum, options, hash
12
- end
13
- def undefine_enum
14
- remove_const :COLORS
15
- end
16
- def reset_mocks
17
- @inclusion_validations = []
18
- @scopes = []
19
- end
20
-
21
7
  # mocking validates_inclusion_of
22
8
  attr_reader :inclusion_validations
23
9
  def validates_inclusion_of(*attributes)
24
- @inclusion_validations << attributes
10
+ (@inclusion_validations ||= []) << attributes
25
11
  end
26
12
  # mocking scopes
27
13
  def where(*attributes)
@@ -29,137 +15,59 @@ class UsesEnumColumn < Hash # to allow setting 'attributes'
29
15
  end
30
16
  attr_reader :scopes
31
17
  def scope(name, value)
32
- @scopes << [name, value.call]
33
- end
34
-
35
- end
36
-
37
- # mocking setters
38
- def method_missing(method, *args, &block)
39
- if method.to_s.end_with?('=') and args.length == 1
40
- self[method.to_s.chop.to_sym] = args.first
41
- elsif method =~ /^[a-z_]*$/ and args.length == 0
42
- self[method]
43
- else
44
- super
18
+ (@scopes ||= []) << [name, value.call]
45
19
  end
46
20
  end
47
21
  end
48
22
 
49
- class UsesAnoterEnumColumn < UsesEnumColumn
50
- end
51
-
52
- def enum_generator_specs
53
- describe Enum::Helpers::EnumGenerator do
54
- subject { UsesEnumColumn::COLORS }
55
-
56
- its(:name) { should == :COLORS }
57
- its(:klass) { should == UsesEnumColumn }
58
- its(:by_name) { should == { :red => 1, :blue => 2 } }
59
- end # describe Enum::Helpers::EnumGenerator
60
- end
61
-
62
- def enum_columns_attribute_specs
63
- context "attributes" do
64
- before do
65
- @record = UsesEnumColumn.new
66
- @record[:color] = :unknown
67
- end
68
- subject { @record }
69
-
70
- context "setter" do
71
- specify "nil" do
72
- @record.color = nil
73
- @record[:color].should be_nil
74
- @record[:color].should_not be_enum_value
75
- end
76
-
77
- specify "name" do
78
- @record.color = :red
79
- @record[:color].should == 1
80
- @record[:color].should_not be_enum_value
81
- end
82
-
83
- specify "value" do
84
- @record.color = 2
85
- @record[:color].should == 2
86
- @record[:color].should_not be_enum_value
87
- end
88
-
89
- specify "invalid" do
90
- expect { @record.color = 3 }.to raise_error(StandardError)
91
- end
92
- end # context "setter"
93
-
94
- context "getter" do
95
- specify "nil" do
96
- @record[:color] = nil
97
- @record.color.should be_nil
98
- @record.color.should be_enum_value
99
- end
100
-
101
- specify "value" do
102
- @record[:color] = 2
103
- @record.color.should be_blue
104
- @record.color.should be_enum_value
105
- end
106
-
107
- specify "invalid" do
108
- @record[:color] = 3
109
- @record.color.should == 3
110
- @record.color.should be_enum_value
111
- end
112
- end # context "getter"
113
- end # context "attribute"
114
-
115
- context "validations" do
23
+ describe Enum::Helpers::EnumColumn do
24
+ shared_examples_for "validations" do
116
25
  its(:inclusion_validations) { should have(1).item }
117
26
  its(:inclusion_validations) { should include([:color, :in => [1, 2], :allow_nil => true]) }
118
- end # context "validations"
119
- end
27
+ end
120
28
 
121
- describe Enum::Helpers::EnumColumn do
122
- after { UsesEnumColumn.undefine_enum }
123
- subject { UsesEnumColumn }
29
+ subject(:klass) { EnumColumnUser.create_class }
124
30
 
125
31
  context "not scoped" do
126
- before { UsesEnumColumn.define_enum(:color, :COLORS, :red => 1, :blue => 2) }
32
+ before { klass.enum_column(:color, :COLORS, :red => 1, :blue => 2) }
127
33
 
128
- enum_generator_specs
129
- enum_columns_attribute_specs
130
- end # context "not scoped"
34
+ it_behaves_like Enum::Helpers::EnumGenerator
35
+ it_behaves_like "validations"
36
+ end
131
37
 
132
38
  context "scoped" do
133
- before { UsesEnumColumn.define_enum(:color, :COLORS, { :scoped => true }, :red => 1, :blue => 2) }
39
+ before { klass.enum_column(:color, :COLORS, { :scoped => true }, :red => 1, :blue => 2) }
134
40
 
135
- enum_generator_specs
136
- enum_columns_attribute_specs
41
+ it_behaves_like Enum::Helpers::EnumGenerator
42
+ it_behaves_like Enum::Helpers::EnumAttribute
43
+ it_behaves_like "validations"
137
44
 
138
- context "scopes" do
45
+ describe "scopes" do
139
46
  its(:scopes) { should have(2).items }
140
47
  its(:scopes) { should include([:red, :where => [:color => 1]]) }
141
48
  its(:scopes) { should include([:blue, :where => [:color => 2]]) }
142
- end # context "scopes"
49
+ end
143
50
 
144
- context "questions" do
145
- before do
146
- @record = UsesEnumColumn.new
147
- @record.color = :red
148
- end
149
- subject { @record }
51
+ describe "questions" do
52
+ subject(:record) { klass.new }
53
+ before { record.color = :red }
150
54
 
151
55
  it { should be_red }
152
56
  it { should_not be_blue }
153
- end # context "questions"
154
- end # context "scoped"
57
+ end
58
+ end
155
59
 
156
60
  context "use another enum" do
61
+ subject(:klass) { EnumColumnUser.create_class }
62
+
157
63
  before do
158
- UsesEnumColumn.define_enum(:color, :COLORS, { :scoped => true }, :red => 1, :blue => 2)
159
- UsesAnoterEnumColumn.define_enum(:color, UsesEnumColumn::COLORS)
64
+ klass.enum_column(:color, :COLORS, { :scoped => true }, :red => 1, :blue => 2)
65
+ another_klass = EnumColumnUser.create_class(:AnotherEnumColumnUser)
66
+ another_klass.enum_column(:color, klass::COLORS)
160
67
  end
161
68
 
162
- enum_generator_specs
163
- enum_columns_attribute_specs
69
+ it_behaves_like Enum::Helpers::EnumGenerator
70
+ it_behaves_like Enum::Helpers::EnumAttribute
71
+ it_behaves_like "validations"
164
72
  end
165
- end # describe Enum::Helpers::EnumColumn
73
+ end
@@ -1,13 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
- class UsesEnumGenerator
4
- enum :COLORS, :red => 1, :blue => 2
5
- end
6
-
7
3
  describe Enum::Helpers::EnumGenerator do
8
- subject { UsesEnumGenerator::COLORS }
4
+ let(:klass) { EnumUserBase.create_class }
5
+ before { klass.enum(:COLORS, :red => 1, :blue => 2) }
6
+ subject { klass::COLORS }
9
7
 
10
8
  its(:name) { should == :COLORS }
11
- its(:klass) { should == UsesEnumGenerator }
9
+ its(:klass) { should == klass }
12
10
  its(:by_name) { should == { :red => 1, :blue => 2 } }
13
- end # describe Enum::Helpers::EnumGenerator
11
+ end
@@ -1,39 +1,47 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Enum do
4
- context "accessors" do
5
- before { @enum = Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
4
+ describe "accessors" do
5
+ subject(:enum) { Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
6
6
 
7
- specify { @enum.red.should == 1 }
8
- specify { @enum[:red].should == 1 }
9
- specify { expect { @enum[:black] }.to raise_error(StandardError) }
10
- specify { @enum[:red, :blue].should == [1, 2] }
11
- end # context "accessors
7
+ its(:red) { should == 1 }
8
+ specify { enum[:red].should == 1 }
9
+ specify { expect { enum[:black] }.to raise_error(StandardError) }
10
+ specify { enum[:red, :blue].should == [1, 2] }
11
+ end
12
12
 
13
13
  context "keys on left and right" do
14
- before { @enum = Enum.new(:MY_COLORS, :red => 1, 2 => :blue) }
15
- subject { @enum }
14
+ subject(:enum) { Enum.new(:MY_COLORS, :red => 1, 2 => :blue) }
16
15
 
17
16
  its(:names) { should have(2).items }
18
17
  its(:names) { should include(:red, :blue) }
19
18
  its(:values) { should have(2).items }
20
19
  its(:values) { should include(1, 2) }
21
20
  its(:to_a) { should have(2).items }
22
- end # context "keys on left and right"
21
+ end
23
22
 
24
23
  context "no parent" do
25
- before { @enum = Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
26
- subject { @enum }
24
+ subject(:enum) { Enum.new(:MY_COLORS, :red => 1, :blue => 2) }
27
25
 
28
26
  its(:to_s) { should == "MY_COLORS" }
29
27
  its(:inspect) { should == "MY_COLORS(:red => 1, :blue => 2)" }
30
- end # context "no parent"
28
+ end
31
29
 
32
30
  context "with parent" do
33
- before { @enum = Enum.new(:MY_COLORS, Object, :red => 1, :blue => 2) }
34
- subject { @enum }
31
+ subject(:enum) { Enum.new(:MY_COLORS, Object, :red => 1, :blue => 2) }
35
32
 
36
33
  its(:to_s) { should == "Object::MY_COLORS" }
37
34
  its(:inspect) { should == "Object::MY_COLORS(:red => 1, :blue => 2)" }
38
- end # context "with parent"
39
- end # describe Enum
35
+ end
36
+
37
+ context "valueless" do
38
+ subject(:enum) { Enum.new(:MY_COLORS, [:red, :blue]) }
39
+
40
+ its(:to_s) { should == "MY_COLORS" }
41
+ its(:inspect) { should == 'MY_COLORS(:red => "red", :blue => "blue")' }
42
+ its(:red) { should == "red" }
43
+ specify { enum[:red].should == "red" }
44
+ specify { expect { enum[:black] }.to raise_error(StandardError) }
45
+ specify { enum[:red, :blue].should == ["red", "blue"] }
46
+ end
47
+ end
data/yinum.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.version = Enum::VERSION
8
8
  s.authors = ["Oded Niv"]
9
9
  s.email = ["oded.niv@gmail.com"]
10
- s.homepage = "https://github.com/toplex/enum"
10
+ s.homepage = "https://github.com/odedniv/enum"
11
11
  s.summary = %q{Enum implementation}
12
12
  s.description = %q{Yummy implementation of enum that gives integer values with a special wrapping.}
13
13
  s.license = 'UNLICENSE'
@@ -19,5 +19,6 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
 
22
- s.add_development_dependency 'rspec'
22
+ s.add_development_dependency 'rspec', '~> 2.0'
23
+ s.add_development_dependency 'nil_or', '~> 2.0'
23
24
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yinum
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oded Niv
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-04 00:00:00.000000000 Z
11
+ date: 2014-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nil_or
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
27
41
  description: Yummy implementation of enum that gives integer values with a special
28
42
  wrapping.
29
43
  email:
@@ -32,7 +46,7 @@ executables: []
32
46
  extensions: []
33
47
  extra_rdoc_files: []
34
48
  files:
35
- - .gitignore
49
+ - ".gitignore"
36
50
  - CHANGELOG.md
37
51
  - Gemfile
38
52
  - Gemfile.lock
@@ -48,13 +62,14 @@ files:
48
62
  - lib/enum/version.rb
49
63
  - lib/yinum.rb
50
64
  - spec/lib/enum/enum_value_spec.rb
65
+ - spec/lib/enum/helpers/common_specs.rb
51
66
  - spec/lib/enum/helpers/enum_attribute_spec.rb
52
67
  - spec/lib/enum/helpers/enum_column_spec.rb
53
68
  - spec/lib/enum/helpers/enum_generator_spec.rb
54
69
  - spec/lib/enum_spec.rb
55
70
  - spec/spec_helper.rb
56
71
  - yinum.gemspec
57
- homepage: https://github.com/toplex/enum
72
+ homepage: https://github.com/odedniv/enum
58
73
  licenses:
59
74
  - UNLICENSE
60
75
  metadata: {}
@@ -64,18 +79,25 @@ require_paths:
64
79
  - lib
65
80
  required_ruby_version: !ruby/object:Gem::Requirement
66
81
  requirements:
67
- - - '>='
82
+ - - ">="
68
83
  - !ruby/object:Gem::Version
69
84
  version: '0'
70
85
  required_rubygems_version: !ruby/object:Gem::Requirement
71
86
  requirements:
72
- - - '>='
87
+ - - ">="
73
88
  - !ruby/object:Gem::Version
74
89
  version: '0'
75
90
  requirements: []
76
91
  rubyforge_project: yinum
77
- rubygems_version: 2.0.3
92
+ rubygems_version: 2.2.0
78
93
  signing_key:
79
94
  specification_version: 4
80
95
  summary: Enum implementation
81
- test_files: []
96
+ test_files:
97
+ - spec/lib/enum/enum_value_spec.rb
98
+ - spec/lib/enum/helpers/common_specs.rb
99
+ - spec/lib/enum/helpers/enum_attribute_spec.rb
100
+ - spec/lib/enum/helpers/enum_column_spec.rb
101
+ - spec/lib/enum/helpers/enum_generator_spec.rb
102
+ - spec/lib/enum_spec.rb
103
+ - spec/spec_helper.rb