duty_free 1.0.0 → 1.0.5
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.
- checksums.yaml +4 -4
- data/lib/duty_free.rb +130 -0
- data/lib/duty_free/column.rb +9 -11
- data/lib/duty_free/extensions.rb +384 -195
- data/lib/duty_free/suggest_template.rb +23 -19
- data/lib/duty_free/util.rb +24 -10
- data/lib/duty_free/version_number.rb +1 -1
- data/lib/generators/duty_free/USAGE +1 -1
- data/lib/generators/duty_free/install_generator.rb +8 -10
- metadata +15 -16
@@ -40,26 +40,25 @@ 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.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
43
|
+
is_belongs_to = assoc.belongs_to? # is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
44
44
|
# Figure out if it's belongs_to, has_many, or has_one
|
45
|
+
# HasAndBelongsToManyReflection
|
45
46
|
belongs_to_or_has_many =
|
46
47
|
if is_belongs_to
|
47
48
|
'belongs_to'
|
48
|
-
elsif (is_habtm = assoc.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection))
|
49
|
+
elsif (is_habtm = assoc.respond_to?(:macro) ? (assoc.macro == :has_and_belongs_to_many) : assoc.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection))
|
49
50
|
'has_and_belongs_to_many'
|
51
|
+
elsif assoc.respond_to?(:macro) ? (assoc.macro == :has_many) : assoc.is_a?(ActiveRecord::Reflection::HasManyReflection)
|
52
|
+
'has_many'
|
50
53
|
else
|
51
|
-
|
54
|
+
'has_one'
|
52
55
|
end
|
53
56
|
# Always process belongs_to, and also process has_one and has_many if do_has_many is chosen.
|
54
57
|
# Skip any HMT or HABTM. (Maybe break out HABTM into a combo HM and BT in the future.)
|
55
58
|
if is_habtm
|
56
|
-
unless ActiveRecord::Base.connection.table_exists?(assoc.join_table)
|
57
|
-
puts "* In the #{this_klass.name} model there's a problem with: \"has_and_belongs_to_many :#{assoc.name}\" because join table \"#{assoc.join_table}\" does not exist. You can create it with a create_join_table migration."
|
58
|
-
end
|
59
|
+
puts "* In the #{this_klass.name} model there's a problem with: \"has_and_belongs_to_many :#{assoc.name}\" because join table \"#{assoc.join_table}\" does not exist. You can create it with a create_join_table migration." unless ActiveRecord::Base.connection.table_exists?(assoc.join_table)
|
59
60
|
# %%% Search for other associative candidates to use instead of this HABTM contraption
|
60
|
-
if assoc.options.include?(:through)
|
61
|
-
puts "* In the #{this_klass.name} model there's a problem with: \"has_and_belongs_to_many :#{assoc.name}\" because it includes \"through: #{assoc.options[:through].inspect}\" which is pointless and should be removed."
|
62
|
-
end
|
61
|
+
puts "* In the #{this_klass.name} model there's a problem with: \"has_and_belongs_to_many :#{assoc.name}\" because it includes \"through: #{assoc.options[:through].inspect}\" which is pointless and should be removed." if assoc.options.include?(:through)
|
63
62
|
end
|
64
63
|
if (is_through = assoc.is_a?(ActiveRecord::Reflection::ThroughReflection)) && assoc.options.include?(:as)
|
65
64
|
puts "* In the #{this_klass.name} model there's a problem with: \"has_many :#{assoc.name} through: #{assoc.options[:through].inspect}\" because it also includes \"as: #{assoc.options[:as].inspect}\", so please choose either for this line to be a \"has_many :#{assoc.name} through:\" or to be a polymorphic \"has_many :#{assoc.name} as:\". It can't be both."
|
@@ -167,7 +166,7 @@ module DutyFree
|
|
167
166
|
# belongs_to is more involved since there may be multiple foreign keys which point
|
168
167
|
# from the foreign table to this primary one, so exclude all these links.
|
169
168
|
_find_belongs_tos(assoc.first.last, assoc.last, errored_assocs).map do |f_assoc|
|
170
|
-
[f_assoc.foreign_key.to_s, f_assoc.active_record]
|
169
|
+
[[f_assoc.foreign_key.to_s], f_assoc.active_record]
|
171
170
|
end
|
172
171
|
end
|
173
172
|
# puts "New Poison: #{new_poison_links.inspect}"
|
@@ -182,7 +181,8 @@ module DutyFree
|
|
182
181
|
# Find belongs_tos for this model to one more more other klasses
|
183
182
|
def self._find_belongs_tos(klass, to_klass, errored_assocs)
|
184
183
|
klass.reflect_on_all_associations.each_with_object([]) do |bt_assoc, s|
|
185
|
-
|
184
|
+
# .is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
185
|
+
next unless bt_assoc.belongs_to? && !errored_assocs.include?(bt_assoc)
|
186
186
|
|
187
187
|
begin
|
188
188
|
s << bt_assoc if !bt_assoc.polymorphic? && bt_assoc.klass == to_klass
|
@@ -203,9 +203,7 @@ module DutyFree
|
|
203
203
|
|
204
204
|
# Requireds takes its cues from all attributes having a presence validator
|
205
205
|
requireds = _find_requireds(klass)
|
206
|
-
if priority_excluded_columns
|
207
|
-
klass_columns = klass_columns.reject { |col| priority_excluded_columns.include?(col.name) }
|
208
|
-
end
|
206
|
+
klass_columns = klass_columns.reject { |col| priority_excluded_columns.include?(col.name) } if priority_excluded_columns
|
209
207
|
excluded_columns = %w[created_at updated_at deleted_at]
|
210
208
|
unique = [(
|
211
209
|
# Find the first text field of a required if one exists
|
@@ -240,18 +238,24 @@ module DutyFree
|
|
240
238
|
if klass.columns.map(&:name).include?(attrib)
|
241
239
|
s << attrib
|
242
240
|
else
|
243
|
-
|
244
|
-
|
241
|
+
bt_names = klass.reflect_on_all_associations.each_with_object([]) do |assoc, names|
|
242
|
+
names << assoc.name.to_s if assoc.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
243
|
+
names
|
244
|
+
end
|
245
|
+
unless bt_names.include?(attrib)
|
246
|
+
puts "* In the #{klass.name} model \"validates_presence_of :#{attrib}\" should be removed as it does not refer to any existing column."
|
247
|
+
errored_columns << klass_col
|
248
|
+
end
|
245
249
|
end
|
246
250
|
end
|
247
251
|
end
|
248
252
|
end
|
249
253
|
|
250
|
-
# Show a "pretty" version of
|
254
|
+
# Show a "pretty" version of IMPORT_TEMPLATE, to be placed in a model
|
251
255
|
def self._template_pretty_print(template, indent = 0, child_count = 0, is_hash_in_hash = false)
|
252
256
|
unless indent.negative?
|
253
257
|
if indent.zero?
|
254
|
-
print '
|
258
|
+
print 'IMPORT_TEMPLATE = '
|
255
259
|
else
|
256
260
|
puts unless is_hash_in_hash
|
257
261
|
end
|
@@ -305,7 +309,7 @@ module DutyFree
|
|
305
309
|
if indent == 2
|
306
310
|
puts
|
307
311
|
indent = 0
|
308
|
-
puts '}'
|
312
|
+
puts '}.freeze'
|
309
313
|
elsif indent >= 0
|
310
314
|
print "#{' ' unless child_count.zero?}}"
|
311
315
|
end
|
data/lib/duty_free/util.rb
CHANGED
@@ -35,20 +35,34 @@ module DutyFree
|
|
35
35
|
end
|
36
36
|
|
37
37
|
# ActiveRecord AREL objects
|
38
|
-
elsif piece.is_a?(Arel::Nodes::JoinSource)
|
39
|
-
# The left side is the "FROM" table
|
40
|
-
# names += _recurse_arel(piece.left)
|
41
|
-
# The right side is an array of all JOINs
|
42
|
-
names += piece.right.inject([]) { |s, v| s + _recurse_arel(v) }
|
43
38
|
elsif piece.is_a?(Arel::Nodes::Join) # INNER or OUTER JOIN
|
44
|
-
#
|
45
|
-
|
46
|
-
|
39
|
+
# rubocop:disable Style/IdenticalConditionalBranches
|
40
|
+
if piece.right.is_a?(Arel::Table) # Came in from AR < 3.2?
|
41
|
+
# Arel 2.x and older is a little curious because these JOINs work "back to front".
|
42
|
+
# The left side here is either another earlier JOIN, or at the end of the whole tree, it is
|
43
|
+
# the first table.
|
44
|
+
names += _recurse_arel(piece.left)
|
45
|
+
# The right side here at the top is the very last table, and anywhere else down the tree it is
|
46
|
+
# the later "JOIN" table of this pair. (The table that comes after all the rest of the JOINs
|
47
|
+
# from the left side.)
|
48
|
+
names << piece.right.name
|
49
|
+
else # "Normal" setup, fed from a JoinSource which has an array of JOINs
|
50
|
+
# The left side is the "JOIN" table
|
51
|
+
names += _recurse_arel(piece.left)
|
52
|
+
# (The right side of these is the "ON" clause)
|
53
|
+
end
|
54
|
+
# rubocop:enable Style/IdenticalConditionalBranches
|
47
55
|
elsif piece.is_a?(Arel::Table) # Table
|
48
56
|
names << piece.name
|
49
57
|
elsif piece.is_a?(Arel::Nodes::TableAlias) # Alias
|
50
58
|
# Can get the real table name from: self._recurse_arel(piece.left)
|
51
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!
|
61
|
+
# The left side is the "FROM" table
|
62
|
+
# names += _recurse_arel(piece.left)
|
63
|
+
names << piece.left.name
|
64
|
+
# The right side is an array of all JOINs
|
65
|
+
names += piece.right.inject([]) { |s, v| s + _recurse_arel(v) }
|
52
66
|
end
|
53
67
|
names
|
54
68
|
end
|
@@ -57,11 +71,11 @@ module DutyFree
|
|
57
71
|
prefixes.reject(&:blank?).join(separator || '.')
|
58
72
|
end
|
59
73
|
|
60
|
-
def self._clean_name(name,
|
74
|
+
def self._clean_name(name, import_template_as)
|
61
75
|
return name if name.is_a?(Symbol)
|
62
76
|
|
63
77
|
# Expand aliases
|
64
|
-
(
|
78
|
+
(import_template_as || []).each do |k, v|
|
65
79
|
if (k[-1] == ' ' && name.start_with?(k)) || name == k
|
66
80
|
name.replace(v + name[k.length..-1])
|
67
81
|
break
|
@@ -1,2 +1,2 @@
|
|
1
1
|
Description:
|
2
|
-
|
2
|
+
Modifies an existing model so that it includes an IMPORT_TEMPLATE.
|
@@ -4,18 +4,10 @@ require 'rails/generators'
|
|
4
4
|
require 'rails/generators/active_record'
|
5
5
|
|
6
6
|
module DutyFree
|
7
|
-
#
|
7
|
+
# Auto-generates an IMPORT_TEMPLATE entry for one or more models
|
8
8
|
class InstallGenerator < ::Rails::Generators::Base
|
9
9
|
include ::Rails::Generators::Migration
|
10
10
|
|
11
|
-
# Class names of MySQL adapters.
|
12
|
-
# - `MysqlAdapter` - Used by gems: `mysql`, `activerecord-jdbcmysql-adapter`.
|
13
|
-
# - `Mysql2Adapter` - Used by `mysql2` gem.
|
14
|
-
MYSQL_ADAPTERS = [
|
15
|
-
'ActiveRecord::ConnectionAdapters::MysqlAdapter',
|
16
|
-
'ActiveRecord::ConnectionAdapters::Mysql2Adapter'
|
17
|
-
].freeze
|
18
|
-
|
19
11
|
source_root File.expand_path('templates', __dir__)
|
20
12
|
class_option(
|
21
13
|
:with_changes,
|
@@ -68,8 +60,14 @@ module DutyFree
|
|
68
60
|
"[#{major}.#{ActiveRecord::VERSION::MINOR}]"
|
69
61
|
end
|
70
62
|
|
63
|
+
# Class names of MySQL adapters.
|
64
|
+
# - `MysqlAdapter` - Used by gems: `mysql`, `activerecord-jdbcmysql-adapter`.
|
65
|
+
# - `Mysql2Adapter` - Used by `mysql2` gem.
|
71
66
|
def mysql?
|
72
|
-
|
67
|
+
[
|
68
|
+
'ActiveRecord::ConnectionAdapters::MysqlAdapter',
|
69
|
+
'ActiveRecord::ConnectionAdapters::Mysql2Adapter'
|
70
|
+
].freeze.include?(ActiveRecord::Base.connection.class.name)
|
73
71
|
end
|
74
72
|
|
75
73
|
# Even modern versions of MySQL still use `latin1` as the default character
|
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.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '3.0'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '6.
|
22
|
+
version: '6.1'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '3.0'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '6.
|
32
|
+
version: '6.1'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: appraisal
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,19 +45,19 @@ dependencies:
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '2.2'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name: byebug
|
48
|
+
name: pry-byebug
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- - "
|
51
|
+
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
53
|
+
version: 3.7.0
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
|
-
- - "
|
58
|
+
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
60
|
+
version: 3.7.0
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: ffaker
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -204,10 +204,9 @@ dependencies:
|
|
204
204
|
- - "~>"
|
205
205
|
- !ruby/object:Gem::Version
|
206
206
|
version: '1.4'
|
207
|
-
description:
|
208
|
-
|
209
|
-
|
210
|
-
XLSX, ODT, HTML tables, or simple Ruby arrays.
|
207
|
+
description: 'Simplify data imports and exports with this slick ActiveRecord extension
|
208
|
+
|
209
|
+
'
|
211
210
|
email: lorint@gmail.com
|
212
211
|
executables: []
|
213
212
|
extensions: []
|
@@ -243,7 +242,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
243
242
|
requirements:
|
244
243
|
- - ">="
|
245
244
|
- !ruby/object:Gem::Version
|
246
|
-
version: 2.
|
245
|
+
version: 2.3.5
|
247
246
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
248
247
|
requirements:
|
249
248
|
- - ">="
|