camel_trail 0.0.1
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/Rakefile +28 -0
- data/app/models/camel_trail/application_record.rb +7 -0
- data/app/models/camel_trail/encrypted_history.rb +21 -0
- data/app/models/camel_trail/history.rb +24 -0
- data/config/database.yml +7 -0
- data/db/migrate/20200514201449_create_camel_trails.rb +20 -0
- data/docs/README.md +74 -0
- data/lib/camel_trail/config.rb +30 -0
- data/lib/camel_trail/engine.rb +27 -0
- data/lib/camel_trail/entry_presenter.rb +65 -0
- data/lib/camel_trail/recordable.rb +38 -0
- data/lib/camel_trail/version.rb +6 -0
- data/lib/camel_trail/yaml_unsafe_coder.rb +23 -0
- data/lib/camel_trail.rb +61 -0
- metadata +219 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 74fe79d392691d6f939590e1742163bc77d2379982d238e36b626cd03f657636
|
4
|
+
data.tar.gz: bc8a4444544e8f23c7312c5951e91026689d3b79aef0a3b51b7d872539422767
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 93cf6bcfd5c406f8c3b9489d89cd831c59fc414aeffd35f880a4b4db63a6d3067a257ccdd68744241d07a2a801c2193f7858eec12c02830054ae50628916212e
|
7
|
+
data.tar.gz: 6995ef5aad5760118c4b1bc450655b009c559958737707a81d45db513dd6487d646bfe6b7be4fa2cf04351d6e7c85a684098b5626320d18c10cc5cb449f4b148
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/gem_tasks"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
require "rubocop/rake_task"
|
7
|
+
|
8
|
+
begin
|
9
|
+
require "bundler/setup"
|
10
|
+
require "yard"
|
11
|
+
YARD::Rake::YardocTask.new do |t|
|
12
|
+
t.files = ["lib/**/*.rb"]
|
13
|
+
t.files = ["app/models/camel_trail/*.rb"]
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
puts "You must `bundle install` to run rake tasks"
|
17
|
+
end
|
18
|
+
|
19
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
20
|
+
load "rails/tasks/engine.rake"
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
RSpec::Core::RakeTask.new(:spec)
|
25
|
+
|
26
|
+
RuboCop::RakeTask.new(:rubocop)
|
27
|
+
|
28
|
+
task default: %i[rubocop app:db:prepare spec]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CamelTrail
|
4
|
+
class EncryptedHistory < ::CamelTrail::History
|
5
|
+
extend AttrEncrypted
|
6
|
+
|
7
|
+
attr_encrypted :note, key: NitroConfig.get_deferred!("encryption_key"),
|
8
|
+
encode: true,
|
9
|
+
insecure_mode: true,
|
10
|
+
algorithm: "aes-256-cbc",
|
11
|
+
mode: :single_iv_and_salt
|
12
|
+
|
13
|
+
before_save :clear_plain_note
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def clear_plain_note
|
18
|
+
self[:note] = nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CamelTrail
|
4
|
+
class History < ::CamelTrail::ApplicationRecord
|
5
|
+
serialize :source_changes, ::CamelTrail::YAMLUnsafeCoder
|
6
|
+
serialize :backtrace, Array
|
7
|
+
|
8
|
+
default_scope { order("id DESC") }
|
9
|
+
|
10
|
+
scope :for_source, ->(source_object) do
|
11
|
+
where(source_id: source_object.id, source_type: source_object.class.to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
scope :in_natural_order, -> { reorder("id ASC") }
|
15
|
+
|
16
|
+
before_create :set_backtrace
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def set_backtrace
|
21
|
+
self.backtrace = CamelTrail::Config.backtrace_cleaner&.clean(caller) || caller
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/config/database.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Metrics/MethodLength
|
4
|
+
class CreateCamelTrails < ActiveRecord::Migration[6.0]
|
5
|
+
def change
|
6
|
+
create_table :"#{CamelTrail.table_name_prefix}histories" do |t|
|
7
|
+
t.string :source_type
|
8
|
+
t.string :source_id
|
9
|
+
t.text :source_changes
|
10
|
+
t.integer :user_id
|
11
|
+
t.text :note
|
12
|
+
t.string :activity
|
13
|
+
t.text :encrypted_note
|
14
|
+
t.text :backtrace
|
15
|
+
end
|
16
|
+
|
17
|
+
add_index :"#{CamelTrail.table_name_prefix}histories", %i[source_type source_id]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
# rubocop:enable Metrics/MethodLength
|
data/docs/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
## What is CamelTrail
|
2
|
+
|
3
|
+
CamelTrail makes it easy to keep a history of attribute changes on a model
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'camel_trail'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install camel_trail
|
20
|
+
|
21
|
+
|
22
|
+
# Configuration
|
23
|
+
|
24
|
+
1. Add CamelTrail config to your initializer file.
|
25
|
+
2. You need to set `current_session_user_id` to include user info in `camel_trail_histories` table.
|
26
|
+
3. You can optionally set `table_name_prefix` to customize default table name. Defaults to `camel_trail_histories`.
|
27
|
+
4. CamelTrail stores backtrace info in `camel_trail_histories`. It defaults to `Rails.backtrace_cleaner`. You can optionally set it to your customized backtrace cleaner.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
CamelTrail.config do
|
31
|
+
table_name_prefix "myapp_"
|
32
|
+
current_session_user_id { MyApp.current_session_user_id }
|
33
|
+
backtrace_cleaner { YourCustom.backtrace_cleaner }
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
## Usage
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
class Project < ApplicationRecord
|
41
|
+
include ::CamelTrail::Recordable
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
Inlcude `camel_trail` in your lib files if you need to call it there:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require "camel_trail"
|
49
|
+
```
|
50
|
+
|
51
|
+
|
52
|
+
Now you can access the object history through `CamelTrail.for(object)` like:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
project = Project.create
|
56
|
+
CamelTrail.for(project).size
|
57
|
+
# => 1
|
58
|
+
```
|
59
|
+
|
60
|
+
The user performing the action will be recorded from the Thread local `:user_id`.
|
61
|
+
|
62
|
+
Then, require the engine in your `application.rb`
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
require "camel_trail"
|
66
|
+
```
|
67
|
+
|
68
|
+
## Contributing
|
69
|
+
|
70
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/powerhome/power-tools.
|
71
|
+
|
72
|
+
## License
|
73
|
+
|
74
|
+
The package is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CamelTrail
|
4
|
+
module Config
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# CamelTrail Stores backtrace info in `camel_trail_histories`
|
8
|
+
# It's config defaults to `Rails.backtrace_cleaner`
|
9
|
+
# You can optionally set it to your customized backtrace cleaner
|
10
|
+
# via `CamelTrail.config.backtrace_cleaner = MyBacktraceCleaner`
|
11
|
+
mattr_accessor :backtrace_cleaner
|
12
|
+
|
13
|
+
# Allows to set configurion for CamelTrail
|
14
|
+
def config(&block)
|
15
|
+
class_eval(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Optionally set `table_name_prefix` to customize default table name.
|
19
|
+
# Defaults to `camel_trail_histories`
|
20
|
+
def table_name_prefix(value)
|
21
|
+
CamelTrail.table_name_prefix = value
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sets `current_session_user_id` to include user info in `camel_trail_histories` table.
|
25
|
+
def current_session_user_id(&block)
|
26
|
+
@current_session_user_id = block if block
|
27
|
+
@current_session_user_id
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CamelTrail
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
isolate_namespace CamelTrail
|
6
|
+
|
7
|
+
config.generators do |g|
|
8
|
+
g.test_framework :rspec
|
9
|
+
end
|
10
|
+
|
11
|
+
config.generators do |g|
|
12
|
+
g.fixture_replacement :factory_bot, dir: "spec/factories"
|
13
|
+
end
|
14
|
+
|
15
|
+
initializer :append_migrations do |app|
|
16
|
+
unless app.root.to_s.match? root.to_s
|
17
|
+
config.paths["db/migrate"].expanded.each do |expanded_path|
|
18
|
+
app.config.paths["db/migrate"] << expanded_path
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
initializer "camel_trail.backtrace_cleaner" do
|
24
|
+
CamelTrail::Config.backtrace_cleaner ||= Rails.backtrace_cleaner
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CamelTrail
|
4
|
+
class EntryPresenter
|
5
|
+
delegate :backtrace,
|
6
|
+
:created_at,
|
7
|
+
:activity,
|
8
|
+
:source_type,
|
9
|
+
:source_id,
|
10
|
+
:source_changes,
|
11
|
+
:user_id,
|
12
|
+
:user,
|
13
|
+
:note,
|
14
|
+
:id,
|
15
|
+
to: :history, prefix: false
|
16
|
+
def initialize(history)
|
17
|
+
@history = history
|
18
|
+
end
|
19
|
+
|
20
|
+
# Details the changes made to the source object.
|
21
|
+
def describe_changes
|
22
|
+
@history.source_changes.map do |field, change|
|
23
|
+
describe_change(field, change)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :history
|
30
|
+
|
31
|
+
def describe_change(field, change)
|
32
|
+
values = change.map { |value| format_value(field, value) }
|
33
|
+
return unless values.any?
|
34
|
+
|
35
|
+
from, to = *values
|
36
|
+
to = "nothing" if to.blank?
|
37
|
+
build_message(field, from, to)
|
38
|
+
rescue
|
39
|
+
"#{field}: #{from} - #{to}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def format_value(field, val)
|
43
|
+
val = val.strftime("%m/%d/%Y") if val.respond_to?(:strftime)
|
44
|
+
val = val.map(&:humanize).join(", ") if val.is_a?(Array) && val.first.is_a?(String)
|
45
|
+
val = number_to_currency(val, precision: 2) if numeric?(field, val)
|
46
|
+
val
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_message(field, from, to)
|
50
|
+
if to == true
|
51
|
+
"Selected #{field.to_s.titleize}"
|
52
|
+
elsif from == true
|
53
|
+
"Deselected #{field.to_s.titleize}"
|
54
|
+
elsif from.present?
|
55
|
+
"Changed #{field.to_s.titleize} from #{from} to #{to}"
|
56
|
+
else
|
57
|
+
"Changed #{field.to_s.titleize} to #{to}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def numeric?(field, val)
|
62
|
+
field =~ /amount|price|cost|ceiling/i && val.respond_to?(:to_f) && val != ""
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CamelTrail
|
4
|
+
module Recordable
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
around_save :__record_changes
|
9
|
+
end
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
attr_reader :__camel_trail_source_changes
|
13
|
+
|
14
|
+
def history_options(source_changes: nil)
|
15
|
+
@__camel_trail_source_changes = source_changes
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def __record_changes
|
22
|
+
activity = new_record? ? :created : :updated
|
23
|
+
yield
|
24
|
+
CamelTrail.record!(self, activity, __camel_trail_source_changes,
|
25
|
+
CamelTrail::Config.current_session_user_id&.call)
|
26
|
+
end
|
27
|
+
|
28
|
+
def __camel_trail_source_changes
|
29
|
+
source_changes = self.class.__camel_trail_source_changes
|
30
|
+
|
31
|
+
case source_changes
|
32
|
+
when Proc then instance_exec(&source_changes)
|
33
|
+
when Symbol then send(source_changes)
|
34
|
+
else saved_changes
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CamelTrail
|
4
|
+
module YAMLUnsafeCoder
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Loads the object from YAML.
|
8
|
+
def load(payload)
|
9
|
+
return unless payload
|
10
|
+
|
11
|
+
if YAML.respond_to?(:unsafe_load)
|
12
|
+
YAML.unsafe_load(payload)
|
13
|
+
else
|
14
|
+
YAML.load(payload) # rubocop:disable Security/YAMLLoad
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Dumps the object to YAML.
|
19
|
+
def dump(obj)
|
20
|
+
YAML.dump obj
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/camel_trail.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "attr_encrypted"
|
4
|
+
require "nitro_config"
|
5
|
+
require "camel_trail/engine"
|
6
|
+
require "camel_trail/entry_presenter"
|
7
|
+
require "camel_trail/recordable"
|
8
|
+
require "camel_trail/yaml_unsafe_coder"
|
9
|
+
require "camel_trail/config"
|
10
|
+
|
11
|
+
module CamelTrail
|
12
|
+
module_function
|
13
|
+
|
14
|
+
mattr_accessor(:table_name_prefix) { "camel_trail_" }
|
15
|
+
|
16
|
+
# Allows to set configurion for CamelTrail
|
17
|
+
#
|
18
|
+
# CamelTrail.config do
|
19
|
+
# configs to be set
|
20
|
+
# end
|
21
|
+
def config(...)
|
22
|
+
Config.config(...)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Records a history activity for the given object
|
26
|
+
#
|
27
|
+
# @param object [#id] the object recording a history
|
28
|
+
# @param activity [Symbol] the activity that generated the history entry (i.e.: :created)
|
29
|
+
# @param changes [Hash] an ActiveRecord changes hash (i.e.: { 'name' => ['old', 'new'] })
|
30
|
+
# @param user_id [Integer] the id of the user triggered the history entry
|
31
|
+
# @param note [String] a note that can be attached to a history
|
32
|
+
# @param encrypted [Boolean] whether to encrypt or not the note
|
33
|
+
# @return [CamelTrail::EntryPresenter]
|
34
|
+
|
35
|
+
# rubocop:disable Metrics/ParameterLists
|
36
|
+
def record!(object, activity, changes, user_id, note = nil, encrypted: false)
|
37
|
+
klass = encrypted ? CamelTrail::EncryptedHistory : CamelTrail::History
|
38
|
+
|
39
|
+
history = klass.for_source(object).create!(
|
40
|
+
source_changes: changes,
|
41
|
+
activity: activity,
|
42
|
+
user_id: user_id,
|
43
|
+
note: note
|
44
|
+
)
|
45
|
+
EntryPresenter.new(history)
|
46
|
+
end
|
47
|
+
# rubocop:enable Metrics/ParameterLists
|
48
|
+
|
49
|
+
# A collection of the history entries associated with the object
|
50
|
+
#
|
51
|
+
# @param object [#id] the object recording a history
|
52
|
+
# @return [Array<CamelTrail::EntryPresenter>]
|
53
|
+
def for(object, encrypted: false, in_natural_order: false)
|
54
|
+
klass = encrypted ? CamelTrail::EncryptedHistory : CamelTrail::History
|
55
|
+
|
56
|
+
history_collection = in_natural_order ? klass.for_source(object).in_natural_order : klass.for_source(object)
|
57
|
+
history_collection.to_a.map do |history|
|
58
|
+
CamelTrail::EntryPresenter.new(history)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
metadata
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: camel_trail
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gurban Haydarov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-03-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nitro_config
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: powerhome-attr_encrypted
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.2.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.2.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 6.0.6.1
|
48
|
+
- - "<"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '7.0'
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 6.0.6.1
|
58
|
+
- - "<"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '7.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: license_finder
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '7.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '7.0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rake
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '13'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '13'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: rspec
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '3.0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '3.0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: rspec-rails
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 5.1.2
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 5.1.2
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: rubocop-powerhome
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - '='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 0.5.0
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - '='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 0.5.0
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: simplecov
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - '='
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: 0.15.1
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - '='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: 0.15.1
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: sqlite3
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: 1.4.2
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: 1.4.2
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: yard
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - '='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 0.9.21
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - '='
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 0.9.21
|
173
|
+
description: CamelTrail makes it easy to keep a history of attribute changes on a
|
174
|
+
model
|
175
|
+
email:
|
176
|
+
- gurban@hey.com
|
177
|
+
executables: []
|
178
|
+
extensions: []
|
179
|
+
extra_rdoc_files: []
|
180
|
+
files:
|
181
|
+
- Rakefile
|
182
|
+
- app/models/camel_trail/application_record.rb
|
183
|
+
- app/models/camel_trail/encrypted_history.rb
|
184
|
+
- app/models/camel_trail/history.rb
|
185
|
+
- config/database.yml
|
186
|
+
- db/migrate/20200514201449_create_camel_trails.rb
|
187
|
+
- docs/README.md
|
188
|
+
- lib/camel_trail.rb
|
189
|
+
- lib/camel_trail/config.rb
|
190
|
+
- lib/camel_trail/engine.rb
|
191
|
+
- lib/camel_trail/entry_presenter.rb
|
192
|
+
- lib/camel_trail/recordable.rb
|
193
|
+
- lib/camel_trail/version.rb
|
194
|
+
- lib/camel_trail/yaml_unsafe_coder.rb
|
195
|
+
homepage: https://github.com/powerhome/power-tools
|
196
|
+
licenses:
|
197
|
+
- MIT
|
198
|
+
metadata:
|
199
|
+
rubygems_mfa_required: 'true'
|
200
|
+
post_install_message:
|
201
|
+
rdoc_options: []
|
202
|
+
require_paths:
|
203
|
+
- lib
|
204
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '2.7'
|
209
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
210
|
+
requirements:
|
211
|
+
- - ">="
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '0'
|
214
|
+
requirements: []
|
215
|
+
rubygems_version: 3.4.6
|
216
|
+
signing_key:
|
217
|
+
specification_version: 4
|
218
|
+
summary: Simple way to track database changes
|
219
|
+
test_files: []
|