simple_enum 1.6.9 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/LICENSE +1 -1
- data/README.md +248 -0
- data/Rakefile +4 -21
- data/lib/simple_enum/accessors/accessor.rb +55 -0
- data/lib/simple_enum/accessors/ignore_accessor.rb +11 -0
- data/lib/simple_enum/accessors/whiny_accessor.rb +12 -0
- data/lib/simple_enum/accessors.rb +18 -0
- data/lib/simple_enum/attribute.rb +77 -0
- data/lib/simple_enum/enum.rb +37 -0
- data/lib/simple_enum/hasher.rb +26 -0
- data/lib/simple_enum/mongoid.rb +11 -15
- data/lib/simple_enum/translation.rb +17 -0
- data/lib/simple_enum/version.rb +2 -2
- data/lib/simple_enum.rb +19 -276
- data/simple_enum.gemspec +9 -9
- data/spec/simple_enum/accessors_spec.rb +212 -0
- data/spec/simple_enum/attribute_spec.rb +208 -0
- data/spec/simple_enum/enum_spec.rb +96 -0
- data/spec/simple_enum/hasher_spec.rb +63 -0
- data/spec/simple_enum/mongoid_spec.rb +44 -0
- data/spec/simple_enum/translation_spec.rb +66 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/active_record_support.rb +23 -0
- data/spec/support/i18n_support.rb +12 -0
- data/spec/support/model_support.rb +47 -0
- data/spec/support/mongoid_support.rb +21 -0
- metadata +50 -56
- data/README.rdoc +0 -293
- data/lib/simple_enum/enum_hash.rb +0 -64
- data/lib/simple_enum/validation.rb +0 -58
- data/locales/en.yml +0 -10
- data/test/array_conversions_test.rb +0 -21
- data/test/class_methods_test.rb +0 -114
- data/test/dirty_attributes_test.rb +0 -37
- data/test/enum_hash_test.rb +0 -73
- data/test/finders_test.rb +0 -45
- data/test/locales.yml +0 -25
- data/test/mongoid_test.rb +0 -66
- data/test/object_backed_test.rb +0 -61
- data/test/orm/active_record.rb +0 -114
- data/test/orm/common.rb +0 -23
- data/test/orm/mongoid.rb +0 -114
- data/test/poro_test.rb +0 -20
- data/test/prefixes_test.rb +0 -36
- data/test/simple_enum_test.rb +0 -314
- data/test/test_helper.rb +0 -40
- data/test/without_shortcuts_test.rb +0 -39
data/lib/simple_enum.rb
CHANGED
@@ -3,299 +3,42 @@
|
|
3
3
|
# but instead on integer columns.
|
4
4
|
#
|
5
5
|
# Author:: Lukas Westermann
|
6
|
-
# Copyright:: Copyright (c) 2009 Lukas Westermann (Zurich, Switzerland)
|
7
|
-
#
|
6
|
+
# Copyright:: Copyright (c) 2009-2014 Lukas Westermann (Zurich, Switzerland)
|
7
|
+
# License:: MIT-Licence (http://www.opensource.org/licenses/mit-license.php)
|
8
8
|
#
|
9
9
|
# See the +as_enum+ documentation for more details.
|
10
10
|
|
11
|
-
# because we depend on i18n and activesupport
|
12
|
-
require 'i18n'
|
13
11
|
require 'active_support'
|
14
12
|
|
15
|
-
require 'simple_enum/
|
16
|
-
require 'simple_enum/
|
17
|
-
|
18
|
-
require 'active_support/deprecation'
|
13
|
+
require 'simple_enum/version'
|
14
|
+
require 'simple_enum/attribute'
|
15
|
+
require 'simple_enum/translation'
|
19
16
|
|
20
17
|
# Base module which gets included in <tt>ActiveRecord::Base</tt>. See documentation
|
21
18
|
# of +SimpleEnum::ClassMethods+ for more details.
|
22
19
|
module SimpleEnum
|
20
|
+
mattr_accessor :with
|
21
|
+
@@with = [:attribute, :dirty, :scope]
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
# Provides configurability to SimpleEnum, allows to override some defaults which are
|
27
|
-
# defined for all uses of +as_enum+. Most options from +as_enum+ are available, such as:
|
28
|
-
# * <tt>:prefix</tt> - Define a prefix, which is prefixed to the shortcut methods (e.g. <tt><symbol>!</tt> and
|
29
|
-
# <tt><symbol>?</tt>), if it's set to <tt>true</tt> the enumeration name is used as a prefix, else a custom
|
30
|
-
# prefix (symbol or string) (default is <tt>nil</tt> => no prefix)
|
31
|
-
# * <tt>:slim</tt> - If set to <tt>true</tt> no shortcut methods for all enumeration values are being generated, if
|
32
|
-
# set to <tt>:class</tt> only class-level shortcut methods are disabled (default is <tt>nil</tt> => they are generated)
|
33
|
-
# * <tt>:upcase</tt> - If set to +true+ the <tt>Klass.foos</tt> is named <tt>Klass.FOOS</tt>, why? To better suite some
|
34
|
-
# coding-styles (default is +false+ => downcase)
|
35
|
-
# * <tt>:whiny</tt> - Boolean value which if set to <tt>true</tt> will throw an <tt>ArgumentError</tt>
|
36
|
-
# if an invalid value is passed to the setter (e.g. a value for which no enumeration exists). if set to
|
37
|
-
# <tt>false</tt> no exception is thrown and the internal value is set to <tt>nil</tt> (default is <tt>true</tt>)
|
38
|
-
# * <tt>:dirty</tt> - Boolean value which if set to <tt>true</tt> generates <tt>..._was</tt> and <tt>..._changed?</tt>
|
39
|
-
# methods for the enum, which delegate to the internal column.
|
40
|
-
# * <tt>:strings</tt> - Boolean value which if set to <tt>true</tt> defaults array values as strings instead of integers.
|
41
|
-
def default_options
|
42
|
-
@default_options ||= {
|
43
|
-
:whiny => true,
|
44
|
-
:upcase => false
|
45
|
-
}
|
46
|
-
end
|
47
|
-
|
48
|
-
def included(base) #:nodoc:
|
49
|
-
base.send :class_attribute, :simple_enum_definitions, :instance_writer => false, :instance_reader => false
|
50
|
-
base.send :extend, ClassMethods
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
module ClassMethods
|
55
|
-
|
56
|
-
# Provides ability to create simple enumerations based on hashes or arrays, backed
|
57
|
-
# by integer columns (but not limited to integer columns).
|
58
|
-
#
|
59
|
-
# Columns are supposed to be suffixed by <tt>_cd</tt>, if not, use <tt>:column => 'the_column_name'</tt>,
|
60
|
-
# so some example migrations:
|
61
|
-
#
|
62
|
-
# add_column :users, :gender_cd, :integer
|
63
|
-
# add_column :users, :status, :integer # and a custom column...
|
64
|
-
#
|
65
|
-
# and then in your model:
|
66
|
-
#
|
67
|
-
# class User < ActiveRecord::Base
|
68
|
-
# as_enum :gender, [:male, :female]
|
69
|
-
# end
|
70
|
-
#
|
71
|
-
# # or use a hash:
|
72
|
-
#
|
73
|
-
# class User < ActiveRecord::Base
|
74
|
-
# as_enum :user_status, { :active => 1, :inactive => 0, :archived => 2, :deleted => 3 }, :column => 'status'
|
75
|
-
# end
|
76
|
-
#
|
77
|
-
# Now it's possible to access the enumeration and the internally stored value like:
|
78
|
-
#
|
79
|
-
# john_doe = User.new
|
80
|
-
# john_doe.gender # => nil
|
81
|
-
# john_doe.gender = :male
|
82
|
-
# john_doe.gender # => :male
|
83
|
-
# john_doe.gender_cd # => 0
|
84
|
-
#
|
85
|
-
# And to make life a tad easier: a few shortcut methods to work with the enumeration are also created.
|
86
|
-
#
|
87
|
-
# john_doe.male? # => true
|
88
|
-
# john_doe.female? # => false
|
89
|
-
# john_doe.female! # => :female (set's gender to :female => gender_cd = 1)
|
90
|
-
# john_doe.male? # => false
|
91
|
-
#
|
92
|
-
# Sometimes it's required to access the db-backed values, like e.g. in a query:
|
93
|
-
#
|
94
|
-
# User.genders # => { :male => 0, :female => 1}, values hash
|
95
|
-
# User.genders(:male) # => 0, value access (via hash)
|
96
|
-
# User.female # => 1, direct access
|
97
|
-
# User.find :all, :conditions => { :gender_cd => User.female } # => [...], list with all women
|
98
|
-
#
|
99
|
-
# To access the key/value assocations in a helper like the select helper or similar use:
|
100
|
-
#
|
101
|
-
# <%= select(:user, :gender, User.genders.keys)
|
102
|
-
#
|
103
|
-
# The generated shortcut methods (like <tt>male?</tt> or <tt>female!</tt> etc.) can also be prefixed
|
104
|
-
# using the <tt>:prefix</tt> option. If the value is <tt>true</tt>, the shortcut methods are prefixed
|
105
|
-
# with the name of the enumeration.
|
106
|
-
#
|
107
|
-
# class User < ActiveRecord::Base
|
108
|
-
# as_enum :gender, [:male, :female], :prefix => true
|
109
|
-
# end
|
110
|
-
#
|
111
|
-
# jane_doe = User.new
|
112
|
-
# jane_doe.gender = :female # this is still as-is
|
113
|
-
# jane_doe.gender_cd # => 1, and so it this
|
114
|
-
#
|
115
|
-
# jane_doe.gender_female? # => true (instead of jane_doe.female?)
|
116
|
-
#
|
117
|
-
# It is also possible to supply a custom prefix.
|
118
|
-
#
|
119
|
-
# class Item < ActiveRecord::Base
|
120
|
-
# as_enum :status, [:inactive, :active, :deleted], :prefix => :state
|
121
|
-
# end
|
122
|
-
#
|
123
|
-
# item = Item.new(:status => :active)
|
124
|
-
# item.state_inactive? # => false
|
125
|
-
# Item.state_deleted # => 2
|
126
|
-
# Item.status(:deleted) # => 2, same as above...
|
127
|
-
#
|
128
|
-
# To disable the generation of the shortcut methods for all enumeration values, add <tt>:slim => true</tt> to
|
129
|
-
# the options.
|
130
|
-
#
|
131
|
-
# class Address < ActiveRecord::Base
|
132
|
-
# as_enum :canton, {:aargau => 'ag', ..., :wallis => 'vs', :zug => 'zg', :zurich => 'zh'}, :slim => true
|
133
|
-
# end
|
134
|
-
#
|
135
|
-
# home = Address.new(:canton => :zurich, :street => 'Bahnhofstrasse 1', ...)
|
136
|
-
# home.canton # => :zurich
|
137
|
-
# home.canton_cd # => 'zh'
|
138
|
-
# home.aargau! # throws NoMethodError: undefined method `aargau!'
|
139
|
-
# Address.aargau # throws NoMethodError: undefined method `aargau`
|
140
|
-
#
|
141
|
-
# This is especially useful if there are (too) many enumeration values, or these shortcut methods
|
142
|
-
# are not required.
|
143
|
-
#
|
144
|
-
# === Configuration options:
|
145
|
-
# * <tt>:column</tt> - Specifies a custom column name, instead of the default suffixed <tt>_cd</tt> column
|
146
|
-
# * <tt>:prefix</tt> - Define a prefix, which is prefixed to the shortcut methods (e.g. <tt><symbol>!</tt> and
|
147
|
-
# <tt><symbol>?</tt>), if it's set to <tt>true</tt> the enumeration name is used as a prefix, else a custom
|
148
|
-
# prefix (symbol or string) (default is <tt>nil</tt> => no prefix)
|
149
|
-
# * <tt>:slim</tt> - If set to <tt>true</tt> no shortcut methods for all enumeration values are being generated, if
|
150
|
-
# set to <tt>:class</tt> only class-level shortcut methods are disabled (default is <tt>nil</tt> => they are generated)
|
151
|
-
# * <tt>:upcase</tt> - If set to +true+ the <tt>Klass.foos</tt> is named <tt>Klass.FOOS</tt>, why? To better suite some
|
152
|
-
# coding-styles (default is +false+ => downcase)
|
153
|
-
# * <tt>:whiny</tt> - Boolean value which if set to <tt>true</tt> will throw an <tt>ArgumentError</tt>
|
154
|
-
# if an invalid value is passed to the setter (e.g. a value for which no enumeration exists). if set to
|
155
|
-
# <tt>false</tt> no exception is thrown and the internal value is set to <tt>nil</tt> (default is <tt>true</tt>)
|
156
|
-
# * <tt>:dirty</tt> - Boolean value which if set to <tt>true</tt> generates <tt>..._was</tt> and <tt>..._changed?</tt>
|
157
|
-
# methods for the enum, which delegate to the internal column (default is <tt>false</tt>)
|
158
|
-
# * <tt>:strings</tt> - Boolean value which if set to <tt>true</tt> stores array values as strings instead of it's index.
|
159
|
-
# * <tt>:field</tt> - Also allowed as valid key, for Mongoid integration + default options, see simple_enum#27.
|
160
|
-
#
|
161
|
-
def as_enum(enum_cd, values, options = {})
|
162
|
-
options = SimpleEnum.default_options.merge({ :column => "#{enum_cd}_cd" }).merge(options)
|
163
|
-
options.assert_valid_keys(:column, :whiny, :prefix, :slim, :upcase, :dirty, :strings, :field)
|
164
|
-
|
165
|
-
metaclass = (class << self; self; end)
|
166
|
-
|
167
|
-
# convert array to hash
|
168
|
-
values = SimpleEnum::EnumHash.new(values, options[:strings])
|
169
|
-
values_inverted = values.invert
|
170
|
-
|
171
|
-
# store info away
|
172
|
-
self.enum_definitions[enum_cd] = self.enum_definitions[options[:column]] = { :name => enum_cd, :column => options[:column], :options => options }
|
173
|
-
|
174
|
-
# raise error if enum_cd == column
|
175
|
-
raise ArgumentError, "[simple_enum] use different names for #{enum_cd}'s name and column name." if enum_cd.to_s == options[:column].to_s
|
176
|
-
|
177
|
-
# generate getter
|
178
|
-
define_method("#{enum_cd}") do
|
179
|
-
id = send(options[:column])
|
180
|
-
values_inverted[id]
|
181
|
-
end
|
182
|
-
|
183
|
-
# generate setter
|
184
|
-
define_method("#{enum_cd}=") do |new_value|
|
185
|
-
return send("#{options[:column]}=", nil) if new_value.blank?
|
186
|
-
|
187
|
-
new_value = new_value.to_s if options[:strings]
|
188
|
-
real = nil
|
189
|
-
if values.contains?(new_value)
|
190
|
-
real = values[EnumHash.symbolize(new_value)]
|
191
|
-
real = new_value if real.nil? && values_inverted[new_value].present?
|
192
|
-
end
|
193
|
-
|
194
|
-
raise ArgumentError, "Invalid enumeration value: #{new_value}" if options[:whiny] && !real
|
195
|
-
send("#{options[:column]}=", real)
|
196
|
-
end
|
197
|
-
|
198
|
-
# generate checker
|
199
|
-
define_method("#{enum_cd}?") do |*args|
|
200
|
-
current = send(enum_cd)
|
201
|
-
return current.to_s == args.first.to_s if args.length > 0
|
23
|
+
mattr_accessor :accessor
|
24
|
+
@@accessor = :default
|
202
25
|
|
203
|
-
|
204
|
-
|
26
|
+
mattr_accessor :builder
|
27
|
+
@@builder = :default
|
205
28
|
|
206
|
-
|
207
|
-
|
208
|
-
define_method("#{enum_cd}_changed?") do
|
209
|
-
self.send("#{options[:column]}_changed?")
|
210
|
-
end
|
29
|
+
mattr_accessor :suffix
|
30
|
+
@@suffix = "_cd"
|
211
31
|
|
212
|
-
|
213
|
-
|
214
|
-
end
|
215
|
-
end
|
32
|
+
mattr_accessor :field
|
33
|
+
@@field = {}
|
216
34
|
|
217
|
-
|
218
|
-
|
219
|
-
enum_attr = :"#{attr_name.downcase}_enum_hash"
|
220
|
-
|
221
|
-
define_method("human_#{enum_cd}") do
|
222
|
-
self.class.human_enum_name(attr_name, self.send(enum_cd)) unless self.send(enum_cd).nil?
|
223
|
-
end
|
224
|
-
|
225
|
-
# generate find_by enum singleton
|
226
|
-
(class << self; self end).send(:define_method, "find_by_#{enum_cd}") do |*args|
|
227
|
-
send("find_by_#{options[:column]}", args)
|
228
|
-
end
|
229
|
-
|
230
|
-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
231
|
-
class_attribute #{enum_attr.inspect}, :instance_writer => false, :instance_reader => false
|
232
|
-
|
233
|
-
def self.#{attr_name}(*args)
|
234
|
-
return #{enum_attr} if args.first.nil?
|
235
|
-
return #{enum_attr}[args.first] if args.size == 1
|
236
|
-
args.inject([]) { |ary, sym| ary << #{enum_attr}[sym]; ary }
|
237
|
-
end
|
238
|
-
|
239
|
-
def self.#{attr_name}_for_select(attr = :key, &block)
|
240
|
-
self.#{attr_name}.map do |k,v|
|
241
|
-
[block_given? ? yield(k,v) : self.human_enum_name(#{attr_name.inspect}, k), attr == :value ? v : k]
|
242
|
-
end
|
243
|
-
end
|
244
|
-
RUBY
|
245
|
-
|
246
|
-
# write values
|
247
|
-
self.send "#{enum_attr}=", values
|
248
|
-
|
249
|
-
# only create if :slim is not defined
|
250
|
-
if options[:slim] != true
|
251
|
-
# create both, boolean operations and *bang* operations for each
|
252
|
-
# enum "value"
|
253
|
-
prefix = options[:prefix] && "#{options[:prefix] == true ? enum_cd : options[:prefix]}_"
|
254
|
-
|
255
|
-
values.each do |k,code|
|
256
|
-
sym = EnumHash.symbolize(k)
|
257
|
-
|
258
|
-
define_method("#{prefix}#{sym}?") do
|
259
|
-
current = send(options[:column])
|
260
|
-
code == current
|
261
|
-
end
|
262
|
-
define_method("#{prefix}#{sym}!") do
|
263
|
-
send("#{options[:column]}=", code)
|
264
|
-
sym
|
265
|
-
end
|
266
|
-
|
267
|
-
# allow class access to each value
|
268
|
-
unless options[:slim] === :class
|
269
|
-
metaclass.send(:define_method, "#{prefix}#{sym}", Proc.new { |*args| args.first ? k : code })
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
def human_enum_name(enum, key, options = {})
|
276
|
-
defaults = lookup_ancestors.map do |klass|
|
277
|
-
:"#{self.i18n_scope}.enums.#{klass.model_name.i18n_key}.#{enum}.#{key}"
|
278
|
-
end
|
279
|
-
|
280
|
-
defaults << :"enums.#{self.model_name.i18n_key}.#{enum}.#{key}"
|
281
|
-
defaults << :"enums.#{enum}.#{key}"
|
282
|
-
defaults << options.delete(:default) if options[:default]
|
283
|
-
defaults << key.to_s.humanize
|
284
|
-
|
285
|
-
options.reverse_merge! :count => 1, :default => defaults
|
286
|
-
I18n.translate(defaults.shift, options)
|
287
|
-
end
|
288
|
-
|
289
|
-
def enum_definitions
|
290
|
-
self.simple_enum_definitions ||= {}
|
291
|
-
end
|
35
|
+
def self.configure
|
36
|
+
yield(self)
|
292
37
|
end
|
293
38
|
end
|
294
39
|
|
295
40
|
# include in AR
|
296
41
|
ActiveSupport.on_load(:active_record) do
|
297
|
-
ActiveRecord::Base.send(:
|
42
|
+
ActiveRecord::Base.send(:extend, SimpleEnum::Attribute)
|
43
|
+
ActiveRecord::Base.send(:extend, SimpleEnum::Translation)
|
298
44
|
end
|
299
|
-
|
300
|
-
# setup i18n load path...
|
301
|
-
I18n.load_path << File.join(File.dirname(__FILE__), '..', 'locales', 'en.yml')
|
data/simple_enum.gemspec
CHANGED
@@ -8,23 +8,23 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.summary = "Simple enum-like field support for models."
|
9
9
|
s.description = "Provides enum-like fields for ActiveRecord, ActiveModel and Mongoid models."
|
10
10
|
|
11
|
-
s.required_ruby_version = ">= 1.
|
12
|
-
s.required_rubygems_version = ">=
|
11
|
+
s.required_ruby_version = ">= 1.9.3"
|
12
|
+
s.required_rubygems_version = ">= 2.0.0"
|
13
13
|
|
14
14
|
s.authors = ["Lukas Westermann"]
|
15
15
|
s.email = ["lukas.westermann@gmail.com"]
|
16
16
|
s.homepage = "http://lwe.github.com/simple_enum/"
|
17
17
|
|
18
|
-
s.files = %w{.gitignore Rakefile Gemfile README.
|
19
|
-
s.test_files = s.files.grep(%r{^(test|spec
|
18
|
+
s.files = %w{.gitignore Rakefile Gemfile README.md LICENSE simple_enum.gemspec} + Dir['**/*.{rb,yml}']
|
19
|
+
s.test_files = s.files.grep(%r{^(test|spec)/})
|
20
20
|
s.require_paths = %w{lib}
|
21
21
|
|
22
22
|
s.license = 'MIT'
|
23
23
|
|
24
|
-
s.add_dependency
|
24
|
+
s.add_dependency 'activesupport', '>= 4.0.0'
|
25
25
|
|
26
|
-
s.add_development_dependency 'rake', '>=
|
27
|
-
s.add_development_dependency '
|
28
|
-
s.add_development_dependency '
|
29
|
-
s.add_development_dependency '
|
26
|
+
s.add_development_dependency 'rake', '>= 10.1.0'
|
27
|
+
s.add_development_dependency 'activerecord', '>= 4.0.0'
|
28
|
+
s.add_development_dependency 'mongoid', '>= 4.0.0.beta1'
|
29
|
+
s.add_development_dependency 'rspec', '~> 2.14'
|
30
30
|
end
|
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleEnum::Accessors do
|
4
|
+
let(:enum) { SimpleEnum::Enum.new(:gender, "male" => 0, "female" => 1) }
|
5
|
+
fake_model(:klass)
|
6
|
+
let(:object) { klass.new }
|
7
|
+
|
8
|
+
context '.accessor' do
|
9
|
+
it 'returns Accessor instance' do
|
10
|
+
expect(described_class.accessor(:gender, enum)).to be_a(described_class::Accessor)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns a WhinyAccessor instance if accessor: :whiny' do
|
14
|
+
expect(described_class.accessor(:gender, enum, accessor: :whiny)).to be_a(described_class::WhinyAccessor)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'sets source to "gender" if source: :gender' do
|
18
|
+
expect(described_class.accessor(:gender, enum, source: :gender).source).to eq 'gender'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'Accessor' do
|
23
|
+
subject { described_class::Accessor.new(:gender, enum) }
|
24
|
+
|
25
|
+
context '#name' do
|
26
|
+
it 'returns the enum name as string' do
|
27
|
+
expect(subject.name).to eq 'gender'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context '#to_s' do
|
32
|
+
it 'returns the name' do
|
33
|
+
expect(subject.to_s).to eq 'gender'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context '#prefix' do
|
38
|
+
it 'returns empty string when prefix is nil' do
|
39
|
+
expect(described_class::Accessor.new(:gender, enum).prefix).to eq ''
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns gender_ when prefix is true' do
|
43
|
+
expect(described_class::Accessor.new(:gender, enum, nil, true).prefix).to eq 'gender_'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns other_ when prefix is "other"' do
|
47
|
+
expect(described_class::Accessor.new(:gender, hash, nil, 'other').prefix).to eq 'other_'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context '#source' do
|
52
|
+
it 'returns gender_cd when source is nil' do
|
53
|
+
expect(described_class::Accessor.new(:gender, hash, nil).source).to eq 'gender_cd'
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'returns "some_column" when source is set to :some_column' do
|
57
|
+
expect(described_class::Accessor.new(:gender, hash, :some_column).source).to eq 'some_column'
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'returns "gender" when source is set to "gender"' do
|
61
|
+
expect(described_class::Accessor.new(:gender, hash, 'gender').source).to eq 'gender'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context '#read' do
|
66
|
+
shared_examples_for 'reading an enum' do
|
67
|
+
it 'returns nil then gender_cd is nil' do
|
68
|
+
expect(subject.read(object)).to be_nil
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'returns :male when gender_cd is 0' do
|
72
|
+
expect(subject.read(klass.new(0))).to eq :male
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'returns :female when gender_cd is 1' do
|
76
|
+
expect(subject.read(klass.new(1))).to eq :female
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it_behaves_like 'reading an enum'
|
81
|
+
|
82
|
+
context 'with name == source' do
|
83
|
+
subject { described_class::Accessor.new(:gender_cd, enum, :gender_cd) }
|
84
|
+
it_behaves_like 'reading an enum'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context '#write' do
|
89
|
+
shared_examples_for 'writing an enum' do
|
90
|
+
it 'writes nil to object' do
|
91
|
+
object = klass.new(0)
|
92
|
+
expect(subject.write(object, nil)).to be_nil
|
93
|
+
expect(object.gender_cd).to be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'writes 1 to object with :female' do
|
97
|
+
expect(subject.write(object, :female)).to eq :female
|
98
|
+
expect(object.gender_cd).to eq 1
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'writes 0 to object with "male"' do
|
102
|
+
expect(subject.write(object, 'male')).to eq 'male'
|
103
|
+
expect(object.gender_cd).to eq 0
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'writes 1 to object with 1' do
|
107
|
+
expect(subject.write(object, 1)).to eq 1
|
108
|
+
expect(object.gender_cd).to eq 1
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'writes nil to object with :other' do
|
112
|
+
object = klass.new(1)
|
113
|
+
expect(subject.write(object, :other)).to be_nil
|
114
|
+
expect(object.gender_cd).to be_nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
it_behaves_like 'writing an enum'
|
119
|
+
|
120
|
+
context 'with name == source' do
|
121
|
+
subject { described_class::Accessor.new(:gender_cd, enum, :gender_cd) }
|
122
|
+
it_behaves_like 'writing an enum'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context '#selected?' do
|
127
|
+
it 'returns false when gender_cd is nil' do
|
128
|
+
expect(subject.selected?(object)).to be_false
|
129
|
+
expect(subject.selected?(object, :male)).to be_false
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'returns true when gender_cd is != nil' do
|
133
|
+
expect(subject.selected?(klass.new(0))).to be_true
|
134
|
+
expect(subject.selected?(klass.new(1))).to be_true
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'returns true when gender_cd is 0 and :male is passed' do
|
138
|
+
expect(subject.selected?(klass.new(0), :male)).to be_true
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'returns false when gender_cd is 0 and :female is passed' do
|
142
|
+
expect(subject.selected?(klass.new(0), :female)).to be_false
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'returns false when gender_cd is 1 and :other is passed' do
|
146
|
+
expect(subject.selected?(klass.new(0), :other)).to be_false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context '#changed?' do
|
151
|
+
it 'delegates to attribute_changed?' do
|
152
|
+
expect(object).to receive(:attribute_changed?).with('gender_cd') { true }
|
153
|
+
expect(subject.changed?(object)).to be_true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context 'was' do
|
158
|
+
it 'delegates to attribute_was and resolves symbol' do
|
159
|
+
expect(object).to receive(:attribute_was).with('gender_cd') { 1 }
|
160
|
+
expect(subject.was(object)).to eq :female
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'IgnoreAccessor' do
|
166
|
+
subject { described_class::IgnoreAccessor.new(:gender, enum) }
|
167
|
+
|
168
|
+
it 'sets gender_cd to 0 with symbol' do
|
169
|
+
expect(subject.write(object, :male)).to_not be_false
|
170
|
+
expect(object.gender_cd).to eq 0
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'sets gender_cd to 1 via value (1)' do
|
174
|
+
expect(subject.write(object, 1)).to_not be_false
|
175
|
+
expect(object.gender_cd).to eq 1
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'sets gender_cd to nil' do
|
179
|
+
expect(subject.write(object, nil)).to be_false
|
180
|
+
expect(object.gender_cd).to be_nil
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'keeps existing value when unknown value is passed' do
|
184
|
+
object.gender_cd = 1
|
185
|
+
expect(subject.write(object, :other)).to be_false
|
186
|
+
expect(object.gender_cd).to eq 1
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context 'WhinyAccessor' do
|
191
|
+
subject { described_class::WhinyAccessor.new(:gender, enum) }
|
192
|
+
|
193
|
+
it 'raises no error when setting existing key' do
|
194
|
+
expect { subject.write(object, :male) }.to_not raise_error
|
195
|
+
expect(object.gender_cd).to eq 0
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'raises no error when setting with existing value' do
|
199
|
+
expect { subject.write(object, 1) }.to_not raise_error
|
200
|
+
expect(object.gender_cd).to eq 1
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'raises no error when setting to nil' do
|
204
|
+
expect { subject.write(object, nil) }.to_not raise_error
|
205
|
+
expect(object.gender_cd).to be_nil
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'raises ArgumentError when setting invalid key' do
|
209
|
+
expect { subject.write(object, :other) }.to raise_error(ArgumentError)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|