mongoid-history 0.8.3 → 0.8.5

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.
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