brick 0.1.0 → 1.0.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.
data/lib/brick/util.rb ADDED
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module Brick
5
+ module Util
6
+ # ===================================
7
+ # Epic require patch
8
+ def self._patch_require(module_filename, folder_matcher, search_text, replacement_text, autoload_symbol = nil, is_bundler = false)
9
+ mod_name_parts = module_filename.split('.')
10
+ extension = case mod_name_parts.last
11
+ when 'rb', 'so', 'o'
12
+ module_filename = mod_name_parts[0..-2].join('.')
13
+ ".#{mod_name_parts.last}"
14
+ else
15
+ '.rb'
16
+ end
17
+
18
+ if autoload_symbol
19
+ unless Object.const_defined?('ActiveSupport::Dependencies')
20
+ require 'active_support'
21
+ require 'active_support/dependencies'
22
+ end
23
+ alp = ActiveSupport::Dependencies.autoload_paths
24
+ custom_require_dir = ::Brick::Util._custom_require_dir
25
+ # Create any missing folder structure leading up to this file
26
+ module_filename.split('/')[0..-2].inject(custom_require_dir) do |s, part|
27
+ new_part = File.join(s, part)
28
+ Dir.mkdir(new_part) unless Dir.exist?(new_part)
29
+ new_part
30
+ end
31
+ if ::Brick::Util._write_patched(folder_matcher, module_filename, extension, custom_require_dir, nil, search_text, replacement_text) &&
32
+ !alp.include?(custom_require_dir)
33
+ alp.unshift(custom_require_dir)
34
+ end
35
+ elsif is_bundler
36
+ puts "Bundler hack"
37
+ require 'pry-byebug'
38
+ binding.pry
39
+ x = 5
40
+ # bin_path
41
+ # puts Bundler.require.inspect
42
+ else
43
+ unless (require_overrides = ::Brick::Util.instance_variable_get(:@_require_overrides))
44
+ ::Brick::Util.instance_variable_set(:@_require_overrides, (require_overrides = {}))
45
+
46
+ # Patch "require" itself so that when it specifically sees "active_support/values/time_zone" then
47
+ # a copy is taken of the original, an attempt is made to find the line with a circular error, that
48
+ # single line is patched, and then an updated version is written to a temporary folder which is
49
+ # then required in place of the original.
50
+
51
+ Kernel.module_exec do
52
+ # class << self
53
+ alias_method :orig_require, :require
54
+ # end
55
+ # To be most faithful to Ruby's normal behaviour, this should look like a public singleton
56
+ define_method(:require) do |name|
57
+ puts name if name.to_s.include?('cucu')
58
+ if (require_override = ::Brick::Util.instance_variable_get(:@_require_overrides)[name])
59
+ extension, folder_matcher, search_text, replacement_text, autoload_symbol = require_override
60
+ patched_filename = "/patched_#{name.tr('/', '_')}#{extension}"
61
+ if $LOADED_FEATURES.find { |f| f.end_with?(patched_filename) }
62
+ false
63
+ else
64
+ is_replaced = false
65
+ if (replacement_path = ::Brick::Util._write_patched(folder_matcher, name, extension, ::Brick::Util._custom_require_dir, patched_filename, search_text, replacement_text))
66
+ is_replaced = Kernel.send(:orig_require, replacement_path)
67
+ elsif replacement_path.nil?
68
+ puts "Couldn't find #{name} to require it!"
69
+ end
70
+ is_replaced
71
+ end
72
+ else
73
+ Kernel.send(:orig_require, name)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ require_overrides[module_filename] = [extension, folder_matcher, search_text, replacement_text, autoload_symbol]
79
+ end
80
+ end
81
+
82
+ def self._custom_require_dir
83
+ unless (custom_require_dir = ::Brick::Util.instance_variable_get(:@_custom_require_dir))
84
+ ::Brick::Util.instance_variable_set(:@_custom_require_dir, (custom_require_dir = Dir.mktmpdir))
85
+ # So normal Ruby require will now pick this one up
86
+ $LOAD_PATH.unshift(custom_require_dir)
87
+ # When Ruby is exiting, remove this temporary directory
88
+ at_exit do
89
+ FileUtils.rm_rf(::Brick::Util.instance_variable_get(:@_custom_require_dir))
90
+ end
91
+ end
92
+ custom_require_dir
93
+ end
94
+
95
+ # Returns the full path to the replaced filename, or
96
+ # false if the file already exists, and nil if it was unable to write anything.
97
+ def self._write_patched(folder_matcher, name, extension, dir, patched_filename, search_text, replacement_text)
98
+ # See if our replacement file might already exist for some reason
99
+ name = +"/#{name}" unless name.start_with?('/')
100
+ name << extension unless name.end_with?(extension)
101
+ puts (replacement_path = "#{dir}#{patched_filename || name}")
102
+ return false if File.exist?(replacement_path)
103
+
104
+ # Dredge up the original .rb file, doctor it, and then require it instead
105
+ num_written = nil
106
+ orig_path = nil
107
+ orig_as = nil
108
+ # Using Ruby's approach to find files to require
109
+ $LOAD_PATH.each do |path|
110
+ orig_path = "#{path}#{name}"
111
+ break if path.include?(folder_matcher) && (orig_as = File.open(orig_path))
112
+ end
113
+ puts [folder_matcher, name].inspect
114
+ if (orig_text = orig_as&.read)
115
+ File.open(replacement_path, 'w') do |replacement|
116
+ num_written = replacement.write(orig_text.gsub(search_text, replacement_text))
117
+ end
118
+ orig_as.close
119
+ end
120
+ (num_written&.> 0) ? replacement_path : nil
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module Brick
5
+ module VERSION
6
+ MAJOR = 1
7
+ MINOR = 0
8
+ TINY = 0
9
+
10
+ # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
+ PRE = nil
12
+
13
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.').freeze
14
+
15
+ def self.to_s
16
+ STRING
17
+ end
18
+ end
19
+ end
data/lib/brick.rb ADDED
@@ -0,0 +1,470 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record/version'
4
+
5
+ # ActiveRecord before 4.0 didn't have #version
6
+ unless ActiveRecord.respond_to?(:version)
7
+ module ActiveRecord
8
+ def self.version
9
+ ::Gem::Version.new(ActiveRecord::VERSION::STRING)
10
+ end
11
+ end
12
+ end
13
+
14
+ # In ActiveSupport older than 5.0, the duplicable? test tries to new up a BigDecimal,
15
+ # and Ruby 2.6 and later deprecates #new. This removes the warning from BigDecimal.
16
+ require 'bigdecimal'
17
+ if (ruby_version = ::Gem::Version.new(RUBY_VERSION)) >= ::Gem::Version.new('2.6') &&
18
+ ActiveRecord.version < ::Gem::Version.new('5.0')
19
+ def BigDecimal.new(*args, **kwargs)
20
+ BigDecimal(*args, **kwargs)
21
+ end
22
+ end
23
+
24
+ # Allow ActiveRecord 4.0 and 4.1 to work with newer Ruby (>= 2.4) by avoiding a "stack level too deep"
25
+ # error when ActiveSupport tries to smarten up Numeric by messing with Fixnum and Bignum at the end of:
26
+ # activesupport-4.0.13/lib/active_support/core_ext/numeric/conversions.rb
27
+ if ActiveRecord.version < ::Gem::Version.new('4.2') &&
28
+ ActiveRecord.version > ::Gem::Version.new('3.2') &&
29
+ Object.const_defined?('Integer') && Integer.superclass.name == 'Numeric'
30
+ class OurFixnum < Integer; end
31
+ Numeric.const_set('Fixnum', OurFixnum)
32
+ class OurBignum < Integer; end
33
+ Numeric.const_set('Bignum', OurBignum)
34
+ end
35
+
36
+ # Allow ActiveRecord < 3.2 to run with newer versions of Psych gem
37
+ if BigDecimal.respond_to?(:yaml_tag) && !BigDecimal.respond_to?(:yaml_as)
38
+ class BigDecimal
39
+ class <<self
40
+ alias yaml_as yaml_tag
41
+ end
42
+ end
43
+ end
44
+
45
+ require 'brick/util'
46
+
47
+ # Allow ActiveRecord < 3.2 to work with Ruby 2.7 and later
48
+ if ActiveRecord.version < ::Gem::Version.new('3.2') &&
49
+ ruby_version >= ::Gem::Version.new('2.7')
50
+ # Remove circular reference for "now"
51
+ ::Brick::Util._patch_require(
52
+ 'active_support/values/time_zone.rb', '/activesupport',
53
+ ' def parse(str, now=now)',
54
+ ' def parse(str, now=now())'
55
+ )
56
+ # Remove circular reference for "reflection" for ActiveRecord 3.1
57
+ if ActiveRecord.version >= ::Gem::Version.new('3.1')
58
+ ::Brick::Util._patch_require(
59
+ 'active_record/associations/has_many_association.rb', '/activerecord',
60
+ 'reflection = reflection)',
61
+ 'reflection = reflection())',
62
+ :HasManyAssociation # Make sure the path for this guy is available to be autoloaded
63
+ )
64
+ end
65
+ end
66
+
67
+ # puts ::Brick::Util._patch_require(
68
+ # 'cucumber/cli/options.rb', '/cucumber/cli/options', # /cli/options
69
+ # ' def extract_environment_variables',
70
+ # " def extract_environment_variables\n
71
+ # puts 'Patch test!'"
72
+ # ).inspect
73
+
74
+ # An ActiveRecord extension that uses INFORMATION_SCHEMA views to reflect on all
75
+ # tables and views in the database (just once at the time the database connection
76
+ # is first established), and then automatically creates models, controllers, views,
77
+ # and routes based on those available relations.
78
+ require 'brick/config'
79
+ require 'brick/frameworks/rails'
80
+ module Brick
81
+ class << self
82
+ def append_routes
83
+ ::Rails.application.routes.append do
84
+ relations = (::Brick.instance_variable_get(:@relations) || {})[ActiveRecord::Base.connection_pool.object_id] || {}
85
+ relations.each do |k, v|
86
+ options = {}
87
+ options[:only] = [:index, :show] if v.key?(:isView)
88
+ send(:resources, k.underscore.pluralize.to_sym, **options)
89
+ end
90
+ end
91
+ end
92
+
93
+ # Switches Brick auto-routes on or off, for all threads
94
+ # @api public
95
+ def enable_routes=(value)
96
+ Brick.config.enable_routes = value
97
+ end
98
+
99
+ # Returns `true` if Brick routes are on, `false` otherwise. This is the
100
+ # on/off switch that affects all threads. Enabled by default.
101
+ # @api public
102
+ def enable_routes?
103
+ !!Brick.config.enable_routes
104
+ end
105
+
106
+ # Returns Brick's `::Gem::Version`, convenient for comparisons. This is
107
+ # recommended over `::Brick::VERSION::STRING`.
108
+ #
109
+ # @api public
110
+ def gem_version
111
+ ::Gem::Version.new(VERSION::STRING)
112
+ end
113
+
114
+ # Set the Brick serializer. This setting affects all threads.
115
+ # @api public
116
+ def serializer=(value)
117
+ Brick.config.serializer = value
118
+ end
119
+
120
+ # Get the Brick serializer used by all threads.
121
+ # @api public
122
+ def serializer
123
+ Brick.config.serializer
124
+ end
125
+
126
+ # Returns Brick's global configuration object, a singleton. These
127
+ # settings affect all threads.
128
+ # @api private
129
+ def config
130
+ @config ||= Brick::Config.instance
131
+ yield @config if block_given?
132
+ @config
133
+ end
134
+ alias configure config
135
+
136
+ def version
137
+ VERSION::STRING
138
+ end
139
+ end
140
+ end
141
+
142
+ require 'brick/extensions'
143
+ require 'brick/version_number'
144
+ # require 'brick/serializers/json'
145
+ # require 'brick/serializers/yaml'
146
+
147
+ require 'active_record'
148
+ # Major compatibility fixes for ActiveRecord < 4.2
149
+ # ================================================
150
+ ActiveSupport.on_load(:active_record) do
151
+ # rubocop:disable Lint/ConstantDefinitionInBlock
152
+ module ActiveRecord
153
+ class Base
154
+ unless respond_to?(:execute_sql)
155
+ class << self
156
+ def execute_sql(sql, *param_array)
157
+ param_array = param_array.first if param_array.length == 1 && param_array.first.is_a?(Array)
158
+ connection.execute(send(:sanitize_sql_array, [sql] + param_array))
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ # Rails < 4.0 cannot do #find_by, #find_or_create_by, or do #pluck on multiple columns, so here are the patches:
165
+ if version < ::Gem::Version.new('4.0')
166
+ # Normally find_by is in FinderMethods, which older AR doesn't have
167
+ module Calculations
168
+ def find_by(*args)
169
+ where(*args).limit(1).to_a.first
170
+ end
171
+
172
+ def find_or_create_by(attributes, &block)
173
+ find_by(attributes) || create(attributes, &block)
174
+ end
175
+
176
+ def pluck(*column_names)
177
+ column_names.map! do |column_name|
178
+ if column_name.is_a?(Symbol) && self.column_names.include?(column_name.to_s)
179
+ "#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
180
+ else
181
+ column_name
182
+ end
183
+ end
184
+
185
+ # Same as: if has_include?(column_names.first)
186
+ if eager_loading? || (includes_values.present? && (column_names.first || references_eager_loaded_tables?))
187
+ construct_relation_for_association_calculations.pluck(*column_names)
188
+ else
189
+ relation = clone # spawn
190
+ relation.select_values = column_names
191
+ result = if klass.connection.class.name.end_with?('::PostgreSQLAdapter')
192
+ rslt = klass.connection.execute(relation.arel.to_sql)
193
+ rslt.type_map =
194
+ @type_map ||= proc do
195
+ # This aliasing avoids the warning:
196
+ # "no type cast defined for type "numeric" with oid 1700. Please cast this type
197
+ # explicitly to TEXT to be safe for future changes."
198
+ PG::BasicTypeRegistry.alias_type(0, 'numeric', 'text') # oid 1700
199
+ PG::BasicTypeRegistry.alias_type(0, 'time', 'text') # oid 1083
200
+ PG::BasicTypeMapForResults.new(klass.connection.raw_connection)
201
+ end.call
202
+ rslt.to_a
203
+ elsif respond_to?(:bind_values)
204
+ klass.connection.select_all(relation.arel, nil, bind_values)
205
+ else
206
+ klass.connection.select_all(relation.arel.to_sql, nil)
207
+ end
208
+ if result.empty?
209
+ []
210
+ else
211
+ columns = result.first.keys.map do |key|
212
+ # rubocop:disable Style/SingleLineMethods Naming/MethodParameterName
213
+ klass.columns_hash.fetch(key) do
214
+ Class.new { def type_cast(v); v; end }.new
215
+ end
216
+ # rubocop:enable Style/SingleLineMethods Naming/MethodParameterName
217
+ end
218
+
219
+ result = result.map do |attributes|
220
+ values = klass.initialize_attributes(attributes).values
221
+
222
+ columns.zip(values).map do |column, value|
223
+ column.type_cast(value)
224
+ end
225
+ end
226
+ columns.one? ? result.map!(&:first) : result
227
+ end
228
+ end
229
+ end
230
+ end
231
+
232
+ unless Base.is_a?(Calculations)
233
+ class Base
234
+ class << self
235
+ delegate :pluck, :find_by, :find_or_create_by, to: :scoped
236
+ end
237
+ end
238
+ end
239
+
240
+ # ActiveRecord < 3.2 doesn't have initialize_attributes, used by .pluck()
241
+ unless AttributeMethods.const_defined?('Serialization')
242
+ class Base
243
+ class << self
244
+ def initialize_attributes(attributes, options = {}) #:nodoc:
245
+ serialized = (options.delete(:serialized) { true }) ? :serialized : :unserialized
246
+ # super(attributes, options)
247
+
248
+ serialized_attributes.each do |key, coder|
249
+ attributes[key] = Attribute.new(coder, attributes[key], serialized) if attributes.key?(key)
250
+ end
251
+
252
+ attributes
253
+ end
254
+ end
255
+ end
256
+ end
257
+
258
+ # This only gets added for ActiveRecord < 3.2
259
+ module Reflection
260
+ unless AssociationReflection.instance_methods.include?(:foreign_key)
261
+ class AssociationReflection < MacroReflection
262
+ alias foreign_key association_foreign_key
263
+ end
264
+ end
265
+ end
266
+
267
+ # ActiveRecord 3.1 and 3.2 didn't try to bring in &block for the .extending() convenience thing
268
+ # that smartens up scopes, and Ruby 2.7 complained loudly about just doing the magical "Proc.new"
269
+ # that historically would just capture the incoming block.
270
+ module QueryMethods
271
+ unless instance_method(:extending).parameters.include?([:block, :block])
272
+ # These first two lines used to be:
273
+ # def extending(*modules)
274
+ # modules << Module.new(&Proc.new) if block_given?
275
+
276
+ def extending(*modules, &block)
277
+ modules << Module.new(&block) if block_given?
278
+
279
+ return self if modules.empty?
280
+
281
+ relation = clone
282
+ relation.send(:apply_modules, modules.flatten)
283
+ relation
284
+ end
285
+ end
286
+ end
287
+
288
+ # Same kind of thing for ActiveRecord::Scoping::Default#default_scope
289
+ module Scoping
290
+ module Default
291
+ module ClassMethods
292
+ if instance_methods.include?(:default_scope) &&
293
+ !instance_method(:default_scope).parameters.include?([:block, :block])
294
+ # Fix for AR 3.2-5.1
295
+ def default_scope(scope = nil, &block)
296
+ scope = block if block_given?
297
+
298
+ if scope.is_a?(Relation) || !scope.respond_to?(:call)
299
+ raise ArgumentError,
300
+ 'Support for calling #default_scope without a block is removed. For example instead ' \
301
+ "of `default_scope where(color: 'red')`, please use " \
302
+ "`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
303
+ 'self.default_scope.)'
304
+ end
305
+
306
+ self.default_scopes += [scope]
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end
312
+ end
313
+ end
314
+ # rubocop:enable Lint/ConstantDefinitionInBlock
315
+
316
+ # Rails < 4.2 is not innately compatible with Ruby 2.4 and later, and comes up with:
317
+ # "TypeError: Cannot visit Integer" unless we patch like this:
318
+ if ruby_version >= ::Gem::Version.new('2.4') &&
319
+ Arel::Visitors.const_defined?('DepthFirst') &&
320
+ !Arel::Visitors::DepthFirst.private_instance_methods.include?(:visit_Integer)
321
+ module Arel
322
+ module Visitors
323
+ class DepthFirst < Visitor
324
+ alias visit_Integer terminal
325
+ end
326
+
327
+ class Dot < Visitor
328
+ alias visit_Integer visit_String
329
+ end
330
+
331
+ class ToSql < Visitor
332
+ private
333
+
334
+ # ActiveRecord before v3.2 uses Arel < 3.x, which does not have Arel#literal.
335
+ unless private_instance_methods.include?(:literal)
336
+ def literal(obj)
337
+ obj
338
+ end
339
+ end
340
+ alias visit_Integer literal
341
+ end
342
+ end
343
+ end
344
+ end
345
+
346
+ unless DateTime.instance_methods.include?(:nsec)
347
+ class DateTime < Date
348
+ def nsec
349
+ (sec_fraction * 1_000_000_000).to_i
350
+ end
351
+ end
352
+ end
353
+
354
+ # First part of arel_table_type stuff:
355
+ # ------------------------------------
356
+ # (more found below)
357
+ # was: ActiveRecord.version >= ::Gem::Version.new('3.2') &&
358
+ if ActiveRecord.version < ::Gem::Version.new('5.0')
359
+ # Used by Util#_arel_table_type
360
+ module ActiveRecord
361
+ class Base
362
+ def self.arel_table
363
+ @arel_table ||= Arel::Table.new(table_name, arel_engine).tap do |x|
364
+ x.instance_variable_set(:@_arel_table_type, self)
365
+ end
366
+ end
367
+ end
368
+ end
369
+ end
370
+
371
+ include ::Brick::Extensions
372
+
373
+ unless ::Brick::Extensions::IS_AMOEBA
374
+ # Add amoeba-compatible support
375
+ module ActiveRecord
376
+ class Base
377
+ def self.amoeba(*args)
378
+ puts "Amoeba called from #{name} with #{args.inspect}"
379
+ end
380
+ end
381
+ end
382
+ end
383
+ end
384
+
385
+ # Do this earlier because stuff here gets mixed into JoinDependency::JoinAssociation and AssociationScope
386
+ if ActiveRecord.version < ::Gem::Version.new('5.0') && Object.const_defined?('PG::Connection')
387
+ # Avoid pg gem deprecation warning: "You should use PG::Connection, PG::Result, and PG::Error instead"
388
+ PGconn = PG::Connection
389
+ PGresult = PG::Result
390
+ PGError = PG::Error
391
+ end
392
+
393
+ # More arel_table_type stuff:
394
+ # ---------------------------
395
+ if ActiveRecord.version < ::Gem::Version.new('5.2')
396
+ # Specifically for AR 3.1 and 3.2 to avoid: "undefined method `delegate' for ActiveRecord::Reflection::ThroughReflection:Class"
397
+ require 'active_support/core_ext/module/delegation' if ActiveRecord.version < ::Gem::Version.new('4.0')
398
+ # Used by Util#_arel_table_type
399
+ # rubocop:disable Style/CommentedKeyword
400
+ module ActiveRecord
401
+ module Reflection
402
+ # AR < 4.0 doesn't know about join_table and derive_join_table
403
+ unless AssociationReflection.instance_methods.include?(:join_table)
404
+ class AssociationReflection < MacroReflection
405
+ def join_table
406
+ @join_table ||= options[:join_table] || derive_join_table
407
+ end
408
+
409
+ private
410
+
411
+ def derive_join_table
412
+ [active_record.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').gsub("\0", '_')
413
+ end
414
+ end
415
+ end
416
+ end
417
+
418
+ module Associations
419
+ # Specific to AR 4.2 - 5.1:
420
+ if Associations.const_defined?('JoinDependency') && JoinDependency.private_instance_methods.include?(:table_aliases_for)
421
+ class JoinDependency
422
+ private
423
+
424
+ if ActiveRecord.version < ::Gem::Version.new('5.1') # 4.2 or 5.0
425
+ def table_aliases_for(parent, node)
426
+ node.reflection.chain.map do |reflection|
427
+ alias_tracker.aliased_table_for(
428
+ reflection.table_name,
429
+ table_alias_for(reflection, parent, reflection != node.reflection)
430
+ ).tap do |x|
431
+ # %%% Specific only to Rails 4.2 (and maybe 4.1?)
432
+ x = x.left if x.is_a?(Arel::Nodes::TableAlias)
433
+ y = reflection.chain.find { |c| c.table_name == x.name }
434
+ x.instance_variable_set(:@_arel_table_type, y.klass)
435
+ end
436
+ end
437
+ end
438
+ end
439
+ end
440
+ elsif Associations.const_defined?('JoinHelper') && JoinHelper.private_instance_methods.include?(:construct_tables)
441
+ module JoinHelper
442
+ private
443
+
444
+ # AR > 3.0 and < 4.2 (%%% maybe only < 4.1?) uses construct_tables like this:
445
+ def construct_tables
446
+ tables = []
447
+ chain.each do |reflection|
448
+ tables << alias_tracker.aliased_table_for(
449
+ table_name_for(reflection),
450
+ table_alias_for(reflection, reflection != self.reflection)
451
+ ).tap do |x|
452
+ x = x.left if x.is_a?(Arel::Nodes::TableAlias)
453
+ x.instance_variable_set(:@_arel_table_type, reflection.chain.find { |c| c.table_name == x.name }.klass)
454
+ end
455
+
456
+ next unless reflection.source_macro == :has_and_belongs_to_many
457
+
458
+ tables << alias_tracker.aliased_table_for(
459
+ (reflection.source_reflection || reflection).join_table,
460
+ table_alias_for(reflection, true)
461
+ )
462
+ end
463
+ tables
464
+ end
465
+ end
466
+ end
467
+ end
468
+ end # module ActiveRecord
469
+ # rubocop:enable Style/CommentedKeyword
470
+ end
@@ -0,0 +1,2 @@
1
+ Description:
2
+ Modifies an existing model so that it includes an IMPORT_TEMPLATE.