aiwilliams-dataset 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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