replicate 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
data/HACKING ADDED
@@ -0,0 +1,61 @@
1
+ Grab a local clone of rtomayko/replicate:
2
+
3
+ git clone git://github.com/rtomayko/replicate.git
4
+ cd replicate
5
+
6
+ The default rake task installs the latest supported activerecord
7
+ version to a project local GEM_HOME=./vendor and runs the unit
8
+ tests:
9
+
10
+ $ rake
11
+ installing activerecord-3.1.0 to ./vendor/1.8
12
+ installing sqlite3 to ./vendor/1.8
13
+ Using activerecord 3.1.0
14
+ Loaded suite ...
15
+ Started
16
+ ....................
17
+ Finished in 0.150186 seconds.
18
+
19
+ 20 tests, 106 assertions, 0 failures, 0 errors
20
+
21
+ Use `rake test:all' to run tests under all activerecord versions:
22
+
23
+ $ rake test:all
24
+ installing activerecord ~> 2.2.3 to ./vendor
25
+ installing activerecord ~> 2.3.14 to ./vendor
26
+ installing activerecord ~> 3.0.10 to ./vendor
27
+ installing activerecord ~> 3.1.0 to ./vendor
28
+ ==> testing activerecord ~> 2.2.3
29
+ Started
30
+ ....................
31
+ Finished in 0.119517 seconds.
32
+
33
+ 20 tests, 106 assertions, 0 failures, 0 errors
34
+ ==> testing activerecord ~> 2.3.14
35
+ Started
36
+ ....................
37
+ Finished in 0.119517 seconds.
38
+
39
+ 20 tests, 106 assertions, 0 failures, 0 errors
40
+ <snip>
41
+
42
+ rake test:all should always be passing under latest stable MRI
43
+ 1.8.7 and MRI 1.9.x.
44
+
45
+ Running individual test files directly requires setting the
46
+ GEM_HOME environment variable and ensuring ./lib is on the load
47
+ path:
48
+
49
+ export GEM_HOME=vendor/1.9 # or 1.8.7
50
+ ruby -Ilib test/active_record_test.rb
51
+
52
+ You can also control which activerecord version is used in the
53
+ test with the AR_VERSION environment variable:
54
+
55
+ rake setup:all
56
+ export GEM_HOME=vendor/1.8.7
57
+ AR_VERSION=3.1.0 ruby -rubygems -Ilib test/active_record_test.rb
58
+
59
+ If you have something worth sharing, please send a pull request:
60
+
61
+ https://github.com/rtomayko/replicate
data/README.md CHANGED
@@ -1,15 +1,20 @@
1
- # Replicate
2
-
3
1
  Dump and load relational objects between Ruby environments.
2
+ ===========================================================
3
+
4
+ The project started at GitHub to simplify the process of getting real production
5
+ data into development and staging environments. We use it to replicate entire
6
+ repository data (including associated issue, pull request, commit comment, etc.
7
+ records) from production to our development environments with a single command.
8
+ It's excessively useful for troubleshooting issues, support requests, and
9
+ exception reports as well as for establishing real data for evaluating design
10
+ concepts.
4
11
 
5
- The project was started at GitHub to ease the process of getting real production
6
- data into staging and development environments. We have a custom command that
7
- uses the replicate machinery to dump entire repository data (including
8
- associated objects like issues, pull requests, commit comments, etc.) from
9
- production and load it into the current environment. This is excessively useful
10
- for troubleshooting issues, support requests, and exception reports.
12
+ Synopsis
13
+ --------
11
14
 
12
- ## Synopsis
15
+ Installing:
16
+
17
+ $ gem install replicate
13
18
 
14
19
  Dumping objects:
15
20
 
@@ -32,16 +37,34 @@ Dumping and loading over SSH:
32
37
  $ remote_command="replicate -r /app/config/environment -d 'User.find(1234)'"
33
38
  $ ssh example.org "$remote_command" |replicate -r config/environment -l
34
39
 
35
- ## ActiveRecord
40
+ ActiveRecord
41
+ ------------
42
+
43
+ Basic support for dumping and loading ActiveRecord objects is included. The
44
+ tests pass under ActiveRecord versions 2.2.3, 2.3.14, 3.0.10, and 3.1.0 under
45
+ MRI 1.8.7 as well as under MRI 1.9.2.
46
+
47
+ To use customization macros in your models, require the replicate library after
48
+ ActiveRecord (in e.g., `config/initializers/libraries.rb`):
49
+
50
+ require 'active_record'
51
+ require 'replicate'
52
+
53
+ ActiveRecord support works sensibly without customization so this isn't strictly
54
+ necessary to use the `replicate` command. The following sections document the
55
+ available customization macros.
36
56
 
37
- *NOTE: Replicate has been tested only under ActiveRecord 2.2. Support for
38
- ActiveRecord 3.x is planned.*
57
+ ### Association Dumping
39
58
 
40
- Basic support for dumping and loading ActiveRecord objects is included. When an
41
- object is dumped, all `belongs_to` and `has_one` associations are automatically
42
- followed and included in the dump. You can mark `has_many` and
43
- `has_and_belongs_to_many` associations for automatic inclusion using the
44
- `replicate_associations` macro:
59
+ The baked in support adds some more or less sensible default behavior for all
60
+ subclasses of `ActiveRecord::Base` such that dumping an object will bring in
61
+ objects related via `belongs_to` and `has_one` associations.
62
+
63
+ Unlike 1:1 associations, `has_many` and `has_and_belongs_to_many` associations
64
+ are not automatically included. Doing so would quickly lead to the entire
65
+ database being sucked in. It can be useful to mark specific associations for
66
+ automatic inclusion using the `replicate_associations` macro. For instance,
67
+ to always include `EmailAddress` records belonging to a `User`:
45
68
 
46
69
  class User < ActiveRecord::Base
47
70
  belongs_to :profile
@@ -50,10 +73,13 @@ followed and included in the dump. You can mark `has_many` and
50
73
  replicate_associations :email_addresses
51
74
  end
52
75
 
53
- By default, the loader attempts to create a new record for all objects. This can
54
- lead to unique constraint errors when a record already exists with matching
55
- attributes. To update existing records instead of always creating new ones,
56
- define a natural key for the model using the `replicate_natural_key` macro:
76
+ ### Natural Keys
77
+
78
+ By default, the loader attempts to create a new record with a new primary key id
79
+ for all objects. This can lead to unique constraint errors when a record already
80
+ exists with matching attributes. To update existing records instead of
81
+ creating new ones, define a natural key for the model using the `replicate_natural_key`
82
+ macro:
57
83
 
58
84
  class User < ActiveRecord::Base
59
85
  belongs_to :profile
@@ -63,13 +89,45 @@ define a natural key for the model using the `replicate_natural_key` macro:
63
89
  replicate_associations :email_addresses
64
90
  end
65
91
 
66
- Multiple attribute names may be specified to define a compound key.
92
+ class EmailAddress < ActiveRecord::Base
93
+ belongs_to :user
94
+ replicate_natural_key :user_id, :email
95
+ end
96
+
97
+ Multiple attribute names may be specified to define a compound key. Foreign key
98
+ column attributes (`user_id`) are often included in natural keys.
99
+
100
+ ### Validations and Callbacks
101
+
102
+ __IMPORTANT:__ All ActiveRecord validations and callbacks are disabled on the
103
+ loading side. While replicate piggybacks on AR for relationship information and
104
+ uses `ActiveRecord::Base#save` to write objects to the database, it's designed
105
+ to act as a simple dump / load tool.
106
+
107
+ It's sometimes useful to run certain types of callbacks on replicate. For
108
+ instance, you might want to create files on disk or load information into a
109
+ separate data store any time an object enters the database. The best way to go
110
+ about this currently is to override the model's `load_replicant` class method:
111
+
112
+ class User < ActiveRecord::Base
113
+ def self.load_replicant(type, id, attrs)
114
+ id, object = super
115
+ object.register_in_redis
116
+ object.some_other_callback
117
+ [id, object]
118
+ end
119
+ end
120
+
121
+ This interface will be improved in future versions.
67
122
 
68
- ## Custom Objects
123
+ Custom Objects
124
+ --------------
69
125
 
70
126
  Other object types may be included in the dump stream so long as they implement
71
127
  the `dump_replicant` and `load_replicant` methods.
72
128
 
129
+ ### dump_replicant
130
+
73
131
  The dump side calls `#dump_replicant(dumper)` on each object. The method must
74
132
  call `dumper.write()` with the class name, id, and hash of primitively typed
75
133
  attributes for the object:
@@ -84,6 +142,8 @@ attributes for the object:
84
142
  end
85
143
  end
86
144
 
145
+ ### load_replicant
146
+
87
147
  The load side calls `::load_replicant(type, id, attributes)` on the class to
88
148
  load each object into the current environment. The method must return an
89
149
  `[id, object]` tuple:
@@ -97,3 +157,28 @@ load each object into the current environment. The method must return an
97
157
  [user.id, user]
98
158
  end
99
159
  end
160
+
161
+ How it works
162
+ ------------
163
+
164
+ The dump format is designed for streaming relational data. Each object is
165
+ encoded as a `[type, id, attributes]` tuple and marshalled directly onto the
166
+ stream. The `type` (class name string) and `id` must form a distinct key when
167
+ combined, `attributes` must consist of only string keys and simply typed values.
168
+
169
+ Relationships between objects in the stream are managed as follows:
170
+
171
+ - An object's attributes may encode references to objects that precede it
172
+ in the stream using a simple tuple format: [:id, 'User', 1234].
173
+
174
+ - The dump side ensures that objects are written to the dump stream in
175
+ "reference order" such that when an object A includes a reference attribute
176
+ to an object B, B is guaranteed to arrive before A.
177
+
178
+ - The load side maintains a mapping of ids from the dumping system to the newly
179
+ replicated objects on the loading system. When the loader encounters a
180
+ reference value [:id, 'User', 1234] in an object's attributes, it converts it
181
+ to the load side id value.
182
+
183
+ Dumping and loading happens in a streaming fashion. There is no limit on the
184
+ number of objects included in the stream.
data/Rakefile CHANGED
@@ -1,6 +1,71 @@
1
- task :default => :test
1
+ require 'rbconfig'
2
+ require 'rake/clean'
3
+ task :default => [:setup, :test]
4
+
5
+ vendor_dir = './vendor'
6
+ ruby_version = RbConfig::CONFIG['ruby_version']
7
+ ENV['GEM_HOME'] = "#{vendor_dir}/#{ruby_version}"
8
+
9
+ desc "Install gem dependencies for development"
10
+ task :setup => 'setup:latest' do
11
+ verbose(false) { gem_install 'sqlite3' }
12
+ end
2
13
 
3
14
  desc "Run tests"
4
15
  task :test do
16
+ ENV['RUBYOPT'] = [ENV['RUBYOPT'], 'rubygems'].compact.join(' ')
17
+ ENV['RUBYLIB'] = ['lib', ENV['RUBYLIB']].compact.join(':')
5
18
  sh "testrb test/*_test.rb", :verbose => false
6
19
  end
20
+ CLEAN.include 'test/db'
21
+
22
+ desc "Build gem"
23
+ task :build do
24
+ sh "gem build replicate.gemspec"
25
+ end
26
+
27
+ # supported activerecord gem versions
28
+ AR_VERSIONS = []
29
+ AR_VERSIONS << '2.2.3' if RUBY_VERSION < '1.9'
30
+ AR_VERSIONS.concat %w[2.3.14 3.0.10 3.1.0]
31
+
32
+ desc "Run unit tests under all supported AR versions"
33
+ task 'test:all' => 'setup:all' do
34
+ failures = []
35
+ AR_VERSIONS.each do |vers|
36
+ warn "==> testing activerecord ~> #{vers}"
37
+ ENV['AR_VERSION'] = vers
38
+ ok = system("rake -s test")
39
+ failures << vers if !ok
40
+ warn ''
41
+ end
42
+ fail "activerecord version failures: #{failures.join(', ')}" if failures.any?
43
+ end
44
+
45
+ # file tasks for installing each AR version
46
+ desc 'Install gem dependencies for all supported AR versions'
47
+ task 'setup:all' => 'setup'
48
+ AR_VERSIONS.each do |vers|
49
+ version_file = "#{ENV['GEM_HOME']}/versions/activerecord-#{vers}"
50
+ file version_file do |f|
51
+ verbose(false) { gem_install 'activerecord', vers }
52
+ end
53
+ task "setup:#{vers}" => version_file
54
+ task "setup:all" => "setup:#{vers}"
55
+ end
56
+ task "setup:latest" => "setup:#{AR_VERSIONS.last}"
57
+ CLEAN.include 'vendor'
58
+
59
+ # Install a gem to the local GEM_HOME but only if it isn't already installed
60
+ def gem_install(name, version = nil)
61
+ version_name = [name, version].compact.join('-')
62
+ version_file = "#{ENV['GEM_HOME']}/versions/#{version_name}"
63
+ return if File.exist?(version_file)
64
+ warn "installing #{version_name} to #{ENV['GEM_HOME']}"
65
+ command = "gem install --no-rdoc --no-ri #{name}"
66
+ command += " -v '~> #{version}'" if version
67
+ command += " >/dev/null"
68
+ sh command
69
+ mkdir_p File.dirname(version_file)
70
+ File.open(version_file, 'wb') { }
71
+ end
data/bin/replicate CHANGED
@@ -10,6 +10,7 @@
10
10
  #/ -r, --require Require the library. Often used with 'config/environment'.
11
11
  #/ -d, --dump Dump the repository and all related objects to stdout.
12
12
  #/ -l, --load Load dump file data from stdin.
13
+ #/ -i, --keep-id Use replicated ids when loading dump file.
13
14
  #/
14
15
  #/ -v, --verbose Write more status output.
15
16
  #/ -q, --quiet Write less status output.
@@ -20,6 +21,7 @@ require 'optparse'
20
21
  mode = nil
21
22
  verbose = false
22
23
  quiet = false
24
+ keep_id = false
23
25
  out = $stdout
24
26
 
25
27
  # parse arguments
@@ -31,6 +33,7 @@ ARGV.options do |opts|
31
33
  opts.on("-r", "--require=f") { |file| require file }
32
34
  opts.on("-v", "--verbose") { verbose = true }
33
35
  opts.on("-q", "--quiet") { quiet = true }
36
+ opts.on("-i", "--keep-id") { keep_id = true }
34
37
  opts.on_tail("-h", "--help", &usage)
35
38
  opts.parse!
36
39
  end
@@ -38,8 +41,9 @@ end
38
41
  # load rails environment and replicator lib.
39
42
  require 'replicate'
40
43
 
41
- # hack to enable AR query cache
42
44
  if defined?(ActiveRecord::Base)
45
+ ActiveRecord::Base.replicate_id = keep_id
46
+ # hack to enable AR query cache
43
47
  ActiveRecord::ConnectionAdapters::QueryCache.
44
48
  send :attr_writer, :query_cache, :query_cache_enabled
45
49
  ActiveRecord::Base.connection.send(:query_cache=, {})
@@ -126,6 +126,18 @@ module Replicate
126
126
  @replicate_natural_key = attribute_names
127
127
  end
128
128
 
129
+ # Set or retrieve whether replicated object should keep its original id.
130
+ # When not set, replicated objects will be created with new id.
131
+ def replicate_id(boolean=nil)
132
+ self.replicate_id = boolean unless boolean.nil?
133
+ @replicate_id.nil? ? superclass.replicate_id : @replicate_id
134
+ end
135
+
136
+ # Set flag for replicating original id.
137
+ def replicate_id=(boolean)
138
+ @replicate_id = boolean
139
+ end
140
+
129
141
  # Load an individual record into the database. If the models defines a
130
142
  # replicate_natural_key then an existing record will be updated if found
131
143
  # instead of a new record being created.
@@ -156,17 +168,47 @@ module Replicate
156
168
 
157
169
  # Update an AR object's attributes and persist to the database without
158
170
  # running validations or callbacks.
171
+ #
172
+ # Returns the [id, object] tuple for the newly replicated objected.
159
173
  def create_or_update_replicant(instance, attributes)
160
- def instance.callback(*args);end # Rails 2.x hack to disable callbacks.
161
-
174
+ # write replicated attributes to the instance
162
175
  attributes.each do |key, value|
163
- next if key == primary_key
164
- instance.write_attribute key, value
176
+ next if key == primary_key and not replicate_id
177
+ instance.send :write_attribute, key, value
178
+ end
179
+
180
+ # save the instance bypassing all callbacks and validations
181
+ replicate_disable_callbacks instance
182
+ if ::ActiveRecord::VERSION::MAJOR >= 3
183
+ instance.save :validate => false
184
+ else
185
+ instance.save false
165
186
  end
166
187
 
167
- instance.save false
168
188
  [instance.id, instance]
169
189
  end
190
+
191
+ # Disable all callbacks on an ActiveRecord::Base instance. Only the
192
+ # instance is effected. There is no way to re-enable callbacks once
193
+ # they've been disabled on an object.
194
+ def replicate_disable_callbacks(instance)
195
+ if ::ActiveRecord::VERSION::MAJOR >= 3
196
+ # AR 3.1.x
197
+ def instance.run_callbacks(*args); yield; end
198
+
199
+ # AR 3.0.x
200
+ def instance._run_save_callbacks(*args); yield; end
201
+ def instance._run_create_callbacks(*args); yield; end
202
+ def instance._run_update_callbacks(*args); yield; end
203
+ else
204
+ # AR 2.x
205
+ def instance.callback(*args)
206
+ end
207
+ def instance.record_timestamps
208
+ false
209
+ end
210
+ end
211
+ end
170
212
  end
171
213
 
172
214
  # Special object used to dump the list of associated ids for a
@@ -213,5 +255,6 @@ module Replicate
213
255
  ::ActiveRecord::Base.send :extend, ClassMethods
214
256
  ::ActiveRecord::Base.replicate_associations = []
215
257
  ::ActiveRecord::Base.replicate_natural_key = []
258
+ ::ActiveRecord::Base.replicate_id = false
216
259
  end
217
260
  end
@@ -1,12 +1,22 @@
1
1
  require 'test/unit'
2
2
  require 'stringio'
3
+
4
+ # require a specific AR version.
5
+ version = ENV['AR_VERSION']
6
+ gem 'activerecord', "~> #{version}" if version
3
7
  require 'active_record'
8
+ require 'active_record/version'
9
+ warn "Using activerecord #{ActiveRecord::VERSION::STRING}"
10
+
11
+ # replicate must be loaded after AR
4
12
  require 'replicate'
5
13
 
14
+ # create the sqlite db on disk
6
15
  dbfile = File.expand_path('../db', __FILE__)
7
16
  File.unlink dbfile if File.exist?(dbfile)
8
17
  ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => dbfile)
9
18
 
19
+ # load schema
10
20
  ActiveRecord::Migration.verbose = false
11
21
  ActiveRecord::Schema.define do
12
22
  create_table "users", :force => true do |t|
@@ -28,25 +38,25 @@ ActiveRecord::Schema.define do
28
38
  end
29
39
  end
30
40
 
41
+ # models
31
42
  class User < ActiveRecord::Base
32
43
  has_one :profile, :dependent => :destroy
33
44
  has_many :emails, :dependent => :destroy, :order => 'id'
34
-
35
45
  replicate_natural_key :login
36
46
  end
37
47
 
38
48
  class Profile < ActiveRecord::Base
39
49
  belongs_to :user
40
-
41
50
  replicate_natural_key :user_id
42
51
  end
43
52
 
44
53
  class Email < ActiveRecord::Base
45
54
  belongs_to :user
46
-
47
55
  replicate_natural_key :user_id, :email
48
56
  end
49
57
 
58
+ # The test case loads some fixture data once and uses transaction rollback to
59
+ # reset fixture state for each test's setup.
50
60
  class ActiveRecordTest < Test::Unit::TestCase
51
61
  def setup
52
62
  self.class.fixtures
@@ -250,4 +260,93 @@ class ActiveRecordTest < Test::Unit::TestCase
250
260
  assert !user.emails.empty?, "#{login} has no emails" if login != 'tmm1'
251
261
  end
252
262
  end
263
+
264
+ def test_loading_with_replicating_id
265
+ objects = []
266
+ @dumper.listen do |type, id, attrs, obj|
267
+ objects << [type, id, attrs, obj] if type == 'User'
268
+ end
269
+
270
+ dumped_users = {}
271
+ %w[rtomayko kneath tmm1].each do |login|
272
+ user = User.find_by_login(login)
273
+ @dumper.dump user
274
+ dumped_users[login] = user
275
+ end
276
+ assert_equal 3, objects.size
277
+
278
+ User.destroy_all
279
+ User.replicate_id = false
280
+
281
+ # load everything back up
282
+ objects.each { |type, id, attrs, obj| User.load_replicant type, id, attrs }
283
+
284
+ user = User.find_by_login('rtomayko')
285
+ assert_not_equal dumped_users['rtomayko'].id, user.id
286
+
287
+ User.destroy_all
288
+ User.replicate_id = true
289
+
290
+ # load everything back up
291
+ objects.each { |type, id, attrs, obj| User.load_replicant type, id, attrs }
292
+
293
+ user = User.find_by_login('rtomayko')
294
+ assert_equal dumped_users['rtomayko'].id, user.id
295
+ end
296
+
297
+ def test_loader_saves_without_validations
298
+ # note when a record is saved with validations
299
+ ran_validations = false
300
+ User.class_eval { validate { ran_validations = true } }
301
+
302
+ # check our assumptions
303
+ user = User.create(:login => 'defunkt')
304
+ assert ran_validations, "should run validations here"
305
+ ran_validations = false
306
+
307
+ # load one and verify validations are not run
308
+ user = nil
309
+ @loader.listen { |type, id, attrs, obj| user = obj }
310
+ @loader.feed 'User', 1, 'login' => 'rtomayko'
311
+ assert_not_nil user
312
+ assert !ran_validations, 'validations should not run on save'
313
+ end
314
+
315
+ def test_loader_saves_without_callbacks
316
+ # note when a record is saved with callbacks
317
+ callbacks = false
318
+ User.class_eval { after_save { callbacks = true } }
319
+
320
+ # check our assumptions
321
+ user = User.create(:login => 'defunkt')
322
+ assert callbacks, "should run callbacks here"
323
+ callbacks = false
324
+
325
+ # load one and verify validations are not run
326
+ user = nil
327
+ @loader.listen { |type, id, attrs, obj| user = obj }
328
+ @loader.feed 'User', 1, 'login' => 'rtomayko'
329
+ assert_not_nil user
330
+ assert !callbacks, 'callbacks should not run on save'
331
+ end
332
+
333
+ def test_loader_saves_without_updating_created_at_timestamp
334
+ timestamp = Time.at((Time.now - (24 * 60 * 60)).to_i)
335
+ user = nil
336
+ @loader.listen { |type, id, attrs, obj| user = obj }
337
+ @loader.feed 'User', 23, 'login' => 'brianmario', 'created_at' => timestamp
338
+ assert_equal timestamp, user.created_at
339
+ user = User.find(user.id)
340
+ assert_equal timestamp, user.created_at
341
+ end
342
+
343
+ def test_loader_saves_without_updating_updated_at_timestamp
344
+ timestamp = Time.at((Time.now - (24 * 60 * 60)).to_i)
345
+ user = nil
346
+ @loader.listen { |type, id, attrs, obj| user = obj }
347
+ @loader.feed 'User', 29, 'login' => 'rtomayko', 'updated_at' => timestamp
348
+ assert_equal timestamp, user.updated_at
349
+ user = User.find(user.id)
350
+ assert_equal timestamp, user.updated_at
351
+ end
253
352
  end
data/test/dumper_test.rb CHANGED
@@ -46,6 +46,7 @@ class DumperTest < Test::Unit::TestCase
46
46
 
47
47
  def test_writing_to_io
48
48
  io = StringIO.new
49
+ io.set_encoding 'BINARY' if io.respond_to?(:set_encoding)
49
50
  @dumper.marshal_to io
50
51
  @dumper.dump object = thing
51
52
  data = Marshal.dump(['Replicate::Object', object.id, object.attributes])
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: replicate
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 0
9
- version: "1.0"
8
+ - 1
9
+ version: "1.1"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ryan Tomayko
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-09-08 00:00:00 Z
17
+ date: 2011-09-09 00:00:00 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: activerecord
@@ -24,15 +24,29 @@ dependencies:
24
24
  requirements:
25
25
  - - ~>
26
26
  - !ruby/object:Gem::Version
27
- hash: 7
27
+ hash: 5
28
28
  segments:
29
- - 2
30
- - 2
31
- version: "2.2"
29
+ - 3
30
+ - 1
31
+ version: "3.1"
32
32
  type: :development
33
33
  version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: sqlite3
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :development
47
+ version_requirements: *id002
34
48
  description: Dump and load relational objects between Ruby environments.
35
- email: r@tomayko.com
49
+ email: ryan@github.com
36
50
  executables:
37
51
  - replicate
38
52
  extensions: []
@@ -41,6 +55,7 @@ extra_rdoc_files: []
41
55
 
42
56
  files:
43
57
  - COPYING
58
+ - HACKING
44
59
  - README.md
45
60
  - Rakefile
46
61
  - bin/replicate
@@ -55,7 +70,7 @@ files:
55
70
  - test/dumper_test.rb
56
71
  - test/loader_test.rb
57
72
  - test/replicate_test.rb
58
- homepage: http://github.com/rtomayko/replicate/
73
+ homepage: http://github.com/rtomayko/replicate
59
74
  licenses: []
60
75
 
61
76
  post_install_message: