duty_free 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/duty_free.rb +86 -0
- data/lib/duty_free/column.rb +56 -0
- data/lib/duty_free/config.rb +32 -0
- data/lib/duty_free/extensions.rb +525 -0
- data/lib/duty_free/frameworks/cucumber.rb +28 -0
- data/lib/duty_free/frameworks/rails.rb +4 -0
- data/lib/duty_free/frameworks/rails/controller.rb +41 -0
- data/lib/duty_free/frameworks/rails/engine.rb +14 -0
- data/lib/duty_free/frameworks/rspec.rb +18 -0
- data/lib/duty_free/serializers/json.rb +36 -0
- data/lib/duty_free/serializers/yaml.rb +26 -0
- data/lib/duty_free/suggest_template.rb +315 -0
- data/lib/duty_free/util.rb +73 -0
- data/lib/duty_free/version_number.rb +19 -0
- data/lib/generators/duty_free/USAGE +2 -0
- data/lib/generators/duty_free/install_generator.rb +98 -0
- data/lib/generators/duty_free/templates/add_object_changes_to_versions.rb.erb +12 -0
- data/lib/generators/duty_free/templates/create_versions.rb.erb +36 -0
- metadata +257 -0
@@ -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,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: []
|