syncify 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cb790579afcec3a69a0241d30029691ede3a17ef
4
+ data.tar.gz: 71380e359bb049e5f945337e4948c2d3a6bab75e
5
+ SHA512:
6
+ metadata.gz: d019996265b60d5a5f9c3a721e27282815766a2a3a7de3b514cccd21599d2e68b8319d6a78b78f3a31ee4a14701ea65b9db7bdc95ec8431c8a7f13ecd7e6dbdd
7
+ data.tar.gz: d8e4eaca79bae5ba9058f1205e46b8d88db5f1211262b55c35d106814f729cf69871e9856445d04f2e7b1ee22bebca94de3132851261ad35dfdf51d2ddff1616
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+ .idea
13
+
14
+ # ignore temp databases for testing
15
+ spec/default.db
16
+ spec/faux_remote.db
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.3.7
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in syncify.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,119 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ syncify (0.1.0)
5
+ active_interaction (~> 3.0)
6
+ activerecord (~> 4.2)
7
+ activerecord-import (~> 0.17)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionpack (4.2.11.1)
13
+ actionview (= 4.2.11.1)
14
+ activesupport (= 4.2.11.1)
15
+ rack (~> 1.6)
16
+ rack-test (~> 0.6.2)
17
+ rails-dom-testing (~> 1.0, >= 1.0.5)
18
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
19
+ actionview (4.2.11.1)
20
+ activesupport (= 4.2.11.1)
21
+ builder (~> 3.1)
22
+ erubis (~> 2.7.0)
23
+ rails-dom-testing (~> 1.0, >= 1.0.5)
24
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
25
+ active_interaction (3.7.1)
26
+ activemodel (>= 4, < 7)
27
+ activemodel (4.2.11.1)
28
+ activesupport (= 4.2.11.1)
29
+ builder (~> 3.1)
30
+ activerecord (4.2.11.1)
31
+ activemodel (= 4.2.11.1)
32
+ activesupport (= 4.2.11.1)
33
+ arel (~> 6.0)
34
+ activerecord-import (0.28.2)
35
+ activerecord (>= 3.2)
36
+ activesupport (4.2.11.1)
37
+ i18n (~> 0.7)
38
+ minitest (~> 5.1)
39
+ thread_safe (~> 0.3, >= 0.3.4)
40
+ tzinfo (~> 1.1)
41
+ arel (6.0.4)
42
+ builder (3.2.3)
43
+ byebug (11.0.1)
44
+ coderay (1.1.2)
45
+ concurrent-ruby (1.1.5)
46
+ crass (1.0.4)
47
+ diff-lcs (1.3)
48
+ erubis (2.7.0)
49
+ factory_bot (4.11.1)
50
+ activesupport (>= 3.0.0)
51
+ factory_bot_rails (4.11.1)
52
+ factory_bot (~> 4.11.1)
53
+ railties (>= 3.0.0)
54
+ i18n (0.9.5)
55
+ concurrent-ruby (~> 1.0)
56
+ loofah (2.2.3)
57
+ crass (~> 1.0.2)
58
+ nokogiri (>= 1.5.9)
59
+ method_source (0.9.2)
60
+ mini_portile2 (2.4.0)
61
+ minitest (5.11.3)
62
+ nokogiri (1.10.3)
63
+ mini_portile2 (~> 2.4.0)
64
+ pry (0.12.2)
65
+ coderay (~> 1.1.0)
66
+ method_source (~> 0.9.0)
67
+ pry-byebug (3.7.0)
68
+ byebug (~> 11.0)
69
+ pry (~> 0.10)
70
+ rack (1.6.11)
71
+ rack-test (0.6.3)
72
+ rack (>= 1.0)
73
+ rails-deprecated_sanitizer (1.0.3)
74
+ activesupport (>= 4.2.0.alpha)
75
+ rails-dom-testing (1.0.9)
76
+ activesupport (>= 4.2.0, < 5.0)
77
+ nokogiri (~> 1.6)
78
+ rails-deprecated_sanitizer (>= 1.0.1)
79
+ rails-html-sanitizer (1.1.0)
80
+ loofah (~> 2.2, >= 2.2.2)
81
+ railties (4.2.11.1)
82
+ actionpack (= 4.2.11.1)
83
+ activesupport (= 4.2.11.1)
84
+ rake (>= 0.8.7)
85
+ thor (>= 0.18.1, < 2.0)
86
+ rake (10.5.0)
87
+ rspec (3.8.0)
88
+ rspec-core (~> 3.8.0)
89
+ rspec-expectations (~> 3.8.0)
90
+ rspec-mocks (~> 3.8.0)
91
+ rspec-core (3.8.2)
92
+ rspec-support (~> 3.8.0)
93
+ rspec-expectations (3.8.4)
94
+ diff-lcs (>= 1.2.0, < 2.0)
95
+ rspec-support (~> 3.8.0)
96
+ rspec-mocks (3.8.1)
97
+ diff-lcs (>= 1.2.0, < 2.0)
98
+ rspec-support (~> 3.8.0)
99
+ rspec-support (3.8.2)
100
+ sqlite3 (1.3.13)
101
+ thor (0.20.3)
102
+ thread_safe (0.3.6)
103
+ tzinfo (1.2.5)
104
+ thread_safe (~> 0.1)
105
+
106
+ PLATFORMS
107
+ ruby
108
+
109
+ DEPENDENCIES
110
+ bundler (~> 2.0)
111
+ factory_bot_rails (~> 4.11)
112
+ pry-byebug (~> 3.7)
113
+ rake (~> 10.0)
114
+ rspec (~> 3.0)
115
+ sqlite3 (~> 1.3, < 1.4)
116
+ syncify!
117
+
118
+ BUNDLED WITH
119
+ 2.0.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Doug Hughes
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,196 @@
1
+ # Syncify
2
+
3
+ Syncify is a gem used to sync records and associations you specify from one remote ActiveRecord environment to your local environment.
4
+
5
+ Consider this hypothetical problem: You have a gigantic production database with complex associations between your models, including polymorphic associations. The database includes sensitive data that shouldn't really be in your development or staging environments. But, there's something wrong in production and you need production data to be able to debug it. It's not practical, efficient, safe, or generally advisable to restore a backup of the production database locally.
6
+
7
+ How do you get that data safely from production to an environment where you can make use of it? This is the problem that Syncify aims to address.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'syncify'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install syncify
24
+
25
+ ## Usage
26
+
27
+
28
+ Syncify doesn't require Rails, just ActiveRecord, but it's a reasonable foundation for the following examples.
29
+
30
+ Also, you can sync from any environment to whatever your current environment is. So, you could sync from your staging environment to your client test environment or from staging to development. Heck, you could go from staging to prod if you'd like.
31
+
32
+ For the purposes of this documentation we'll assume that you're syncing data in a Rails app from production to your local development environment.
33
+
34
+ Syncify has a pretty simple API. There's just one method, `run!`. Here's a really basic example where we're syncing a single `Widget` from production to the current environment. The current environment could be any environment, but we'll assume it's development for this documentation.
35
+
36
+ ```ruby
37
+ Syncify::Sync.run!(klass: Widget, id: 123, remote_database: :production)
38
+ ```
39
+
40
+ Boom! You've copied `Widget` 123 to local dev. The widget will have all the same values including its `id`, `created_at`, `updated_at`, etc values. The above example assumes that the `Widget` doesn't have any foreign keys that don't exist locally.
41
+
42
+ Now, let's say a `Widget` `belongs_to` a `Manufacturer`. Furthermore, let's say a `Manufacturer` `has_many` `Widget`s. We'll pretend we have this data in the prod database:
43
+
44
+ `widgets`:
45
+
46
+ | id | name | manufacturer_id |
47
+ | --- | -------------------------------------------------- | --------------- |
48
+ | 123 | Lubricated Stainless Steel Helical Insert | 78 |
49
+ | 124 | Magnetic Contact Alarm Switches | 79 |
50
+ | 125 | Idler Sprocket for Double-Strand ANSI Roller Chain | 78 |
51
+ | 126 | Rod End Bolt Blank | 79 |
52
+ | 127 | Press-Fit Drill Bushing | 78 |
53
+
54
+ `manufacturers`:
55
+
56
+ | id | name |
57
+ | --- | -------------------------- |
58
+ | 78 | South Seas Trading Company |
59
+ | 79 | Blandco Manufacturing |
60
+
61
+ If your database uses foreign keys and the production `Widget`'s `Manufacturer` doesn't exist locally then the example above would fail. To get around this we can specify an association to also sync when syncing the `Widget`.
62
+
63
+ ```ruby
64
+ Syncify::Sync.run!(klass: Widget,
65
+ id: 123,
66
+ association: :manufacturer,
67
+ remote_database : :production)
68
+ ```
69
+
70
+ Running the above example will copy two records into your local database:
71
+
72
+ * The `Widget` with id 123 (Lubricated Stainless Steel Helical Insert)
73
+ * The `Manufacturer` with id 78 (South Seas Trading Company)
74
+
75
+ It's important to note that Syncer _does not_ recursively follow associations. You'll note that not all of the the manufacturer's widgets were synced, only the one we specified.
76
+
77
+ The `association` attribute passed into the `run!` method can be any valid value that you might use when joining records with ActiveRecord. The above effectively becomes:
78
+
79
+ ```ruby
80
+ Widget.eager_load(:manufacturer).find(123)
81
+ ```
82
+
83
+ Because of this, you can pass any sort of ActiveRecord association into Syncify's `run!` method.
84
+
85
+ Now let's imagine that a `Manufacturer` `has_many` `Plant`s which `belong_to` a `State`. Here are some example rows in these tables:
86
+
87
+ `plants`:
88
+
89
+ | id | name | manufacturer_id | city | state_id |
90
+ | --- | --------------- | --------------- | ------- | -------- |
91
+ | 64 | Rapid Run | 78 | Lansing | 13 |
92
+ | 65 | Ye Olde Factory | 78 | Naples | 15 |
93
+ | 66 | Catco | 79 | Balston | 43 |
94
+
95
+ `states`:
96
+
97
+ | id | name |
98
+ | --- | -------- |
99
+ | 13 | Michigan |
100
+ | 15 | Florida |
101
+ | 43 | Virginia |
102
+
103
+ We could sync a `Manufacturer` along with its widgets, factories, and the state the factory is in with this example:
104
+
105
+ ```ruby
106
+ Syncify::Sync.run!(klass: Manufacturer,
107
+ id: 78,
108
+ association: [
109
+ :widgets,
110
+ { factories: :state }
111
+ ],
112
+ remote_database: :production)
113
+ ```
114
+
115
+ You can really go wild with the associations; well beyond what you could normally run with an ActiveRecord query! In one app I have a hash defining a ton of associations across dozens of models that is more than 150 lines long. When I run this sync it identifies more than 500 records and syncs them all to local dev in about 30 seconds.
116
+
117
+ ### Polymorphic Associations
118
+
119
+ Syncify also works with (and across) Polymorphic associations! To sync across polymorphic associations you need to specify an association using the `Syncer::PolymorphicAssociation` class. This is put in place in your otherwise-normal associations.
120
+
121
+ Let's imagine that we run an online store that sells both physical and digital goods. A given invoice then might have line items that refer to either type of good.
122
+
123
+ Here's our model:
124
+
125
+ * `Customer`
126
+ * `has_many :invoices`
127
+ * `Invoice`
128
+ * `belongs_to :customer`
129
+ * `has_many :line_items`
130
+ * `LineItem`
131
+ * `belongs_to :invoice`
132
+ * `belongs_to :product, polymorphic: true`
133
+ * `DigitalProduct`
134
+ * `has_many :line_items, as: :product`
135
+ * `belongs_to :category`
136
+ * `PhysicalProduct`
137
+ * `has_many :line_items, as: :product`
138
+ * `belongs_to :distributor`
139
+ * `Category`
140
+ * `has_many :digital_products`
141
+ * `Distributor`
142
+ * `has_many :physical_products`
143
+
144
+ There's a lot going on above, and I'll spare you the example database tables. You can use your imagination! 😉
145
+
146
+ Let's say we want to sync a particular `LineItem`. With ActiveRecord queries you can't simply `eager_load` across a polymorphic association, much less to any sub-associations (EG: category or distributor). With Syncify you can.
147
+
148
+ Here's an example. For simplicity's sake it assumes that the database doesn't use foreign keys. (Don't worry, we'll do a more complex example next!):
149
+
150
+ ```ruby
151
+ Syncify::Sync.run!(klass: Customer,
152
+ id: 999,
153
+ association: Syncer::PolymorphicAssociation.new(
154
+ :product,
155
+ DigitalProduct => {},
156
+ PhysicalProduct => {}
157
+ ),
158
+ remote_database: :production)
159
+ ```
160
+
161
+ Assuming that line item 42's product is a `DigitalProduct`, this example would have synced the `LineItem` and its `DigitalProduct` and nothing else.
162
+
163
+ The `Syncer::PolymorphicAssociation` is saying that, for the `LineItem`'s `product` polymorphic association, when the product is a `DigitalProduct`, sync it with the specified associations (in this case none). When the product is a `PhysicalProduct`, sync it with the specified associations (again, none in this case).
164
+
165
+ Now let's say that we want to sync a specific `Customer` and all of their invoices and the related products. IE: the whole kit and caboodle. Here's how you can do it:
166
+
167
+ ```ruby
168
+ Syncify::Sync.run!(klass: Customer,
169
+ id: 999,
170
+ association: {
171
+ invoices: {
172
+ line_items: Syncer::PolymorphicAssociation.new(
173
+ :product,
174
+ DigitalProduct => :category,
175
+ PhysicalProduct => :distributor
176
+ )
177
+ }
178
+ },
179
+ remote_database: :production)
180
+ ```
181
+
182
+ This will sync a customer, all of their invoices, all of those invoice's line items. It goes on to sync all of the line item's products, whether digital or physical, as well as the digital product's category and the physical product's distributor.
183
+
184
+ ## Development
185
+
186
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
187
+
188
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
189
+
190
+ ## Contributing
191
+
192
+ Bug reports and pull requests are welcome on GitHub at https://github.com/dhughes/syncify.
193
+
194
+ ## License
195
+
196
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "syncify"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/syncify.rb ADDED
@@ -0,0 +1,9 @@
1
+ require "syncify/version"
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+
5
+ Dir[File.expand_path('syncify/*.rb', __dir__)].each { |f| require f }
6
+
7
+ module Syncify
8
+ class Error < StandardError; end
9
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Syncify
4
+ class NormalizeAssociations < ActiveInteraction::Base
5
+ object :association, class: Object
6
+
7
+ def execute
8
+ normalize_associations(association)
9
+ end
10
+
11
+ private
12
+
13
+ def normalize_associations(association)
14
+ Array.wrap(
15
+ case association
16
+ when Symbol
17
+ Hash[association, {}]
18
+ when Array
19
+ association.map { |node| normalize_associations(node) }
20
+ when Hash
21
+ association.reduce([]) do |memo, (key, value)|
22
+ values = normalize_associations(value)
23
+
24
+ if values.empty?
25
+ memo << Hash[key, {}]
26
+ else
27
+ values.each do |value|
28
+ memo << Hash[key, value]
29
+ end
30
+ end
31
+
32
+ memo
33
+ end
34
+ else
35
+ association
36
+ end
37
+ ).flatten
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Syncify
4
+ class PolymorphicAssociation
5
+ attr_accessor :property
6
+ attr_accessor :associations
7
+
8
+ def initialize(property, associations)
9
+ @property = property
10
+ @associations = associations
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Syncify
4
+ class Sync < ActiveInteraction::Base
5
+ object :klass, class: Class
6
+ integer :id
7
+ object :association, class: Object, default: []
8
+ object :callback, class: Proc, default: nil
9
+
10
+ symbol :remote_database
11
+
12
+ attr_accessor :identified_records
13
+
14
+ def execute
15
+ @identified_records = Set[]
16
+
17
+ remote do
18
+ identify_associated_records(klass.find(id), normalized_associations(association))
19
+ end
20
+
21
+ callback.call(identified_records) if callback.present?
22
+
23
+ sync_records
24
+ end
25
+
26
+ def identify_associated_records(root, associations)
27
+ identified_records << root
28
+
29
+ standard_associations = associations.reject(&method(:includes_polymorphic_association))
30
+ polymorphic_associations = associations.select(&method(:includes_polymorphic_association))
31
+
32
+ standard_associations.each do |association|
33
+ traverse_associations(
34
+ root.class.eager_load(association).find(root.id),
35
+ association
36
+ )
37
+ end
38
+
39
+ identify_polymorphic_associated_records(root, polymorphic_associations)
40
+ end
41
+
42
+ def identify_polymorphic_associated_records(root, polymorphic_associations)
43
+ polymorphic_associations.each do |polymorphic_association|
44
+ if polymorphic_association.is_a?(Hash)
45
+ polymorphic_association.each do |key, association|
46
+ Array.wrap(root.__send__(key)).each do |target|
47
+ identify_polymorphic_associated_records(target, Array.wrap(association))
48
+ end
49
+ end
50
+ else
51
+ target = root.__send__(polymorphic_association.property)
52
+ type = polymorphic_association.associations.keys.detect do |association_type|
53
+ target.is_a?(association_type)
54
+ end
55
+ associations = polymorphic_association.associations[type]
56
+ identify_associated_records(target, normalized_associations(associations))
57
+ end
58
+ end
59
+ end
60
+
61
+ def traverse_associations(records, associations)
62
+ records = Array(records)
63
+
64
+ identified_records.merge records
65
+
66
+ records.each do |record|
67
+ associations.each do |association, nested_associations|
68
+ traverse_associations(record.__send__(association), nested_associations)
69
+ end
70
+ end
71
+ end
72
+
73
+ def sync_records
74
+ ActiveRecord::Base.connection.disable_referential_integrity do
75
+ classify_identified_instances.each do |class_name, new_instances|
76
+ puts "Syncing #{new_instances.size} #{class_name} objects"
77
+ clazz = Object.const_get(class_name)
78
+ clazz.import(new_instances, validate: false, on_duplicate_key_update: [:id])
79
+ end
80
+ end
81
+ end
82
+
83
+ def classify_identified_instances
84
+ puts "Classifying #{identified_records.size} records for bulk import."
85
+
86
+ identified_records.each_with_object({}) do |instance, memo|
87
+ clazz = instance.class
88
+ class_name = clazz.name
89
+ memo[class_name] ||= []
90
+ memo[class_name] << clone_instance(instance)
91
+ end
92
+ end
93
+
94
+ def clone_instance(instance)
95
+ clazz = instance.class
96
+ new_instance = clazz.new
97
+
98
+ instance.attributes.each do |attribute, value|
99
+ new_instance[attribute.to_s] = value
100
+ end
101
+
102
+ new_instance
103
+ end
104
+
105
+ def includes_polymorphic_association(association)
106
+ association.to_s.include?('Syncify::PolymorphicAssociation')
107
+ end
108
+
109
+ def normalized_associations(association)
110
+ Syncify::NormalizeAssociations.run!(association: association)
111
+ end
112
+
113
+ def remote
114
+ run_in_environment(remote_database) { yield }
115
+ end
116
+
117
+ def run_in_environment(environment)
118
+ initial_config = ActiveRecord::Base.connection_config
119
+ ActiveRecord::Base.establish_connection environment
120
+ yield
121
+ ensure
122
+ ActiveRecord::Base.establish_connection initial_config
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,3 @@
1
+ module Syncify
2
+ VERSION = "0.1.0"
3
+ end
data/syncify.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "syncify/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "syncify"
7
+ spec.version = Syncify::VERSION
8
+ spec.authors = ["Doug Hughes"]
9
+ spec.email = ["doug@doughughes.net"]
10
+
11
+ spec.summary = %q{Copies data between Rails environments}
12
+ spec.description = %q{You can use this gem to copy records and their specified associations from production (or other) environments to your local environment.}
13
+ spec.homepage = "http://github.com/dhughes/syncify"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "http://github.com/dhughes/syncify"
18
+ spec.metadata["changelog_uri"] = "http://github.com/dhughes/syncify"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "bundler", "~> 2.0"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rspec", "~> 3.0"
32
+ spec.add_development_dependency "pry-byebug", "~> 3.7"
33
+ spec.add_development_dependency "sqlite3", '~> 1.3', '< 1.4'
34
+ spec.add_development_dependency "factory_bot_rails", "~> 4.11"
35
+
36
+ spec.add_runtime_dependency "active_interaction", "~> 3.0"
37
+ spec.add_runtime_dependency "activerecord", "~> 4.2"
38
+ spec.add_runtime_dependency "activerecord-import", "~> 0.17"
39
+ end
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: syncify
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Doug Hughes
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.3'
76
+ - - "<"
77
+ - !ruby/object:Gem::Version
78
+ version: '1.4'
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '1.3'
86
+ - - "<"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.4'
89
+ - !ruby/object:Gem::Dependency
90
+ name: factory_bot_rails
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '4.11'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '4.11'
103
+ - !ruby/object:Gem::Dependency
104
+ name: active_interaction
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '3.0'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '3.0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: activerecord
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '4.2'
124
+ type: :runtime
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '4.2'
131
+ - !ruby/object:Gem::Dependency
132
+ name: activerecord-import
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '0.17'
138
+ type: :runtime
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '0.17'
145
+ description: You can use this gem to copy records and their specified associations
146
+ from production (or other) environments to your local environment.
147
+ email:
148
+ - doug@doughughes.net
149
+ executables: []
150
+ extensions: []
151
+ extra_rdoc_files: []
152
+ files:
153
+ - ".gitignore"
154
+ - ".rspec"
155
+ - ".travis.yml"
156
+ - Gemfile
157
+ - Gemfile.lock
158
+ - LICENSE.txt
159
+ - README.md
160
+ - Rakefile
161
+ - bin/console
162
+ - bin/setup
163
+ - lib/syncify.rb
164
+ - lib/syncify/normalize_associations.rb
165
+ - lib/syncify/polymorphic_association.rb
166
+ - lib/syncify/sync.rb
167
+ - lib/syncify/version.rb
168
+ - syncify.gemspec
169
+ homepage: http://github.com/dhughes/syncify
170
+ licenses:
171
+ - MIT
172
+ metadata:
173
+ homepage_uri: http://github.com/dhughes/syncify
174
+ source_code_uri: http://github.com/dhughes/syncify
175
+ changelog_uri: http://github.com/dhughes/syncify
176
+ post_install_message:
177
+ rdoc_options: []
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ requirements: []
191
+ rubyforge_project:
192
+ rubygems_version: 2.5.2.3
193
+ signing_key:
194
+ specification_version: 4
195
+ summary: Copies data between Rails environments
196
+ test_files: []