rails-persona 0.2.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 151d4c30715f7f5cf797f1f6924aa286446a57bdc50b4d7b37b9a269cad539ce
4
- data.tar.gz: 26210723fafa5b8f2039d658657793603a7c331f1290bf61c13cccd06d3de47e
3
+ metadata.gz: 504b3d7d32f878f9b512a0d70ce5b5b6870fb311cfdb097d023c564a41716127
4
+ data.tar.gz: 5869948b33c80f3f1bf744ba0edc7875c1af22cb392f0fbabc8726aa70359cc9
5
5
  SHA512:
6
- metadata.gz: f104c0ef798b1db64ecea07ebc75609981be6f34239bb3e471d9f10122399c5e8847f969797163da05f260255cfecd7937cfc84b7ffd87cba55608ecc5c6b754
7
- data.tar.gz: 4707c46dd121ca57529b24418f03b51d5266c4e381d373edc1d9287b77cbc83014dd362521fd76bc9e957da1fa336d69aa0839c82643a9cfcab3e848dbfb19d6
6
+ metadata.gz: 96ebda806fbdd89448dea893b5befb3e17c82d5e1be9dd4d63103e93df29a2ef34a46cfbe8b24228b96012b046e7e7f273020df92bf018fb1981fa934b918fa2
7
+ data.tar.gz: e12d8d2b32ec67d57a30dfad49cfcd78ac0ac0daf4cf3596a9d1cbf1ca5595f7285bdf629359554ad22caf05d90915f384b010866f931bfec38c2da997f4ffe5
data/CHANGELOG.md CHANGED
@@ -1,14 +1,20 @@
1
- # Changelog
2
-
3
- ## [0.1.0] - 2024-05-31
4
-
5
- ### Added
6
- - `Persona::Trackable` concern with DSL (`persona do track :action end`)
7
- - `track!` instance method with optional metadata
8
- - Full query API: `action_count`, `most_frequent_action`, `least_frequent_action`,
9
- `last_action`, `last_active_at`, `inactive_since?`, `ever_did?`,
10
- `persona_summary`, `actions_between`, `activity_log`
11
- - `Persona::Configuration` with `inactivity_threshold_days` and `max_events_per_record`
12
- - `UntrackedActionError` for safety when tracking undeclared actions
13
- - Database migration with polymorphic `persona_events` table
14
- - Railtie for automatic migration path injection
1
+ # Changelog
2
+
3
+ ## [0.2.1] - 2026-06-01
4
+ ### Fixed
5
+ - Replace `config.paths` in Railtie with `File.expand_path` to fix `NoMethodError` on boot (fixes #1)
6
+ - Add missing `tasks/persona_tasks.rake` that was referenced but never created (fixes #2)
7
+ - Fix rake task load path using `__dir__` instead of relative path
8
+
9
+ ## [0.1.0] - 2024-05-31
10
+
11
+ ### Added
12
+ - `Persona::Trackable` concern with DSL (`persona do track :action end`)
13
+ - `track!` instance method with optional metadata
14
+ - Full query API: `action_count`, `most_frequent_action`, `least_frequent_action`,
15
+ `last_action`, `last_active_at`, `inactive_since?`, `ever_did?`,
16
+ `persona_summary`, `actions_between`, `activity_log`
17
+ - `Persona::Configuration` with `inactivity_threshold_days` and `max_events_per_record`
18
+ - `UntrackedActionError` for safety when tracking undeclared actions
19
+ - Database migration with polymorphic `persona_events` table
20
+ - Railtie for automatic migration path injection
data/README.md CHANGED
@@ -1,270 +1,270 @@
1
- # rails-persona 🎭
2
-
3
- > Model-level behavioral analytics for Rails — own your data, zero external services.
4
-
5
- [![Gem Version](https://badge.fury.io/rb/rails-persona.svg)](https://badge.fury.io/rb/rails-persona)
6
- [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
-
8
- **rails-persona** is a lightweight Rails gem that adds first-class behavioral tracking directly to your ActiveRecord models. Unlike [ahoy](https://github.com/ankane/ahoy), which is focused on HTTP visit and page-view tracking, rails-persona is built for **model-level action tracking** — understanding *what your users actually do* in your app, not just what pages they visit.
9
-
10
- ---
11
-
12
- ## Why rails-persona over ahoy?
13
-
14
- | | ahoy | rails-persona |
15
- |---|---|---|
16
- | Focus | HTTP visits + page views | Model actions + user behavior |
17
- | Setup | Controllers + JS snippet | Pure Ruby — one concern |
18
- | Async | Manual Sidekiq setup | Built-in (`async: true`) |
19
- | Bulk tracking | ❌ | ✅ `bulk_track!` with `insert_all!` |
20
- | Class-level analytics | ❌ | ✅ Leaderboards, class summaries |
21
- | Open tracking mode | ❌ | ✅ No whitelist required |
22
- | Streak / pattern queries | ❌ | ✅ `daily_activity`, `peak_hour` |
23
- | Cookies / sessions | Required | Never needed |
24
- | Works on non-User models | Awkward | First-class |
25
-
26
- ---
27
-
28
- ## Installation
29
-
30
- ```ruby
31
- gem "rails-persona"
32
- ```
33
-
34
- ```bash
35
- bundle install
36
- rails db:migrate
37
- ```
38
-
39
- ---
40
-
41
- ## Quick start
42
-
43
- ### 1. Include in any model
44
-
45
- ```ruby
46
- class User < ApplicationRecord
47
- include Persona::Trackable
48
-
49
- persona do
50
- track :login
51
- track :export_report
52
- track :view_dashboard
53
- track :upgrade_plan
54
- end
55
- end
56
- ```
57
-
58
- ### 2. Track actions in your app
59
-
60
- ```ruby
61
- # In a controller, service, or job:
62
- current_user.track!(:login)
63
- current_user.track!(:upgrade_plan, metadata: { plan: "pro", amount: 49 })
64
- ```
65
-
66
- ### 3. Query behavior
67
-
68
- ```ruby
69
- user.action_count(:login) # => 42
70
- user.most_frequent_action # => :login
71
- user.least_frequent_action # => :upgrade_plan
72
- user.top_actions(3) # => { login: 42, view_dashboard: 18, export_report: 5 }
73
- user.last_action # => :export_report
74
- user.last_active_at # => 2024-05-30 14:22 UTC
75
- user.first_action # => :login
76
- user.first_active_at # => 2023-01-10 08:00 UTC
77
- user.inactive_since? # => false (default threshold: 30 days)
78
- user.inactive_since?(7) # => false (custom: 7 days)
79
- user.days_since_last_activity # => 2
80
- user.ever_did?(:export_report) # => true
81
- user.never_did?(:upgrade_plan) # => false
82
- user.action_share(:login) # => 64.6 (% of all events)
83
- user.total_events # => 65
84
-
85
- user.persona_summary
86
- # => { login: 42, view_dashboard: 18, export_report: 5, upgrade_plan: 1 }
87
-
88
- user.actions_between(1.week.ago, Time.current)
89
- # => { login: 7, view_dashboard: 3 }
90
-
91
- user.activity_log(5)
92
- # => [
93
- # { action: :export_report, at: 2024-05-30 14:22:00, metadata: {} },
94
- # { action: :login, at: 2024-05-30 09:01:00, metadata: {} },
95
- # ]
96
-
97
- user.daily_activity(30)
98
- # => { "2024-05-28" => 4, "2024-05-29" => 7, "2024-05-30" => 2 }
99
-
100
- user.peak_hour
101
- # => 14 (2pm is when this user is most active)
102
- ```
103
-
104
- ---
105
-
106
- ## Class-level analytics
107
-
108
- ```ruby
109
- # Top 10 most active users
110
- User.persona_leaderboard(limit: 10)
111
- # => [
112
- # { record: #<User id=4>, total_events: 128 },
113
- # { record: #<User id=9>, total_events: 97 },
114
- # ]
115
-
116
- # App-wide breakdown of all user actions
117
- User.persona_class_summary
118
- # => { login: 8420, view_dashboard: 5210, export_report: 820 }
119
- ```
120
-
121
- ---
122
-
123
- ## Bulk tracking (high-performance)
124
-
125
- Uses `insert_all!` — no N+1, no per-row callbacks:
126
-
127
- ```ruby
128
- user.bulk_track!([:login, :view_dashboard, :export_report])
129
- user.bulk_track!([:login, :login, :login]) # track repeated actions
130
- ```
131
-
132
- ---
133
-
134
- ## Async tracking (Sidekiq)
135
-
136
- ```ruby
137
- # config/initializers/persona.rb
138
- Persona.configure do |config|
139
- config.async = true # fires a Sidekiq job instead of writing inline
140
- end
141
- ```
142
-
143
- Requires the `sidekiq` gem. Falls back to synchronous if Sidekiq is not available.
144
-
145
- ---
146
-
147
- ## Open tracking (no whitelist)
148
-
149
- If you want to track arbitrary actions without declaring them:
150
-
151
- ```ruby
152
- class Post < ApplicationRecord
153
- include Persona::Trackable
154
-
155
- persona do
156
- open_tracking! # any string is valid — no UntrackedActionError raised
157
- end
158
- end
159
-
160
- post.track!("custom_#{SecureRandom.hex(4)}") # works fine
161
- ```
162
-
163
- ---
164
-
165
- ## Works on any model
166
-
167
- ```ruby
168
- class Post < ApplicationRecord
169
- include Persona::Trackable
170
-
171
- persona do
172
- track :viewed
173
- track :shared
174
- track :bookmarked
175
- end
176
- end
177
-
178
- post.track!(:viewed)
179
- post.action_count(:viewed) # => 128
180
- post.most_frequent_action # => :viewed
181
- Post.persona_class_summary # => { viewed: 50_420, shared: 890, bookmarked: 210 }
182
- ```
183
-
184
- ---
185
-
186
- ## Configuration
187
-
188
- ```ruby
189
- # config/initializers/persona.rb
190
- Persona.configure do |config|
191
- config.inactivity_threshold_days = 14 # default: 30
192
- config.max_events_per_record = 500 # default: nil (unlimited)
193
- config.async = true # default: false
194
- config.auto_prune_after_days = 90 # default: nil (no auto-prune)
195
- end
196
- ```
197
-
198
- ---
199
-
200
- ## Manual pruning
201
-
202
- ```ruby
203
- # Delete events older than 60 days for all records
204
- Persona::Pruner.prune_older_than(60)
205
- ```
206
-
207
- Add to a scheduled job (e.g. `whenever` or Sidekiq-Cron):
208
-
209
- ```ruby
210
- # lib/tasks/persona.rake
211
- namespace :persona do
212
- desc "Prune old persona events"
213
- task prune: :environment do
214
- Persona::Pruner.prune_older_than(Persona.configuration.auto_prune_after_days || 90)
215
- puts "Pruned old persona events"
216
- end
217
- end
218
- ```
219
-
220
- ---
221
-
222
- ## Comparison with other gems
223
-
224
- | Gem | Tracks | rails-persona advantage |
225
- |---|---|---|
226
- | **ahoy** | HTTP visits, JS events | Model actions, no JS needed, async built-in |
227
- | **paper_trail** | Model attribute changes | Behavioral patterns, not diffs |
228
- | **audited** | CRUD audit logs | Who *acted*, not what *changed* |
229
- | **mixpanel-ruby** | Remote SaaS events | Your DB, no 3rd party, no cost |
230
-
231
- ---
232
-
233
- ## API reference
234
-
235
- | Method | Description |
236
- |--------|-------------|
237
- | `track!(action, metadata: {})` | Record an action (sync or async) |
238
- | `bulk_track!(actions)` | Record multiple actions via `insert_all!` |
239
- | `reset_persona!` | Delete all events for this record |
240
- | `action_count(action)` | Count of a specific action |
241
- | `total_events` | Total event count |
242
- | `most_frequent_action` | Most-performed action |
243
- | `least_frequent_action` | Least-performed action |
244
- | `top_actions(n)` | Top N actions by count |
245
- | `last_action` | Most recent action symbol |
246
- | `last_active_at` | Timestamp of last action |
247
- | `first_action` | Earliest action symbol |
248
- | `first_active_at` | Timestamp of first action |
249
- | `inactive_since?(days)` | True if no action in N days |
250
- | `days_since_last_activity` | Integer days since last event |
251
- | `ever_did?(action)` | True if action occurred |
252
- | `never_did?(action)` | True if action never occurred |
253
- | `action_share(action)` | % of all events this action represents |
254
- | `persona_summary` | Full action → count hash |
255
- | `actions_between(from, to)` | Actions in a time window |
256
- | `activity_log(limit)` | Recent events as array of hashes |
257
- | `daily_activity(days)` | Events grouped by day |
258
- | `peak_hour` | Hour (0-23) with most activity |
259
- | `User.persona_leaderboard(limit:)` | Top N most active records |
260
- | `User.persona_class_summary` | App-wide action breakdown |
261
-
262
- ---
263
-
264
- ## Contributing
265
-
266
- Bug reports and pull requests welcome at https://github.com/sghani001/rails-persona.
267
-
268
- ## License
269
-
270
- MIT — © Syed M. Ghani
1
+ # rails-persona 🎭
2
+
3
+ > Model-level behavioral analytics for Rails — own your data, zero external services.
4
+
5
+ [![Gem Version](https://img.shields.io/gem/v/rails-persona.svg)](https://rubygems.org/gems/rails-persona)
6
+ [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+
8
+ **rails-persona** is a lightweight Rails gem that adds first-class behavioral tracking directly to your ActiveRecord models. Unlike [ahoy](https://github.com/ankane/ahoy), which is focused on HTTP visit and page-view tracking, rails-persona is built for **model-level action tracking** — understanding *what your users actually do* in your app, not just what pages they visit.
9
+
10
+ ---
11
+
12
+ ## Why rails-persona over ahoy?
13
+
14
+ | | ahoy | rails-persona |
15
+ |---|---|---|
16
+ | Focus | HTTP visits + page views | Model actions + user behavior |
17
+ | Setup | Controllers + JS snippet | Pure Ruby — one concern |
18
+ | Async | Manual Sidekiq setup | Built-in (`async: true`) |
19
+ | Bulk tracking | ❌ | ✅ `bulk_track!` with `insert_all!` |
20
+ | Class-level analytics | ❌ | ✅ Leaderboards, class summaries |
21
+ | Open tracking mode | ❌ | ✅ No whitelist required |
22
+ | Streak / pattern queries | ❌ | ✅ `daily_activity`, `peak_hour` |
23
+ | Cookies / sessions | Required | Never needed |
24
+ | Works on non-User models | Awkward | First-class |
25
+
26
+ ---
27
+
28
+ ## Installation
29
+
30
+ ```ruby
31
+ gem "rails-persona"
32
+ ```
33
+
34
+ ```bash
35
+ bundle install
36
+ rails db:migrate
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Quick start
42
+
43
+ ### 1. Include in any model
44
+
45
+ ```ruby
46
+ class User < ApplicationRecord
47
+ include Persona::Trackable
48
+
49
+ persona do
50
+ track :login
51
+ track :export_report
52
+ track :view_dashboard
53
+ track :upgrade_plan
54
+ end
55
+ end
56
+ ```
57
+
58
+ ### 2. Track actions in your app
59
+
60
+ ```ruby
61
+ # In a controller, service, or job:
62
+ current_user.track!(:login)
63
+ current_user.track!(:upgrade_plan, metadata: { plan: "pro", amount: 49 })
64
+ ```
65
+
66
+ ### 3. Query behavior
67
+
68
+ ```ruby
69
+ user.action_count(:login) # => 42
70
+ user.most_frequent_action # => :login
71
+ user.least_frequent_action # => :upgrade_plan
72
+ user.top_actions(3) # => { login: 42, view_dashboard: 18, export_report: 5 }
73
+ user.last_action # => :export_report
74
+ user.last_active_at # => 2024-05-30 14:22 UTC
75
+ user.first_action # => :login
76
+ user.first_active_at # => 2023-01-10 08:00 UTC
77
+ user.inactive_since? # => false (default threshold: 30 days)
78
+ user.inactive_since?(7) # => false (custom: 7 days)
79
+ user.days_since_last_activity # => 2
80
+ user.ever_did?(:export_report) # => true
81
+ user.never_did?(:upgrade_plan) # => false
82
+ user.action_share(:login) # => 64.6 (% of all events)
83
+ user.total_events # => 65
84
+
85
+ user.persona_summary
86
+ # => { login: 42, view_dashboard: 18, export_report: 5, upgrade_plan: 1 }
87
+
88
+ user.actions_between(1.week.ago, Time.current)
89
+ # => { login: 7, view_dashboard: 3 }
90
+
91
+ user.activity_log(5)
92
+ # => [
93
+ # { action: :export_report, at: 2024-05-30 14:22:00, metadata: {} },
94
+ # { action: :login, at: 2024-05-30 09:01:00, metadata: {} },
95
+ # ]
96
+
97
+ user.daily_activity(30)
98
+ # => { "2024-05-28" => 4, "2024-05-29" => 7, "2024-05-30" => 2 }
99
+
100
+ user.peak_hour
101
+ # => 14 (2pm is when this user is most active)
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Class-level analytics
107
+
108
+ ```ruby
109
+ # Top 10 most active users
110
+ User.persona_leaderboard(limit: 10)
111
+ # => [
112
+ # { record: #<User id=4>, total_events: 128 },
113
+ # { record: #<User id=9>, total_events: 97 },
114
+ # ]
115
+
116
+ # App-wide breakdown of all user actions
117
+ User.persona_class_summary
118
+ # => { login: 8420, view_dashboard: 5210, export_report: 820 }
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Bulk tracking (high-performance)
124
+
125
+ Uses `insert_all!` — no N+1, no per-row callbacks:
126
+
127
+ ```ruby
128
+ user.bulk_track!([:login, :view_dashboard, :export_report])
129
+ user.bulk_track!([:login, :login, :login]) # track repeated actions
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Async tracking (Sidekiq)
135
+
136
+ ```ruby
137
+ # config/initializers/persona.rb
138
+ Persona.configure do |config|
139
+ config.async = true # fires a Sidekiq job instead of writing inline
140
+ end
141
+ ```
142
+
143
+ Requires the `sidekiq` gem. Falls back to synchronous if Sidekiq is not available.
144
+
145
+ ---
146
+
147
+ ## Open tracking (no whitelist)
148
+
149
+ If you want to track arbitrary actions without declaring them:
150
+
151
+ ```ruby
152
+ class Post < ApplicationRecord
153
+ include Persona::Trackable
154
+
155
+ persona do
156
+ open_tracking! # any string is valid — no UntrackedActionError raised
157
+ end
158
+ end
159
+
160
+ post.track!("custom_#{SecureRandom.hex(4)}") # works fine
161
+ ```
162
+
163
+ ---
164
+
165
+ ## Works on any model
166
+
167
+ ```ruby
168
+ class Post < ApplicationRecord
169
+ include Persona::Trackable
170
+
171
+ persona do
172
+ track :viewed
173
+ track :shared
174
+ track :bookmarked
175
+ end
176
+ end
177
+
178
+ post.track!(:viewed)
179
+ post.action_count(:viewed) # => 128
180
+ post.most_frequent_action # => :viewed
181
+ Post.persona_class_summary # => { viewed: 50_420, shared: 890, bookmarked: 210 }
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Configuration
187
+
188
+ ```ruby
189
+ # config/initializers/persona.rb
190
+ Persona.configure do |config|
191
+ config.inactivity_threshold_days = 14 # default: 30
192
+ config.max_events_per_record = 500 # default: nil (unlimited)
193
+ config.async = true # default: false
194
+ config.auto_prune_after_days = 90 # default: nil (no auto-prune)
195
+ end
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Manual pruning
201
+
202
+ ```ruby
203
+ # Delete events older than 60 days for all records
204
+ Persona::Pruner.prune_older_than(60)
205
+ ```
206
+
207
+ Add to a scheduled job (e.g. `whenever` or Sidekiq-Cron):
208
+
209
+ ```ruby
210
+ # lib/tasks/persona.rake
211
+ namespace :persona do
212
+ desc "Prune old persona events"
213
+ task prune: :environment do
214
+ Persona::Pruner.prune_older_than(Persona.configuration.auto_prune_after_days || 90)
215
+ puts "Pruned old persona events"
216
+ end
217
+ end
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Comparison with other gems
223
+
224
+ | Gem | Tracks | rails-persona advantage |
225
+ |---|---|---|
226
+ | **ahoy** | HTTP visits, JS events | Model actions, no JS needed, async built-in |
227
+ | **paper_trail** | Model attribute changes | Behavioral patterns, not diffs |
228
+ | **audited** | CRUD audit logs | Who *acted*, not what *changed* |
229
+ | **mixpanel-ruby** | Remote SaaS events | Your DB, no 3rd party, no cost |
230
+
231
+ ---
232
+
233
+ ## API reference
234
+
235
+ | Method | Description |
236
+ |--------|-------------|
237
+ | `track!(action, metadata: {})` | Record an action (sync or async) |
238
+ | `bulk_track!(actions)` | Record multiple actions via `insert_all!` |
239
+ | `reset_persona!` | Delete all events for this record |
240
+ | `action_count(action)` | Count of a specific action |
241
+ | `total_events` | Total event count |
242
+ | `most_frequent_action` | Most-performed action |
243
+ | `least_frequent_action` | Least-performed action |
244
+ | `top_actions(n)` | Top N actions by count |
245
+ | `last_action` | Most recent action symbol |
246
+ | `last_active_at` | Timestamp of last action |
247
+ | `first_action` | Earliest action symbol |
248
+ | `first_active_at` | Timestamp of first action |
249
+ | `inactive_since?(days)` | True if no action in N days |
250
+ | `days_since_last_activity` | Integer days since last event |
251
+ | `ever_did?(action)` | True if action occurred |
252
+ | `never_did?(action)` | True if action never occurred |
253
+ | `action_share(action)` | % of all events this action represents |
254
+ | `persona_summary` | Full action → count hash |
255
+ | `actions_between(from, to)` | Actions in a time window |
256
+ | `activity_log(limit)` | Recent events as array of hashes |
257
+ | `daily_activity(days)` | Events grouped by day |
258
+ | `peak_hour` | Hour (0-23) with most activity |
259
+ | `User.persona_leaderboard(limit:)` | Top N most active records |
260
+ | `User.persona_class_summary` | App-wide action breakdown |
261
+
262
+ ---
263
+
264
+ ## Contributing
265
+
266
+ Bug reports and pull requests welcome at https://github.com/sghani001/rails-persona.
267
+
268
+ ## License
269
+
270
+ MIT — © Syed M. Ghani
@@ -2,20 +2,15 @@ require "rails"
2
2
 
3
3
  module Persona
4
4
  class Railtie < Rails::Railtie
5
- initializer "persona.load_app_instance_data" do |app|
6
- Persona::Railtie.instance_variable_set(:@app, app)
7
- end
8
-
9
5
  initializer "persona.append_migrations" do |app|
10
6
  unless app.root.to_s == File.expand_path("../..", __dir__)
11
- config.paths["db/migrate"].expanded.each do |path|
12
- app.config.paths["db/migrate"] << path
13
- end
7
+ migrations_path = File.expand_path("../../../db/migrate", __dir__)
8
+ app.config.paths["db/migrate"] << migrations_path
14
9
  end
15
10
  end
16
11
 
17
12
  rake_tasks do
18
- load "tasks/persona_tasks.rake"
13
+ load File.expand_path("../../../tasks/persona_tasks.rake", __dir__)
19
14
  end
20
15
  end
21
- end
16
+ end
@@ -1,3 +1,3 @@
1
- module Persona
2
- VERSION = "0.2.0"
3
- end
1
+ module Persona
2
+ VERSION = "0.2.1"
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-persona
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Syed M. Ghani
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-31 00:00:00.000000000 Z
11
+ date: 2026-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails