historiographer 3.1.2 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +115 -39
- data/{Gemfile → Users/brettshollenberger/programming/historiographer/Gemfile} +1 -2
- data/Users/brettshollenberger/programming/historiographer/Gemfile.lock +341 -0
- data/Users/brettshollenberger/programming/historiographer/Guardfile +4 -0
- data/Users/brettshollenberger/programming/historiographer/LICENSE.txt +20 -0
- data/Users/brettshollenberger/programming/historiographer/README.md +298 -0
- data/Users/brettshollenberger/programming/historiographer/historiographer-4.1.0.gem +0 -0
- data/{historiographer.gemspec → Users/brettshollenberger/programming/historiographer/historiographer.gemspec} +5 -46
- data/Users/brettshollenberger/programming/historiographer/lib/historiographer/configuration.rb +36 -0
- data/{lib → Users/brettshollenberger/programming/historiographer/lib}/historiographer/history.rb +9 -2
- data/{lib → Users/brettshollenberger/programming/historiographer/lib}/historiographer/history_migration.rb +13 -5
- data/{lib → Users/brettshollenberger/programming/historiographer/lib}/historiographer/relation.rb +1 -1
- data/Users/brettshollenberger/programming/historiographer/lib/historiographer/version.rb +3 -0
- data/{lib → Users/brettshollenberger/programming/historiographer/lib}/historiographer.rb +183 -13
- data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/database.yml +5 -3
- data/Users/brettshollenberger/programming/historiographer/spec/db/migrate/20241109182017_create_comments.rb +13 -0
- data/Users/brettshollenberger/programming/historiographer/spec/db/migrate/20241109182020_create_comment_histories.rb +9 -0
- data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/schema.rb +80 -41
- data/Users/brettshollenberger/programming/historiographer/spec/examples.txt +40 -0
- data/{spec → Users/brettshollenberger/programming/historiographer/spec}/historiographer_spec.rb +265 -40
- data/{spec → Users/brettshollenberger/programming/historiographer/spec}/spec_helper.rb +8 -4
- metadata +43 -41
- data/.document +0 -5
- data/.rspec +0 -1
- data/.ruby-version +0 -1
- data/.standalone_migrations +0 -6
- data/Gemfile.lock +0 -289
- data/Guardfile +0 -70
- data/VERSION +0 -1
- data/spec/examples.txt +0 -29
- /data/{Rakefile → Users/brettshollenberger/programming/historiographer/Rakefile} +0 -0
- /data/{init.rb → Users/brettshollenberger/programming/historiographer/init.rb} +0 -0
- /data/{lib → Users/brettshollenberger/programming/historiographer/lib}/historiographer/history_migration_mysql.rb +0 -0
- /data/{lib → Users/brettshollenberger/programming/historiographer/lib}/historiographer/mysql_migration.rb +0 -0
- /data/{lib → Users/brettshollenberger/programming/historiographer/lib}/historiographer/postgres_migration.rb +0 -0
- /data/{lib → Users/brettshollenberger/programming/historiographer/lib}/historiographer/safe.rb +0 -0
- /data/{lib → Users/brettshollenberger/programming/historiographer/lib}/historiographer/silent.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20161121212228_create_posts.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20161121212229_create_post_histories.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20161121212230_create_authors.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20161121212231_create_author_histories.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20161121212232_create_users.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20171011194624_create_safe_posts.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20171011194715_create_safe_post_histories.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20191024142304_create_thing_with_compound_index.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20191024142352_create_thing_with_compound_index_history.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20191024203106_create_thing_without_history.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20221018204220_create_silent_posts.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/db/migrate/20221018204255_create_silent_post_histories.rb +0 -0
- /data/{spec → Users/brettshollenberger/programming/historiographer/spec}/factories/post.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23b67927669a8cddbbf3a4097aba1c238f086324ad6e277bb728525263e12381
|
4
|
+
data.tar.gz: bf24dcdae837fc9a443810e24d1f559a87d3c8d778acb1904c308dd11017d15f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49c8d86b477f67c016d52aae1cb721a7d33bfecc04de761f50d7c3cc42c4481eb6b3863f2b3c89f226f2321a79c92411f70e6344f6e933bde7a2245504a876a1
|
7
|
+
data.tar.gz: 667b8032e144c0bc0a61cedbbffcf51dd5a90eac68ee8dfe95920e6500da6fc9f39c6b374f419907031822fa12d858b9bf79c77a8323a57192ca3c01da680b8b
|
data/README.md
CHANGED
@@ -8,21 +8,11 @@ Historiographer fixes this problem in a better way than existing auditing gems.
|
|
8
8
|
|
9
9
|
The Audited gem has some serious flaws.
|
10
10
|
|
11
|
-
|
11
|
+
1. The `versions` table quickly grows too large to query
|
12
12
|
|
13
|
-
|
13
|
+
2. It doesn't provide the indexes you need from your primary tables
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
Why does this happen?
|
18
|
-
|
19
|
-
First, `audited` only tracks a record of what changed, so there's no way to "go back in time" and see what the data looked like back when a problem occurred without replaying every single audit.
|
20
|
-
|
21
|
-
Second, it tracks changes as JSON. While some data stores have JSON querying semantics, not all do, making it very hard to ask complex questions of your historical data -- that's the whole reason you're keeping it around.
|
22
|
-
|
23
|
-
Third, it doesn't maintain indexes on your data. If you maintain an index on the primary table, wouldn't you also want to look up historical records using the same columns? Historical data is MUCH larger than "latest snapshot" data, so, duh, of course you do.
|
24
|
-
|
25
|
-
Finally, Audited creates just one table for all audits. Historical data is big. It's not unusual for an audited gem table to get into the many millions of rows, and need to be constantly partitioned to maintain any kind of efficiency.
|
15
|
+
3. It doesn't provdie out-of-the-box snapshots
|
26
16
|
|
27
17
|
## How does Historiographer solve these problems?
|
28
18
|
|
@@ -30,44 +20,116 @@ Historiographer introduces the concept of _history tables:_ append-only tables t
|
|
30
20
|
|
31
21
|
If you have a `posts` table:
|
32
22
|
|
33
|
-
| id
|
34
|
-
|
|
35
|
-
| 1
|
36
|
-
| 2
|
23
|
+
| id | title |
|
24
|
+
| :-- | :------------- |
|
25
|
+
| 1 | My Great Post |
|
26
|
+
| 2 | My Second Post |
|
37
27
|
|
38
28
|
You'll also have a `post_histories_table`:
|
39
29
|
|
40
|
-
| id
|
41
|
-
|
|
42
|
-
| 1
|
43
|
-
| 2
|
30
|
+
| id | post_id | title | history_started_at | history_ended_at | history_user_id |
|
31
|
+
| :-- | :------ | :------------- | :----------------- | :--------------- | :-------------- |
|
32
|
+
| 1 | 1 | My Great Post | '2019-11-08' | NULL | 1 |
|
33
|
+
| 2 | 2 | My Second Post | '2019-11-08' | NULL | 1 |
|
44
34
|
|
45
35
|
If you change the title of the 1st post:
|
46
36
|
|
47
|
-
|
37
|
+
`Post.find(1).update(title: "Title With Better SEO", history_user_id: current_user.id)`
|
48
38
|
|
49
39
|
You'll expect your `posts` table to be updated directly:
|
50
40
|
|
51
|
-
| id
|
52
|
-
|
|
53
|
-
| 1
|
54
|
-
| 2
|
41
|
+
| id | title |
|
42
|
+
| :-- | :-------------------- |
|
43
|
+
| 1 | Title With Better SEO |
|
44
|
+
| 2 | My Second Post |
|
55
45
|
|
56
46
|
But also, your `histories` table will be updated:
|
57
47
|
|
58
|
-
| id
|
59
|
-
|
|
60
|
-
| 1
|
61
|
-
| 2
|
62
|
-
| 1
|
48
|
+
| id | post_id | title | history_started_at | history_ended_at | history_user_id |
|
49
|
+
| :-- | :------ | :-------------------- | :----------------- | :--------------- | :-------------- |
|
50
|
+
| 1 | 1 | My Great Post | '2019-11-08' | '2019-11-09' | 1 |
|
51
|
+
| 2 | 2 | My Second Post | '2019-11-08' | NULL | 1 |
|
52
|
+
| 1 | 1 | Title With Better SEO | '2019-11-09' | NULL | 1 |
|
63
53
|
|
64
54
|
A few things have happened here:
|
65
55
|
|
66
56
|
1. The primary table (`posts`) is updated directly
|
67
57
|
2. The existing history for `post_id=1` is timestamped when its `history_ended_at`, so that we can see when the post had the title "My Great Post"
|
68
|
-
3. A new history record is appended to the table containing a complete snapshot of the record, and a `NULL` `history_ended_at`. That's because this is the current history.
|
58
|
+
3. A new history record is appended to the table containing a complete snapshot of the record, and a `NULL` `history_ended_at`. That's because this is the current history.
|
69
59
|
4. A record of _who_ made the change is saved (`history_user_id`). You can join to your users table to see more data.
|
70
60
|
|
61
|
+
## Snapshots
|
62
|
+
|
63
|
+
Snapshots are particularly useful for two key use cases:
|
64
|
+
|
65
|
+
### 1. Time Travel & Auditing
|
66
|
+
|
67
|
+
When you need to see exactly what your data looked like at a specific point in time - not just individual records, but entire object graphs with all their associations. This is invaluable for:
|
68
|
+
|
69
|
+
- Debugging production issues ("What did the entire order look like when this happened?")
|
70
|
+
- Compliance requirements ("Show me the exact state of this patient's record on January 1st")
|
71
|
+
- Auditing complex workflows ("What was the state of this loan application when it was approved?")
|
72
|
+
|
73
|
+
### 2. Machine Learning & Analytics
|
74
|
+
|
75
|
+
When you need immutable snapshots of data for:
|
76
|
+
|
77
|
+
- Training data versioning
|
78
|
+
- Feature engineering
|
79
|
+
- Model validation
|
80
|
+
- A/B test analysis
|
81
|
+
- Ensuring reproducibility of results
|
82
|
+
|
83
|
+
### Taking Snapshots
|
84
|
+
|
85
|
+
You can take a snapshot of a record and all its associated records:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
post = Post.find(1)
|
89
|
+
post.snapshot(history_user_id: current_user.id)
|
90
|
+
```
|
91
|
+
|
92
|
+
This will:
|
93
|
+
|
94
|
+
1. Create a history record for the post
|
95
|
+
2. Create history records for all associated records (comments, author, etc.)
|
96
|
+
3. Link these history records together with a shared `snapshot_id`
|
97
|
+
|
98
|
+
You can retrieve the latest snapshot using:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
post = Post.find(1)
|
102
|
+
snapshot = post.latest_snapshot
|
103
|
+
|
104
|
+
# Access associated records from the snapshot
|
105
|
+
snapshot.comments # Returns CommentHistory records
|
106
|
+
snapshot.author # Returns AuthorHistory record
|
107
|
+
```
|
108
|
+
|
109
|
+
Snapshots are immutable - you cannot modify history records that are part of a snapshot. This guarantees that your historical data remains unchanged, which is crucial for both auditing and machine learning applications.
|
110
|
+
|
111
|
+
### Snapshot-Only Mode
|
112
|
+
|
113
|
+
If you want to only track snapshots and not record every individual change, you can configure Historiographer to operate in snapshot-only mode:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
Historiographer::Configuration.mode = :snapshot_only
|
117
|
+
```
|
118
|
+
|
119
|
+
In this mode:
|
120
|
+
|
121
|
+
- Regular updates/changes will not create history records
|
122
|
+
- Only explicit calls to `snapshot` will create history records
|
123
|
+
- Each snapshot still captures the complete state of the record and its associations
|
124
|
+
|
125
|
+
This can be useful when:
|
126
|
+
|
127
|
+
- You only care about specific points in time rather than every change
|
128
|
+
- You want to reduce the number of history records created
|
129
|
+
- You need to capture the state of complex object graphs at specific moments
|
130
|
+
- You're versioning training data for machine learning models
|
131
|
+
- You need to maintain immutable audit trails at specific checkpoints
|
132
|
+
|
71
133
|
# Getting Started
|
72
134
|
|
73
135
|
Whenever you include the `Historiographer` gem in your ActiveRecord model, it allows you to insert, update, or delete data as you normally would.
|
@@ -78,18 +140,33 @@ class Post < ActiveRecord::Base
|
|
78
140
|
end
|
79
141
|
```
|
80
142
|
|
81
|
-
|
143
|
+
### History Modes
|
144
|
+
|
145
|
+
Historiographer supports two modes of operation:
|
146
|
+
|
147
|
+
1. **:histories mode** (default) - Records history for every change to a record
|
148
|
+
2. **:snapshot_only mode** - Only records history when explicitly taking snapshots
|
149
|
+
|
150
|
+
You can configure the mode globally:
|
82
151
|
|
83
152
|
```ruby
|
84
|
-
|
85
|
-
|
153
|
+
# In an initializer
|
154
|
+
Historiographer::Configuration.mode = :histories # Default mode
|
155
|
+
# or
|
156
|
+
Historiographer::Configuration.mode = :snapshot_only
|
86
157
|
```
|
87
158
|
|
88
|
-
|
159
|
+
Or per model using `historiographer_mode`:
|
89
160
|
|
90
161
|
```ruby
|
91
162
|
class Post < ActiveRecord::Base
|
92
|
-
include Historiographer
|
163
|
+
include Historiographer
|
164
|
+
historiographer_mode :snapshot_only # Only record history when .snapshot is called
|
165
|
+
end
|
166
|
+
|
167
|
+
class Comment < ActiveRecord::Base
|
168
|
+
include Historiographer
|
169
|
+
historiographer_mode :histories # Record history for every change (default)
|
93
170
|
end
|
94
171
|
```
|
95
172
|
|
@@ -210,12 +287,11 @@ end
|
|
210
287
|
== Mysql Install
|
211
288
|
|
212
289
|
For contributors on OSX, you may have difficulty installing mysql:
|
213
|
-
|
290
|
+
|
214
291
|
```
|
215
292
|
gem install mysql2 -v '0.4.10' --source 'https://rubygems.org/' -- --with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include
|
216
293
|
```
|
217
294
|
|
218
|
-
|
219
295
|
== Copyright
|
220
296
|
|
221
297
|
Copyright (c) 2016-2020 brettshollenberger. See LICENSE.txt for
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
source 'https://rubygems.org'
|
4
|
-
ruby '
|
4
|
+
ruby '3.0.2'
|
5
5
|
|
6
6
|
gem 'activerecord', '>= 6'
|
7
7
|
gem 'activerecord-import'
|
@@ -19,7 +19,6 @@ group :development, :test do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
group :development do
|
22
|
-
gem 'bundler', '~> 1.0'
|
23
22
|
gem 'jeweler', git: 'https://github.com/technicalpickles/jeweler', branch: 'master'
|
24
23
|
gem 'rdoc', '~> 3.12'
|
25
24
|
gem 'simplecov', '>= 0'
|
@@ -0,0 +1,341 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/technicalpickles/jeweler
|
3
|
+
revision: 2ab86309fc2494ba2a4e9c86c514742cd4f681c2
|
4
|
+
branch: master
|
5
|
+
specs:
|
6
|
+
jeweler (2.3.9)
|
7
|
+
builder
|
8
|
+
bundler
|
9
|
+
git (>= 1.2.5)
|
10
|
+
github_api (~> 0.16.0)
|
11
|
+
highline (>= 1.6.15)
|
12
|
+
nokogiri (>= 1.5.10)
|
13
|
+
psych
|
14
|
+
rake
|
15
|
+
rdoc
|
16
|
+
semver2
|
17
|
+
|
18
|
+
GEM
|
19
|
+
remote: https://rubygems.org/
|
20
|
+
specs:
|
21
|
+
actioncable (7.1.5)
|
22
|
+
actionpack (= 7.1.5)
|
23
|
+
activesupport (= 7.1.5)
|
24
|
+
nio4r (~> 2.0)
|
25
|
+
websocket-driver (>= 0.6.1)
|
26
|
+
zeitwerk (~> 2.6)
|
27
|
+
actionmailbox (7.1.5)
|
28
|
+
actionpack (= 7.1.5)
|
29
|
+
activejob (= 7.1.5)
|
30
|
+
activerecord (= 7.1.5)
|
31
|
+
activestorage (= 7.1.5)
|
32
|
+
activesupport (= 7.1.5)
|
33
|
+
mail (>= 2.7.1)
|
34
|
+
net-imap
|
35
|
+
net-pop
|
36
|
+
net-smtp
|
37
|
+
actionmailer (7.1.5)
|
38
|
+
actionpack (= 7.1.5)
|
39
|
+
actionview (= 7.1.5)
|
40
|
+
activejob (= 7.1.5)
|
41
|
+
activesupport (= 7.1.5)
|
42
|
+
mail (~> 2.5, >= 2.5.4)
|
43
|
+
net-imap
|
44
|
+
net-pop
|
45
|
+
net-smtp
|
46
|
+
rails-dom-testing (~> 2.2)
|
47
|
+
actionpack (7.1.5)
|
48
|
+
actionview (= 7.1.5)
|
49
|
+
activesupport (= 7.1.5)
|
50
|
+
nokogiri (>= 1.8.5)
|
51
|
+
racc
|
52
|
+
rack (>= 2.2.4)
|
53
|
+
rack-session (>= 1.0.1)
|
54
|
+
rack-test (>= 0.6.3)
|
55
|
+
rails-dom-testing (~> 2.2)
|
56
|
+
rails-html-sanitizer (~> 1.6)
|
57
|
+
actiontext (7.1.5)
|
58
|
+
actionpack (= 7.1.5)
|
59
|
+
activerecord (= 7.1.5)
|
60
|
+
activestorage (= 7.1.5)
|
61
|
+
activesupport (= 7.1.5)
|
62
|
+
globalid (>= 0.6.0)
|
63
|
+
nokogiri (>= 1.8.5)
|
64
|
+
actionview (7.1.5)
|
65
|
+
activesupport (= 7.1.5)
|
66
|
+
builder (~> 3.1)
|
67
|
+
erubi (~> 1.11)
|
68
|
+
rails-dom-testing (~> 2.2)
|
69
|
+
rails-html-sanitizer (~> 1.6)
|
70
|
+
activejob (7.1.5)
|
71
|
+
activesupport (= 7.1.5)
|
72
|
+
globalid (>= 0.3.6)
|
73
|
+
activemodel (7.1.5)
|
74
|
+
activesupport (= 7.1.5)
|
75
|
+
activerecord (7.1.5)
|
76
|
+
activemodel (= 7.1.5)
|
77
|
+
activesupport (= 7.1.5)
|
78
|
+
timeout (>= 0.4.0)
|
79
|
+
activerecord-import (1.8.1)
|
80
|
+
activerecord (>= 4.2)
|
81
|
+
activestorage (7.1.5)
|
82
|
+
actionpack (= 7.1.5)
|
83
|
+
activejob (= 7.1.5)
|
84
|
+
activerecord (= 7.1.5)
|
85
|
+
activesupport (= 7.1.5)
|
86
|
+
marcel (~> 1.0)
|
87
|
+
activesupport (7.1.5)
|
88
|
+
base64
|
89
|
+
benchmark (>= 0.3)
|
90
|
+
bigdecimal
|
91
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
92
|
+
connection_pool (>= 2.2.5)
|
93
|
+
drb
|
94
|
+
i18n (>= 1.6, < 2)
|
95
|
+
logger (>= 1.4.2)
|
96
|
+
minitest (>= 5.1)
|
97
|
+
mutex_m
|
98
|
+
securerandom (>= 0.3)
|
99
|
+
tzinfo (~> 2.0)
|
100
|
+
addressable (2.4.0)
|
101
|
+
base64 (0.2.0)
|
102
|
+
benchmark (0.4.0)
|
103
|
+
bigdecimal (3.1.8)
|
104
|
+
builder (3.3.0)
|
105
|
+
coderay (1.1.3)
|
106
|
+
concurrent-ruby (1.3.4)
|
107
|
+
connection_pool (2.4.1)
|
108
|
+
crass (1.0.6)
|
109
|
+
database_cleaner (2.1.0)
|
110
|
+
database_cleaner-active_record (>= 2, < 3)
|
111
|
+
database_cleaner-active_record (2.2.0)
|
112
|
+
activerecord (>= 5.a)
|
113
|
+
database_cleaner-core (~> 2.0.0)
|
114
|
+
database_cleaner-core (2.0.1)
|
115
|
+
date (3.4.0)
|
116
|
+
descendants_tracker (0.0.4)
|
117
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
118
|
+
diff-lcs (1.5.1)
|
119
|
+
docile (1.4.1)
|
120
|
+
drb (2.2.1)
|
121
|
+
erubi (1.13.0)
|
122
|
+
factory_bot (6.5.0)
|
123
|
+
activesupport (>= 5.0.0)
|
124
|
+
factory_bot_rails (6.4.4)
|
125
|
+
factory_bot (~> 6.5)
|
126
|
+
railties (>= 5.0.0)
|
127
|
+
faraday (0.9.2)
|
128
|
+
multipart-post (>= 1.2, < 3)
|
129
|
+
ffi (1.17.0-arm64-darwin)
|
130
|
+
ffi (1.17.0-x86_64-darwin)
|
131
|
+
formatador (1.1.0)
|
132
|
+
git (1.11.0)
|
133
|
+
rchardet (~> 1.8)
|
134
|
+
github_api (0.16.0)
|
135
|
+
addressable (~> 2.4.0)
|
136
|
+
descendants_tracker (~> 0.0.4)
|
137
|
+
faraday (~> 0.8, < 0.10)
|
138
|
+
hashie (>= 3.4)
|
139
|
+
mime-types (>= 1.16, < 3.0)
|
140
|
+
oauth2 (~> 1.0)
|
141
|
+
globalid (1.2.1)
|
142
|
+
activesupport (>= 6.1)
|
143
|
+
guard (2.19.0)
|
144
|
+
formatador (>= 0.2.4)
|
145
|
+
listen (>= 2.7, < 4.0)
|
146
|
+
lumberjack (>= 1.0.12, < 2.0)
|
147
|
+
nenv (~> 0.1)
|
148
|
+
notiffany (~> 0.0)
|
149
|
+
pry (>= 0.13.0)
|
150
|
+
shellany (~> 0.0)
|
151
|
+
thor (>= 0.18.1)
|
152
|
+
guard-compat (1.2.1)
|
153
|
+
guard-rspec (4.7.3)
|
154
|
+
guard (~> 2.1)
|
155
|
+
guard-compat (~> 1.1)
|
156
|
+
rspec (>= 2.99.0, < 4.0)
|
157
|
+
hashie (5.0.0)
|
158
|
+
highline (3.1.1)
|
159
|
+
reline
|
160
|
+
i18n (1.14.6)
|
161
|
+
concurrent-ruby (~> 1.0)
|
162
|
+
io-console (0.7.2)
|
163
|
+
irb (1.12.0)
|
164
|
+
rdoc
|
165
|
+
reline (>= 0.4.2)
|
166
|
+
json (1.8.6)
|
167
|
+
jwt (2.9.3)
|
168
|
+
base64
|
169
|
+
listen (3.9.0)
|
170
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
171
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
172
|
+
logger (1.6.1)
|
173
|
+
loofah (2.23.1)
|
174
|
+
crass (~> 1.0.2)
|
175
|
+
nokogiri (>= 1.12.0)
|
176
|
+
lumberjack (1.2.10)
|
177
|
+
mail (2.8.1)
|
178
|
+
mini_mime (>= 0.1.1)
|
179
|
+
net-imap
|
180
|
+
net-pop
|
181
|
+
net-smtp
|
182
|
+
marcel (1.0.4)
|
183
|
+
method_source (1.1.0)
|
184
|
+
mime-types (2.99.3)
|
185
|
+
mini_mime (1.1.5)
|
186
|
+
minitest (5.25.1)
|
187
|
+
multi_json (1.15.0)
|
188
|
+
multi_xml (0.6.0)
|
189
|
+
multipart-post (2.4.1)
|
190
|
+
mutex_m (0.2.0)
|
191
|
+
mysql2 (0.5.0)
|
192
|
+
nenv (0.3.0)
|
193
|
+
net-imap (0.4.18)
|
194
|
+
date
|
195
|
+
net-protocol
|
196
|
+
net-pop (0.1.2)
|
197
|
+
net-protocol
|
198
|
+
net-protocol (0.2.2)
|
199
|
+
timeout
|
200
|
+
net-smtp (0.5.0)
|
201
|
+
net-protocol
|
202
|
+
nio4r (2.7.4)
|
203
|
+
nokogiri (1.16.7-arm64-darwin)
|
204
|
+
racc (~> 1.4)
|
205
|
+
nokogiri (1.16.7-x86_64-darwin)
|
206
|
+
racc (~> 1.4)
|
207
|
+
notiffany (0.1.3)
|
208
|
+
nenv (~> 0.1)
|
209
|
+
shellany (~> 0.0)
|
210
|
+
oauth2 (1.4.8)
|
211
|
+
faraday (>= 0.8, < 3.0)
|
212
|
+
jwt (>= 1.0, < 3.0)
|
213
|
+
multi_json (~> 1.3)
|
214
|
+
multi_xml (~> 0.5)
|
215
|
+
rack (>= 1.2, < 3)
|
216
|
+
paranoia (3.0.0)
|
217
|
+
activerecord (>= 6, < 8.1)
|
218
|
+
pg (1.5.9)
|
219
|
+
pry (0.14.2)
|
220
|
+
coderay (~> 1.1)
|
221
|
+
method_source (~> 1.0)
|
222
|
+
psych (5.2.0)
|
223
|
+
stringio
|
224
|
+
racc (1.8.1)
|
225
|
+
rack (2.2.10)
|
226
|
+
rack-session (1.0.2)
|
227
|
+
rack (< 3)
|
228
|
+
rack-test (2.1.0)
|
229
|
+
rack (>= 1.3)
|
230
|
+
rackup (1.0.1)
|
231
|
+
rack (< 3)
|
232
|
+
webrick
|
233
|
+
rails (7.1.5)
|
234
|
+
actioncable (= 7.1.5)
|
235
|
+
actionmailbox (= 7.1.5)
|
236
|
+
actionmailer (= 7.1.5)
|
237
|
+
actionpack (= 7.1.5)
|
238
|
+
actiontext (= 7.1.5)
|
239
|
+
actionview (= 7.1.5)
|
240
|
+
activejob (= 7.1.5)
|
241
|
+
activemodel (= 7.1.5)
|
242
|
+
activerecord (= 7.1.5)
|
243
|
+
activestorage (= 7.1.5)
|
244
|
+
activesupport (= 7.1.5)
|
245
|
+
bundler (>= 1.15.0)
|
246
|
+
railties (= 7.1.5)
|
247
|
+
rails-dom-testing (2.2.0)
|
248
|
+
activesupport (>= 5.0.0)
|
249
|
+
minitest
|
250
|
+
nokogiri (>= 1.6)
|
251
|
+
rails-html-sanitizer (1.6.0)
|
252
|
+
loofah (~> 2.21)
|
253
|
+
nokogiri (~> 1.14)
|
254
|
+
railties (7.1.5)
|
255
|
+
actionpack (= 7.1.5)
|
256
|
+
activesupport (= 7.1.5)
|
257
|
+
irb
|
258
|
+
rackup (>= 1.0.0)
|
259
|
+
rake (>= 12.2)
|
260
|
+
thor (~> 1.0, >= 1.2.2)
|
261
|
+
zeitwerk (~> 2.6)
|
262
|
+
rake (13.2.1)
|
263
|
+
rb-fsevent (0.11.2)
|
264
|
+
rb-inotify (0.11.1)
|
265
|
+
ffi (~> 1.0)
|
266
|
+
rchardet (1.8.0)
|
267
|
+
rdoc (3.12.2)
|
268
|
+
json (~> 1.4)
|
269
|
+
reline (0.5.11)
|
270
|
+
io-console (~> 0.5)
|
271
|
+
rollbar (3.6.0)
|
272
|
+
rspec (3.13.0)
|
273
|
+
rspec-core (~> 3.13.0)
|
274
|
+
rspec-expectations (~> 3.13.0)
|
275
|
+
rspec-mocks (~> 3.13.0)
|
276
|
+
rspec-core (3.13.2)
|
277
|
+
rspec-support (~> 3.13.0)
|
278
|
+
rspec-expectations (3.13.3)
|
279
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
280
|
+
rspec-support (~> 3.13.0)
|
281
|
+
rspec-mocks (3.13.2)
|
282
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
283
|
+
rspec-support (~> 3.13.0)
|
284
|
+
rspec-support (3.13.1)
|
285
|
+
securerandom (0.3.1)
|
286
|
+
semver2 (3.4.2)
|
287
|
+
shellany (0.0.1)
|
288
|
+
simplecov (0.22.0)
|
289
|
+
docile (~> 1.1)
|
290
|
+
simplecov-html (~> 0.11)
|
291
|
+
simplecov_json_formatter (~> 0.1)
|
292
|
+
simplecov-html (0.13.1)
|
293
|
+
simplecov_json_formatter (0.1.4)
|
294
|
+
standalone_migrations (7.2.0)
|
295
|
+
activerecord (>= 6.0.0, < 8.0)
|
296
|
+
nokogiri (~> 1.14)
|
297
|
+
railties (>= 6.0.0, < 8.0)
|
298
|
+
rake (>= 10.0)
|
299
|
+
stringio (3.1.2)
|
300
|
+
thor (1.3.2)
|
301
|
+
thread_safe (0.3.6)
|
302
|
+
timecop (0.9.10)
|
303
|
+
timeout (0.4.2)
|
304
|
+
tzinfo (2.0.6)
|
305
|
+
concurrent-ruby (~> 1.0)
|
306
|
+
webrick (1.9.0)
|
307
|
+
websocket-driver (0.7.6)
|
308
|
+
websocket-extensions (>= 0.1.0)
|
309
|
+
websocket-extensions (0.1.5)
|
310
|
+
zeitwerk (2.6.18)
|
311
|
+
|
312
|
+
PLATFORMS
|
313
|
+
arm64-darwin
|
314
|
+
x86_64-darwin
|
315
|
+
|
316
|
+
DEPENDENCIES
|
317
|
+
activerecord (>= 6)
|
318
|
+
activerecord-import
|
319
|
+
activesupport
|
320
|
+
database_cleaner
|
321
|
+
factory_bot_rails
|
322
|
+
guard
|
323
|
+
guard-rspec
|
324
|
+
jeweler!
|
325
|
+
mysql2 (= 0.5)
|
326
|
+
paranoia
|
327
|
+
pg
|
328
|
+
pry
|
329
|
+
rails (>= 6)
|
330
|
+
rdoc (~> 3.12)
|
331
|
+
rollbar
|
332
|
+
rspec
|
333
|
+
simplecov
|
334
|
+
standalone_migrations
|
335
|
+
timecop
|
336
|
+
|
337
|
+
RUBY VERSION
|
338
|
+
ruby 3.0.2p107
|
339
|
+
|
340
|
+
BUNDLED WITH
|
341
|
+
2.5.23
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2016 Brett Shollenberger
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|