mongoid-history 0.8.3 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -1
  3. data/.document +5 -5
  4. data/.github/workflows/test.yml +72 -0
  5. data/.gitignore +46 -46
  6. data/.rspec +2 -2
  7. data/.rubocop.yml +6 -6
  8. data/.rubocop_todo.yml +99 -99
  9. data/CHANGELOG.md +173 -163
  10. data/CONTRIBUTING.md +117 -118
  11. data/Dangerfile +1 -1
  12. data/Gemfile +49 -40
  13. data/LICENSE.txt +20 -20
  14. data/README.md +609 -608
  15. data/RELEASING.md +66 -67
  16. data/Rakefile +24 -24
  17. data/UPGRADING.md +53 -53
  18. data/lib/mongoid/history/attributes/base.rb +72 -72
  19. data/lib/mongoid/history/attributes/create.rb +45 -45
  20. data/lib/mongoid/history/attributes/destroy.rb +34 -34
  21. data/lib/mongoid/history/attributes/update.rb +104 -104
  22. data/lib/mongoid/history/options.rb +177 -177
  23. data/lib/mongoid/history/trackable.rb +588 -583
  24. data/lib/mongoid/history/tracker.rb +247 -247
  25. data/lib/mongoid/history/version.rb +5 -5
  26. data/lib/mongoid/history.rb +77 -77
  27. data/lib/mongoid-history.rb +1 -1
  28. data/mongoid-history.gemspec +25 -25
  29. data/perf/benchmark_modified_attributes_for_create.rb +65 -65
  30. data/perf/gc_suite.rb +21 -21
  31. data/spec/integration/embedded_in_polymorphic_spec.rb +112 -112
  32. data/spec/integration/integration_spec.rb +976 -976
  33. data/spec/integration/multi_relation_spec.rb +47 -47
  34. data/spec/integration/multiple_trackers_spec.rb +68 -68
  35. data/spec/integration/nested_embedded_documents_spec.rb +64 -64
  36. data/spec/integration/nested_embedded_documents_tracked_in_parent_spec.rb +124 -124
  37. data/spec/integration/nested_embedded_polymorphic_documents_spec.rb +115 -115
  38. data/spec/integration/subclasses_spec.rb +47 -47
  39. data/spec/integration/track_history_order_spec.rb +84 -84
  40. data/spec/integration/validation_failure_spec.rb +76 -76
  41. data/spec/spec_helper.rb +32 -30
  42. data/spec/support/error_helpers.rb +7 -0
  43. data/spec/support/mongoid.rb +11 -11
  44. data/spec/support/mongoid_history.rb +12 -12
  45. data/spec/unit/attributes/base_spec.rb +141 -141
  46. data/spec/unit/attributes/create_spec.rb +342 -342
  47. data/spec/unit/attributes/destroy_spec.rb +228 -228
  48. data/spec/unit/attributes/update_spec.rb +342 -342
  49. data/spec/unit/callback_options_spec.rb +165 -165
  50. data/spec/unit/embedded_methods_spec.rb +87 -87
  51. data/spec/unit/history_spec.rb +58 -58
  52. data/spec/unit/my_instance_methods_spec.rb +555 -555
  53. data/spec/unit/options_spec.rb +365 -365
  54. data/spec/unit/singleton_methods_spec.rb +406 -406
  55. data/spec/unit/store/default_store_spec.rb +11 -11
  56. data/spec/unit/store/request_store_spec.rb +13 -13
  57. data/spec/unit/trackable_spec.rb +1057 -987
  58. data/spec/unit/tracker_spec.rb +190 -190
  59. metadata +9 -7
  60. data/.travis.yml +0 -36
@@ -1,25 +1,25 @@
1
- $LOAD_PATH.push File.expand_path('../lib', __FILE__)
2
- require 'mongoid/history/version'
3
-
4
- Gem::Specification.new do |s|
5
- s.name = 'mongoid-history'
6
- s.version = Mongoid::History::VERSION
7
- s.authors = ['Aaron Qian', 'Justin Grimes', 'Daniel Doubrovkine']
8
- s.summary = 'Track and audit, undo and redo changes on Mongoid documents.'
9
- s.description = 'This library tracks historical changes for any document, including embedded ones. It achieves this by storing all history tracks in a single collection that you define. Embedded documents are referenced by storing an association path, which is an array of document_name and document_id fields starting from the top most parent document and down to the embedded document that should track history. Mongoid-history implements multi-user undo, which allows users to undo any history change in any order. Undoing a document also creates a new history track. This is great for auditing and preventing vandalism, but it is probably not suitable for use cases such as a wiki.'
10
- s.email = ['aq1018@gmail.com', 'justin.mgrimes@gmail.com', 'dblock@dblock.org']
11
- s.homepage = 'http://github.com/mongoid/mongoid-history'
12
- s.license = 'MIT'
13
-
14
- s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
15
- s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
- s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
- s.require_paths = ['lib']
18
-
19
- s.post_install_message = File.read('UPGRADING') if File.exist?('UPGRADING')
20
-
21
- s.add_runtime_dependency 'easy_diff'
22
- s.add_runtime_dependency 'mongoid', '>= 3.0'
23
- s.add_runtime_dependency 'mongoid-compatibility', '>= 0.5.1'
24
- s.add_runtime_dependency 'activesupport'
25
- end
1
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
2
+ require 'mongoid/history/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'mongoid-history'
6
+ s.version = Mongoid::History::VERSION
7
+ s.authors = ['Aaron Qian', 'Justin Grimes', 'Daniel Doubrovkine']
8
+ s.summary = 'Track and audit, undo and redo changes on Mongoid documents.'
9
+ s.description = 'This library tracks historical changes for any document, including embedded ones. It achieves this by storing all history tracks in a single collection that you define. Embedded documents are referenced by storing an association path, which is an array of document_name and document_id fields starting from the top most parent document and down to the embedded document that should track history. Mongoid-history implements multi-user undo, which allows users to undo any history change in any order. Undoing a document also creates a new history track. This is great for auditing and preventing vandalism, but it is probably not suitable for use cases such as a wiki.'
10
+ s.email = ['aq1018@gmail.com', 'justin.mgrimes@gmail.com', 'dblock@dblock.org']
11
+ s.homepage = 'http://github.com/mongoid/mongoid-history'
12
+ s.license = 'MIT'
13
+
14
+ s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
15
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
+ s.require_paths = ['lib']
18
+
19
+ s.post_install_message = File.read('UPGRADING') if File.exist?('UPGRADING')
20
+
21
+ s.add_runtime_dependency 'easy_diff'
22
+ s.add_runtime_dependency 'mongoid', '>= 3.0'
23
+ s.add_runtime_dependency 'mongoid-compatibility', '>= 0.5.1'
24
+ s.add_runtime_dependency 'activesupport'
25
+ end
@@ -1,65 +1,65 @@
1
- $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
-
3
- require 'mongoid'
4
- require 'mongoid/history'
5
-
6
- require 'benchmark/ips'
7
- require './perf/gc_suite'
8
-
9
- Mongoid.connect_to('mongoid_history_perf_test')
10
- Mongo::Logger.logger.level = ::Logger::FATAL
11
- Mongoid.purge!
12
-
13
- Attributes = Mongoid::History::Attributes
14
-
15
- module ZeroPointEight
16
- class Create < Attributes::Create
17
- def attributes
18
- @attributes = {}
19
- trackable.attributes.each do |k, v|
20
- next unless trackable_class.tracked_field?(k, :create)
21
- modified = if changes[k]
22
- changes[k].class == Array ? changes[k].last : changes[k]
23
- else
24
- v
25
- end
26
- @attributes[k] = [nil, format_field(k, modified)]
27
- end
28
- insert_embeds_one_changes
29
- insert_embeds_many_changes
30
- @attributes
31
- end
32
- end
33
- end
34
-
35
- class Person
36
- include Mongoid::Document
37
- include Mongoid::History::Trackable
38
-
39
- field :first_name, type: String
40
- field :last_name, type: String
41
- field :birth_date, type: Date
42
- field :title, type: String
43
-
44
- track_history on: %i[first_name last_name birth_date]
45
- end
46
-
47
- new_person = Person.new(first_name: 'Eliot', last_name: 'Horowitz', birth_date: '1981-05-01', title: 'CTO')
48
-
49
- Benchmark.ips do |bm|
50
- bm.config(suite: GCSuite.new)
51
-
52
- bm.report('HEAD') do
53
- Attributes::Create.new(new_person).attributes
54
- end
55
-
56
- bm.report('v0.8.2') do
57
- ZeroPointEight::Create.new(new_person).attributes
58
- end
59
-
60
- bm.report('v0.5.0') do
61
- new_person.attributes.each_with_object({}) { |(k, v), h| h[k] = [nil, v] }.select { |k, _| new_person.class.tracked_field?(k, :create) }
62
- end
63
-
64
- bm.compare!
65
- end
1
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'mongoid'
4
+ require 'mongoid/history'
5
+
6
+ require 'benchmark/ips'
7
+ require './perf/gc_suite'
8
+
9
+ Mongoid.connect_to('mongoid_history_perf_test')
10
+ Mongo::Logger.logger.level = ::Logger::FATAL
11
+ Mongoid.purge!
12
+
13
+ Attributes = Mongoid::History::Attributes
14
+
15
+ module ZeroPointEight
16
+ class Create < Attributes::Create
17
+ def attributes
18
+ @attributes = {}
19
+ trackable.attributes.each do |k, v|
20
+ next unless trackable_class.tracked_field?(k, :create)
21
+ modified = if changes[k]
22
+ changes[k].class == Array ? changes[k].last : changes[k]
23
+ else
24
+ v
25
+ end
26
+ @attributes[k] = [nil, format_field(k, modified)]
27
+ end
28
+ insert_embeds_one_changes
29
+ insert_embeds_many_changes
30
+ @attributes
31
+ end
32
+ end
33
+ end
34
+
35
+ class Person
36
+ include Mongoid::Document
37
+ include Mongoid::History::Trackable
38
+
39
+ field :first_name, type: String
40
+ field :last_name, type: String
41
+ field :birth_date, type: Date
42
+ field :title, type: String
43
+
44
+ track_history on: %i[first_name last_name birth_date]
45
+ end
46
+
47
+ new_person = Person.new(first_name: 'Eliot', last_name: 'Horowitz', birth_date: '1981-05-01', title: 'CTO')
48
+
49
+ Benchmark.ips do |bm|
50
+ bm.config(suite: GCSuite.new)
51
+
52
+ bm.report('HEAD') do
53
+ Attributes::Create.new(new_person).attributes
54
+ end
55
+
56
+ bm.report('v0.8.2') do
57
+ ZeroPointEight::Create.new(new_person).attributes
58
+ end
59
+
60
+ bm.report('v0.5.0') do
61
+ new_person.attributes.each_with_object({}) { |(k, v), h| h[k] = [nil, v] }.select { |k, _| new_person.class.tracked_field?(k, :create) }
62
+ end
63
+
64
+ bm.compare!
65
+ end
data/perf/gc_suite.rb CHANGED
@@ -1,21 +1,21 @@
1
- class GCSuite
2
- def warming(*)
3
- run_gc
4
- end
5
-
6
- def running(*)
7
- run_gc
8
- end
9
-
10
- def warmup_stats(*); end
11
-
12
- def add_report(*); end
13
-
14
- private
15
-
16
- def run_gc
17
- GC.enable
18
- GC.start
19
- GC.disable
20
- end
21
- end
1
+ class GCSuite
2
+ def warming(*)
3
+ run_gc
4
+ end
5
+
6
+ def running(*)
7
+ run_gc
8
+ end
9
+
10
+ def warmup_stats(*); end
11
+
12
+ def add_report(*); end
13
+
14
+ private
15
+
16
+ def run_gc
17
+ GC.enable
18
+ GC.start
19
+ GC.disable
20
+ end
21
+ end
@@ -1,112 +1,112 @@
1
- require 'spec_helper'
2
-
3
- describe Mongoid::History::Tracker do
4
- before :each do
5
- class RealState
6
- include Mongoid::Document
7
- include Mongoid::History::Trackable
8
-
9
- field :name, type: String
10
- belongs_to :user
11
- embeds_one :address, class_name: 'Contact', as: :contactable
12
- embeds_one :embone, as: :embedable
13
-
14
- track_history
15
- end
16
-
17
- class Company
18
- include Mongoid::Document
19
- include Mongoid::History::Trackable
20
-
21
- field :name
22
- belongs_to :user
23
- embeds_one :address, class_name: 'Contact', as: :contactable
24
- embeds_one :second_address, class_name: 'Contact', as: :contactable
25
- embeds_one :embone, as: :embedable
26
-
27
- track_history
28
- end
29
-
30
- class Embone
31
- include Mongoid::Document
32
- include Mongoid::History::Trackable
33
-
34
- field :name
35
- embedded_in :embedable, polymorphic: true
36
-
37
- track_history scope: :embedable
38
- end
39
-
40
- class Contact
41
- include Mongoid::Document
42
- include Mongoid::History::Trackable
43
-
44
- field :address
45
- field :city
46
- field :state
47
- embedded_in :contactable, polymorphic: true
48
-
49
- track_history scope: %i[real_state company]
50
- end
51
-
52
- class User
53
- include Mongoid::Document
54
- has_many :companies, dependent: :destroy
55
- has_many :real_states, dependent: :destroy
56
- end
57
- end
58
-
59
- after :each do
60
- Object.send(:remove_const, :RealState)
61
- Object.send(:remove_const, :Company)
62
- Object.send(:remove_const, :Embone)
63
- Object.send(:remove_const, :Contact)
64
- Object.send(:remove_const, :User)
65
- end
66
-
67
- let!(:user) { User.create! }
68
-
69
- it 'tracks history for nested embedded documents with polymorphic relations' do
70
- real_state = user.real_states.build(name: 'rs_name', modifier: user)
71
- real_state.save!
72
- real_state.build_address(address: 'Main Street #123', city: 'Highland Park', state: 'IL', modifier: user).save!
73
- expect(real_state.history_tracks.count).to eq(2)
74
- expect(real_state.address.history_tracks.count).to eq(1)
75
-
76
- real_state.reload
77
- real_state.address.update_attributes!(address: 'Second Street', modifier: user)
78
- expect(real_state.history_tracks.count).to eq(3)
79
- expect(real_state.address.history_tracks.count).to eq(2)
80
- expect(real_state.history_tracks.last.action).to eq('update')
81
-
82
- real_state.build_embone(name: 'Lorem ipsum', modifier: user).save!
83
- expect(real_state.history_tracks.count).to eq(4)
84
- expect(real_state.embone.history_tracks.count).to eq(1)
85
- expect(real_state.embone.history_tracks.last.action).to eq('create')
86
- expect(real_state.embone.history_tracks.last.association_chain.last['name']).to eq('embone')
87
-
88
- company = user.companies.build(name: 'co_name', modifier: user)
89
- company.save!
90
- company.build_address(address: 'Main Street #456', city: 'Evanston', state: 'IL', modifier: user).save!
91
- expect(company.history_tracks.count).to eq(2)
92
- expect(company.address.history_tracks.count).to eq(1)
93
-
94
- company.reload
95
- company.address.update_attributes!(address: 'Second Street', modifier: user)
96
- expect(company.history_tracks.count).to eq(3)
97
- expect(company.address.history_tracks.count).to eq(2)
98
- expect(company.history_tracks.last.action).to eq('update')
99
-
100
- company.build_second_address(address: 'Main Street #789', city: 'Highland Park', state: 'IL', modifier: user).save!
101
- expect(company.history_tracks.count).to eq(4)
102
- expect(company.second_address.history_tracks.count).to eq(1)
103
- expect(company.second_address.history_tracks.last.action).to eq('create')
104
- expect(company.second_address.history_tracks.last.association_chain.last['name']).to eq('second_address')
105
-
106
- company.build_embone(name: 'Lorem ipsum', modifier: user).save!
107
- expect(company.history_tracks.count).to eq(5)
108
- expect(company.embone.history_tracks.count).to eq(1)
109
- expect(company.embone.history_tracks.last.action).to eq('create')
110
- expect(company.embone.history_tracks.last.association_chain.last['name']).to eq('embone')
111
- end
112
- end
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::History::Tracker do
4
+ before :each do
5
+ class RealState
6
+ include Mongoid::Document
7
+ include Mongoid::History::Trackable
8
+
9
+ field :name, type: String
10
+ belongs_to :user
11
+ embeds_one :address, class_name: 'Contact', as: :contactable
12
+ embeds_one :embone, as: :embedable
13
+
14
+ track_history
15
+ end
16
+
17
+ class Company
18
+ include Mongoid::Document
19
+ include Mongoid::History::Trackable
20
+
21
+ field :name
22
+ belongs_to :user
23
+ embeds_one :address, class_name: 'Contact', as: :contactable
24
+ embeds_one :second_address, class_name: 'Contact', as: :contactable
25
+ embeds_one :embone, as: :embedable
26
+
27
+ track_history
28
+ end
29
+
30
+ class Embone
31
+ include Mongoid::Document
32
+ include Mongoid::History::Trackable
33
+
34
+ field :name
35
+ embedded_in :embedable, polymorphic: true
36
+
37
+ track_history scope: :embedable
38
+ end
39
+
40
+ class Contact
41
+ include Mongoid::Document
42
+ include Mongoid::History::Trackable
43
+
44
+ field :address
45
+ field :city
46
+ field :state
47
+ embedded_in :contactable, polymorphic: true
48
+
49
+ track_history scope: %i[real_state company]
50
+ end
51
+
52
+ class User
53
+ include Mongoid::Document
54
+ has_many :companies, dependent: :destroy
55
+ has_many :real_states, dependent: :destroy
56
+ end
57
+ end
58
+
59
+ after :each do
60
+ Object.send(:remove_const, :RealState)
61
+ Object.send(:remove_const, :Company)
62
+ Object.send(:remove_const, :Embone)
63
+ Object.send(:remove_const, :Contact)
64
+ Object.send(:remove_const, :User)
65
+ end
66
+
67
+ let!(:user) { User.create! }
68
+
69
+ it 'tracks history for nested embedded documents with polymorphic relations' do
70
+ real_state = user.real_states.build(name: 'rs_name', modifier: user)
71
+ real_state.save!
72
+ real_state.build_address(address: 'Main Street #123', city: 'Highland Park', state: 'IL', modifier: user).save!
73
+ expect(real_state.history_tracks.count).to eq(2)
74
+ expect(real_state.address.history_tracks.count).to eq(1)
75
+
76
+ real_state.reload
77
+ real_state.address.update_attributes!(address: 'Second Street', modifier: user)
78
+ expect(real_state.history_tracks.count).to eq(3)
79
+ expect(real_state.address.history_tracks.count).to eq(2)
80
+ expect(real_state.history_tracks.last.action).to eq('update')
81
+
82
+ real_state.build_embone(name: 'Lorem ipsum', modifier: user).save!
83
+ expect(real_state.history_tracks.count).to eq(4)
84
+ expect(real_state.embone.history_tracks.count).to eq(1)
85
+ expect(real_state.embone.history_tracks.last.action).to eq('create')
86
+ expect(real_state.embone.history_tracks.last.association_chain.last['name']).to eq('embone')
87
+
88
+ company = user.companies.build(name: 'co_name', modifier: user)
89
+ company.save!
90
+ company.build_address(address: 'Main Street #456', city: 'Evanston', state: 'IL', modifier: user).save!
91
+ expect(company.history_tracks.count).to eq(2)
92
+ expect(company.address.history_tracks.count).to eq(1)
93
+
94
+ company.reload
95
+ company.address.update_attributes!(address: 'Second Street', modifier: user)
96
+ expect(company.history_tracks.count).to eq(3)
97
+ expect(company.address.history_tracks.count).to eq(2)
98
+ expect(company.history_tracks.last.action).to eq('update')
99
+
100
+ company.build_second_address(address: 'Main Street #789', city: 'Highland Park', state: 'IL', modifier: user).save!
101
+ expect(company.history_tracks.count).to eq(4)
102
+ expect(company.second_address.history_tracks.count).to eq(1)
103
+ expect(company.second_address.history_tracks.last.action).to eq('create')
104
+ expect(company.second_address.history_tracks.last.association_chain.last['name']).to eq('second_address')
105
+
106
+ company.build_embone(name: 'Lorem ipsum', modifier: user).save!
107
+ expect(company.history_tracks.count).to eq(5)
108
+ expect(company.embone.history_tracks.count).to eq(1)
109
+ expect(company.embone.history_tracks.last.action).to eq('create')
110
+ expect(company.embone.history_tracks.last.association_chain.last['name']).to eq('embone')
111
+ end
112
+ end