table_differ 0.5.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: 753fc1ecd3ac45fb1a11785069a8236127cde352
4
+ data.tar.gz: 10d8fd04834d8cf542e86717332f8ad831f48cf8
5
+ SHA512:
6
+ metadata.gz: 383647ef5b7608af4b895548868e33459bc752ec9ba5c82700d1678229c166d2b219b858e35fdb6aead81a72c3c50aec80acf0cc7f4134c76222a6f39707c806
7
+ data.tar.gz: 809cf0d2b6519daf343f5f1d8e01f7b9f7739bdd71b7c811ff19b7702bc2997ad74f23fae0f09e85653b29921181c7f00e19155d376bbe3d51a1247eefe52505
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ 1.9.3
3
+ 2.0.0
4
+ 2.1.1
5
+ ruby-head
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Table Differ Changelog
2
+
3
+ **0.5.0**   26 June 2014
4
+
5
+ * First public release
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,11 @@
1
+ guard :bundler do
2
+ watch('Gemfile')
3
+ watch(/^.+\.gemspec/)
4
+ end
5
+
6
+ guard :rspec do
7
+ watch(%r{^spec/.+_spec\.rb$})
8
+ watch(%r{.*\.rb})
9
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
10
+ watch('spec/spec_helper.rb') { "spec" }
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Scott Bronson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # Table Differ
2
+
3
+ Take snapshots of database tables and compute the differences between two snapshots.
4
+
5
+ [![Build Status](https://api.travis-ci.org/bronson/table_differ.png?branch=master)](http://travis-ci.org/bronson/table_differ)
6
+
7
+ ## Installation
8
+
9
+ The usual, add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'table_differ'
13
+ ```
14
+
15
+ ## Synopsis
16
+
17
+ ```ruby
18
+ Attachment.create_snapshot
19
+ => "attachments_20140626_233336"
20
+ Attachment.first.touch # set updated_at to right now
21
+ => true
22
+ added,removed,changed = Attachment.diff_snapshot
23
+ => [[], [], [<Attachment 1>]]
24
+ changed.first.original_attributes # returns the fields that have changed
25
+ => {"updated_at"=>Fri, 27 Jun 2014 05:45:56 UTC +00:00}
26
+ Attachment.delete_snapshot "attachments_20140626_233336"
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ Include TableDiffer in models that will be snapshotted:
32
+
33
+ ```ruby
34
+ class Property < ActiveRecord::Base
35
+ include TableDiffer
36
+ ...
37
+ end
38
+ ```
39
+
40
+ ### Snapshot a Table
41
+
42
+ Any time you want to snapshot a table (say, before a new data import),
43
+ call `create_snapshot`.
44
+
45
+ ```ruby
46
+ Property.create_snapshot
47
+ Property.create_snapshot 'import_0012'
48
+ ```
49
+
50
+ If you don't specify a name then a numeric name based on the current
51
+ date will be used (something like `property_20140606_124722`)
52
+ Whatever naming scheme you use, the names need to sort alphabetically so
53
+ Table Differ can know which one is most recent.
54
+
55
+ Use the snapshots method to return all the snapshots that exist now:
56
+
57
+ ```ruby
58
+ Property.snapshots
59
+ => ['property_import_0011', 'property_import_0012']
60
+ ```
61
+
62
+ ### Compute Differences
63
+
64
+ Now, to retrieve a list of the differences, call diff_snapshot:
65
+
66
+ ```ruby
67
+ added,removed,changed = Property.diff_snapshot
68
+ ```
69
+
70
+ This computes the difference between the current table and the most recent
71
+ snapshot (determined alphabetically). Each value is an array of ActiveRecord
72
+ objects. `added` contains the records that have been added since the snapshot
73
+ was taken, `removed` contains the records that were removed, and `changed` contains
74
+ records where, of course, one or more of their columns have changed. Tablediffer
75
+ doesn't follow foreign keys so, if you want that, you'll need to do it manually.
76
+
77
+ Records in `added` and `changed` are regular ActiveRecord objects -- you can modify
78
+ their attributes and save them. Records in `removed`, however, aren't backed by
79
+ a database object and should be treated read-only.
80
+
81
+ Changed records include a hash of the original attributes before the change was
82
+ made. For example, if you changed the name column from 'Nexus' to 'Nexii':
83
+
84
+ ```ruby
85
+ record.attributes
86
+ => { 'id' => 1, 'name' => 'Nexus' }
87
+ record.original_attributes
88
+ => { 'name' => 'Nexii' } # id didn't change so it's not included
89
+ ```
90
+
91
+ Single-Table Inheritance (STI) appears to work correctly (TODO: add this to tests!)
92
+
93
+
94
+ #### Columns to Ignore
95
+
96
+ By default, every column will be considered in the diff.
97
+ You can pass columns to ignore like this:
98
+
99
+ ```ruby
100
+ Property.diff_snapshot ignore: %w[ id created_at updated_at ]
101
+ ```
102
+
103
+ Note that if you ignore the primary key, Table Differ can no longer compute which
104
+ columns have changed. Changed records will appear as a remove followed by an add,
105
+ so you can ignore the empty third array.
106
+
107
+ ```ruby
108
+ added,removed = Attachment.diff_snapshot(ignore: 'id')
109
+ ```
110
+
111
+ Also, if you ignore the ID, you won't be able to update or save any models directly.
112
+ You must copy the attributes to another model, one that was loaded from the database
113
+ normally and still knows its ID.
114
+
115
+ #### Specifying the Snapshot
116
+
117
+ You can name the tables you want to diff explicitly:
118
+
119
+ ```ruby
120
+ a,r,c = Property.diff_snapshot(old: 'import_0012') # changes between the named snapshot and now
121
+ a,r,c = Property.diff_snapshot('cc', 'cd') # difference between the two snapshots named cc and cd
122
+ ```
123
+
124
+ ### Delete Snapshots
125
+
126
+ delete_snapshot gets rid of unwanted snapshots.
127
+ Either pass a name or a proc to specify which snapshots should be deleted.
128
+
129
+ ```ruby
130
+ Property.delete_snapshot 'import_0012'
131
+
132
+ week_old_name = Property.snapshot_name(1.week.ago)
133
+ old_snapshots = Property.snapshots.select { |name| name < week_old_name }
134
+ Property.delete_snapshots(old_snapshots)
135
+ ```
136
+
137
+ ## Internals
138
+
139
+ Table Differ creates a full copy of the table whenever Snapshot is called.
140
+ If your table is large enough that it would cause problems if it suddenly
141
+ doubled in size, then this is not the gem for you.
142
+
143
+ Table Differ diffs the tables server-side using only two SELECT queries.
144
+ This should be plenty fast for any normal usage.
145
+
146
+
147
+ ## Contributing
148
+
149
+ Send issues and pull requests to [Table Differ's Github](github.com/bronson/table_differ).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => ['spec']
7
+ task :test => ['spec']
8
+
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ TODO: try to mark relevant records read-only
2
+ TODO: could CREATE DATABASE ... TEMPLATE work to create snapshots?
@@ -0,0 +1,3 @@
1
+ module TableDiffer
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,89 @@
1
+ require "active_support/concern"
2
+ require "active_record"
3
+
4
+
5
+ module TableDiffer
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_accessor :original_attributes
10
+ end
11
+
12
+ module ClassMethods
13
+ # pass a date or name fragment, receive the full snapshot name.
14
+ # it's ok to pass a snapshot name; it will be returned unchaged.
15
+ def snapshot_name name
16
+ return nil if name.nil?
17
+
18
+ if name.kind_of?(Date) || name.kind_of?(Time)
19
+ name = name.strftime("%Y%m%d_%H%M%S")
20
+ end
21
+
22
+ unless name.index(table_name) == 0
23
+ name = "#{table_name}_#{name}"
24
+ end
25
+
26
+ name
27
+ end
28
+
29
+ # returns an array of the snapshot names that currently exist
30
+ def snapshots
31
+ connection.tables.grep(/^#{table_name}_/).sort
32
+ end
33
+
34
+ # creates a new snapshot
35
+ def create_snapshot suggestion=Time.now
36
+ name = snapshot_name(suggestion)
37
+ connection.execute("CREATE TABLE #{name} AS SELECT * FROM #{table_name}")
38
+ name
39
+ end
40
+
41
+ # deletes the named snapshot
42
+ def delete_snapshot name
43
+ connection.execute("DROP TABLE #{snapshot_name(name)}")
44
+ end
45
+
46
+ # deletes every snapshot named in the array
47
+ def delete_snapshots snapshots
48
+ snapshots.each { |name| delete_snapshot(name) }
49
+ end
50
+
51
+ # ignore: %w[ created_at updated_at id ]
52
+ def diff_snapshot options={}
53
+ oldtable = snapshot_name(options[:old]) || snapshots.last
54
+ newtable = snapshot_name(options[:new]) || table_name
55
+
56
+ ignore = []
57
+ if options[:ignore]
58
+ ignore = Array(options[:ignore]).map(&:to_s)
59
+ end
60
+
61
+ columns = column_names - ignore
62
+ cols = columns.map { |c| "#{c} as #{c}" }.join(", ")
63
+
64
+ added = find_by_sql("SELECT #{cols} FROM #{newtable} EXCEPT SELECT #{cols} FROM #{oldtable}")
65
+ removed = find_by_sql("SELECT #{cols} from #{oldtable} EXCEPT SELECT #{cols} FROM #{newtable}")
66
+
67
+ # hm, none of this seems to matter... TODO: mark appropriate objects read-only: obj.readonly!
68
+ # AR always thinks the record is persisted in the db, even when it obviously isn't
69
+ # added.each { |o| o.instance_variable_set("@new_record", true) } unless table_name == oldtable
70
+ # removed.each { |o| o.instance_variable_set("@new_record", true) } unless table_name == newtable
71
+ # actually, it's probably more reliable just to use the presence of an id to determine if the record can be saved
72
+ # [*added, *removed].select { |o| !o.id }.each { |o| o.instance_variable_set("@new_record", true) }
73
+
74
+ changed = added & removed
75
+ changed.each do |obj|
76
+ orig = removed.find { |r| r == obj }
77
+ raise "this is impossible" if orig.nil?
78
+
79
+ nattrs = obj.attributes
80
+ # remove all unchanged elements -- original_attributes only contains changed values
81
+ oattrs = orig.attributes.reject { |k,v| nattrs.include?(k) && nattrs[k] == v }
82
+
83
+ obj.original_attributes = HashWithIndifferentAccess.new(oattrs)
84
+ end
85
+
86
+ [added - changed, removed - changed, changed]
87
+ end
88
+ end
89
+ end
data/spec/diff_spec.rb ADDED
@@ -0,0 +1,177 @@
1
+ describe "diffing a model" do
2
+ include_context "model"
3
+
4
+ before(:each) do
5
+ Model.create!(name: 'one')
6
+ Model.create!(name: 'two')
7
+ Model.create_snapshot('original')
8
+ end
9
+
10
+ # around(:all) do |group|
11
+ # # puts 'before'
12
+ # # group.run_examples
13
+ # # puts 'after'
14
+ # end
15
+
16
+
17
+ describe "with IDs" do
18
+ it "detects no changes" do
19
+ added,removed,changed = Model.diff_snapshot
20
+
21
+ expect(added).to eq []
22
+ expect(removed).to eq []
23
+ expect(changed).to eq []
24
+ end
25
+
26
+ it "detects an added record" do
27
+ three = Model.create!(name: 'three')
28
+ added,removed,changed = Model.diff_snapshot
29
+
30
+ expect(added).to eq [three]
31
+ expect(added.first.new_record?).to eq false
32
+ expect(removed).to eq []
33
+ expect(changed).to eq []
34
+
35
+ # added records are normal AR objects, try using it
36
+ added.first.update_attributes!(name: 'trois')
37
+ expect(Model.find(added.first.id).name).to eq 'trois'
38
+ end
39
+
40
+ it "detects a removed record" do
41
+ two = Model.where(name: 'two').first.destroy
42
+ added,removed,changed = Model.diff_snapshot
43
+
44
+ expect(added).to eq []
45
+ expect(removed).to eq [two]
46
+ expect(removed.first.new_record?).to eq false
47
+ expect(changed).to eq []
48
+
49
+ # calling save on the returned record should do nothing
50
+ expect(Model.count).to eq 1
51
+ removed.first.save!
52
+ expect(Model.count).to eq 1
53
+ end
54
+
55
+ it "detects a changed field" do
56
+ one = Model.where(name: 'one').first
57
+ one.update_attributes!(name: 'uno')
58
+ added,removed,changed = Model.diff_snapshot
59
+
60
+ expect(added).to eq []
61
+ expect(removed).to eq []
62
+ expect(changed).to eq [one]
63
+ expect(changed.first.name).to eq 'uno'
64
+
65
+ # ensure we can access the previous value, with indifferent access
66
+ expect(changed.first.original_attributes[:name]).to eq 'one'
67
+ expect(changed.first.original_attributes).to eq({'name' => 'one'})
68
+
69
+ # changed records are normal AR objects, try using it
70
+ changed.first.update_attributes!(name: 'nuevo')
71
+ expect(Model.find(changed.first.id).name).to eq 'nuevo'
72
+ end
73
+
74
+ it "resurrects a removed record" do
75
+ Model.where(name: 'two').first.destroy
76
+ _,removed,_ = Model.diff_snapshot
77
+
78
+ expect(Model.count).to eq 1
79
+ # we're expicitly setting the ID to the previous ID, that might not be ok?
80
+ Model.create!(removed.first.attributes)
81
+ expect(Model.count).to eq 2
82
+
83
+ # and now there are no differences
84
+ differences = Model.diff_snapshot
85
+ expect(differences).to eq [[], [], []]
86
+ end
87
+ end
88
+
89
+
90
+ # if we can't trust the model's primary key, we can't tell if anything
91
+ # changed. we can only see what's new and what's been deleted.
92
+ describe "ignoring IDs" do
93
+ it "detects no changes" do
94
+ added,removed,changed = Model.diff_snapshot(ignore: :id)
95
+
96
+ expect(added).to eq []
97
+ expect(removed).to eq []
98
+ expect(changed).to eq []
99
+ end
100
+
101
+ it "detects an added record" do
102
+ Model.create!(name: 'three')
103
+ added,removed = Model.diff_snapshot(ignore: :id)
104
+
105
+ expect(added.map(&:attributes)).to eq [{"id" => nil, "name" => "three"}]
106
+ expect(added.first.new_record?).to eq false # oh well
107
+ expect(removed).to eq []
108
+
109
+ # wthout an ID, updating attributes should do nothing
110
+ added.first.update_attributes!(name: 'trois')
111
+ expect(Model.count).to eq 3
112
+ expect(Model.pluck(:name).sort).to eq ['one', 'three', 'two'] # no trois
113
+ end
114
+
115
+ it "detects a removed record" do
116
+ Model.where(name: 'two').first.destroy
117
+ added,removed,changed = Model.diff_snapshot(ignore: :id)
118
+
119
+ expect(added).to eq []
120
+ expect(removed.map(&:attributes)).to eq [{"id" => nil, "name" => "two"}]
121
+ expect(removed.first.new_record?).to eq false # oh well
122
+ expect(changed).to eq []
123
+ end
124
+
125
+ # without an ID, we can't tell if anything changed
126
+ it "detects a changed field" do
127
+ one = Model.where(name: 'one').first
128
+ one.update_attributes!(name: 'uno')
129
+ added,removed,changed = Model.diff_snapshot(ignore: :id)
130
+
131
+ expect(added.map(&:attributes)).to eq [{"id" => nil, "name" => "uno"}]
132
+ expect(removed.map(&:attributes)).to eq [{"id" => nil, "name" => "one"}]
133
+ expect(changed).to eq []
134
+ end
135
+
136
+ it "resurrects a removed record" do
137
+ Model.where(name: 'two').first.destroy
138
+ _,removed,_ = Model.diff_snapshot(ignore: :id)
139
+
140
+ expect(Model.count).to eq 1
141
+ Model.create!(removed.first.attributes)
142
+ expect(Model.count).to eq 2
143
+
144
+ differences = Model.diff_snapshot(ignore: :id)
145
+ expect(differences).to eq [[], [], []]
146
+ end
147
+ end
148
+
149
+ # ensure we select the correct snapshots to diff between
150
+ it "uses the correct snapshot" do
151
+ insecond = Model.create!(name: 'only in second')
152
+ name = Model.create_snapshot('second')
153
+ expect(name).to eq "models_second"
154
+ main = Model.create!(name: 'only in main table')
155
+
156
+
157
+ # each of the following should be an individual test.
158
+ # not sure how I can make them all use the same db setup though...
159
+ # rspec really really needs a before(:all) { }.
160
+
161
+ # first make sure default diffs newer table
162
+ differences = Model.diff_snapshot
163
+ expect(differences).to eq [[main], [], []]
164
+
165
+ # now diff against older snapshot, ensure more changes
166
+ differences = Model.diff_snapshot old: 'original'
167
+ expect(differences).to eq [[insecond, main], [], []]
168
+
169
+ # specifying an older snapshot produces a reverse diff against the most recent snapshot
170
+ differences = Model.diff_snapshot new: 'models_original'
171
+ expect(differences).to eq [[], [insecond], []]
172
+
173
+ # finally, specify two named snapshots
174
+ differences = Model.diff_snapshot old: 'original', new: 'models_second'
175
+ expect(differences).to eq [[insecond], [], []]
176
+ end
177
+ end
@@ -0,0 +1,50 @@
1
+ describe TableDiffer do
2
+ include_context "model"
3
+
4
+ it "takes a snapshot" do
5
+ expect(Model.snapshots.size).to eq 0
6
+ Model.create_snapshot
7
+ expect(Model.snapshots.size).to eq 1
8
+ end
9
+
10
+ it "takes a name for a snapshot" do
11
+ expect(Model.snapshots.size).to eq 0
12
+ Model.create_snapshot('snapname')
13
+ expect(Model.snapshots).to eq ['models_snapname']
14
+ end
15
+
16
+ it "errors out if asked to create a duplicate snapshot" do
17
+ Model.create_snapshot('snapname')
18
+ expect {
19
+ Model.create_snapshot('snapname')
20
+ }.to raise_error(ActiveRecord::StatementInvalid, /already exists/)
21
+ end
22
+
23
+ it "returns a list of snapshots" do
24
+ Model.create_snapshot('aiee')
25
+ Model.create_snapshot('bee')
26
+ Model.create_snapshot('cee')
27
+ expect(Model.snapshots.sort).to eq ['models_aiee', 'models_bee', 'models_cee']
28
+ end
29
+
30
+ it "deletes a named snapshot" do
31
+ Model.create_snapshot('snapname')
32
+ expect(Model.snapshots.size).to eq 1
33
+ Model.delete_snapshot('snapname')
34
+ expect(Model.snapshots.size).to eq 0
35
+ end
36
+
37
+ it "deletes a bunch of snapshots" do
38
+ Model.create_snapshot('21')
39
+ Model.create_snapshot('22')
40
+ Model.create_snapshot('33')
41
+
42
+ to_delete = Model.snapshots.select do |snapname|
43
+ # return true for all tables with names divisble by 11
44
+ name = /(\d+)$/.match(snapname)[1]
45
+ (name.to_i % 11) == 0
46
+ end
47
+ Model.delete_snapshots(to_delete)
48
+ expect(Model.snapshots.sort).to eq ['models_21']
49
+ end
50
+ end
@@ -0,0 +1,64 @@
1
+ require 'table_differ'
2
+ require 'database_cleaner'
3
+
4
+
5
+ RSpec.configure do |config|
6
+ config.order = :random
7
+
8
+ config.expect_with :rspec do |expectations|
9
+ # Enable only the newer, non-monkey-patching expect syntax.
10
+ expectations.syntax = :expect
11
+ end
12
+
13
+ config.before(:suite) do
14
+ if false
15
+ ActiveRecord::Base.logger = Logger.new(STDERR)
16
+ ActiveRecord::Base.logger.level = Logger::ERROR
17
+ ActiveRecord::Base.logger.level = Logger::DEBUG
18
+ end
19
+
20
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
21
+
22
+ ActiveRecord::Schema.define do
23
+ create_table :models do |table|
24
+ table.column :name, :string
25
+ end
26
+ end
27
+
28
+ # need to explicitly specify active_record since we don't have a database.yml?
29
+ DatabaseCleaner[:active_record].strategy = :transaction
30
+ DatabaseCleaner.clean_with(:truncation)
31
+ end
32
+
33
+ config.around(:each) do |example|
34
+ DatabaseCleaner.cleaning do
35
+ example.run
36
+ end
37
+ end
38
+ end
39
+
40
+
41
+ RSpec.shared_context "model" do
42
+ class Model < ActiveRecord::Base
43
+ include TableDiffer
44
+ end
45
+ end
46
+
47
+ =begin
48
+ maybe later...
49
+
50
+ # Many RSpec users commonly either run the entire suite or an individual
51
+ # file, and it's useful to allow more verbose output when running an
52
+ # individual spec file.
53
+ if config.files_to_run.one?
54
+ # Use the documentation formatter for detailed output,
55
+ # unless a formatter has already been configured
56
+ # (e.g. via a command-line flag).
57
+ config.default_formatter = 'doc'
58
+ end
59
+
60
+ # Print the 10 slowest examples and example groups at the
61
+ # end of the spec run, to help surface which specs are running
62
+ # particularly slow.
63
+ config.profile_examples = 10
64
+ =end
@@ -0,0 +1,27 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'table_differ/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "table_differ"
7
+ spec.version = TableDiffer::VERSION
8
+ spec.authors = ["Scott Bronson"]
9
+ spec.email = ["brons_tablediffer@rinspin.com"]
10
+ spec.summary = %q{Take snapshots of database tables and compute the differences between two snapshots.}
11
+ # spec.description = %q{}
12
+ spec.homepage = "https://github.com/bronson/table_differ"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_runtime_dependency "activerecord"
21
+
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ # spec.add_development_dependency "rspec_around_all"
25
+ spec.add_development_dependency "database_cleaner"
26
+ spec.add_development_dependency "sqlite3"
27
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: table_differ
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Scott Bronson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-27 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: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '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: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '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: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: database_cleaner
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description:
84
+ email:
85
+ - brons_tablediffer@rinspin.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - CHANGELOG.md
94
+ - Gemfile
95
+ - Guardfile
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - TODO
100
+ - lib/table_differ.rb
101
+ - lib/table_differ/version.rb
102
+ - spec/diff_spec.rb
103
+ - spec/snapshot_spec.rb
104
+ - spec/spec_helper.rb
105
+ - tablediffer.gemspec
106
+ homepage: https://github.com/bronson/table_differ
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.2.2
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Take snapshots of database tables and compute the differences between two
130
+ snapshots.
131
+ test_files:
132
+ - spec/diff_spec.rb
133
+ - spec/snapshot_spec.rb
134
+ - spec/spec_helper.rb