aiwilliams-dataset 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,47 @@
1
+ module Dataset
2
+ class Load # :nodoc:
3
+ attr_reader :datasets, :dataset_binding, :helper_methods
4
+
5
+ def initialize(datasets, parent_binding)
6
+ @datasets = datasets
7
+ @dataset_binding = SessionBinding.new(parent_binding)
8
+ @helper_methods = Module.new
9
+ end
10
+
11
+ def execute(loaded_datasets, dataset_resolver)
12
+ (datasets - loaded_datasets).each do |dataset|
13
+ instance = dataset.new
14
+ instance.extend dataset_binding.record_methods
15
+ instance.extend dataset_binding.model_finders
16
+ used_datasets(dataset, dataset_resolver).each do |ds|
17
+ next unless ds.helper_methods
18
+ instance.extend ds.helper_methods
19
+ helper_methods.module_eval do
20
+ include ds.helper_methods
21
+ end
22
+ end
23
+ instance.load
24
+ end
25
+ end
26
+
27
+ def used_datasets(dataset, dataset_resolver, collector = [])
28
+ dataset.used_datasets.each do |used|
29
+ ds = dataset_resolver.resolve(used)
30
+ used_datasets(ds, dataset_resolver, collector)
31
+ collector << ds
32
+ end if dataset.used_datasets
33
+ collector << dataset
34
+ collector.uniq
35
+ end
36
+ end
37
+
38
+ class Reload # :nodoc:
39
+ attr_reader :dataset_binding, :load
40
+ delegate :datasets, :helper_methods, :to => :load
41
+
42
+ def initialize(load)
43
+ @load = load
44
+ @dataset_binding = SessionBinding.new(@load.dataset_binding)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,73 @@
1
+ require 'active_record/fixtures'
2
+
3
+ module Dataset
4
+ module Record # :nodoc:
5
+
6
+ class Fixture # :nodoc:
7
+ attr_reader :meta, :symbolic_name, :session_binding
8
+
9
+ def initialize(meta, attributes, symbolic_name, session_binding)
10
+ @meta = meta
11
+ @attributes = attributes.stringify_keys
12
+ @symbolic_name = symbolic_name || object_id
13
+ @session_binding = session_binding
14
+
15
+ install_default_attributes!
16
+ end
17
+
18
+ def create
19
+ record_class.connection.insert_fixture to_fixture, meta.table_name
20
+ id
21
+ end
22
+
23
+ def id
24
+ @attributes['id']
25
+ end
26
+
27
+ def record_class
28
+ meta.record_class
29
+ end
30
+
31
+ def to_fixture
32
+ ::Fixture.new(to_hash, meta.class_name)
33
+ end
34
+
35
+ def to_hash
36
+ hash = @attributes.dup
37
+ hash[meta.inheritance_column] = meta.sti_name if meta.inheriting_record?
38
+ record_class.reflections.each do |name, reflection|
39
+ name = name.to_s
40
+ add_reflection_attributes(hash, name, reflection) if hash[name]
41
+ end
42
+ hash
43
+ end
44
+
45
+ def install_default_attributes!
46
+ @attributes['id'] ||= symbolic_name.to_s.hash.abs
47
+ install_timestamps!
48
+ end
49
+
50
+ def install_timestamps!
51
+ meta.timestamp_columns.each do |column|
52
+ @attributes[column.name] = now(column) unless @attributes.key?(column.name)
53
+ end
54
+ end
55
+
56
+ def now(column)
57
+ (ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now).to_s(:db)
58
+ end
59
+
60
+ private
61
+ def add_reflection_attributes(hash, name, reflection)
62
+ value = hash.delete(name)
63
+ case value
64
+ when Symbol
65
+ hash[reflection.primary_key_name] = session_binding.find_id(reflection.klass, value)
66
+ else
67
+ hash[reflection.primary_key_name] = value
68
+ end
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,58 @@
1
+ module Dataset
2
+ module Record # :nodoc:
3
+
4
+ # A mechanism to cache information about an ActiveRecord class to speed
5
+ # things up a bit for insertions, finds, and method generation.
6
+ class Meta # :nodoc:
7
+ attr_reader :class_name, :columns, :record_class, :table_name
8
+
9
+ # Provides information necessary to insert STI classes correctly for
10
+ # later reading.
11
+ delegate :name, :inheritance_column, :sti_name, :to => :record_class
12
+
13
+ def initialize(record_class)
14
+ @record_class = record_class
15
+ @class_name = record_class.name
16
+ @table_name = record_class.table_name
17
+ @columns = record_class.columns
18
+ end
19
+
20
+ def id_cache_key
21
+ @id_cache_key ||= table_name
22
+ end
23
+
24
+ def inheriting_record?
25
+ !record_class.descends_from_active_record?
26
+ end
27
+
28
+ def timestamp_columns
29
+ @timestamp_columns ||= begin
30
+ timestamps = %w(created_at created_on updated_at updated_on)
31
+ columns.select do |column|
32
+ timestamps.include?(column.name)
33
+ end
34
+ end
35
+ end
36
+
37
+ def id_finder_names
38
+ @id_finder_names ||= begin
39
+ names = record_class.self_and_descendents_from_active_record.collect {|c| finder_name c}
40
+ names.uniq.collect {|n| "#{n}_id".to_sym}
41
+ end
42
+ end
43
+
44
+ def model_finder_names
45
+ @record_finder_names ||= record_class.self_and_descendents_from_active_record.collect {|c| finder_name(c).pluralize.to_sym}.uniq
46
+ end
47
+
48
+ def to_s
49
+ "#<RecordMeta: #{table_name}>"
50
+ end
51
+
52
+ def finder_name(klass)
53
+ klass.name.underscore.gsub('/', '_').sub(/^(\w)_/, '\1').gsub(/_(\w)_/, '_\1')
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,50 @@
1
+ module Dataset
2
+ module Record # :nodoc:
3
+
4
+ class Model # :nodoc:
5
+ attr_reader :attributes, :model, :meta, :symbolic_name, :session_binding
6
+
7
+ def initialize(meta, attributes, symbolic_name, session_binding)
8
+ @meta = meta
9
+ @attributes = attributes.stringify_keys
10
+ @symbolic_name = symbolic_name || object_id
11
+ @session_binding = session_binding
12
+ end
13
+
14
+ def record_class
15
+ meta.record_class
16
+ end
17
+
18
+ def id
19
+ model.id
20
+ end
21
+
22
+ def create
23
+ model = to_model
24
+ model.save!
25
+ model
26
+ end
27
+
28
+ def to_hash
29
+ to_model.attributes
30
+ end
31
+
32
+ def to_model
33
+ @model ||= begin
34
+ m = meta.record_class.new
35
+ attributes.each do |k,v|
36
+ if reflection = record_class.reflect_on_association(k.to_sym)
37
+ case v
38
+ when Symbol
39
+ v = session_binding.find_model(reflection.klass, v)
40
+ end
41
+ end
42
+ m.send "#{k}=", v
43
+ end
44
+ m
45
+ end
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,110 @@
1
+ module Dataset
2
+ # An error raised when a dataset class cannot be found.
3
+ #
4
+ class DatasetNotFound < StandardError
5
+ end
6
+
7
+ # A dataset may be referenced as a class or as a name. A Dataset::Resolver
8
+ # will take an identifier, whether a class or a name, and return the class.
9
+ #
10
+ class Resolver
11
+ cattr_accessor :default
12
+
13
+ def identifiers
14
+ @identifiers ||= {}
15
+ end
16
+
17
+ # Attempt to convert a name to a constant. With the identifier :people, it
18
+ # will search for 'PeopleDataset', then 'People'.
19
+ #
20
+ def resolve(identifier)
21
+ return identifier if identifier.is_a?(Class)
22
+ if constant = identifiers[identifier]
23
+ return constant
24
+ end
25
+
26
+ constant = resolve_class(identifier)
27
+ unless constant
28
+ constant = resolve_identifier(identifier)
29
+ end
30
+ identifiers[identifier] = constant
31
+ end
32
+
33
+ protected
34
+ def resolve_identifier(identifier) # :nodoc:
35
+ constant = resolve_class(identifier)
36
+ unless constant
37
+ raise Dataset::DatasetNotFound, "Could not find a dataset '#{identifier.to_s.camelize}' or '#{identifier.to_s.camelize + suffix}'."
38
+ end
39
+ constant
40
+ end
41
+
42
+ def resolve_class(identifier)
43
+ names = [identifier.to_s.camelize, identifier.to_s.camelize + suffix]
44
+ constant = resolve_these(names.reverse)
45
+ if constant && constant.superclass != ::Dataset::Base
46
+ raise Dataset::DatasetNotFound, "Found a class '#{constant.name}', but it does not subclass 'Dataset::Base'."
47
+ end
48
+ constant
49
+ end
50
+
51
+ def resolve_these(names) # :nodoc:
52
+ names.each do |name|
53
+ constant = name.constantize rescue nil
54
+ return constant if constant && constant.is_a?(Class)
55
+ end
56
+ nil
57
+ end
58
+
59
+ def suffix # :nodoc:
60
+ @suffix ||= 'Dataset'
61
+ end
62
+ end
63
+
64
+ # Resolves a dataset by looking for a file in the provided directory path
65
+ # that has a name matching the identifier. Of course, should the identifier
66
+ # be a class already, it is simply returned.
67
+ #
68
+ class DirectoryResolver < Resolver
69
+ def initialize(*paths)
70
+ @paths = paths
71
+ end
72
+
73
+ def <<(path)
74
+ @paths << path
75
+ end
76
+
77
+ protected
78
+ def resolve_identifier(identifier) # :nodoc:
79
+ @paths.each do |path|
80
+ file = File.join(path, identifier.to_s)
81
+ unless File.exists?(file + '.rb')
82
+ file = file + '_' + file_suffix
83
+ next unless File.exists?(file + '.rb')
84
+ end
85
+ require file
86
+ begin
87
+ return super
88
+ rescue Dataset::DatasetNotFound => dnf
89
+ if dnf.message =~ /\ACould not find/
90
+ raise Dataset::DatasetNotFound, "Found the dataset file '#{file + '.rb'}', but it did not define #{dnf.message.sub('Could not find ', '')}"
91
+ else
92
+ raise Dataset::DatasetNotFound, "Found the dataset file '#{file + '.rb'}' and a class #{dnf.message.sub('Found a class ', '')}"
93
+ end
94
+ end
95
+ end
96
+ raise DatasetNotFound, "Could not find a dataset file in #{@paths.inspect} having the name '#{identifier}.rb' or '#{identifier}_#{file_suffix}.rb'."
97
+ end
98
+
99
+ def file_suffix # :nodoc:
100
+ @file_suffix ||= suffix.downcase
101
+ end
102
+ end
103
+
104
+ # The default resolver, used by the Dataset::Sessions that aren't given a
105
+ # different instance. You can set this to something else in your
106
+ # test/spec_helper.
107
+ #
108
+ Resolver.default = Resolver.new
109
+
110
+ end
@@ -0,0 +1,51 @@
1
+ module Dataset
2
+ class Session # :nodoc:
3
+ attr_accessor :dataset_resolver
4
+
5
+ def initialize(database, dataset_resolver = Resolver.default)
6
+ @database = database
7
+ @dataset_resolver = dataset_resolver
8
+ @datasets = Hash.new
9
+ @load_stack = []
10
+ end
11
+
12
+ def add_dataset(test_class, dataset_identifier)
13
+ dataset = dataset_resolver.resolve(dataset_identifier)
14
+ if dataset.used_datasets
15
+ dataset.used_datasets.each { |used_dataset| self.add_dataset(test_class, used_dataset) }
16
+ end
17
+ datasets_for(test_class) << dataset
18
+ end
19
+
20
+ def datasets_for(test_class)
21
+ if test_class.superclass
22
+ @datasets[test_class] ||= Collection.new(datasets_for(test_class.superclass) || [])
23
+ end
24
+ end
25
+
26
+ def load_datasets_for(test_class)
27
+ datasets = datasets_for(test_class)
28
+ if last_load = @load_stack.last
29
+ if last_load.datasets == datasets
30
+ current_load = Reload.new(last_load)
31
+ elsif last_load.datasets.subset?(datasets)
32
+ @database.capture(last_load.datasets)
33
+ current_load = Load.new(datasets, last_load.dataset_binding)
34
+ current_load.execute(last_load.datasets, @dataset_resolver)
35
+ @load_stack.push(current_load)
36
+ else
37
+ @load_stack.pop
38
+ last_load = @load_stack.last
39
+ @database.restore(last_load.datasets) if last_load
40
+ current_load = load_datasets_for(test_class)
41
+ end
42
+ else
43
+ @database.clear
44
+ current_load = Load.new(datasets, @database)
45
+ current_load.execute([], @dataset_resolver)
46
+ @load_stack.push(current_load)
47
+ end
48
+ current_load
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,317 @@
1
+ module Dataset
2
+ # An error that will be raised when an attempt is made to load a named model
3
+ # that doesn't exist. For example, if you do people(:jenny), and yet no
4
+ # record was ever created with the symbolic name :jenny, this error will be
5
+ # raised.
6
+ #
7
+ class RecordNotFound < StandardError
8
+ def initialize(record_type, symbolic_name)
9
+ super "There is no '#{record_type.name}' found for the symbolic name ':#{symbolic_name}'."
10
+ end
11
+ end
12
+
13
+ # Whenever you use Dataset::RecordMethods, you will get finder methods in
14
+ # your tests that help you load instances of the records you have created
15
+ # (or named models).
16
+ #
17
+ # create_record :person, :jimmy, :name => 'Jimmy'
18
+ # person_id(:jimmy) => The id was captured from create_record
19
+ # people(:jimmy) => The same as Jimmy.find(person_id(:jimmy))
20
+ #
21
+ # The methods will not exist in a test unless it utilizes a dataset (or
22
+ # defines one itself through the block technique) that creates a record for
23
+ # the type.
24
+ #
25
+ # You may also pass multiple names to these methods, which will have them
26
+ # return an array of values.
27
+ #
28
+ # people(:jimmy, :jane, :jeff) => [<# Person :name => 'Jimmy'>, <# Person :name => 'Jane'>, <# Person :name => 'Jeff'>]
29
+ # person_id(:jimmy, :jane, :jeff) => [1, 2, 3]
30
+ #
31
+ # NOTE the plurality of the instance finder, versus the singularity of the
32
+ # id finder.
33
+ #
34
+ # == Single Table Inheritence
35
+ #
36
+ # class Person < ActiveRecord::Base; end
37
+ # class User < Person; end
38
+ #
39
+ # create_record :user, :bobby, :name => 'Bobby'
40
+ #
41
+ # people(:bobby) OR users(:bobby)
42
+ #
43
+ module ModelFinders
44
+ def create_finder(record_meta) # :nodoc:
45
+ @finders_generated ||= []
46
+
47
+ return if @finders_generated.include?(record_meta)
48
+
49
+ record_meta.model_finder_names.each do |finder_name|
50
+ unless instance_methods.include?(finder_name)
51
+ define_method finder_name do |*symbolic_names|
52
+ names = Array(symbolic_names)
53
+ models = names.inject([]) do |c,n|
54
+ c << dataset_session_binding.find_model(record_meta, n); c
55
+ end
56
+ names.size == 1 ? models.first : models
57
+ end
58
+ end
59
+ end
60
+
61
+ record_meta.id_finder_names.each do |finder_name|
62
+ unless instance_methods.include?(finder_name)
63
+ define_method finder_name do |*symbolic_names|
64
+ names = Array(symbolic_names)
65
+ ids = names.inject([]) do |c,n|
66
+ c << dataset_session_binding.find_id(record_meta, n); c
67
+ end
68
+ names.size == 1 ? ids.first : ids
69
+ end
70
+ end
71
+ end
72
+
73
+ @finders_generated << record_meta
74
+ end
75
+ end
76
+
77
+ # Any Dataset::Base subclass, dataset block, or test method in a
78
+ # dataset-using test context (including setup/teardown/before/after) may
79
+ # create and access models through these methods. Note that you should use
80
+ # Dataset::ModelFinders if you can for finding your created data.
81
+ #
82
+ module RecordMethods
83
+
84
+ # Similar to old fashioned fixtures, this will do a direct database
85
+ # insert, without running any validations or preventing you from writing
86
+ # attr_protected attributes. Very nice for speed, but kind of a pain if
87
+ # you have complex structures or hard to keep right validations.
88
+ #
89
+ # create_record :type, :symbolic_name, :attr1 => 'value', :attr2 => 'value', :etc => 'etc'
90
+ #
91
+ # The _symbolic_name_ is an optional parameter. You may replace _type_
92
+ # with an ActiveRecord::Base subclass or anything that works with:
93
+ #
94
+ # to_s.classify.constantize
95
+ #
96
+ # The id of the model will be a hash of the symbolic name.
97
+ #
98
+ def create_record(*args)
99
+ dataset_session_binding.create_record(*args)
100
+ end
101
+
102
+ # This will instantiate your model class and assign each attribute WITHOUT
103
+ # using mass assignment. Validations will be run. Very nice for complex
104
+ # structures or hard to keep right validations, but potentially a bit
105
+ # slower, since it runs through all that ActiveRecord code.
106
+ #
107
+ # create_model :type, :symbolic_name, :attr1 => 'value', :attr2 => 'value', :etc => 'etc'
108
+ #
109
+ # The _symbolic_name_ is an optional parameter. You may replace _type_
110
+ # with an ActiveRecord::Base subclass or anything that works with:
111
+ #
112
+ # to_s.classify.constantize
113
+ #
114
+ # The id of the record will be kept from the instance that is saved.
115
+ #
116
+ def create_model(*args)
117
+ dataset_session_binding.create_model(*args)
118
+ end
119
+
120
+ # Dataset will track each of the records it creates by symbolic name to
121
+ # id. When you need the id of a record, there is no need to go to the
122
+ # database.
123
+ #
124
+ # find_id :person, :bobby => 23425234
125
+ #
126
+ # You may pass one name or many, with many returning an Array of ids.
127
+ #
128
+ def find_id(*args)
129
+ dataset_session_binding.find_id(*args)
130
+ end
131
+
132
+ # Dataset will track each of the records it creates by symbolic name to
133
+ # id. When you need an instance of a record, the stored id will be used to
134
+ # do the fastest lookup possible: Person.find(23425234).
135
+ #
136
+ # find_model :person, :bobby => <#Person :id => 23425234, :name => 'Bobby'>
137
+ #
138
+ # You may pass one name or many, with many returning an Array of
139
+ # instances.
140
+ #
141
+ def find_model(*args)
142
+ dataset_session_binding.find_model(*args)
143
+ end
144
+
145
+ # This is a great help when you want to create records in a custom helper
146
+ # method, then make it and maybe things associated to it available to
147
+ # tests through the Dataset::ModelFinders.
148
+ #
149
+ # thingy = create_very_complex_thingy_and_stuff
150
+ # name_model thingy, :thingy_bob
151
+ # name_model thingy.part, :thingy_part
152
+ #
153
+ # In tests:
154
+ #
155
+ # thingies(:thingy_bob)
156
+ # parts(:thingy_part)
157
+ #
158
+ def name_model(*args)
159
+ dataset_session_binding.name_model(*args)
160
+ end
161
+
162
+ # Converts string names into symbols for use in naming models
163
+ #
164
+ # name_to_sym 'my name' => :my_name
165
+ # name_to_sym 'RPaul' => :r_paul
166
+ #
167
+ def name_to_sym(name)
168
+ dataset_session_binding.name_to_sym(name)
169
+ end
170
+ end
171
+
172
+ class SessionBinding # :nodoc:
173
+ attr_reader :database, :parent_binding
174
+ attr_reader :model_finders, :record_methods
175
+ attr_reader :block_variables
176
+
177
+ def initialize(database_or_parent_binding)
178
+ @id_cache = Hash.new {|h,k| h[k] = {}}
179
+ @record_methods = new_record_methods_module
180
+ @model_finders = new_model_finders_module
181
+ @block_variables = Hash.new
182
+
183
+ case database_or_parent_binding
184
+ when Dataset::SessionBinding
185
+ @parent_binding = database_or_parent_binding
186
+ @database = parent_binding.database
187
+ @model_finders.module_eval { include database_or_parent_binding.model_finders }
188
+ @block_variables.update(database_or_parent_binding.block_variables)
189
+ else
190
+ @database = database_or_parent_binding
191
+ end
192
+ end
193
+
194
+ def copy_block_variables(dataset_block)
195
+ dataset_block.instance_variables.each do |name|
196
+ self.block_variables[name] = dataset_block.instance_variable_get(name)
197
+ end
198
+ end
199
+
200
+ def create_model(record_type, *args)
201
+ insert(Dataset::Record::Model, record_type, *args)
202
+ end
203
+
204
+ def create_record(record_type, *args)
205
+ insert(Dataset::Record::Fixture, record_type, *args)
206
+ end
207
+
208
+ def find_id(record_type_or_meta, symbolic_name)
209
+ record_meta = record_meta_for_type(record_type_or_meta)
210
+ if local_id = @id_cache[record_meta.id_cache_key][symbolic_name]
211
+ local_id
212
+ elsif !parent_binding.nil?
213
+ parent_binding.find_id record_meta, symbolic_name
214
+ else
215
+ raise RecordNotFound.new(record_meta, symbolic_name)
216
+ end
217
+ end
218
+
219
+ def find_model(record_type_or_meta, symbolic_name)
220
+ record_meta = record_meta_for_type(record_type_or_meta)
221
+ if local_id = @id_cache[record_meta.id_cache_key][symbolic_name]
222
+ record_meta.record_class.find local_id
223
+ elsif !parent_binding.nil?
224
+ parent_binding.find_model record_meta, symbolic_name
225
+ else
226
+ raise RecordNotFound.new(record_meta, symbolic_name)
227
+ end
228
+ end
229
+
230
+ def install_block_variables(target)
231
+ block_variables.each do |k,v|
232
+ target.instance_variable_set(k,v)
233
+ end
234
+ end
235
+
236
+ def name_model(record, symbolic_name)
237
+ record_meta = database.record_meta(record.class)
238
+ @model_finders.create_finder(record_meta)
239
+ @id_cache[record_meta.id_cache_key][symbolic_name] = record.id
240
+ record
241
+ end
242
+
243
+ def record_meta_for_type(record_type)
244
+ record_type.is_a?(Record::Meta) ? record_type : begin
245
+ record_class = resolve_record_class(record_type)
246
+ database.record_meta(record_class)
247
+ end
248
+ end
249
+
250
+ def name_to_sym(name)
251
+ name.to_s.underscore.gsub("'", "").gsub("\"", "").gsub(" ", "_").to_sym if name
252
+ end
253
+
254
+ protected
255
+ def insert(dataset_record_class, record_type, *args)
256
+ symbolic_name, attributes = extract_creation_arguments args
257
+ record_meta = record_meta_for_type(record_type)
258
+ record = dataset_record_class.new(record_meta, attributes, symbolic_name, self)
259
+ return_value = nil
260
+
261
+ @model_finders.create_finder(record_meta)
262
+ ActiveRecord::Base.silence do
263
+ return_value = record.create
264
+ @id_cache[record_meta.id_cache_key][symbolic_name] = record.id
265
+ end
266
+ return_value
267
+ end
268
+
269
+ def extract_creation_arguments(arguments)
270
+ if arguments.size == 2 && arguments.last.kind_of?(Hash)
271
+ arguments
272
+ elsif arguments.size == 1 && arguments.last.kind_of?(Hash)
273
+ [nil, arguments.last]
274
+ elsif arguments.size == 1 && arguments.last.kind_of?(Symbol)
275
+ [arguments.last, Hash.new]
276
+ else
277
+ [nil, Hash.new]
278
+ end
279
+ end
280
+
281
+ def new_model_finders_module
282
+ mod = Module.new
283
+ dataset_binding = self
284
+ mod.module_eval do
285
+ define_method :dataset_session_binding do
286
+ dataset_binding
287
+ end
288
+ end
289
+ mod.extend ModelFinders
290
+ mod
291
+ end
292
+
293
+ def new_record_methods_module
294
+ mod = Module.new do
295
+ include RecordMethods
296
+ end
297
+ dataset_binding = self
298
+ mod.module_eval do
299
+ define_method :dataset_session_binding do
300
+ dataset_binding
301
+ end
302
+ end
303
+ mod
304
+ end
305
+
306
+ def resolve_record_class(record_type)
307
+ case record_type
308
+ when Symbol
309
+ resolve_record_class record_type.to_s.singularize.camelize
310
+ when Class
311
+ record_type
312
+ when String
313
+ record_type.constantize
314
+ end
315
+ end
316
+ end
317
+ end