duty_free 1.0.7 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -25,17 +25,18 @@ module DutyFree
25
25
  def self._recurse_arel(piece, prefix = '')
26
26
  names = []
27
27
  # Our JOINs mashup of nested arrays and hashes
28
- if piece.is_a?(Array)
28
+ case piece
29
+ when Array
29
30
  names += piece.inject([]) { |s, v| s + _recurse_arel(v, prefix) }
30
- elsif piece.is_a?(Hash)
31
+ when Hash
31
32
  names += piece.inject([]) do |s, v|
32
33
  new_prefix = "#{prefix}#{v.first}_"
33
- s << new_prefix
34
+ s << [v.last.shift, new_prefix]
34
35
  s + _recurse_arel(v.last, new_prefix)
35
36
  end
36
37
 
37
38
  # ActiveRecord AREL objects
38
- elsif piece.is_a?(Arel::Nodes::Join) # INNER or OUTER JOIN
39
+ when Arel::Nodes::Join # INNER or OUTER JOIN
39
40
  # rubocop:disable Style/IdenticalConditionalBranches
40
41
  if piece.right.is_a?(Arel::Table) # Came in from AR < 3.2?
41
42
  # Arel 2.x and older is a little curious because these JOINs work "back to front".
@@ -45,28 +46,38 @@ module DutyFree
45
46
  # The right side here at the top is the very last table, and anywhere else down the tree it is
46
47
  # the later "JOIN" table of this pair. (The table that comes after all the rest of the JOINs
47
48
  # from the left side.)
48
- names << (piece.right.table_alias || piece.right.name)
49
+ names << [_arel_table_type(piece.right), (piece.right.table_alias || piece.right.name)]
49
50
  else # "Normal" setup, fed from a JoinSource which has an array of JOINs
50
51
  # The left side is the "JOIN" table
51
52
  names += _recurse_arel(piece.left)
52
53
  # (The right side of these is the "ON" clause)
53
54
  end
54
55
  # rubocop:enable Style/IdenticalConditionalBranches
55
- elsif piece.is_a?(Arel::Table) # Table
56
- names << (piece.table_alias || piece.name)
57
- elsif piece.is_a?(Arel::Nodes::TableAlias) # Alias
56
+ when Arel::Table # Table
57
+ names << [_arel_table_type(piece), (piece.table_alias || piece.name)]
58
+ when Arel::Nodes::TableAlias # Alias
58
59
  # Can get the real table name from: self._recurse_arel(piece.left)
59
- names << piece.right.to_s # This is simply a string; the alias name itself
60
- elsif piece.is_a?(Arel::Nodes::JoinSource) # Leaving this until the end because AR < 3.2 doesn't know at all about JoinSource!
60
+ names << [_arel_table_type(piece.left), piece.right.to_s] # This is simply a string; the alias name itself
61
+ when Arel::Nodes::JoinSource # Leaving this until the end because AR < 3.2 doesn't know at all about JoinSource!
61
62
  # The left side is the "FROM" table
62
63
  # names += _recurse_arel(piece.left)
63
- names << (piece.left.table_alias || piece.left.name)
64
+ names << [_arel_table_type(piece.left), (piece.left.table_alias || piece.left.name)]
64
65
  # The right side is an array of all JOINs
65
66
  names += piece.right.inject([]) { |s, v| s + _recurse_arel(v) }
66
67
  end
67
68
  names
68
69
  end
69
70
 
71
+ def self._arel_table_type(tbl)
72
+ # AR < 4.2 doesn't have type_caster at all, so rely on an instance variable getting set
73
+ # AR 4.2 - 5.1 have buggy type_caster entries for the root node
74
+ tbl.instance_variable_get(:@_arel_table_type) ||
75
+ # 5.2-6.1 does type_caster just fine, no bugs there, but the property with the type differs:
76
+ # 5.2 has "types" as public, 6.0 "types" as private, and 6.1 "klass" as private.
77
+ ((tc = tbl.send(:type_caster)) && tc.instance_variable_get(:@types)) ||
78
+ tc.send(:klass)
79
+ end
80
+
70
81
  def self._prefix_join(prefixes, separator = nil)
71
82
  prefixes.reject(&:blank?).join(separator || '.')
72
83
  end
@@ -83,5 +94,112 @@ module DutyFree
83
94
  end
84
95
  name
85
96
  end
97
+
98
+ # ===================================
99
+ # Epic require patch
100
+ def self._patch_require(module_filename, folder_matcher, search_text, replacement_text, autoload_symbol = nil)
101
+ mod_name_parts = module_filename.split('.')
102
+ extension = case mod_name_parts.last
103
+ when 'rb', 'so', 'o'
104
+ module_filename = mod_name_parts[0..-2].join('.')
105
+ ".#{mod_name_parts.last}"
106
+ else
107
+ '.rb'
108
+ end
109
+
110
+ if autoload_symbol
111
+ unless Object.const_defined?('ActiveSupport::Dependencies')
112
+ require 'active_support'
113
+ require 'active_support/dependencies'
114
+ end
115
+ alp = ActiveSupport::Dependencies.autoload_paths
116
+ custom_require_dir = ::DutyFree::Util._custom_require_dir
117
+ # Create any missing folder structure leading up to this file
118
+ module_filename.split('/')[0..-2].inject(custom_require_dir) do |s, part|
119
+ new_part = File.join(s, part)
120
+ Dir.mkdir(new_part) unless Dir.exist?(new_part)
121
+ new_part
122
+ end
123
+ if ::DutyFree::Util._write_patched(folder_matcher, module_filename, extension, custom_require_dir, nil, search_text, replacement_text) &&
124
+ !alp.include?(custom_require_dir)
125
+ alp.unshift(custom_require_dir)
126
+ end
127
+ else
128
+ unless (require_overrides = ::DutyFree::Util.instance_variable_get(:@_require_overrides))
129
+ ::DutyFree::Util.instance_variable_set(:@_require_overrides, (require_overrides = {}))
130
+
131
+ # Patch "require" itself so that when it specifically sees "active_support/values/time_zone" then
132
+ # a copy is taken of the original, an attempt is made to find the line with a circular error, that
133
+ # single line is patched, and then an updated version is written to a temporary folder which is
134
+ # then required in place of the original.
135
+
136
+ Kernel.module_exec do
137
+ # class << self
138
+ alias_method :orig_require, :require
139
+ # end
140
+ # To be most faithful to Ruby's normal behaviour, this should look like a public singleton
141
+ define_method(:require) do |name|
142
+ if (require_override = ::DutyFree::Util.instance_variable_get(:@_require_overrides)[name])
143
+ extension, folder_matcher, search_text, replacement_text, autoload_symbol = require_override
144
+ patched_filename = "/patched_#{name.tr('/', '_')}#{extension}"
145
+ if $LOADED_FEATURES.find { |f| f.end_with?(patched_filename) }
146
+ false
147
+ else
148
+ is_replaced = false
149
+ if (replacement_path = ::DutyFree::Util._write_patched(folder_matcher, name, extension, ::DutyFree::Util._custom_require_dir, patched_filename, search_text, replacement_text))
150
+ is_replaced = Kernel.send(:orig_require, replacement_path)
151
+ elsif replacement_path.nil?
152
+ puts "Couldn't find #{name} to require it!"
153
+ end
154
+ is_replaced
155
+ end
156
+ else
157
+ Kernel.send(:orig_require, name)
158
+ end
159
+ end
160
+ end
161
+ end
162
+ require_overrides[module_filename] = [extension, folder_matcher, search_text, replacement_text, autoload_symbol]
163
+ end
164
+ end
165
+
166
+ def self._custom_require_dir
167
+ unless (custom_require_dir = ::DutyFree::Util.instance_variable_get(:@_custom_require_dir))
168
+ ::DutyFree::Util.instance_variable_set(:@_custom_require_dir, (custom_require_dir = Dir.mktmpdir))
169
+ # So normal Ruby require will now pick this one up
170
+ $LOAD_PATH.unshift(custom_require_dir)
171
+ # When Ruby is exiting, remove this temporary directory
172
+ at_exit do
173
+ FileUtils.rm_rf(::DutyFree::Util.instance_variable_get(:@_custom_require_dir))
174
+ end
175
+ end
176
+ custom_require_dir
177
+ end
178
+
179
+ # Returns the full path to the replaced filename, or
180
+ # false if the file already exists, and nil if it was unable to write anything.
181
+ def self._write_patched(folder_matcher, name, extension, dir, patched_filename, search_text, replacement_text)
182
+ # See if our replacement file might already exist for some reason
183
+ name = +"/#{name}" unless name.start_with?('/')
184
+ name << extension unless name.end_with?(extension)
185
+ return false if File.exist?(replacement_path = "#{dir}#{patched_filename || name}")
186
+
187
+ # Dredge up the original .rb file, doctor it, and then require it instead
188
+ num_written = nil
189
+ orig_path = nil
190
+ orig_as = nil
191
+ # Using Ruby's approach to find files to require
192
+ $LOAD_PATH.each do |path|
193
+ orig_path = "#{path}#{name}"
194
+ break if path.include?(folder_matcher) && (orig_as = File.open(orig_path))
195
+ end
196
+ if (orig_text = orig_as&.read)
197
+ File.open(replacement_path, 'w') do |replacement|
198
+ num_written = replacement.write(orig_text.gsub(search_text, replacement_text))
199
+ end
200
+ orig_as.close
201
+ end
202
+ (num_written&.> 0) ? replacement_path : nil
203
+ end
86
204
  end
87
205
  end
@@ -5,7 +5,7 @@ module DutyFree
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 7
8
+ TINY = 9
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
data/lib/duty_free.rb CHANGED
@@ -21,8 +21,8 @@ if ActiveRecord.version < ::Gem::Version.new('5.0') &&
21
21
  end
22
22
  end
23
23
 
24
- # Allow Rails 4.0 and 4.1 to work with newer Ruby (>= 2.4) by avoiding a "stack level too deep" error
25
- # when ActiveSupport tries to smarten up Numeric by messing with Fixnum and Bignum at the end of:
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
26
  # activesupport-4.0.13/lib/active_support/core_ext/numeric/conversions.rb
27
27
  if ActiveRecord.version < ::Gem::Version.new('4.2') &&
28
28
  ActiveRecord.version > ::Gem::Version.new('3.2') &&
@@ -33,7 +33,7 @@ if ActiveRecord.version < ::Gem::Version.new('4.2') &&
33
33
  Numeric.const_set('Bignum', OurBignum)
34
34
  end
35
35
 
36
- # Allow Rails < 3.2 to run with newer versions of Psych gem
36
+ # Allow ActiveRecord < 3.2 to run with newer versions of Psych gem
37
37
  if BigDecimal.respond_to?(:yaml_tag) && !BigDecimal.respond_to?(:yaml_as)
38
38
  class BigDecimal
39
39
  class <<self
@@ -42,6 +42,28 @@ if BigDecimal.respond_to?(:yaml_tag) && !BigDecimal.respond_to?(:yaml_as)
42
42
  end
43
43
  end
44
44
 
45
+ require 'duty_free/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
+ ::Gem::Version.new(RUBY_VERSION) >= ::Gem::Version.new('2.7')
50
+ # Remove circular reference for "now"
51
+ ::DutyFree::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
+ ::DutyFree::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
+
45
67
  require 'active_record'
46
68
 
47
69
  require 'duty_free/config'
@@ -107,14 +129,31 @@ end
107
129
  # Major compatibility fixes for ActiveRecord < 4.2
108
130
  # ================================================
109
131
  ActiveSupport.on_load(:active_record) do
110
- # Rails < 4.0 cannot do #find_by, or do #pluck on multiple columns, so here are the patches:
111
- if ActiveRecord.version < ::Gem::Version.new('4.0')
112
- module ActiveRecord
113
- module Calculations # Normally find_by is in FinderMethods, which older AR doesn't have
132
+ # rubocop:disable Lint/ConstantDefinitionInBlock
133
+ module ActiveRecord
134
+ class Base
135
+ unless respond_to?(:execute_sql)
136
+ class << self
137
+ def execute_sql(sql, *param_array)
138
+ param_array = param_array.first if param_array.length == 1 && param_array.first.is_a?(Array)
139
+ connection.execute(send(:sanitize_sql_array, [sql] + param_array))
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ # Rails < 4.0 cannot do #find_by, #find_or_create_by, or do #pluck on multiple columns, so here are the patches:
146
+ if version < ::Gem::Version.new('4.0')
147
+ # Normally find_by is in FinderMethods, which older AR doesn't have
148
+ module Calculations
114
149
  def find_by(*args)
115
150
  where(*args).limit(1).to_a.first
116
151
  end
117
152
 
153
+ def find_or_create_by(attributes, &block)
154
+ find_by(attributes) || create(attributes, &block)
155
+ end
156
+
118
157
  def pluck(*column_names)
119
158
  column_names.map! do |column_name|
120
159
  if column_name.is_a?(Symbol) && self.column_names.include?(column_name.to_s)
@@ -174,7 +213,7 @@ ActiveSupport.on_load(:active_record) do
174
213
  unless Base.is_a?(Calculations)
175
214
  class Base
176
215
  class << self
177
- delegate :pluck, :find_by, to: :scoped
216
+ delegate :pluck, :find_by, :find_or_create_by, to: :scoped
178
217
  end
179
218
  end
180
219
  end
@@ -205,72 +244,208 @@ ActiveSupport.on_load(:active_record) do
205
244
  end
206
245
  end
207
246
  end
208
- end
209
- end
210
247
 
211
- # Rails < 4.2 is not innately compatible with Ruby 2.4 and later, and comes up with:
212
- # "TypeError: Cannot visit Integer" unless we patch like this:
213
- unless ::Gem::Version.new(RUBY_VERSION) < ::Gem::Version.new('2.4')
214
- unless Arel::Visitors::DepthFirst.private_instance_methods.include?(:visit_Integer)
215
- module Arel
216
- module Visitors
217
- class DepthFirst < Visitor
218
- alias visit_Integer terminal
219
- end
248
+ # ActiveRecord 3.1 and 3.2 didn't try to bring in &block for the .extending() convenience thing
249
+ # that smartens up scopes, and Ruby 2.7 complained loudly about just doing the magical "Proc.new"
250
+ # that historically would just capture the incoming block.
251
+ module QueryMethods
252
+ unless instance_method(:extending).parameters.include?([:block, :block])
253
+ # These first two lines used to be:
254
+ # def extending(*modules)
255
+ # modules << Module.new(&Proc.new) if block_given?
256
+
257
+ def extending(*modules, &block)
258
+ modules << Module.new(&block) if block_given?
259
+
260
+ return self if modules.empty?
220
261
 
221
- class Dot < Visitor
222
- alias visit_Integer visit_String
262
+ relation = clone
263
+ relation.send(:apply_modules, modules.flatten)
264
+ relation
223
265
  end
266
+ end
267
+ end
224
268
 
225
- class ToSql < Visitor
226
- private
269
+ # Same kind of thing for ActiveRecord::Scoping::Default#default_scope
270
+ module Scoping
271
+ module Default
272
+ module ClassMethods
273
+ if instance_methods.include?(:default_scope) &&
274
+ !instance_method(:default_scope).parameters.include?([:block, :block])
275
+ # Fix for AR 3.2-5.1
276
+ def default_scope(scope = nil, &block)
277
+ scope = block if block_given?
278
+
279
+ if scope.is_a?(Relation) || !scope.respond_to?(:call)
280
+ raise ArgumentError,
281
+ 'Support for calling #default_scope without a block is removed. For example instead ' \
282
+ "of `default_scope where(color: 'red')`, please use " \
283
+ "`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
284
+ 'self.default_scope.)'
285
+ end
227
286
 
228
- # ActiveRecord before v3.2 uses Arel < 3.x, which does not have Arel#literal.
229
- unless private_instance_methods.include?(:literal)
230
- def literal(obj)
231
- obj
287
+ self.default_scopes += [scope]
232
288
  end
233
289
  end
234
- alias visit_Integer literal
235
290
  end
236
291
  end
237
292
  end
238
293
  end
239
294
  end
295
+ # rubocop:enable Lint/ConstantDefinitionInBlock
240
296
 
241
- if ActiveRecord.version < ::Gem::Version.new('5.0')
242
- # Avoid pg gem deprecation warning: "You should use PG::Connection, PG::Result, and PG::Error instead"
243
- PGconn = PG::Connection
244
- PGresult = PG::Result
245
- PGError = PG::Error
297
+ # Rails < 4.2 is not innately compatible with Ruby 2.4 and later, and comes up with:
298
+ # "TypeError: Cannot visit Integer" unless we patch like this:
299
+ if ::Gem::Version.new(RUBY_VERSION) >= ::Gem::Version.new('2.4') &&
300
+ Arel::Visitors.const_defined?('DepthFirst') &&
301
+ !Arel::Visitors::DepthFirst.private_instance_methods.include?(:visit_Integer)
302
+ module Arel
303
+ module Visitors
304
+ class DepthFirst < Visitor
305
+ alias visit_Integer terminal
306
+ end
307
+
308
+ class Dot < Visitor
309
+ alias visit_Integer visit_String
310
+ end
311
+
312
+ class ToSql < Visitor
313
+ private
314
+
315
+ # ActiveRecord before v3.2 uses Arel < 3.x, which does not have Arel#literal.
316
+ unless private_instance_methods.include?(:literal)
317
+ def literal(obj)
318
+ obj
319
+ end
320
+ end
321
+ alias visit_Integer literal
322
+ end
323
+ end
324
+ end
246
325
  end
247
326
 
248
327
  unless DateTime.instance_methods.include?(:nsec)
249
328
  class DateTime < Date
250
329
  def nsec
251
- (sec_fraction * 1000000000).to_i
330
+ (sec_fraction * 1_000_000_000).to_i
331
+ end
332
+ end
333
+ end
334
+
335
+ # First part of arel_table_type stuff:
336
+ # ------------------------------------
337
+ # (more found below)
338
+ # was: ActiveRecord.version >= ::Gem::Version.new('3.2') &&
339
+ if ActiveRecord.version < ::Gem::Version.new('5.0')
340
+ # Used by Util#_arel_table_type
341
+ module ActiveRecord
342
+ class Base
343
+ def self.arel_table
344
+ @arel_table ||= Arel::Table.new(table_name, arel_engine).tap do |x|
345
+ x.instance_variable_set(:@_arel_table_type, self)
346
+ end
347
+ end
252
348
  end
253
349
  end
254
350
  end
255
351
 
256
352
  include ::DutyFree::Extensions
353
+
354
+ unless ::DutyFree::Extensions::IS_AMOEBA
355
+ # Add amoeba-compatible support
356
+ module ActiveRecord
357
+ class Base
358
+ def self.amoeba(*args)
359
+ puts "Amoeba called from #{name} with #{args.inspect}"
360
+ end
361
+ end
362
+ end
363
+ end
257
364
  end
258
365
 
259
- # # Require frameworks
260
- # if defined?(::Rails)
261
- # # Rails module is sometimes defined by gems like rails-html-sanitizer
262
- # # so we check for presence of Rails.application.
263
- # if defined?(::Rails.application)
264
- # require "duty_free/frameworks/rails"
265
- # else
266
- # ::Kernel.warn(<<-EOS.freeze
267
- # DutyFree has been loaded too early, before rails is loaded. This can
268
- # happen when another gem defines the ::Rails namespace, then DF is loaded,
269
- # all before rails is loaded. You may want to reorder your Gemfile, or defer
270
- # the loading of DF by using `require: false` and a manual require elsewhere.
271
- # EOS
272
- # )
273
- # end
274
- # else
275
- # require "duty_free/frameworks/active_record"
276
- # end
366
+ # Do this earlier because stuff here gets mixed into JoinDependency::JoinAssociation and AssociationScope
367
+ if ActiveRecord.version < ::Gem::Version.new('5.0') && Object.const_defined?('PG::Connection')
368
+ # Avoid pg gem deprecation warning: "You should use PG::Connection, PG::Result, and PG::Error instead"
369
+ PGconn = PG::Connection
370
+ PGresult = PG::Result
371
+ PGError = PG::Error
372
+ end
373
+
374
+ # More arel_table_type stuff:
375
+ # ---------------------------
376
+ if ActiveRecord.version < ::Gem::Version.new('5.2')
377
+ # Specifically for AR 3.1 and 3.2 to avoid: "undefined method `delegate' for ActiveRecord::Reflection::ThroughReflection:Class"
378
+ require 'active_support/core_ext/module/delegation' if ActiveRecord.version < ::Gem::Version.new('4.0')
379
+ # Used by Util#_arel_table_type
380
+ # rubocop:disable Style/CommentedKeyword
381
+ module ActiveRecord
382
+ module Reflection
383
+ # AR < 4.0 doesn't know about join_table and derive_join_table
384
+ unless AssociationReflection.instance_methods.include?(:join_table)
385
+ class AssociationReflection < MacroReflection
386
+ def join_table
387
+ @join_table ||= options[:join_table] || derive_join_table
388
+ end
389
+
390
+ private
391
+
392
+ def derive_join_table
393
+ [active_record.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').gsub("\0", '_')
394
+ end
395
+ end
396
+ end
397
+ end
398
+
399
+ module Associations
400
+ # Specific to AR 4.2 - 5.1:
401
+ if Associations.const_defined?('JoinDependency') && JoinDependency.private_instance_methods.include?(:table_aliases_for)
402
+ class JoinDependency
403
+ private
404
+
405
+ if ActiveRecord.version < ::Gem::Version.new('5.1') # 4.2 or 5.0
406
+ def table_aliases_for(parent, node)
407
+ node.reflection.chain.map do |reflection|
408
+ alias_tracker.aliased_table_for(
409
+ reflection.table_name,
410
+ table_alias_for(reflection, parent, reflection != node.reflection)
411
+ ).tap do |x|
412
+ # %%% Specific only to Rails 4.2 (and maybe 4.1?)
413
+ x = x.left if x.is_a?(Arel::Nodes::TableAlias)
414
+ y = reflection.chain.find { |c| c.table_name == x.name }
415
+ x.instance_variable_set(:@_arel_table_type, y.klass)
416
+ end
417
+ end
418
+ end
419
+ end
420
+ end
421
+ elsif Associations.const_defined?('JoinHelper') && JoinHelper.private_instance_methods.include?(:construct_tables)
422
+ module JoinHelper
423
+ private
424
+
425
+ # AR > 3.0 and < 4.2 (%%% maybe only < 4.1?) uses construct_tables like this:
426
+ def construct_tables
427
+ tables = []
428
+ chain.each do |reflection|
429
+ tables << alias_tracker.aliased_table_for(
430
+ table_name_for(reflection),
431
+ table_alias_for(reflection, reflection != self.reflection)
432
+ ).tap do |x|
433
+ x = x.left if x.is_a?(Arel::Nodes::TableAlias)
434
+ x.instance_variable_set(:@_arel_table_type, reflection.chain.find { |c| c.table_name == x.name }.klass)
435
+ end
436
+
437
+ next unless reflection.source_macro == :has_and_belongs_to_many
438
+
439
+ tables << alias_tracker.aliased_table_for(
440
+ (reflection.source_reflection || reflection).join_table,
441
+ table_alias_for(reflection, true)
442
+ )
443
+ end
444
+ tables
445
+ end
446
+ end
447
+ end
448
+ end
449
+ end # module ActiveRecord
450
+ # rubocop:enable Style/CommentedKeyword
451
+ end