active_record-journal 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 +7 -0
- data/.circleci/config.yml +122 -0
- data/.env +6 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Dockerfile +10 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +134 -0
- data/LICENSE.txt +21 -0
- data/README.md +161 -0
- data/Rakefile +8 -0
- data/active_record-journal.gemspec +50 -0
- data/bin/coverage +9 -0
- data/bin/setup +8 -0
- data/docker-compose.yml +28 -0
- data/lib/active_record/journal/configuration.rb +27 -0
- data/lib/active_record/journal/constants.rb +18 -0
- data/lib/active_record/journal/journable/attributes.rb +35 -0
- data/lib/active_record/journal/journable/callback.rb +75 -0
- data/lib/active_record/journal/journable/changes.rb +53 -0
- data/lib/active_record/journal/journable/context.rb +77 -0
- data/lib/active_record/journal/journable/options.rb +37 -0
- data/lib/active_record/journal/journable/rule.rb +46 -0
- data/lib/active_record/journal/journable.rb +46 -0
- data/lib/active_record/journal/version.rb +7 -0
- data/lib/active_record/journal.rb +49 -0
- metadata +200 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Journal
|
5
|
+
class Configuration
|
6
|
+
attr_writer :entries_class, :tags_class, :autorecording_enabled
|
7
|
+
|
8
|
+
def entries_class
|
9
|
+
return @entries_class if @entries_class.is_a?(Class)
|
10
|
+
|
11
|
+
@entries_class = @entries_class.constantize
|
12
|
+
end
|
13
|
+
|
14
|
+
def tags_class
|
15
|
+
return @tags_class if @tags_class.is_a?(Class)
|
16
|
+
|
17
|
+
@tags_class = @tags_class.constantize
|
18
|
+
end
|
19
|
+
|
20
|
+
def autorecording_enabled
|
21
|
+
return true if @autorecording_enabled.nil?
|
22
|
+
|
23
|
+
@autorecording_enabled
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Journal
|
5
|
+
ACTIONS = { reads: %w[read], writes: %w[update create destroy] }.freeze
|
6
|
+
JOURNABLE_OPTIONS = %i[
|
7
|
+
entries_class
|
8
|
+
tags_class
|
9
|
+
on
|
10
|
+
if
|
11
|
+
unless
|
12
|
+
only
|
13
|
+
except
|
14
|
+
mask
|
15
|
+
type
|
16
|
+
].freeze
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Journal
|
5
|
+
module Journable
|
6
|
+
Attributes = Struct.new(:subject, :rule) do
|
7
|
+
def model
|
8
|
+
subject.class
|
9
|
+
end
|
10
|
+
|
11
|
+
def tracked_keys
|
12
|
+
keys - ignored_keys
|
13
|
+
end
|
14
|
+
|
15
|
+
def ignored_keys
|
16
|
+
if rule.only
|
17
|
+
(keys - rule.only) | default_ignored_keys
|
18
|
+
elsif rule.except
|
19
|
+
default_ignored_keys | rule.except
|
20
|
+
else
|
21
|
+
default_ignored_keys
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def keys
|
26
|
+
model.column_names.map(&:to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_ignored_keys
|
30
|
+
[model.primary_key, model.inheritance_column, model.locking_column].compact
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Journal
|
5
|
+
module Journable
|
6
|
+
class Callback
|
7
|
+
attr_reader :action
|
8
|
+
|
9
|
+
def initialize(action)
|
10
|
+
@action = action
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_proc
|
14
|
+
callback = self
|
15
|
+
->(record) { callback.call(record) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(record) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength
|
19
|
+
return unless valid_context?
|
20
|
+
|
21
|
+
override = rules_for(context: context_override, record: record) || {}
|
22
|
+
rules = rules_for(context: record.class.journable_context, record: record)
|
23
|
+
|
24
|
+
rules&.each do |journal, list|
|
25
|
+
list.each do |rule|
|
26
|
+
next unless rules_met?(rule: rule, override: override[journal], record: record)
|
27
|
+
|
28
|
+
attributes = Attributes.new(record, rule).tracked_keys
|
29
|
+
changes = Changes.new(record, action, attributes, rule.mask).call
|
30
|
+
context = context_override || record.class.journable_context
|
31
|
+
record_changes(
|
32
|
+
changes: changes,
|
33
|
+
record: record,
|
34
|
+
entries_class: rule.entries_class,
|
35
|
+
tag: context.tag(rule.tags_class)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def record_changes(entries_class:, changes:, record:, tag:)
|
44
|
+
return unless action == 'read' || changes.any?
|
45
|
+
|
46
|
+
entries_class.create!(changes_map: changes, journable: record, journal_tag: tag, action: action)
|
47
|
+
end
|
48
|
+
|
49
|
+
def rules_met?(rule:, override:, record:)
|
50
|
+
rule.conditions_met?(record) &&
|
51
|
+
(override.nil? || override.all? { _1.conditions_met?(record) })
|
52
|
+
end
|
53
|
+
|
54
|
+
def rules_for(context:, record:)
|
55
|
+
context
|
56
|
+
&.rules
|
57
|
+
&.search_by(action: action, subject: record)
|
58
|
+
&.group_by { |r| r.entries_class.model_name.param_key }
|
59
|
+
end
|
60
|
+
|
61
|
+
def valid_context?
|
62
|
+
(configuration.autorecording_enabled || context_override) && !!context_override&.ignore_actions == false
|
63
|
+
end
|
64
|
+
|
65
|
+
def context_override
|
66
|
+
ActiveRecord::Journal.context_override
|
67
|
+
end
|
68
|
+
|
69
|
+
def configuration
|
70
|
+
ActiveRecord::Journal.configuration
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Journal
|
5
|
+
module Journable
|
6
|
+
Changes = Struct.new(:subject, :action, :keys, :mask_keys) do
|
7
|
+
def call
|
8
|
+
changes.each_with_object({}) do |(key, value), attrs|
|
9
|
+
attrs[key] = value
|
10
|
+
next unless mask_keys&.include?(key)
|
11
|
+
|
12
|
+
attrs[key] = value.is_a?(Array) ? [nil, nil] : nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def changes
|
19
|
+
case action
|
20
|
+
when 'create'
|
21
|
+
non_persisted_diff
|
22
|
+
when 'update'
|
23
|
+
persisted_diff
|
24
|
+
when 'destroy'
|
25
|
+
destroy_diff
|
26
|
+
else
|
27
|
+
none
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def none
|
32
|
+
{}
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy_diff
|
36
|
+
subject.attributes.select { |k, v| keys.include?(k) && v.present? }
|
37
|
+
end
|
38
|
+
|
39
|
+
def non_persisted_diff
|
40
|
+
diff.select { |k, v| keys.include?(k) && v.last.present? }
|
41
|
+
end
|
42
|
+
|
43
|
+
def persisted_diff
|
44
|
+
diff.select { |k, _v| keys.include?(k) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def diff
|
48
|
+
subject.changes.any? ? subject.changes : subject.previous_changes
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Journal
|
5
|
+
module Journable
|
6
|
+
class Context
|
7
|
+
attr_writer :ignore_actions, :generate_tag
|
8
|
+
|
9
|
+
Storage = Struct.new(*ActiveRecord::Journal::ACTIONS.values.flatten.map(&:to_sym), keyword_init: true) do
|
10
|
+
def initialize
|
11
|
+
actions = ActiveRecord::Journal::ACTIONS.values.flatten
|
12
|
+
kwargs = actions.each_with_object({}) { |a, map| map[a.to_sym] = {} }
|
13
|
+
super(**kwargs)
|
14
|
+
end
|
15
|
+
|
16
|
+
def add(action:, journable:, rule:)
|
17
|
+
map = public_send(action)
|
18
|
+
map[journable.model_name.to_s] ||= []
|
19
|
+
map[journable.model_name.to_s] << rule
|
20
|
+
end
|
21
|
+
|
22
|
+
def search_by(action:, subject: nil)
|
23
|
+
map = public_send(action)
|
24
|
+
return unless map
|
25
|
+
|
26
|
+
return map.values.flatten if subject.nil?
|
27
|
+
|
28
|
+
key = map.keys.find { |name| subject.is_a?(name.constantize) }
|
29
|
+
return unless key
|
30
|
+
|
31
|
+
map[key]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(**tags_args)
|
36
|
+
@tags_args = tags_args
|
37
|
+
end
|
38
|
+
|
39
|
+
def configured_for?(action)
|
40
|
+
rules.search_by(action: action.to_s)&.any? || false
|
41
|
+
end
|
42
|
+
|
43
|
+
def record(journable, type = nil, **with)
|
44
|
+
options = ActiveRecord::Journal::Journable::Options.parse(with, type)
|
45
|
+
rule = ActiveRecord::Journal::Journable::Rule.new(journable, options)
|
46
|
+
options.on.each { |action| rules.add(action: action, journable: journable, rule: rule) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def actions
|
50
|
+
ActiveRecord::Journal.context_override = self
|
51
|
+
yield
|
52
|
+
ActiveRecord::Journal.context_override = nil
|
53
|
+
rescue StandardError
|
54
|
+
ActiveRecord::Journal.context_override = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def ignore_actions
|
58
|
+
@ignore_actions || false
|
59
|
+
end
|
60
|
+
|
61
|
+
def generate_tag
|
62
|
+
@generate_tag || false
|
63
|
+
end
|
64
|
+
|
65
|
+
def rules
|
66
|
+
@rules ||= Storage.new
|
67
|
+
end
|
68
|
+
|
69
|
+
def tag(tags_class)
|
70
|
+
return @tag if defined?(@tag)
|
71
|
+
|
72
|
+
@tag = tags_class.create!(**@tags_args) if generate_tag
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Journal
|
5
|
+
module Journable
|
6
|
+
class OptionError < StandardError; end
|
7
|
+
|
8
|
+
Options = Struct.new(*ActiveRecord::Journal::JOURNABLE_OPTIONS, keyword_init: true) do
|
9
|
+
def self.parse(kwargs, type)
|
10
|
+
options = Options.new(**kwargs, type: type)
|
11
|
+
options.check_actions!
|
12
|
+
options
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(**kwargs) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
16
|
+
type = kwargs[:type].to_sym
|
17
|
+
kwargs[:type] = type
|
18
|
+
kwargs[:entries_class] ||= ActiveRecord::Journal.configuration.entries_class
|
19
|
+
kwargs[:tags_class] ||= ActiveRecord::Journal.configuration.tags_class
|
20
|
+
kwargs[:on] = kwargs[:on]&.map(&:to_s) || ActiveRecord::Journal::ACTIONS[type]
|
21
|
+
kwargs[:only] = kwargs[:only]&.map(&:to_s)
|
22
|
+
kwargs[:except] = kwargs[:except]&.map(&:to_s)
|
23
|
+
kwargs[:mask] = kwargs[:mask]&.map(&:to_s)
|
24
|
+
super(**kwargs)
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_actions!
|
28
|
+
on.each do |action|
|
29
|
+
next if ActiveRecord::Journal::ACTIONS[type.to_sym].include?(action)
|
30
|
+
|
31
|
+
raise OptionError, "#{action} is not a valid value for the on option"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module Journal
|
7
|
+
module Journable
|
8
|
+
class Rule
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
ActiveRecord::Journal::JOURNABLE_OPTIONS.each do |option_name|
|
12
|
+
def_delegator :@options, option_name, option_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def_delegator :@options, :to_h, :to_h
|
16
|
+
|
17
|
+
attr_reader :journable, :options
|
18
|
+
|
19
|
+
def initialize(journable, options)
|
20
|
+
@journable = journable
|
21
|
+
@options = options
|
22
|
+
end
|
23
|
+
|
24
|
+
def conditions_met?(rec)
|
25
|
+
return true unless self.if || self.unless
|
26
|
+
|
27
|
+
assert_value = self.if ? true : false
|
28
|
+
condition = self.if || self.unless
|
29
|
+
assert_condition(condition, rec, assert_value)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def evaluate_condition(condition, rec)
|
35
|
+
return condition.call(rec) if condition.respond_to?(:call)
|
36
|
+
|
37
|
+
rec.send(condition)
|
38
|
+
end
|
39
|
+
|
40
|
+
def assert_condition(condition, rec, assert_value)
|
41
|
+
!!evaluate_condition(condition, rec) == assert_value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'journable/options'
|
4
|
+
require_relative 'journable/rule'
|
5
|
+
require_relative 'journable/context'
|
6
|
+
require_relative 'journable/attributes'
|
7
|
+
require_relative 'journable/changes'
|
8
|
+
require_relative 'journable/callback'
|
9
|
+
|
10
|
+
module ActiveRecord
|
11
|
+
module Journal
|
12
|
+
module Journable
|
13
|
+
def self.extended(subject)
|
14
|
+
subject.class_attribute :journable_context
|
15
|
+
|
16
|
+
subject.after_find(&Callback.new('read'))
|
17
|
+
subject.after_create(&Callback.new('create'))
|
18
|
+
subject.before_update(&Callback.new('update'))
|
19
|
+
subject.before_destroy(&Callback.new('destroy'))
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Enable & configure the tracking of the read actions
|
24
|
+
def journal_reads(**kwargs)
|
25
|
+
init_journable_context
|
26
|
+
journable_context.record(self, :reads, **kwargs)
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Enable & configure the tracking of the writes, updates and destroy actions
|
31
|
+
def journal_writes(**kwargs)
|
32
|
+
init_journable_context
|
33
|
+
journable_context.record(self, :writes, **kwargs)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def init_journable_context
|
39
|
+
return if @init_journable_context
|
40
|
+
|
41
|
+
self.journable_context = Context.new
|
42
|
+
@init_journable_context = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record/journal/version'
|
4
|
+
require 'active_record/journal/constants'
|
5
|
+
require 'active_record/journal/configuration'
|
6
|
+
require 'active_record/journal/journable'
|
7
|
+
|
8
|
+
module ActiveRecord
|
9
|
+
module Journal
|
10
|
+
class Error < StandardError; end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def configuration
|
14
|
+
@configuration ||= Configuration.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def init
|
18
|
+
yield configuration
|
19
|
+
end
|
20
|
+
|
21
|
+
def tag(**kwargs)
|
22
|
+
context = Journable::Context.new(**kwargs)
|
23
|
+
context.generate_tag = true
|
24
|
+
yield context
|
25
|
+
end
|
26
|
+
|
27
|
+
def context
|
28
|
+
context = Journable::Context.new
|
29
|
+
yield context
|
30
|
+
end
|
31
|
+
|
32
|
+
def ignore
|
33
|
+
context = Journable::Context.new
|
34
|
+
context.ignore_actions = true
|
35
|
+
yield context
|
36
|
+
end
|
37
|
+
|
38
|
+
def context_override
|
39
|
+
# https://ruby-doc.org/core-2.5.0/Thread.html#method-i-thread_variable_get
|
40
|
+
Thread.current.thread_variable_get(:activerecord_journable_context_override)
|
41
|
+
end
|
42
|
+
|
43
|
+
def context_override=(context)
|
44
|
+
# https://ruby-doc.org/core-2.5.0/Thread.html#method-i-thread_variable_set
|
45
|
+
Thread.current.thread_variable_set(:activerecord_journable_context_override, context)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_record-journal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- mkiroshdz
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-03-12 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: 6.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 6.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
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: pg
|
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: pry
|
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: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '13.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '13.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 5.0.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 5.0.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: sqlite3
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: A gem to track changes on active record models
|
140
|
+
email:
|
141
|
+
- mkirosh@hey.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".circleci/config.yml"
|
147
|
+
- ".env"
|
148
|
+
- ".gitignore"
|
149
|
+
- ".rspec"
|
150
|
+
- ".rubocop.yml"
|
151
|
+
- CODE_OF_CONDUCT.md
|
152
|
+
- Dockerfile
|
153
|
+
- Gemfile
|
154
|
+
- Gemfile.lock
|
155
|
+
- LICENSE.txt
|
156
|
+
- README.md
|
157
|
+
- Rakefile
|
158
|
+
- active_record-journal.gemspec
|
159
|
+
- bin/coverage
|
160
|
+
- bin/setup
|
161
|
+
- docker-compose.yml
|
162
|
+
- lib/active_record/journal.rb
|
163
|
+
- lib/active_record/journal/configuration.rb
|
164
|
+
- lib/active_record/journal/constants.rb
|
165
|
+
- lib/active_record/journal/journable.rb
|
166
|
+
- lib/active_record/journal/journable/attributes.rb
|
167
|
+
- lib/active_record/journal/journable/callback.rb
|
168
|
+
- lib/active_record/journal/journable/changes.rb
|
169
|
+
- lib/active_record/journal/journable/context.rb
|
170
|
+
- lib/active_record/journal/journable/options.rb
|
171
|
+
- lib/active_record/journal/journable/rule.rb
|
172
|
+
- lib/active_record/journal/version.rb
|
173
|
+
homepage: https://github.com/mkiroshdz/active_record-journal
|
174
|
+
licenses:
|
175
|
+
- MIT
|
176
|
+
metadata:
|
177
|
+
allowed_push_host: https://rubygems.org/
|
178
|
+
homepage_uri: https://github.com/mkiroshdz/active_record-journal
|
179
|
+
source_code_uri: https://github.com/mkiroshdz/active_record-journal
|
180
|
+
changelog_uri: https://github.com/mkiroshdz/active_record-journal/blob/CHANGELOG.md
|
181
|
+
post_install_message:
|
182
|
+
rdoc_options: []
|
183
|
+
require_paths:
|
184
|
+
- lib
|
185
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '2.5'
|
190
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
requirements: []
|
196
|
+
rubygems_version: 3.1.6
|
197
|
+
signing_key:
|
198
|
+
specification_version: 4
|
199
|
+
summary: A gem to track changes on active record models
|
200
|
+
test_files: []
|