acts_as_table 0.0.1

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.
Files changed (34) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/LICENSE +30 -0
  4. data/README.md +256 -0
  5. data/Rakefile +13 -0
  6. data/app/models/acts_as_table/belongs_to.rb +81 -0
  7. data/app/models/acts_as_table/column_model.rb +89 -0
  8. data/app/models/acts_as_table/foreign_key.rb +299 -0
  9. data/app/models/acts_as_table/foreign_key_map.rb +121 -0
  10. data/app/models/acts_as_table/has_many.rb +90 -0
  11. data/app/models/acts_as_table/has_many_target.rb +40 -0
  12. data/app/models/acts_as_table/lense.rb +131 -0
  13. data/app/models/acts_as_table/primary_key.rb +108 -0
  14. data/app/models/acts_as_table/record.rb +109 -0
  15. data/app/models/acts_as_table/record_error.rb +50 -0
  16. data/app/models/acts_as_table/record_model.rb +194 -0
  17. data/app/models/acts_as_table/row_model.rb +285 -0
  18. data/app/models/acts_as_table/table.rb +41 -0
  19. data/app/models/acts_as_table/value.rb +80 -0
  20. data/app/models/concerns/acts_as_table/record_model_class_methods.rb +554 -0
  21. data/app/models/concerns/acts_as_table/value_provider.rb +223 -0
  22. data/app/models/concerns/acts_as_table/value_provider_association_methods.rb +57 -0
  23. data/config/locales/en.yml +8 -0
  24. data/db/migrate/1_acts_as_table_migration.rb +186 -0
  25. data/lib/acts_as_table.rb +288 -0
  26. data/lib/acts_as_table/adapter.rb +81 -0
  27. data/lib/acts_as_table/engine.rb +14 -0
  28. data/lib/acts_as_table/headers.rb +196 -0
  29. data/lib/acts_as_table/mapper.rb +464 -0
  30. data/lib/acts_as_table/path.rb +157 -0
  31. data/lib/acts_as_table/reader.rb +149 -0
  32. data/lib/acts_as_table/version.rb +4 -0
  33. data/lib/acts_as_table/writer.rb +116 -0
  34. metadata +181 -0
@@ -0,0 +1,464 @@
1
+ module ActsAsTable
2
+ # ActsAsTable mapper.
3
+ module Mapper
4
+ # ActsAsTable mapper object (abstract).
5
+ class Base
6
+ # Returns a new ActsAsTable mapper object.
7
+ #
8
+ # @yieldparam [ActsAsTable::Mapper::Base] base
9
+ # @yieldreturn [void]
10
+ # @return [ActsAsTable::Mapper::Base]
11
+ def initialize(&block)
12
+ if block_given?
13
+ case block.arity
14
+ when 1 then block.call(self)
15
+ else self.instance_eval(&block)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # ActsAsTable mapper object for an instance of the {ActsAsTable::BelongsTo} class for the `:belongs_to` macro.
22
+ class BelongsTo < Base
23
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::BelongsTo} class for the `:belongs_to` macro.
24
+ #
25
+ # @param [ActsAsTable::RowModel] row_model
26
+ # @param [Hash<Symbol, ActsAsTable::ColumnModel>] column_model_by_key
27
+ # @param [ActsAsTable::RecordModel] record_model
28
+ # @param [#to_s] method_name
29
+ # @param [ActsAsTable::Mapper::RecordModel] target
30
+ # @yieldparam [ActsAsTable::Mapper::BelongsTo] belongs_to
31
+ # @yieldreturn [void]
32
+ # @return [ActsAsTable::Mapper::BelongsTo]
33
+ def initialize(row_model, column_model_by_key, record_model, method_name, target, &block)
34
+ @row_model, @column_model_by_key, @record_model = row_model, column_model_by_key, record_model
35
+
36
+ @row_model.belongs_tos.build(macro: 'belongs_to', method_name: method_name) do |belongs_to|
37
+ belongs_to.source_record_model = @record_model
38
+
39
+ belongs_to.target_record_model = target.send(:instance_variable_get, :@record_model)
40
+ end
41
+
42
+ super(&block)
43
+ end
44
+ end
45
+
46
+ # ActsAsTable mapper object for an instance of the {ActsAsTable::ForeignKey} class.
47
+ class ForeignKey < Base
48
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::ForeignKey} class.
49
+ #
50
+ # @param [ActsAsTable::RowModel] row_model
51
+ # @param [Hash<Symbol, ActsAsTable::ColumnModel>] column_model_by_key
52
+ # @param [ActsAsTable::RecordModel] record_model
53
+ # @param [#to_s] method_name
54
+ # @param [Integer, Symbol, nil] position_or_key
55
+ # @param [Hash<Symbol, Object>] options
56
+ # @option options [Boolean] :default
57
+ # @option options [#to_s] :primary_key
58
+ # @yieldparam [ActsAsTable::Mapper::ForeignKey] foreign_key
59
+ # @yieldreturn [void]
60
+ # @return [ActsAsTable::Mapper::ForeignKey]
61
+ def initialize(row_model, column_model_by_key, record_model, method_name, position_or_key = nil, **options, &block)
62
+ options.assert_valid_keys(:default, :primary_key)
63
+
64
+ @row_model, @column_model_by_key, @record_model = row_model, column_model_by_key, record_model
65
+
66
+ @foreign_key = @record_model.foreign_keys.build(method_name: method_name, primary_key: options[:primary_key] || 'id', default_value: options[:default]) do |foreign_key|
67
+ unless position_or_key.nil?
68
+ foreign_key.column_model = position_or_key.is_a?(::Symbol) ? @column_model_by_key[position_or_key] : @row_model.column_models[position_or_key - 1]
69
+ end
70
+ end
71
+
72
+ super(&block)
73
+ end
74
+
75
+ # Builds a new instance of the {ActsAsTable::ForeignKeyMap} class.
76
+ #
77
+ # @note Target values for regular expressions may refer to capture groups.
78
+ #
79
+ # @param [String, Regexp] from
80
+ # @param [Hash<Symbol, Object>] options
81
+ # @option options [String] to
82
+ # @return [ActsAsTable::Mapper::ForeignKey]
83
+ #
84
+ # @example Map from a string to another string.
85
+ # map 'source', to: 'target'
86
+ #
87
+ # @example Map from a regular expression to a capture group.
88
+ # map /City:\s+(.+)/i, to: '\1'
89
+ #
90
+ def map(from, **options)
91
+ options.assert_valid_keys(:to)
92
+
93
+ @foreign_key.foreign_key_maps.build({
94
+ source_value: from.is_a?(::Regexp) ? from.source : from.to_s,
95
+ target_value: options[:to].to_s,
96
+ regexp: from.is_a?(::Regexp),
97
+ extended: from.is_a?(::Regexp) && ((from.options & ::Regexp::EXTENDED) != 0),
98
+ ignore_case: from.is_a?(::Regexp) && ((from.options & ::Regexp::IGNORECASE) != 0),
99
+ multiline: from.is_a?(::Regexp) && ((from.options & ::Regexp::MULTILINE) != 0),
100
+ })
101
+
102
+ self
103
+ end
104
+ end
105
+
106
+ # ActsAsTable mapper object for an instance of the {ActsAsTable::HasMany} class for the `:has_and_belongs_to_many` macro.
107
+ class HasAndBelongsToMany < Base
108
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::HasMany} class for the `:has_and_belongs_to_many` macro.
109
+ #
110
+ # @param [ActsAsTable::RowModel] row_model
111
+ # @param [Hash<Symbol, ActsAsTable::ColumnModel>] column_model_by_key
112
+ # @param [ActsAsTable::RecordModel] record_model
113
+ # @param [#to_s] method_name
114
+ # @param [Array<ActsAsTable::Mapper::RecordModel>] targets
115
+ # @yieldparam [ActsAsTable::Mapper::HasAndBelongsToMany] has_and_belongs_to_many
116
+ # @yieldreturn [void]
117
+ # @return [ActsAsTable::Mapper::HasAndBelongsToMany]
118
+ def initialize(row_model, column_model_by_key, record_model, method_name, *targets, &block)
119
+ @row_model, @column_model_by_key, @record_model = row_model, column_model_by_key, record_model
120
+
121
+ @row_model.has_manies.build(macro: 'has_and_belongs_to_many', method_name: method_name) do |has_many|
122
+ has_many.source_record_model = @record_model
123
+
124
+ targets.each_with_index do |target, index|
125
+ has_many.has_many_targets.build(position: index + 1) do |has_many_target|
126
+ has_many_target.record_model = target.send(:instance_variable_get, :@record_model)
127
+ end
128
+ end
129
+ end
130
+
131
+ super(&block)
132
+ end
133
+ end
134
+
135
+ # ActsAsTable mapper object for an instance of the {ActsAsTable::HasMany} class for the `:has_many` macro.
136
+ class HasMany < Base
137
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::HasMany} class for the `:has_many` macro.
138
+ #
139
+ # @param [ActsAsTable::RowModel] row_model
140
+ # @param [Hash<Symbol, ActsAsTable::ColumnModel>] column_model_by_key
141
+ # @param [ActsAsTable::RecordModel] record_model
142
+ # @param [#to_s] method_name
143
+ # @param [Array<ActsAsTable::Mapper::RecordModel>] targets
144
+ # @yieldparam [ActsAsTable::Mapper::HasMany] has_many
145
+ # @yieldreturn [void]
146
+ # @return [ActsAsTable::Mapper::HasMany]
147
+ def initialize(row_model, column_model_by_key, record_model, method_name, *targets, &block)
148
+ @row_model, @column_model_by_key, @record_model = row_model, column_model_by_key, record_model
149
+
150
+ @row_model.has_manies.build(macro: 'has_many', method_name: method_name) do |has_many|
151
+ has_many.source_record_model = @record_model
152
+
153
+ targets.each_with_index do |target, index|
154
+ has_many.has_many_targets.build(position: index + 1) do |has_many_target|
155
+ has_many_target.record_model = target.send(:instance_variable_get, :@record_model)
156
+ end
157
+ end
158
+ end
159
+
160
+ super(&block)
161
+ end
162
+ end
163
+
164
+ # ActsAsTable mapper object for an instance of the {ActsAsTable::BelongsTo} class for the `:has_one` macro.
165
+ class HasOne < Base
166
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::BelongsTo} class for the `:has_one` macro.
167
+ #
168
+ # @param [ActsAsTable::RowModel] row_model
169
+ # @param [Hash<Symbol, ActsAsTable::ColumnModel>] column_model_by_key
170
+ # @param [ActsAsTable::RecordModel] record_model
171
+ # @param [#to_s] method_name
172
+ # @param [ActsAsTable::Mapper::RecordModel] target
173
+ # @yieldparam [ActsAsTable::Mapper::HasOne] has_one
174
+ # @yieldreturn [void]
175
+ # @return [ActsAsTable::Mapper::HasOne]
176
+ def initialize(row_model, column_model_by_key, record_model, method_name, target, &block)
177
+ @row_model, @column_model_by_key, @record_model = row_model, column_model_by_key, record_model
178
+
179
+ @row_model.belongs_tos.build(macro: 'has_one', method_name: method_name) do |belongs_to|
180
+ belongs_to.source_record_model = @record_model
181
+
182
+ belongs_to.target_record_model = target.send(:instance_variable_get, :@record_model)
183
+ end
184
+
185
+ super(&block)
186
+ end
187
+ end
188
+
189
+ # ActsAsTable mapper object for an instance of the {ActsAsTable::Lense} class.
190
+ class Lense < Base
191
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::Lense} class.
192
+ #
193
+ # @param [ActsAsTable::RowModel] row_model
194
+ # @param [Hash<Symbol, ActsAsTable::ColumnModel>] column_model_by_key
195
+ # @param [ActsAsTable::RecordModel] record_model
196
+ # @param [#to_s] method_name
197
+ # @param [Integer, Symbol, nil] position_or_key
198
+ # @param [Hash<Symbol, Object>] options
199
+ # @option options [Boolean] :default
200
+ # @option options [#to_s] :primary_key
201
+ # @yieldparam [ActsAsTable::Mapper::Lense] lense
202
+ # @yieldreturn [void]
203
+ # @return [ActsAsTable::Mapper::Lense]
204
+ def initialize(row_model, column_model_by_key, record_model, method_name, position_or_key = nil, **options, &block)
205
+ options.assert_valid_keys(:default)
206
+
207
+ @row_model, @column_model_by_key, @record_model = row_model, column_model_by_key, record_model
208
+
209
+ @record_model.lenses.build(method_name: method_name, default_value: options[:default]) do |lens|
210
+ unless position_or_key.nil?
211
+ lens.column_model = position_or_key.is_a?(::Symbol) ? @column_model_by_key[position_or_key] : @row_model.column_models[position_or_key - 1]
212
+ end
213
+ end
214
+
215
+ super(&block)
216
+ end
217
+ end
218
+
219
+ # ActsAsTable mapper object for an instance of the {ActsAsTable::PrimaryKey} class.
220
+ class PrimaryKey < Base
221
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::PrimaryKey} class.
222
+ #
223
+ # @param [ActsAsTable::RowModel] row_model
224
+ # @param [Hash<Symbol, ActsAsTable::ColumnModel>] column_model_by_key
225
+ # @param [ActsAsTable::RecordModel] record_model
226
+ # @param [Integer, Symbol, nil] position_or_key
227
+ # @param [#to_s] method_name
228
+ # @yieldparam [ActsAsTable::Mapper::PrimaryKey] primary_key
229
+ # @yieldreturn [void]
230
+ # @return [ActsAsTable::Mapper::PrimaryKey]
231
+ def initialize(row_model, column_model_by_key, record_model, position_or_key, method_name = 'id', &block)
232
+ @row_model, @column_model_by_key, @record_model = row_model, column_model_by_key, record_model
233
+
234
+ @record_model.primary_keys.build(method_name: method_name) do |primary_key|
235
+ primary_key.column_model = position_or_key.is_a?(::Symbol) ? @column_model_by_key[position_or_key] : @row_model.column_models[position_or_key - 1]
236
+ end
237
+
238
+ super(&block)
239
+ end
240
+ end
241
+
242
+ # ActsAsTable mapper object for an instance of the {ActsAsTable::RecordModel} class.
243
+ #
244
+ # @!method attribute(method_name, position_or_key = nil, **options, &block)
245
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::Lense} class.
246
+ #
247
+ # @param [#to_s] method_name
248
+ # @param [Integer, Symbol, nil] position_or_key
249
+ # @param [Hash<Symbol, Object>] options
250
+ # @option options [Boolean] :default
251
+ # @option options [#to_s] :primary_key
252
+ # @yieldparam [ActsAsTable::Mapper::Lense] lense
253
+ # @yieldreturn [void]
254
+ # @return [ActsAsTable::Mapper::Lense]
255
+ # @!method belongs_to(method_name, target, &block)
256
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::BelongsTo} class for the `:belongs_to` macro.
257
+ #
258
+ # @param [#to_s] method_name
259
+ # @param [ActsAsTable::Mapper::RecordModel] target
260
+ # @yieldparam [ActsAsTable::Mapper::BelongsTo] belongs_to
261
+ # @yieldreturn [void]
262
+ # @return [ActsAsTable::Mapper::BelongsTo]
263
+ # @!method foreign_key(method_name, position_or_key = nil, **options, &block)
264
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::ForeignKey} class.
265
+ #
266
+ # @param [#to_s] method_name
267
+ # @param [Integer, Symbol, nil] position_or_key
268
+ # @param [Hash<Symbol, Object>] options
269
+ # @option options [Boolean] :default
270
+ # @option options [#to_s] :primary_key
271
+ # @yieldparam [ActsAsTable::Mapper::ForeignKey] foreign_key
272
+ # @yieldreturn [void]
273
+ # @return [ActsAsTable::Mapper::ForeignKey]
274
+ # @!method has_and_belongs_to_many(method_name, *targets, &block)
275
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::HasMany} class for the `:has_and_belongs_to_many` macro.
276
+ #
277
+ # @param [#to_s] method_name
278
+ # @param [Array<ActsAsTable::Mapper::RecordModel>] targets
279
+ # @yieldparam [ActsAsTable::Mapper::HasAndBelongsToMany] has_and_belongs_to_many
280
+ # @yieldreturn [void]
281
+ # @return [ActsAsTable::Mapper::HasAndBelongsToMany]
282
+ # @!method has_many(method_name, *targets, &block)
283
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::HasMany} class for the `:has_many` macro.
284
+ #
285
+ # @param [#to_s] method_name
286
+ # @param [Array<ActsAsTable::Mapper::RecordModel>] targets
287
+ # @yieldparam [ActsAsTable::Mapper::HasMany] has_many
288
+ # @yieldreturn [void]
289
+ # @return [ActsAsTable::Mapper::HasMany]
290
+ # @!method has_one(method_name, target, &block)
291
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::BelongsTo} class for the `:has_one` macro.
292
+ #
293
+ # @param [#to_s] method_name
294
+ # @param [ActsAsTable::Mapper::RecordModel] target
295
+ # @yieldparam [ActsAsTable::Mapper::HasOne] has_one
296
+ # @yieldreturn [void]
297
+ # @return [ActsAsTable::Mapper::HasOne]
298
+ # @!method primary_key(position_or_key = nil, method_name = 'id', &block)
299
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::PrimaryKey} class.
300
+ #
301
+ # @param [Integer, Symbol, nil] position_or_key
302
+ # @param [#to_s] method_name
303
+ # @yieldparam [ActsAsTable::Mapper::PrimaryKey] primary_key
304
+ # @yieldreturn [void]
305
+ # @return [ActsAsTable::Mapper::PrimaryKey]
306
+ class RecordModel < Base
307
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::RecordModel} class.
308
+ #
309
+ # @param [ActsAsTable::RowModel] row_model
310
+ # @param [Hash<Symbol, ActsAsTable::ColumnModel>] column_model_by_key
311
+ # @param [#to_s] class_name
312
+ # @yieldparam [ActsAsTable::Mapper::RecordModel] record_model
313
+ # @yieldreturn [void]
314
+ # @return [ActsAsTable::Mapper::RecordModel]
315
+ def initialize(row_model, column_model_by_key, class_name, &block)
316
+ @row_model, @column_model_by_key = row_model, column_model_by_key
317
+
318
+ @record_model = row_model.record_models.build(class_name: class_name)
319
+
320
+ super(&block)
321
+ end
322
+
323
+ {
324
+ attribute: :Lense,
325
+ belongs_to: :BelongsTo,
326
+ foreign_key: :ForeignKey,
327
+ has_and_belongs_to_many: :HasAndBelongsToMany,
328
+ has_many: :HasMany,
329
+ has_one: :HasOne,
330
+ primary_key: :PrimaryKey,
331
+ }.each do |method_name, const_name|
332
+ define_method(method_name) do |*args, &block|
333
+ ActsAsTable::Mapper.const_get(const_name).new(@row_model, @column_model_by_key, @record_model, *args, &block)
334
+ end
335
+ end
336
+ end
337
+
338
+ # ActsAsTable mapper object for an instance of the {ActsAsTable::RowModel} class.
339
+ #
340
+ # @see ActsAsTable::RowModel#draw
341
+ class RowModel < Base
342
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::RowModel} class.
343
+ #
344
+ # @param [ActsAsTable::RowModel] row_model
345
+ # @yieldparam [ActsAsTable::Mapper::RowModel] row_model
346
+ # @yieldreturn [void]
347
+ # @return [ActsAsTable::Mapper::RowModel]
348
+ def initialize(row_model, &block)
349
+ @row_model, @column_model_by_key = row_model, {}
350
+
351
+ super(&block)
352
+ end
353
+
354
+ # Builds new ActsAsTable column models in the scope of this ActsAsTable row model and caches them by key, if given.
355
+ #
356
+ # @param [#each_pair, #each, #to_s] object
357
+ # @return [ActsAsTable::Mapper::RowModel]
358
+ def columns=(object)
359
+ # @return [Integer]
360
+ column_models_count = @row_model.column_models.size
361
+
362
+ # @return [void]
363
+ ::Enumerator.new { |enumerator|
364
+ _dfs(object) { |path|
365
+ enumerator << path
366
+ }
367
+ }.each do |path|
368
+ # @return [Symbol, nil]
369
+ key = path[-1].is_a?(::Symbol) ? path.pop : nil
370
+
371
+ column_models_count += 1
372
+
373
+ # @return [ActsAsTable::ColumnModel]
374
+ column_model = @row_model.column_models.build(position: column_models_count, **_to_column_model_attributes(path))
375
+
376
+ unless key.nil?
377
+ @column_model_by_key[key] = column_model
378
+ end
379
+ end
380
+
381
+ self
382
+ end
383
+
384
+ # Set the root ActsAsTable record model for this ActsAsTable row model.
385
+ #
386
+ # @param [ActsAsTable::Mapper::RecordModel] target
387
+ # @return [ActsAsTable::Mapper::RowModel]
388
+ def root_model=(target)
389
+ @row_model.root_record_model = target.send(:instance_variable_get, :@record_model)
390
+
391
+ self
392
+ end
393
+
394
+ # Returns a new ActsAsTable mapper object an instance of the {ActsAsTable::RecordModel} class.
395
+ #
396
+ # @param [#to_s] class_name
397
+ # @yieldparam [ActsAsTable::Mapper::RecordModel] record_model
398
+ # @yieldreturn [void]
399
+ # @return [ActsAsTable::Mapper::RecordModel]
400
+ def model(class_name, &block)
401
+ ActsAsTable::Mapper::RecordModel.new(@row_model, @column_model_by_key, class_name, &block)
402
+ end
403
+
404
+ private
405
+
406
+ # Performs a depth-first search of the given object and yields each path from root to leaf.
407
+ #
408
+ # @param [#each_pair, #each, #to_s] object
409
+ # @param [Array<#to_s>] path
410
+ # @yieldparam [Array<#to_s>] path
411
+ # @yieldreturn [void]
412
+ # @return [void]
413
+ def _dfs(object, path = [], &block)
414
+ unless block.nil?
415
+ if object.respond_to?(:each_pair)
416
+ object.each_pair do |pair|
417
+ # @return [Array<#to_s>]
418
+ key, new_object = *pair
419
+
420
+ # @return [Array<#to_s>]
421
+ new_path = path + [key]
422
+
423
+ _dfs(new_object, new_path, &block)
424
+ end
425
+ elsif object.respond_to?(:each)
426
+ object.each do |new_object|
427
+ _dfs(new_object, path, &block)
428
+ end
429
+ else
430
+ # @return [Array<#to_s>]
431
+ new_path = path + [object]
432
+
433
+ case block.arity
434
+ when 1 then block.call(new_path)
435
+ else new_path.instance_exec(&block)
436
+ end
437
+ end
438
+ end
439
+
440
+ return
441
+ end
442
+
443
+ # @return [String]
444
+ COLUMN_MODEL_SEPARATOR_ = "\t".freeze
445
+
446
+ # @return [String]
447
+ WHITESPACE_PATTERN_ = /\s+/i.freeze
448
+
449
+ # @return [String]
450
+ WHITESPACE_REPLACEMENT_ = ' '.freeze
451
+
452
+ # Returns the +ActsAsTable::ColumnModel#attributes+ for the given path.
453
+ #
454
+ # @param [Array<#to_s>] path
455
+ # @return [Hash<Symbol, Object>]
456
+ def _to_column_model_attributes(path)
457
+ {
458
+ name: path.collect(&:to_s).collect(&:strip).collect { |s| s.strip.gsub(WHITESPACE_PATTERN_, WHITESPACE_REPLACEMENT_) }.join(COLUMN_MODEL_SEPARATOR_),
459
+ separator: COLUMN_MODEL_SEPARATOR_,
460
+ }
461
+ end
462
+ end
463
+ end
464
+ end