omg-audit-group 0.1.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
+ SHA256:
3
+ metadata.gz: 4aefcd1c0eb006272723f7ed68f14cd719e6480d833e9354730ee42340d6b814
4
+ data.tar.gz: 418949a9ea417499e1ff0566f1255940c273bcc5404311bfd4352eecc34b3196
5
+ SHA512:
6
+ metadata.gz: 1ef815f6b87adb3fe2df279b84dd94a7ff48f8075fa2e91292680b270bec764ff1800b38b90523d02c7f5ed92d936fcdc95bf56548a454f4e899ad9e47672f29
7
+ data.tar.gz: 7ce8a2a142907e59690af0cf912302aed6fe607cefd1b133b43520517a68dd1049845d6ef32155c73c088eaebe7ab4011899e3ed859ec48c8934567f788b2299
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ sandbox.md
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # AuditGroup
2
+
3
+ Group ActiveRecord operations together by assigning all of their audits the same `request_uuid`.
4
+
5
+ ## Requirements
6
+
7
+ - [Audited](https://github.com/collectiveidea/audited) gem
8
+
9
+ ## Installation
10
+
11
+ ### Testing locally
12
+ ```sh
13
+ # Build gem
14
+ gem build audit_group.gemspec
15
+
16
+ # Install gem
17
+ gem i -l /path/to/this/repo/omg-audit_group-0.1.0.gem
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ For convenience, the following operations are delegated from the `AuditGroup` module to the `AuditGroup::Request` class:
23
+
24
+ - `new`
25
+ - `request`
26
+ - `current`
27
+ - `request_uuid`
28
+ - `audits`
29
+
30
+ Here are some use cases:
31
+
32
+ ```ruby
33
+ # Group operations under the same request_uuid
34
+ AuditGroup.request { perform_some_operations }
35
+
36
+ # View the last request_uuid (the above also returns it)
37
+ AuditGroup.request_uuid
38
+
39
+ # View the audits from the last request
40
+ AuditGroup.audits
41
+ ```
42
+
43
+ You can also create separate `AuditGroup::Request` objects to reuse.
44
+
45
+ ```ruby
46
+ group = AuditGroup.new
47
+ group.request { perform_some_operations }
48
+ ...
49
+ group.request { perform_more_operations }
50
+ group.audits
51
+ ```
52
+
53
+ ## Running tests
54
+
55
+ ```ruby
56
+ rspec
57
+
58
+ # or
59
+ bundle exec rspec
60
+ ```
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/audit_group/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'omg-audit-group'
7
+ spec.version = AuditGroup::VERSION
8
+ spec.authors = ['Matthew Greenfield']
9
+ spec.email = ['mattgreenfield1@gmail.com']
10
+
11
+ spec.summary = 'Groups transactions from the `audited` gem into a single request_uuid'
12
+ spec.description = 'Create, update, and delete records within a block, assign ' \
13
+ 'the same request_uuid to them, and be able to easily view ' \
14
+ 'and undo them'
15
+
16
+ spec.homepage = 'https://github.com/omgreenfield/omg-util/tree/main/audit_group'
17
+ spec.license = 'MIT'
18
+ spec.required_ruby_version = '>= 2.7.0'
19
+
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['rubygems_mfa_required'] = 'true'
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0").reject do |f|
27
+ (File.expand_path(f) == __FILE__) ||
28
+ f.start_with?(*%w[spec/.git .github Gemfile])
29
+ end
30
+ end
31
+ spec.require_paths = ['lib']
32
+
33
+ spec.add_dependency 'activesupport', '>= 6.0', '< 8.0'
34
+ spec.add_dependency 'audited', '>= 4.9', '< 6.0'
35
+
36
+ # For more information and examples about making a new gem, check out our
37
+ # guide at: https://bundler.io/guides/creating_gem.html
38
+ end
@@ -0,0 +1,59 @@
1
+ require 'active_support/all'
2
+ require 'audited'
3
+ require 'pry-byebug'
4
+
5
+ module AuditGroup
6
+ class Request
7
+ attr_reader :block, :request_uuid
8
+
9
+ delegate :current, :unset_request_uuid, to: :class
10
+
11
+ class << self
12
+ delegate :request_uuid, :audits, to: :current
13
+
14
+ attr_accessor :current
15
+
16
+ def set_request_uuid(request_uuid = SecureRandom.uuid)
17
+ Audited.store[:current_request_uuid] = request_uuid
18
+ end
19
+
20
+ def unset_request_uuid
21
+ Audited.store.delete(:current_request_uuid)
22
+ end
23
+
24
+ def reset
25
+ unset_request_uuid
26
+ @current = nil
27
+ end
28
+
29
+ def request(&block)
30
+ raise ArgumentError, 'No block given and no active group' unless block_given?
31
+
32
+ new.request(&block)
33
+ end
34
+ end
35
+
36
+ def initialize(request_uuid = SecureRandom.uuid)
37
+ @request_uuid = request_uuid
38
+ self.class.current = self
39
+ end
40
+
41
+ def request(&block)
42
+ set_request_uuid
43
+
44
+ block.call if block.present?
45
+
46
+ self
47
+ ensure
48
+ unset_request_uuid
49
+ end
50
+
51
+ def set_request_uuid
52
+ self.class.set_request_uuid(request_uuid)
53
+ end
54
+
55
+ def audits
56
+ Audited::Audit.where(request_uuid: request_uuid)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuditGroup
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'audit_group/request'
4
+ require_relative 'audit_group/version'
5
+
6
+ require 'active_support/all'
7
+ require 'audited'
8
+
9
+ module AuditGroup
10
+ class << self
11
+ delegate :new, :request, :current, :request_uuid, :audits, to: Request
12
+ end
13
+ end
@@ -0,0 +1,110 @@
1
+ require 'audit_group/request'
2
+
3
+ RSpec.describe AuditGroup::Request do
4
+ describe 'class methods' do
5
+ describe '.current' do
6
+ it 'returns the last request created' do
7
+ request = described_class.request {}
8
+ expect(described_class.current).to eq(request)
9
+ end
10
+ end
11
+
12
+ describe '.set_request_uuid' do
13
+ it "sets the Audit store's current_request_uuid" do
14
+ described_class.set_request_uuid('123')
15
+ expect(Audited.store[:current_request_uuid]).to eq('123')
16
+
17
+ described_class.set_request_uuid
18
+ expect(Audited.store[:current_request_uuid]).to match(/\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/)
19
+ end
20
+ end
21
+
22
+ describe '.unset_request_uuid' do
23
+ it "resets the Audit store's current_request_uuid" do
24
+ Audited.store[:current_request_uuid] = '123'
25
+ described_class.unset_request_uuid
26
+ expect(Audited.store[:current_request_uuid]).to be_nil
27
+ end
28
+ end
29
+
30
+ describe '.reset' do
31
+ it 'unsets the request_uuid and current request' do
32
+ described_class.set_request_uuid('123')
33
+ described_class.current = 'some request'
34
+
35
+ expect(Audited.store[:current_request_uuid]).to eq('123')
36
+ expect(described_class.current).to eq('some request')
37
+
38
+ described_class.reset
39
+
40
+ expect(Audited.store[:current_request_uuid]).to be_nil
41
+ expect(described_class.current).to be_nil
42
+ end
43
+ end
44
+
45
+ describe '.request' do
46
+ it 'raises an ArgumentError if no block is given and no active group' do
47
+ expect { described_class.request }.to raise_error(ArgumentError, 'No block given and no active group')
48
+ end
49
+
50
+ it 'creates a new request if block is given' do
51
+ expect { |block| described_class.request(&block) }.to yield_control
52
+ end
53
+ end
54
+
55
+ describe '.request_uuid' do
56
+ it 'delegates to current' do
57
+ described_class.request {}
58
+ expect(described_class.request_uuid).to eq(described_class.current.request_uuid)
59
+ end
60
+ end
61
+
62
+ describe '.audits' do
63
+ it 'delegates to current' do
64
+ described_class.new('123')
65
+ audited_audit = class_double('Audited::Audit').as_stubbed_const
66
+ expect(audited_audit).to receive(:where).with(request_uuid: '123').and_return('some audits')
67
+ expect(described_class.audits).to eq('some audits')
68
+ end
69
+ end
70
+ end
71
+
72
+ describe 'instance methods' do
73
+ describe '#initialize' do
74
+ it 'sets the request_uuid and current request' do
75
+ request = described_class.new('123')
76
+ expect(request.request_uuid).to eq('123')
77
+ expect(described_class.current).to eq(request)
78
+ end
79
+ end
80
+
81
+ describe '#request' do
82
+ it 'sets the current_request_uuid, calls the block, then resets current_request_uuid' do
83
+ request = described_class.new('123')
84
+
85
+ request.request do
86
+ expect(Audited.store[:current_request_uuid]).to eq('123')
87
+ end
88
+
89
+ expect(Audited.store[:current_request_uuid]).to be_nil
90
+ end
91
+ end
92
+
93
+ describe '#set_request_uuid' do
94
+ it 'delegates to class' do
95
+ request = described_class.new('123')
96
+ expect(request).to receive(:set_request_uuid)
97
+ request.set_request_uuid
98
+ end
99
+ end
100
+
101
+ describe '#audits' do
102
+ it 'returns audits with request_uuid' do
103
+ request = described_class.new('123')
104
+ audited_audit = class_double('Audited::Audit').as_stubbed_const
105
+ expect(audited_audit).to receive(:where).with(request_uuid: '123').and_return('some audits')
106
+ expect(request.audits).to eq('some audits')
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe AuditGroup do
4
+ it 'has a version number' do
5
+ expect(AuditGroup::VERSION).not_to be_nil
6
+ end
7
+
8
+ describe '.new' do
9
+ it 'delegates to Request' do
10
+ expect(AuditGroup.new).to be_a(AuditGroup::Request)
11
+ end
12
+ end
13
+
14
+ describe '.request' do
15
+ it 'creates a new Request' do
16
+ request = AuditGroup.request { puts 'Hi, Mom!' }
17
+
18
+ expect(request).to be_a(AuditGroup::Request)
19
+ end
20
+ end
21
+
22
+ describe '.current' do
23
+ it 'returns the last created Request object' do
24
+ request = AuditGroup.request { puts 'Hi, Dad!' }
25
+ expect(AuditGroup.current).to eq(request)
26
+ end
27
+ end
28
+
29
+ describe '.request_uuid' do
30
+ it 'returns the current request_uuid' do
31
+ request = AuditGroup.request { puts 'Hi, Steve!' }
32
+ expect(AuditGroup.request_uuid).to eq(request.request_uuid)
33
+ end
34
+ end
35
+
36
+ describe '.audits' do
37
+ it 'delegates to Request' do
38
+ AuditGroup.request { puts "Who's Steve?" }
39
+ audited_audit = class_double('Audited::Audit').as_stubbed_const
40
+ expect(audited_audit).to receive(:where).with(request_uuid: an_instance_of(String)).and_return('some audits')
41
+ expect(AuditGroup.audits).to eq('some audits')
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "audit_group"
4
+
5
+ RSpec.configure do |config|
6
+ # Enable flags like --only-failures and --next-failure
7
+ config.example_status_persistence_file_path = ".rspec_status"
8
+
9
+ # Disable RSpec exposing methods globally on `Module` and `main`
10
+ config.disable_monkey_patching!
11
+
12
+ config.expect_with :rspec do |c|
13
+ c.syntax = :expect
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omg-audit-group
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Greenfield
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-04-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '6.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: audited
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '4.9'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '6.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '4.9'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '6.0'
53
+ description: Create, update, and delete records within a block, assign the same request_uuid
54
+ to them, and be able to easily view and undo them
55
+ email:
56
+ - mattgreenfield1@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".gitignore"
62
+ - ".rspec"
63
+ - README.md
64
+ - audit_group.gemspec
65
+ - lib/audit_group.rb
66
+ - lib/audit_group/request.rb
67
+ - lib/audit_group/version.rb
68
+ - spec/audit_group/request_spec.rb
69
+ - spec/audit_group_spec.rb
70
+ - spec/spec_helper.rb
71
+ homepage: https://github.com/omgreenfield/omg-util/tree/main/audit_group
72
+ licenses:
73
+ - MIT
74
+ metadata:
75
+ homepage_uri: https://github.com/omgreenfield/omg-util/tree/main/audit_group
76
+ rubygems_mfa_required: 'true'
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: 2.7.0
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.5.9
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Groups transactions from the `audited` gem into a single request_uuid
96
+ test_files: []