usage_meter 0.1.0 → 0.2.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 +4 -4
- data/README.md +21 -3
- data/Rakefile +6 -4
- data/app/controllers/usage_meter/application_controller.rb +2 -0
- data/app/helpers/usage_meter/application_helper.rb +2 -0
- data/app/jobs/usage_meter/application_job.rb +2 -0
- data/app/mailers/usage_meter/application_mailer.rb +4 -2
- data/app/models/usage_meter/application_record.rb +2 -0
- data/app/models/usage_meter/customer.rb +24 -0
- data/app/models/usage_meter/event_type.rb +24 -0
- data/config/locales/en.yml +8 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20251107032323_create_usage_meter_customers.rb +30 -0
- data/db/migrate/20251111204821_create_usage_meter_event_types.rb +14 -0
- data/lib/tasks/usage_meter_tasks.rake +2 -0
- data/lib/usage_meter/engine.rb +7 -0
- data/lib/usage_meter/version.rb +3 -1
- data/lib/usage_meter.rb +4 -2
- metadata +195 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e47d987fdc1401976f35f2bfe86a6f92399ebd39c1f8d5fc7ac5933f28320070
|
|
4
|
+
data.tar.gz: bdbd0f0a8d2c5a67856c9b849fb91dbb7cf6ae7486f5c4cf7a668224907677a9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 73309dd912770cbf1af17937c405deafab64912088242ba506185b7f778ecc966ac2a4fe8cd5df7d0d3b3fec8caa5e58204b08850922176e6e0c33119fced628
|
|
7
|
+
data.tar.gz: b2294a49324a32553406ed7052c1c7684bc3d4a6bd5e68491d6da755efd058aacdcad4262736d343e5c715ef4dde6f13cb1ffa8fc043d3d73d7128c818ec31b9
|
data/README.md
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
# UsageMeter
|
|
2
|
-
|
|
2
|
+
A Rails engine to track usage metrics of features, useful for implementing usage-based billing.
|
|
3
3
|
|
|
4
4
|
## Usage
|
|
5
5
|
How to use my plugin.
|
|
6
6
|
|
|
7
|
+
## Supported Versions
|
|
8
|
+
|
|
9
|
+
This gem supports the following Ruby, Rails, and database versions.
|
|
10
|
+
|
|
11
|
+
### Ruby
|
|
12
|
+
|
|
13
|
+
- Ruby 3.+ and above (tested with 3.0, 3.1, 3.2, 3.3)
|
|
14
|
+
|
|
15
|
+
### Rails
|
|
16
|
+
|
|
17
|
+
- Rails 8.x and above (tested with 8.x)
|
|
18
|
+
|
|
19
|
+
### Databases
|
|
20
|
+
|
|
21
|
+
- **SQLite**: Supported for local development and testing.
|
|
22
|
+
- **PostgreSQL**: Fully supported and recommended for production.
|
|
23
|
+
- **MySQL**: Supported for production environments.
|
|
24
|
+
|
|
7
25
|
## Installation
|
|
8
26
|
Add this line to your application's Gemfile:
|
|
9
27
|
|
|
@@ -22,7 +40,7 @@ $ gem install usage_meter
|
|
|
22
40
|
```
|
|
23
41
|
|
|
24
42
|
## Contributing
|
|
25
|
-
|
|
43
|
+
We are not actively accepting contributions at this early stage of development, and external pull Requests will be automatically closed.
|
|
26
44
|
|
|
27
45
|
## License
|
|
28
|
-
The gem is available as
|
|
46
|
+
The gem is available as under the terms of the [License](LICENCE.txt)
|
data/Rakefile
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
load "rails/tasks/engine.rake"
|
|
3
|
+
require 'bundler/setup'
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
|
6
|
+
load 'rails/tasks/engine.rake'
|
|
7
|
+
|
|
8
|
+
require 'bundler/gem_tasks'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module UsageMeter
|
|
4
|
+
# UsageMeter Customer model
|
|
5
|
+
# A customer in an enttity who's usage is being metered. This is typically a Tenant
|
|
6
|
+
# Organization, or User.
|
|
7
|
+
#
|
|
8
|
+
# UsageMeter tracks it's own customers to ensure consistency and integrity of usage data.
|
|
9
|
+
# Each customer will have a unique composite key of external_type and external_identifier.
|
|
10
|
+
# Usage data is then associated with these customers, with foreign keys referencing the
|
|
11
|
+
# to ensure referential integrity.
|
|
12
|
+
#
|
|
13
|
+
# Once created, records are readonly by design to prevent tampering with historical usage data.
|
|
14
|
+
class Customer < ApplicationRecord
|
|
15
|
+
validates :external_type, presence: true
|
|
16
|
+
validates :external_identifier, presence: true, uniqueness: { scope: :external_type }
|
|
17
|
+
|
|
18
|
+
attr_readonly :external_type, :external_identifier, :created_at, :updated_at
|
|
19
|
+
|
|
20
|
+
def readonly?
|
|
21
|
+
persisted?
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module UsageMeter
|
|
4
|
+
# EventType allows strict categorization of events
|
|
5
|
+
#
|
|
6
|
+
# Events of the same category and Customer will
|
|
7
|
+
# tally together for the usage of that type
|
|
8
|
+
# Events must have a type, and types will be
|
|
9
|
+
# enforced with a foreign key ref.
|
|
10
|
+
#
|
|
11
|
+
# Key must be unique, to allow lookup
|
|
12
|
+
class EventType < ApplicationRecord
|
|
13
|
+
KEY_FORMAT = /\A[a-z0-9\-_]+\z/
|
|
14
|
+
def self.key_format
|
|
15
|
+
KEY_FORMAT
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
validates :key, presence: true
|
|
19
|
+
validates :key, uniqueness: true
|
|
20
|
+
validates :key, format: { with: key_format, message: :invalid, key_format_regex: key_format.inspect }
|
|
21
|
+
|
|
22
|
+
attr_readonly :key
|
|
23
|
+
end
|
|
24
|
+
end
|
data/config/routes.rb
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateUsageMeterCustomers < ActiveRecord::Migration[7.0]
|
|
4
|
+
PK_TYPE = begin
|
|
5
|
+
ApplicationRecord.connection_config[:primary_key_type]
|
|
6
|
+
rescue StandardError
|
|
7
|
+
:bigint
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def change
|
|
11
|
+
create_table :usage_meter_customers do |t|
|
|
12
|
+
if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
|
|
13
|
+
t.string :external_identifier, collation: "utf8mb4_bin"
|
|
14
|
+
t.string :external_type, collation: "utf8mb4_bin"
|
|
15
|
+
else
|
|
16
|
+
t.string :external_identifier
|
|
17
|
+
t.string :external_type
|
|
18
|
+
end
|
|
19
|
+
t.string :human_description
|
|
20
|
+
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
|
21
|
+
t.jsonb :metadata
|
|
22
|
+
else
|
|
23
|
+
t.json :metadata
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
t.timestamps
|
|
27
|
+
end
|
|
28
|
+
add_index :usage_meter_customers, %i[external_type external_identifier], unique: true, name: :index_usage_meter_customers_on_external_type_and_identifier
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class CreateUsageMeterEventTypes < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :usage_meter_event_types do |t|
|
|
4
|
+
if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
|
|
5
|
+
t.string :key, null: false, index: { unique: true }, collation: "utf8mb4_bin"
|
|
6
|
+
else
|
|
7
|
+
t.string :key, null: false, index: { unique: true }
|
|
8
|
+
end
|
|
9
|
+
t.string :human_description
|
|
10
|
+
|
|
11
|
+
t.timestamps
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/usage_meter/engine.rb
CHANGED
data/lib/usage_meter/version.rb
CHANGED
data/lib/usage_meter.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: usage_meter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- James P. McGrath
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-11-
|
|
11
|
+
date: 2025-11-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -16,18 +16,200 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 7.1.0
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 7.1.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: factory_bot_rails
|
|
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: mysql2
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 0.5.7
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 0.5.7
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: pg
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 1.6.2
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 1.6.2
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: reek
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - '='
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 6.5.0
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - '='
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 6.5.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: 8.0.2
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 8.0.2
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rubocop
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: 1.81.0
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: 1.81.0
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rubocop-performance
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: 1.26.1
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: 1.26.1
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: rubocop-rails
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: 2.33.0
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: 2.33.0
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: rubocop-rspec
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: rubocop-rspec_rails
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - ">="
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '0'
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - ">="
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '0'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: shoulda-matchers
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - ">="
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '0'
|
|
174
|
+
type: :development
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - ">="
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '0'
|
|
181
|
+
- !ruby/object:Gem::Dependency
|
|
182
|
+
name: simplecov
|
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
|
184
|
+
requirements:
|
|
185
|
+
- - ">="
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: '0'
|
|
188
|
+
type: :development
|
|
189
|
+
prerelease: false
|
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - ">="
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: '0'
|
|
195
|
+
- !ruby/object:Gem::Dependency
|
|
196
|
+
name: sqlite3
|
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - ">="
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: 2.8.0
|
|
202
|
+
type: :development
|
|
203
|
+
prerelease: false
|
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
+
requirements:
|
|
206
|
+
- - ">="
|
|
207
|
+
- !ruby/object:Gem::Version
|
|
208
|
+
version: 2.8.0
|
|
27
209
|
description: A Rails engine to track usage metrics of features, useful for implementing
|
|
28
210
|
usage-based billing.
|
|
29
211
|
email:
|
|
30
|
-
-
|
|
212
|
+
- gems@jamespmcgrath.com
|
|
31
213
|
executables: []
|
|
32
214
|
extensions: []
|
|
33
215
|
extra_rdoc_files: []
|
|
@@ -40,8 +222,13 @@ files:
|
|
|
40
222
|
- app/jobs/usage_meter/application_job.rb
|
|
41
223
|
- app/mailers/usage_meter/application_mailer.rb
|
|
42
224
|
- app/models/usage_meter/application_record.rb
|
|
225
|
+
- app/models/usage_meter/customer.rb
|
|
226
|
+
- app/models/usage_meter/event_type.rb
|
|
43
227
|
- app/views/layouts/usage_meter/application.html.erb
|
|
228
|
+
- config/locales/en.yml
|
|
44
229
|
- config/routes.rb
|
|
230
|
+
- db/migrate/20251107032323_create_usage_meter_customers.rb
|
|
231
|
+
- db/migrate/20251111204821_create_usage_meter_event_types.rb
|
|
45
232
|
- lib/tasks/usage_meter_tasks.rake
|
|
46
233
|
- lib/usage_meter.rb
|
|
47
234
|
- lib/usage_meter/engine.rb
|
|
@@ -53,6 +240,7 @@ metadata:
|
|
|
53
240
|
homepage_uri: https://github.com/jpmcgrath/usage_meter
|
|
54
241
|
source_code_uri: https://github.com/jpmcgrath/usage_meter
|
|
55
242
|
changelog_uri: https://github.com/jpmcgrath/usage_meter
|
|
243
|
+
rubygems_mfa_required: 'true'
|
|
56
244
|
post_install_message:
|
|
57
245
|
rdoc_options: []
|
|
58
246
|
require_paths:
|
|
@@ -61,14 +249,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
61
249
|
requirements:
|
|
62
250
|
- - ">="
|
|
63
251
|
- !ruby/object:Gem::Version
|
|
64
|
-
version:
|
|
252
|
+
version: 3.1.0
|
|
65
253
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
254
|
requirements:
|
|
67
255
|
- - ">="
|
|
68
256
|
- !ruby/object:Gem::Version
|
|
69
257
|
version: '0'
|
|
70
258
|
requirements: []
|
|
71
|
-
rubygems_version: 3.
|
|
259
|
+
rubygems_version: 3.3.27
|
|
72
260
|
signing_key:
|
|
73
261
|
specification_version: 4
|
|
74
262
|
summary: A Rails engine to track usage metrics of features
|