duty_free 1.0.7 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []