userstamper 4.0.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.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +35 -0
  5. data/CHANGELOG.md +116 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +222 -0
  8. data/LICENSE +22 -0
  9. data/README.md +142 -0
  10. data/lib/userstamper.rb +23 -0
  11. data/lib/userstamper/configuration.rb +40 -0
  12. data/lib/userstamper/controller_concern.rb +44 -0
  13. data/lib/userstamper/migration_concern.rb +9 -0
  14. data/lib/userstamper/model_concern.rb +6 -0
  15. data/lib/userstamper/railtie.rb +15 -0
  16. data/lib/userstamper/stampable.rb +106 -0
  17. data/lib/userstamper/stamper.rb +54 -0
  18. data/lib/userstamper/utilities.rb +57 -0
  19. data/spec/controllers/posts_controller_spec.rb +44 -0
  20. data/spec/controllers/users_controller_spec.rb +50 -0
  21. data/spec/coverage_helper.rb +58 -0
  22. data/spec/dummy/README.rdoc +28 -0
  23. data/spec/dummy/Rakefile +6 -0
  24. data/spec/dummy/app/assets/config/manifest.js +0 -0
  25. data/spec/dummy/app/assets/images/.keep +0 -0
  26. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  27. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  28. data/spec/dummy/app/controllers/application_controller.rb +13 -0
  29. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  30. data/spec/dummy/app/controllers/posts_controller.rb +36 -0
  31. data/spec/dummy/app/controllers/users_controller.rb +22 -0
  32. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  33. data/spec/dummy/app/mailers/.keep +0 -0
  34. data/spec/dummy/app/models/comment.rb +5 -0
  35. data/spec/dummy/app/models/concerns/.keep +0 -0
  36. data/spec/dummy/app/models/person.rb +3 -0
  37. data/spec/dummy/app/models/post.rb +6 -0
  38. data/spec/dummy/app/models/tag.rb +3 -0
  39. data/spec/dummy/app/models/user.rb +3 -0
  40. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  41. data/spec/dummy/bin/bundle +3 -0
  42. data/spec/dummy/bin/rails +4 -0
  43. data/spec/dummy/bin/rake +4 -0
  44. data/spec/dummy/bin/setup +29 -0
  45. data/spec/dummy/config.ru +4 -0
  46. data/spec/dummy/config/application.rb +12 -0
  47. data/spec/dummy/config/boot.rb +5 -0
  48. data/spec/dummy/config/database.yml +23 -0
  49. data/spec/dummy/config/environment.rb +5 -0
  50. data/spec/dummy/config/environments/development.rb +41 -0
  51. data/spec/dummy/config/environments/production.rb +79 -0
  52. data/spec/dummy/config/environments/test.rb +37 -0
  53. data/spec/dummy/config/initializers/assets.rb +11 -0
  54. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  55. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  56. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  57. data/spec/dummy/config/initializers/inflections.rb +16 -0
  58. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  59. data/spec/dummy/config/initializers/session_store.rb +3 -0
  60. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  61. data/spec/dummy/config/locales/en.yml +23 -0
  62. data/spec/dummy/config/routes.rb +56 -0
  63. data/spec/dummy/config/secrets.yml +22 -0
  64. data/spec/dummy/lib/assets/.keep +0 -0
  65. data/spec/dummy/log/.keep +0 -0
  66. data/spec/dummy/public/404.html +67 -0
  67. data/spec/dummy/public/422.html +67 -0
  68. data/spec/dummy/public/500.html +66 -0
  69. data/spec/dummy/public/favicon.ico +0 -0
  70. data/spec/lib/configuration_spec.rb +20 -0
  71. data/spec/lib/migration_spec.rb +60 -0
  72. data/spec/lib/stamper_spec.rb +66 -0
  73. data/spec/lib/stamping_spec.rb +235 -0
  74. data/spec/lib/userstamp_spec.rb +4 -0
  75. data/spec/rails_helper.rb +7 -0
  76. data/spec/spec_helper.rb +98 -0
  77. data/spec/support/database_helpers.rb +73 -0
  78. data/spec/support/with_temporary_table.rb +51 -0
  79. data/userstamper.gemspec +46 -0
  80. metadata +279 -0
@@ -0,0 +1,60 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe 'Migration helpers', type: :model do
4
+ context 'when default attribute names are used' do
5
+ class self::DefaultRandom < ActiveRecord::Base
6
+ stampable
7
+ end
8
+ subject { self.class::DefaultRandom.new }
9
+
10
+ temporary_table(:default_randoms) do |t|
11
+ t.userstamps(null: false)
12
+ end
13
+
14
+ with_temporary_table(:default_randoms) do
15
+ it 'has a creator_id association' do
16
+ expect(subject.has_attribute?(:creator_id)).to be true
17
+ expect(subject.class.columns.find {|c| c.name == 'creator_id' }.null).to be false
18
+ end
19
+
20
+ it 'has an updater_id association' do
21
+ expect(subject.has_attribute?(:updater_id)).to be true
22
+ expect(subject.class.columns.find {|c| c.name == 'updater_id' }.null).to be false
23
+ end
24
+ end
25
+ end
26
+
27
+ context 'when overridden attribute names are used' do
28
+ before(:each) do
29
+ Userstamper.configure do |config|
30
+ config.creator_attribute = :created_by
31
+ config.updater_attribute = :updated_by
32
+ end
33
+ class self.class::OverriddenRandom < ActiveRecord::Base
34
+ stampable
35
+ end
36
+ end
37
+ after(:each) do
38
+ Userstamper.configure do |config|
39
+ config.creator_attribute = :creator_id
40
+ config.updater_attribute = :updater_id
41
+ end
42
+ end
43
+
44
+ subject { self.class::OverriddenRandom.new }
45
+
46
+ temporary_table(:overridden_randoms) do |t|
47
+ t.userstamps
48
+ end
49
+
50
+ with_temporary_table(:overridden_randoms, :each) do
51
+ it 'has a created_by attribute' do
52
+ expect(subject.has_attribute?(:created_by)).to be true
53
+ end
54
+
55
+ it 'has an updated_by attribute' do
56
+ expect(subject.has_attribute?(:updated_by)).to be true
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,66 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe 'Stamper' do
4
+ describe '.model_stamper' do
5
+ it 'can only be included once' do
6
+ expect(User.singleton_class.included_modules.count(
7
+ Userstamper::Stamper::InstanceMethods)).to eq(1)
8
+
9
+ User.class_eval do
10
+ stamper
11
+ end
12
+
13
+ expect(User.singleton_class.included_modules.count(
14
+ Userstamper::Stamper::InstanceMethods)).to eq(1)
15
+ end
16
+ end
17
+
18
+ describe '.stamper' do
19
+ it 'defaults to nil' do
20
+ User.reset_stamper
21
+ expect(User.stamper).to be_nil
22
+ end
23
+ end
24
+
25
+ describe '.stamper=' do
26
+ it 'assigns the stamper' do
27
+ stamper = User.new
28
+ User.stamper = stamper
29
+ expect(User.stamper).to eq(stamper)
30
+ end
31
+
32
+ context 'when the stamper is nil' do
33
+ it 'resets the stamper' do
34
+ User.stamper = nil
35
+ expect(User.stamper).to be(nil)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe '.reset_stamper' do
41
+ it 'resets the stamper' do
42
+ User.reset_stamper
43
+ expect(User.stamper).to be_nil
44
+ end
45
+ end
46
+
47
+ describe '.with_stamper' do
48
+ context 'when within the block' do
49
+ it 'uses the correct stamper' do
50
+ stamper = User.create(name: 'Joel')
51
+ User.with_stamper(stamper) do
52
+ expect(User.stamper).to eq(stamper)
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'when exiting the block' do
58
+ it 'restores the stamper' do
59
+ expect do
60
+ User.with_stamper(User.create(name: 'Joel')) do
61
+ end
62
+ end.not_to change { User.stamper }
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,235 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe 'Stamping', type: :model do
4
+ before(:each) do
5
+ define_first_post
6
+ User.stamper = @zeus
7
+ Person.stamper = @delynn
8
+ end
9
+
10
+ context 'when creating a Person' do
11
+ context 'when the stamper is an object' do
12
+ it 'sets using the the association' do
13
+ User.stamper = @zeus
14
+ expect(User.stamper).to eq(@zeus)
15
+
16
+ person = Person.new
17
+ expect(person).to receive(:creator=)
18
+ person.valid?
19
+ end
20
+
21
+ it 'sets the correct creator and updater' do
22
+ expect(User.stamper).to eq(@zeus)
23
+
24
+ person = Person.create(name: 'David')
25
+ expect(person.creator_id).to eq(@zeus.id)
26
+ expect(person.updater_id).to eq(@zeus.id)
27
+ expect(person.creator).to eq(@zeus)
28
+ expect(person.updater).to eq(@zeus)
29
+ end
30
+
31
+ context 'when a creator is specified' do
32
+ it 'does not reset the creator' do
33
+ expect(User.stamper).to eq(@zeus)
34
+
35
+ person = Person.create(name: 'David', creator: @hera)
36
+ expect(person.creator_id).to eq(@hera.id)
37
+ expect(person.updater_id).to eq(@zeus.id)
38
+ expect(person.creator).to eq(@hera)
39
+ expect(person.updater).to eq(@zeus)
40
+ end
41
+
42
+ it 'does not reset the creator' do
43
+ expect(User.stamper).to eq(@zeus)
44
+
45
+ person = Person.create(name: 'David', creator_id: @hera.id)
46
+ expect(person.creator_id).to eq(@hera.id)
47
+ expect(person.updater_id).to eq(@zeus.id)
48
+ expect(person.creator).to eq(@hera)
49
+ expect(person.updater).to eq(@zeus)
50
+ end
51
+ end
52
+
53
+ context 'when saving without validations' do
54
+ it 'sets the correct creator and updater' do
55
+ expect(User.stamper).to eq(@zeus)
56
+
57
+ person = Person.new(name: 'David')
58
+ person.save(validate: false)
59
+ expect(person.creator_id).to eq(@zeus.id)
60
+ expect(person.updater_id).to eq(@zeus.id)
61
+ expect(person.creator).to eq(@zeus)
62
+ expect(person.updater).to eq(@zeus)
63
+ end
64
+ end
65
+
66
+ context 'when temporarily disabling stampng' do
67
+ it 'does not set the creator and updater' do
68
+ expect(User.stamper).to eq(@zeus)
69
+
70
+ Person.without_stamps do
71
+ person = Person.create(name: 'David')
72
+ expect(person.creator_id).to be_nil
73
+ expect(person.updater_id).to be_nil
74
+ expect(person.creator).to be_nil
75
+ expect(person.updater).to be_nil
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ context 'when the stamper is an ID' do
82
+ it 'sets using the the association ID' do
83
+ User.stamper = @zeus.id
84
+ expect(User.stamper).to eq(@zeus.id)
85
+
86
+ person = Person.new
87
+ expect(person).to receive(:creator_id=)
88
+ person.valid?
89
+ end
90
+
91
+ it 'sets the correct creator and updater' do
92
+ User.stamper = @hera.id
93
+ expect(User.stamper).to eq(@hera.id)
94
+
95
+ person = Person.create(name: 'Daniel')
96
+ expect(person.creator_id).to eq(@hera.id)
97
+ expect(person.updater_id).to eq(@hera.id)
98
+ expect(person.creator).to eq(@hera)
99
+ expect(person.updater).to eq(@hera)
100
+ end
101
+ end
102
+ end
103
+
104
+ context 'when creating a Post' do
105
+ context 'when the stamper is an object' do
106
+ it 'sets the correct creator and updater' do
107
+ expect(Person.stamper).to eq(@delynn)
108
+
109
+ post = Post.create(title: 'Test Post - 1')
110
+ expect(post.creator_id).to eq(@delynn.id)
111
+ expect(post.updater_id).to eq(@delynn.id)
112
+ expect(post.creator).to eq(@delynn)
113
+ expect(post.updater).to eq(@delynn)
114
+ end
115
+ end
116
+
117
+ context 'when the stamper is an ID' do
118
+ it 'sets the correct creator and updater' do
119
+ Person.stamper = @nicole.id
120
+ expect(Person.stamper).to eq(@nicole.id)
121
+
122
+ post = Post.create(title: 'Test Post - 2')
123
+ expect(post.creator_id).to eq(@nicole.id)
124
+ expect(post.updater_id).to eq(@nicole.id)
125
+ expect(post.creator).to eq(@nicole)
126
+ expect(post.updater).to eq(@nicole)
127
+ end
128
+ end
129
+ end
130
+
131
+ context 'when updating a Person' do
132
+ context 'when the stamper is an object' do
133
+ it 'sets the correct updater' do
134
+ User.stamper = @hera
135
+ expect(User.stamper).to eq(@hera)
136
+
137
+ @delynn.name = @delynn.name + " Berry"
138
+ @delynn.save
139
+ @delynn.reload
140
+ expect(@delynn.creator).to eq(@zeus)
141
+ expect(@delynn.updater).to eq(@hera)
142
+ expect(@delynn.creator_id).to eq(@zeus.id)
143
+ expect(@delynn.updater_id).to eq(@hera.id)
144
+ end
145
+ end
146
+
147
+ context 'when the stamper is an ID' do
148
+ it 'sets the correct updater' do
149
+ User.stamper = @hera.id
150
+ expect(User.stamper).to eq(@hera.id)
151
+
152
+ @delynn.name = @delynn.name + " Berry"
153
+ @delynn.save
154
+ @delynn.reload
155
+ expect(@delynn.creator_id).to eq(@zeus.id)
156
+ expect(@delynn.updater_id).to eq(@hera.id)
157
+ expect(@delynn.creator).to eq(@zeus)
158
+ expect(@delynn.updater).to eq(@hera)
159
+ end
160
+ end
161
+
162
+ context 'when temporarily disabling stamping' do
163
+ it 'does not set the updater' do
164
+ User.stamper = @zeus
165
+ expect(User.stamper).to eq(@zeus)
166
+
167
+ original_updater = @delynn.updater
168
+ Person.without_stamps do
169
+ @delynn.name << " Berry"
170
+ @delynn.save
171
+ @delynn.reload
172
+ expect(@delynn.creator).to eq(@zeus)
173
+ expect(@delynn.updater).to eq(original_updater)
174
+ expect(@delynn.creator_id).to eq(@zeus.id)
175
+ expect(@delynn.updater_id).to eq(original_updater.id)
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ context 'when updating a Post' do
182
+ context 'when the stamper is an ID' do
183
+ it 'sets the correct updater' do
184
+ Person.stamper = @nicole.id
185
+ expect(Person.stamper).to eq(@nicole.id)
186
+
187
+ @first_post.title = @first_post.title + " - Updated"
188
+ @first_post.save
189
+ @first_post.reload
190
+ expect(@first_post.creator_id).to eq(@delynn.id)
191
+ expect(@first_post.updater_id).to eq(@nicole.id)
192
+ expect(@first_post.creator).to eq(@delynn)
193
+ expect(@first_post.updater).to eq(@nicole)
194
+ end
195
+ end
196
+
197
+ context 'when the stamper is an object' do
198
+ it 'sets the correct updater' do
199
+ Person.stamper = @nicole
200
+ expect(Person.stamper).to eq(@nicole)
201
+
202
+ @first_post.title = @first_post.title + " - Updated"
203
+ @first_post.save
204
+ @first_post.reload
205
+ expect(@first_post.creator_id).to eq(@delynn.id)
206
+ expect(@first_post.updater_id).to eq(@nicole.id)
207
+ expect(@first_post.creator).to eq(@delynn)
208
+ expect(@first_post.updater).to eq(@nicole)
209
+ end
210
+ end
211
+ end
212
+
213
+ context 'when using a generated model' do
214
+ it 'does not query the model on the columns' do
215
+ class self.class::Post2 < Post
216
+ end
217
+ allow(self.class::Post2).to receive(:column_names).and_raise(StandardError)
218
+
219
+ class self.class::Post2
220
+ has_and_belongs_to_many :tags
221
+ end
222
+ end
223
+ end
224
+
225
+ context 'when using an anonymous model' do
226
+ it 'does not query the model on the columns' do
227
+ post_3_class = Class.new(ActiveRecord::Base) do
228
+ def self.table_name
229
+ 'Post'
230
+ end
231
+ end
232
+ expect(post_3_class.table_name).not_to be_empty
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,4 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Userstamper do
4
+ end
@@ -0,0 +1,7 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+ require 'spec_helper'
3
+
4
+ require File.expand_path('dummy/config/environment.rb', __dir__)
5
+ require 'rspec/rails'
6
+
7
+ Dir[__dir__ + '/support/**/*'].each { |f| require f if File.file?(f) }
@@ -0,0 +1,98 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+ require 'bundler/setup'
20
+ require 'pry'
21
+ Bundler.setup
22
+
23
+ require 'coverage_helper'
24
+
25
+ RSpec.configure do |config|
26
+ # rspec-expectations config goes here. You can use an alternate
27
+ # assertion/expectation library such as wrong or the stdlib/minitest
28
+ # assertions if you prefer.
29
+ config.expect_with :rspec do |expectations|
30
+ # This option will default to `true` in RSpec 4. It makes the `description`
31
+ # and `failure_message` of custom matchers include text for helper methods
32
+ # defined using `chain`, e.g.:
33
+ # be_bigger_than(2).and_smaller_than(4).description
34
+ # # => "be bigger than 2 and smaller than 4"
35
+ # ...rather than:
36
+ # # => "be bigger than 2"
37
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
38
+ end
39
+
40
+ # rspec-mocks config goes here. You can use an alternate test double
41
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
42
+ config.mock_with :rspec do |mocks|
43
+ # Prevents you from mocking or stubbing a method that does not exist on
44
+ # a real object. This is generally recommended, and will default to
45
+ # `true` in RSpec 4.
46
+ mocks.verify_partial_doubles = true
47
+ end
48
+
49
+ # These two settings work together to allow you to limit a spec run
50
+ # to individual examples or groups you care about by tagging them with
51
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
52
+ # get run.
53
+ config.filter_run :focus
54
+ config.run_all_when_everything_filtered = true
55
+
56
+ # Allows RSpec to persist some state between runs in order to support
57
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
58
+ # you configure your source control system to ignore this file.
59
+ config.example_status_persistence_file_path = "spec/examples.txt"
60
+
61
+ # Limits the available syntax to the non-monkey patched syntax that is
62
+ # recommended. For more details, see:
63
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
64
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
65
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
66
+ config.disable_monkey_patching!
67
+
68
+ # This setting enables warnings. It's recommended, but in some cases may
69
+ # be too noisy due to issues in dependencies.
70
+ config.warnings = true
71
+
72
+ # Many RSpec users commonly either run the entire suite or an individual
73
+ # file, and it's useful to allow more verbose output when running an
74
+ # individual spec file.
75
+ if config.files_to_run.one?
76
+ # Use the documentation formatter for detailed output,
77
+ # unless a formatter has already been configured
78
+ # (e.g. via a command-line flag).
79
+ config.default_formatter = 'doc'
80
+ end
81
+
82
+ # Print the 10 slowest examples and example groups at the
83
+ # end of the spec run, to help surface which specs are running
84
+ # particularly slow.
85
+ config.profile_examples = 10
86
+
87
+ # Run specs in random order to surface order dependencies. If you find an
88
+ # order dependency and want to debug it, you can fix the order by providing
89
+ # the seed, which is printed after each run.
90
+ # --seed 1234
91
+ config.order = :random
92
+
93
+ # Seed global randomization in this process using the `--seed` CLI option.
94
+ # Setting this allows you to use `--seed` to deterministically reproduce
95
+ # test failures related to randomization by passing the same `--seed` value
96
+ # as the one that triggered the failure.
97
+ Kernel.srand config.seed
98
+ end