table_differ 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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