duty_free 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module DutyFree
5
+ module Util
6
+ # def self._parse(arel)
7
+ # arel = arel.arel if arel.is_a?(ActiveRecord::Relation)
8
+ # sels = arel.ast.cores.select { |x| x.is_a?(Arel::Nodes::SelectCore) }
9
+ # # source (joinsource) / projections (6) is the most interesting here
10
+ # sels.each_with_index do |sel, idx|
11
+ # puts "#{idx} ============="
12
+ # # Columns:
13
+ # sel.projections.map do |x|
14
+ # case
15
+ # when x.is_a?(Arel::Nodes::SqlLiteral)
16
+ # puts x.to_s
17
+ # else
18
+ # puts "#{x.class} #{x.name}"
19
+ # end
20
+ # end
21
+ # end
22
+ # nil
23
+ # end
24
+
25
+ def self._recurse_arel(piece, prefix = '')
26
+ names = []
27
+ # Our JOINs mashup of nested arrays and hashes
28
+ if piece.is_a?(Array)
29
+ names += piece.inject([]) { |s, v| s + _recurse_arel(v, prefix) }
30
+ elsif piece.is_a?(Hash)
31
+ names += piece.inject([]) do |s, v|
32
+ new_prefix = "#{prefix}#{v.first}_"
33
+ s << new_prefix
34
+ s + _recurse_arel(v.last, new_prefix)
35
+ end
36
+
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
+ elsif piece.is_a?(Arel::Nodes::Join) # INNER or OUTER JOIN
44
+ # The left side is the "JOIN" table
45
+ names += _recurse_arel(piece.left)
46
+ # (The right side of these is the "ON" clause)
47
+ elsif piece.is_a?(Arel::Table) # Table
48
+ names << piece.name
49
+ elsif piece.is_a?(Arel::Nodes::TableAlias) # Alias
50
+ # Can get the real table name from: self._recurse_arel(piece.left)
51
+ names << piece.right.to_s # This is simply a string; the alias name itself
52
+ end
53
+ names
54
+ end
55
+
56
+ def self._prefix_join(prefixes, separator = nil)
57
+ prefixes.reject(&:blank?).join(separator || '.')
58
+ end
59
+
60
+ def self._clean_name(name, import_columns_as)
61
+ return name if name.is_a?(Symbol)
62
+
63
+ # Expand aliases
64
+ (import_columns_as || []).each do |k, v|
65
+ if (k[-1] == ' ' && name.start_with?(k)) || name == k
66
+ name.replace(v + name[k.length..-1])
67
+ break
68
+ end
69
+ end
70
+ name
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module DutyFree
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
@@ -0,0 +1,2 @@
1
+ Description:
2
+ Generates (but does not run) a migration to add a versions table.
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+ require 'rails/generators/active_record'
5
+
6
+ module DutyFree
7
+ # Installs DutyFree in a rails app.
8
+ class InstallGenerator < ::Rails::Generators::Base
9
+ include ::Rails::Generators::Migration
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
+ source_root File.expand_path('templates', __dir__)
20
+ class_option(
21
+ :with_changes,
22
+ type: :boolean,
23
+ default: false,
24
+ desc: 'Store changeset (diff) with each version'
25
+ )
26
+
27
+ desc 'Generates (but does not run) a migration to add a versions table.' \
28
+ ' Also generates an initializer file for configuring DutyFree'
29
+
30
+ def create_migration_file
31
+ add_duty_free_migration('create_versions')
32
+ add_duty_free_migration('add_object_changes_to_versions') if options.with_changes?
33
+ end
34
+
35
+ def self.next_migration_number(dirname)
36
+ ::ActiveRecord::Generators::Base.next_migration_number(dirname)
37
+ end
38
+
39
+ protected
40
+
41
+ def add_duty_free_migration(template)
42
+ migration_dir = File.expand_path('db/migrate')
43
+ if self.class.migration_exists?(migration_dir, template)
44
+ ::Kernel.warn "Migration already exists: #{template}"
45
+ else
46
+ migration_template(
47
+ "#{template}.rb.erb",
48
+ "db/migrate/#{template}.rb",
49
+ item_type_options: item_type_options,
50
+ migration_version: migration_version,
51
+ versions_table_options: versions_table_options
52
+ )
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ # MySQL 5.6 utf8mb4 limit is 191 chars for keys used in indexes.
59
+ def item_type_options
60
+ opt = { null: false }
61
+ opt[:limit] = 191 if mysql?
62
+ ", #{opt}"
63
+ end
64
+
65
+ def migration_version
66
+ return unless (major = ActiveRecord::VERSION::MAJOR) >= 5
67
+
68
+ "[#{major}.#{ActiveRecord::VERSION::MINOR}]"
69
+ end
70
+
71
+ def mysql?
72
+ MYSQL_ADAPTERS.include?(ActiveRecord::Base.connection.class.name)
73
+ end
74
+
75
+ # Even modern versions of MySQL still use `latin1` as the default character
76
+ # encoding. Many users are not aware of this, and run into trouble when they
77
+ # try to use DutyFree in apps that otherwise tend to use UTF-8. Postgres, by
78
+ # comparison, uses UTF-8 except in the unusual case where the OS is configured
79
+ # with a custom locale.
80
+ #
81
+ # - https://dev.mysql.com/doc/refman/5.7/en/charset-applications.html
82
+ # - http://www.postgresql.org/docs/9.4/static/multibyte.html
83
+ #
84
+ # Furthermore, MySQL's original implementation of UTF-8 was flawed, and had
85
+ # to be fixed later by introducing a new charset, `utf8mb4`.
86
+ #
87
+ # - https://mathiasbynens.be/notes/mysql-utf8mb4
88
+ # - https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
89
+ #
90
+ def versions_table_options
91
+ if mysql?
92
+ ', { options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" }'
93
+ else
94
+ ''
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,12 @@
1
+ # This migration adds the optional `object_changes` column, in which DutyFree
2
+ # will store the `changes` diff for each update event. See the readme for
3
+ # details.
4
+ class AddObjectChangesToVersions < ActiveRecord::Migration<%= migration_version %>
5
+ # The largest text column available in all supported RDBMS.
6
+ # See `create_versions.rb` for details.
7
+ TEXT_BYTES = 1_073_741_823
8
+
9
+ def change
10
+ add_column :versions, :object_changes, :text, limit: TEXT_BYTES
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ # This migration creates the `versions` table, the only schema PT requires.
2
+ # All other migrations PT provides are optional.
3
+ class CreateVersions < ActiveRecord::Migration<%= migration_version %>
4
+
5
+ # The largest text column available in all supported RDBMS is
6
+ # 1024^3 - 1 bytes, roughly one gibibyte. We specify a size
7
+ # so that MySQL will use `longtext` instead of `text`. Otherwise,
8
+ # when serializing very large objects, `text` might not be big enough.
9
+ TEXT_BYTES = 1_073_741_823
10
+
11
+ def change
12
+ create_table :versions<%= versions_table_options %> do |t|
13
+ t.string :item_type<%= item_type_options %>
14
+ t.integer :item_id, null: false
15
+ t.string :event, null: false
16
+ t.string :whodunnit
17
+ t.text :object, limit: TEXT_BYTES
18
+
19
+ # Known issue in MySQL: fractional second precision
20
+ # -------------------------------------------------
21
+ #
22
+ # MySQL timestamp columns do not support fractional seconds unless
23
+ # defined with "fractional seconds precision". MySQL users should manually
24
+ # add fractional seconds precision to this migration, specifically, to
25
+ # the `created_at` column.
26
+ # (https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html)
27
+ #
28
+ # MySQL users should also upgrade to rails 4.2, which is the first
29
+ # version of ActiveRecord with support for fractional seconds in MySQL.
30
+ # (https://github.com/rails/rails/pull/14359)
31
+ #
32
+ t.datetime :created_at
33
+ end
34
+ add_index :versions, %i(item_type item_id)
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,257 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: duty_free
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Lorin Thwaits
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-10-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '4.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: appraisal
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.2'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.2'
47
+ - !ruby/object:Gem::Dependency
48
+ name: byebug
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: ffaker
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.11'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2.11'
75
+ - !ruby/object:Gem::Dependency
76
+ name: generator_spec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.9.4
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.9.4
89
+ - !ruby/object:Gem::Dependency
90
+ name: memory_profiler
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 0.9.14
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 0.9.14
103
+ - !ruby/object:Gem::Dependency
104
+ name: rake
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '13.0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '13.0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: rspec-rails
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '4.0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '4.0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: rubocop
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: 0.89.1
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: 0.89.1
145
+ - !ruby/object:Gem::Dependency
146
+ name: rubocop-rspec
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: 1.42.0
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
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
+ - !ruby/object:Gem::Dependency
174
+ name: pg
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0.18'
180
+ - - "<"
181
+ - !ruby/object:Gem::Version
182
+ version: '2.0'
183
+ type: :development
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: '0.18'
190
+ - - "<"
191
+ - !ruby/object:Gem::Version
192
+ version: '2.0'
193
+ - !ruby/object:Gem::Dependency
194
+ name: sqlite3
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: '1.4'
200
+ type: :development
201
+ prerelease: false
202
+ version_requirements: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - "~>"
205
+ - !ruby/object:Gem::Version
206
+ version: '1.4'
207
+ description: |
208
+ An ActiveRecord extension that simplifies importing and exporting of data
209
+ stored in one or more models. Source and destination can be CSV, XLS,
210
+ XLSX, ODT, HTML tables, or simple Ruby arrays.
211
+ email: lorint@gmail.com
212
+ executables: []
213
+ extensions: []
214
+ extra_rdoc_files: []
215
+ files:
216
+ - lib/duty_free.rb
217
+ - lib/duty_free/column.rb
218
+ - lib/duty_free/config.rb
219
+ - lib/duty_free/extensions.rb
220
+ - lib/duty_free/frameworks/cucumber.rb
221
+ - lib/duty_free/frameworks/rails.rb
222
+ - lib/duty_free/frameworks/rails/controller.rb
223
+ - lib/duty_free/frameworks/rails/engine.rb
224
+ - lib/duty_free/frameworks/rspec.rb
225
+ - lib/duty_free/serializers/json.rb
226
+ - lib/duty_free/serializers/yaml.rb
227
+ - lib/duty_free/suggest_template.rb
228
+ - lib/duty_free/util.rb
229
+ - lib/duty_free/version_number.rb
230
+ - lib/generators/duty_free/USAGE
231
+ - lib/generators/duty_free/install_generator.rb
232
+ - lib/generators/duty_free/templates/add_object_changes_to_versions.rb.erb
233
+ - lib/generators/duty_free/templates/create_versions.rb.erb
234
+ homepage: https://github.com/lorint/duty_free
235
+ licenses:
236
+ - MIT
237
+ metadata: {}
238
+ post_install_message:
239
+ rdoc_options: []
240
+ require_paths:
241
+ - lib
242
+ required_ruby_version: !ruby/object:Gem::Requirement
243
+ requirements:
244
+ - - ">="
245
+ - !ruby/object:Gem::Version
246
+ version: 2.4.0
247
+ required_rubygems_version: !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - ">="
250
+ - !ruby/object:Gem::Version
251
+ version: 1.3.6
252
+ requirements: []
253
+ rubygems_version: 3.0.8
254
+ signing_key:
255
+ specification_version: 4
256
+ summary: Import and Export Data
257
+ test_files: []