simple_enum 1.6.9 → 2.0.0.rc1
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 +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
|