duty_free 1.0.7 → 1.0.8

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.
@@ -40,15 +40,14 @@ module DutyFree
40
40
  assocs = {}
41
41
  this_klass.reflect_on_all_associations.each do |assoc|
42
42
  # PolymorphicReflection AggregateReflection RuntimeReflection
43
- is_belongs_to = assoc.belongs_to? # is_a?(ActiveRecord::Reflection::BelongsToReflection)
43
+ is_belongs_to = assoc.belongs_to?
44
44
  # Figure out if it's belongs_to, has_many, or has_one
45
- # HasAndBelongsToManyReflection
46
45
  belongs_to_or_has_many =
47
46
  if is_belongs_to
48
47
  'belongs_to'
49
- elsif (is_habtm = assoc.respond_to?(:macro) ? (assoc.macro == :has_and_belongs_to_many) : assoc.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection))
48
+ elsif (is_habtm = assoc.macro == :has_and_belongs_to_many)
50
49
  'has_and_belongs_to_many'
51
- elsif assoc.respond_to?(:macro) ? (assoc.macro == :has_many) : assoc.is_a?(ActiveRecord::Reflection::HasManyReflection)
50
+ elsif assoc.macro == :has_many
52
51
  'has_many'
53
52
  else
54
53
  'has_one'
@@ -80,8 +79,7 @@ module DutyFree
80
79
 
81
80
  # Find applicable polymorphic has_many associations from each real model
82
81
  model.reflect_on_all_associations.each do |poly_assoc|
83
- next unless poly_assoc.is_a?(ActiveRecord::Reflection::HasManyReflection) &&
84
- poly_assoc.inverse_of == assoc
82
+ next unless poly_assoc.macro == :has_many && poly_assoc.inverse_of == assoc
85
83
 
86
84
  this_belongs_tos += (fkeys = [poly_assoc.type, poly_assoc.foreign_key])
87
85
  assocs["#{assoc.name}_#{poly_assoc.active_record.name.underscore}".to_sym] = [[fkeys, assoc.active_record], poly_assoc.active_record]
@@ -238,11 +236,11 @@ module DutyFree
238
236
  if klass.columns.map(&:name).include?(attrib)
239
237
  s << attrib
240
238
  else
241
- ho_and_bt_names = klass.reflect_on_all_associations.each_with_object([]) do |assoc, names|
242
- names << assoc.name.to_s if assoc.belongs_to? || assoc.macro == :has_one
239
+ hm_and_bt_names = klass.reflect_on_all_associations.each_with_object([]) do |assoc, names|
240
+ names << assoc.name.to_s if [:belongs_to, :has_many, :has_one].include?(assoc.macro)
243
241
  names
244
242
  end
245
- unless ho_and_bt_names.include?(attrib)
243
+ unless hm_and_bt_names.include?(attrib)
246
244
  puts "* In the #{klass.name} model \"validates_presence_of :#{attrib}\" should be removed as it does not refer to any existing column."
247
245
  errored_columns << klass_col
248
246
  end
@@ -287,10 +285,11 @@ module DutyFree
287
285
  v.each_with_index do |item, idx|
288
286
  # This is where most of the commas get printed, so you can do "#{child_count}," to diagnose things
289
287
  print ',' if idx.positive? && indent >= 0
290
- if item.is_a?(Hash)
288
+ case item
289
+ when Hash
291
290
  # puts '^' unless child_count < 5 || indent.negative?
292
291
  child_count = _template_pretty_print(item, indent + 2, child_count)
293
- elsif item.is_a?(Symbol)
292
+ when Symbol
294
293
  if indent.negative?
295
294
  child_count += 1
296
295
  else
@@ -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 = 8
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duty_free
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorin Thwaits
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-24 00:00:00.000000000 Z
11
+ date: 2021-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '3.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6.1'
22
+ version: '6.2'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '3.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6.1'
32
+ version: '6.2'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: appraisal
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -134,14 +134,14 @@ dependencies:
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 0.89.1
137
+ version: '0.93'
138
138
  type: :development
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 0.89.1
144
+ version: '0.93'
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: rubocop-rspec
147
147
  requirement: !ruby/object:Gem::Requirement
@@ -156,20 +156,6 @@ dependencies:
156
156
  - - "~>"
157
157
  - !ruby/object:Gem::Version
158
158
  version: 1.42.0
159
- - !ruby/object:Gem::Dependency
160
- name: mysql2
161
- requirement: !ruby/object:Gem::Requirement
162
- requirements:
163
- - - "~>"
164
- - !ruby/object:Gem::Version
165
- version: '0.5'
166
- type: :development
167
- prerelease: false
168
- version_requirements: !ruby/object:Gem::Requirement
169
- requirements:
170
- - - "~>"
171
- - !ruby/object:Gem::Version
172
- version: '0.5'
173
159
  - !ruby/object:Gem::Dependency
174
160
  name: pg
175
161
  requirement: !ruby/object:Gem::Requirement
@@ -206,7 +192,7 @@ dependencies:
206
192
  version: '1.4'
207
193
  description: 'Simplify data imports and exports with this slick ActiveRecord extension
208
194
 
209
- '
195
+ '
210
196
  email: lorint@gmail.com
211
197
  executables: []
212
198
  extensions: []
@@ -234,7 +220,7 @@ homepage: https://github.com/lorint/duty_free
234
220
  licenses:
235
221
  - MIT
236
222
  metadata: {}
237
- post_install_message:
223
+ post_install_message:
238
224
  rdoc_options: []
239
225
  require_paths:
240
226
  - lib
@@ -249,8 +235,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
249
235
  - !ruby/object:Gem::Version
250
236
  version: 1.3.6
251
237
  requirements: []
252
- rubygems_version: 3.0.8
253
- signing_key:
238
+ rubygems_version: 3.2.3
239
+ signing_key:
254
240
  specification_version: 4
255
241
  summary: Import and Export Data
256
242
  test_files: []