toolx 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f027d545a91be1a02f8ef28f52ced20c6d6ffe3defc99be3f59dd783b78bed2f
4
- data.tar.gz: 453e20a3f42da721d4acdb50fb62de95ad62b4801c6c652c3285c8a5de311a21
3
+ metadata.gz: 71e2fe435a932be8cd57480bce5c52c27e369699cbe6de4f9dacc6eed981476b
4
+ data.tar.gz: 68b6b1546a453e517c25c98359a9e00d6bcae46e01cf2331564e81f0147cbd28
5
5
  SHA512:
6
- metadata.gz: 9551fd33fe000bf1a10e5500a409f770ea64533b3db892825174f96659773fa93b872b78f21cb7dbdfc575045e54024bddb18e499b96417c36a1edf0a931a3b4
7
- data.tar.gz: '018ed1cadf76d903502d6e1b5fdd1c3bc14d3891995d35d2566fb36c2c15ffbd59ea04c6af87d46f7c876cbf840a5f903b3b2eae8b6d43e3afafa3738ee74de1'
6
+ metadata.gz: 4a4d5785740ee58fc8ed1489b4444482c2d9b98569091d8764d1f79038057f4b3421184aba119d2968f3c839845dbf9e708a55354ba09818b58e2c4114c5dff0
7
+ data.tar.gz: 5b38acc866cff44a922234c89093ea23fe44b3c26e84ff92c215404a086940bf9993b6fc065684e29f860fcafc7935c6a79d632df80f51f4fadbdbccffb6f14d
data/README.md CHANGED
@@ -26,6 +26,8 @@ class ApplicationRecord < ActiveRecord::Base
26
26
  include Toolx::Core::Concerns::Transformer
27
27
  include Toolx::Core::Concerns::CustomIdentifier
28
28
  include Toolx::Core::Concerns::DateTimeToBoolean
29
+ include Toolx::Core::Concerns::Keygen
30
+ include Toolx::Core::Concerns::Tokenizer
29
31
  include Toolx::Core::Concerns::WithStateMachine
30
32
  end
31
33
  ```
@@ -135,6 +137,96 @@ user.deleted = true # also sets current time
135
137
  user.deleted = false # sets deleted_at to nil
136
138
  ```
137
139
 
140
+ ### Keygen
141
+
142
+ Generate unique keys for your models, ensuring they are unique across the database.
143
+
144
+ ```ruby
145
+ class User < ApplicationRecord
146
+ include Toolx::Core::Concerns::Keygen
147
+
148
+ keygen :dob, attr: :lic_key, secret: 'my$ecret', limit: 20, separator: '.', br: 3
149
+ end
150
+ user = User.new(dob: '1990-01-01')
151
+ user.save!
152
+ user.lic_key # => '090.cc2.207.c45.3e7.20b.f95'
153
+ ```
154
+
155
+ ### Tokenizer
156
+
157
+ Generate unique tokens for your models before creation, useful for API keys, access tokens, invitations, etc.
158
+
159
+ ```ruby
160
+ class AccessToken < ApplicationRecord
161
+ include Toolx::Core::Concerns::Tokenizer
162
+
163
+ tokenize :token, size: 32, prefix: 'tok'
164
+ end
165
+
166
+ token = AccessToken.create!
167
+ token.token # => "tok-xnT3yM9dPQsA4W8Ks7LZhV5RuKcgByTw"
168
+ ```
169
+
170
+ ### Stateman via with_state_machine
171
+
172
+ It is working only with `Statesman::Adapters::ActiveRecord`
173
+
174
+ You can generate state machine classes via rake task
175
+
176
+ ```bash
177
+ bin/rails "toolx:stateman:generate[Project]"
178
+ ```
179
+ command will generate models for existing `Project` model as
180
+ `Project::StateMachine` and `Project::Transition`.
181
+
182
+ also will add migraion file for those models.
183
+
184
+ Example usage:
185
+
186
+ ```ruby
187
+ class Project::StateMachine
188
+ include Statesman::Machine
189
+
190
+ state :active, initial: true
191
+ state :pending
192
+ state :skipped
193
+ state :cancelled
194
+ state :done
195
+
196
+ transition from: :active, to: [:pending, :pending, :skipped, :cancelled, :done]
197
+ transition from: :pending, to: [:skipped, :cancelled, :done]
198
+ transition from: :skipped, to: [:pending]
199
+
200
+ after_transition do |model, transition|
201
+ model.update!(status: transition.to_state)
202
+ end
203
+ end
204
+
205
+ class Project::Transition < ActiveRecord::Base
206
+ belongs_to :project
207
+
208
+ attribute :most_recent, :boolean, default: false
209
+ attribute :sort_key, :integer
210
+ attribute :to_state, :string
211
+ attribute :metadata, :json, default: {}
212
+
213
+ validates :to_state, inclusion: { in: Project::StateMachine.states }
214
+ end
215
+
216
+ class Project < ActiveRecord::Base
217
+ include Toolx::Core::Concerns::WithStateMachine
218
+ STATUSES = %w[active pending done skipped cancelled].freeze
219
+
220
+ with_state_machine
221
+
222
+ attribute :name, :string
223
+ attribute :status, :string, default: 'active'
224
+
225
+ validates :name, presence: true
226
+ validates :status, inclusion: { in: STATUSES }, allow_nil: true
227
+ end
228
+ ```
229
+
138
230
  ### Errors
139
231
 
140
232
  A structured, extensible error-handling framework:
@@ -227,7 +319,6 @@ end
227
319
  Presenter.auto_present(Article.new(title: "A very long title"))
228
320
  ```
229
321
 
230
-
231
322
  ### SimpleCrypt
232
323
 
233
324
  Simple AES encryption helper using ActiveSupport::MessageEncryptor.
@@ -383,66 +474,6 @@ SignupOperation.flow
383
474
  .perform!(email: 'foo@bar.com', age: 20)
384
475
  ```
385
476
 
386
- ### Stateman via with_state_machine
387
-
388
- It is working only with `Statesman::Adapters::ActiveRecord`
389
-
390
- You can generate state machine classes via rake task
391
-
392
- ```bash
393
- bin/rails "toolx:stateman:generate[Project]"
394
- ```
395
- command will generate models for existing `Project` model as
396
- `Project::StateMachine` and `Project::Transition`.
397
-
398
- also will add migraion file for those models.
399
-
400
- Example usage:
401
-
402
- ```ruby
403
- class Project::StateMachine
404
- include Statesman::Machine
405
-
406
- state :active, initial: true
407
- state :pending
408
- state :skipped
409
- state :cancelled
410
- state :done
411
-
412
- transition from: :active, to: [:pending, :pending, :skipped, :cancelled, :done]
413
- transition from: :pending, to: [:skipped, :cancelled, :done]
414
- transition from: :skipped, to: [:pending]
415
-
416
- after_transition do |model, transition|
417
- model.update!(status: transition.to_state)
418
- end
419
- end
420
-
421
- class Project::Transition < ActiveRecord::Base
422
- belongs_to :project
423
-
424
- attribute :most_recent, :boolean, default: false
425
- attribute :sort_key, :integer
426
- attribute :to_state, :string
427
- attribute :metadata, :json, default: {}
428
-
429
- validates :to_state, inclusion: { in: Project::StateMachine.states }
430
- end
431
-
432
- class Project < ActiveRecord::Base
433
- include Toolx::Core::Concerns::WithStateMachine
434
- STATUSES = %w[active pending done skipped cancelled].freeze
435
-
436
- with_state_machine
437
-
438
- attribute :name, :string
439
- attribute :status, :string, default: 'active'
440
-
441
- validates :name, presence: true
442
- validates :status, inclusion: { in: STATUSES }, allow_nil: true
443
- end
444
- ```
445
-
446
477
  ## License
447
478
 
448
479
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -40,6 +40,8 @@ namespace :toolx do
40
40
  include Toolx::Core::Concerns::CustomIdentifier
41
41
  include Toolx::Core::Concerns::DateTimeToBoolean
42
42
  include Toolx::Core::Concerns::WithStateMachine
43
+ include Toolx::Core::Concerns::Keygen
44
+ include Toolx::Core::Concerns::Tokenizer
43
45
  end
44
46
  RUBY
45
47
  puts "\n"
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Toolx
4
+ module Core
5
+ module Concerns
6
+ module Keygen
7
+ extend ::ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ # Generates a unique key based on the provided attributes and an optional secret.
11
+ # @example
12
+ # class License < ApplicationRecord
13
+ # include Keygen
14
+ # keygen ->(m) { [m.id, m.format_date(m.expire_at), m.type, m.user_id] }
15
+ # end
16
+ #
17
+ # license = License.new(id: '1234', expire_at: Time.current + 1.month, type: 'default', user_id: 'usr_5678')
18
+ # license.key # => "7034-d544-f8d1-fddf-d939-14ce-53c5-3ed9-f71f-3dab"
19
+ #
20
+ # @param source [Array<Symbol, Proc>] Attributes or a Proc to generate the key from.
21
+ # @param attr [Symbol] The attribute to store the generated key in (default)
22
+ # @param secret [String, nil] An optional secret to include in the key generation.
23
+ # @param limit [Integer] The maximum length of the generated key (default: 40).
24
+ # @param separator [String] The separator to use in the generated key (default: '-').
25
+ # @param br [Integer] The number of characters in each segment of the key (default: 4).
26
+ def keygen(*source, attr: :key, secret: nil, limit: 40, separator: '-', br: 4)
27
+ after_save do
28
+ next if source.blank?
29
+
30
+ binding = source.first.class == Proc
31
+ data = binding ? source.first.call(self) : source.map { |attr| send(attr).to_s }
32
+ value = (data.push(secret.to_s)).compact.join
33
+ result = Digest::SHA256.hexdigest(value)[0..limit].scan(/.{#{br}}/).join(separator)
34
+
35
+ next if send(attr) == result
36
+
37
+ update_column(attr, result)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Toolx
4
+ module Core
5
+ module Concerns
6
+ module Tokenizer
7
+ extend ::ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ # Generates a unique token for a given attribute before creation.
11
+ #
12
+ # @example
13
+ # class AccessToken < ApplicationRecord
14
+ # include Toolx::Core::Concerns::Tokenizer
15
+ # tokenize :token, size: 32, prefix: 'tok'
16
+ # end
17
+ #
18
+ # token = AccessToken.create
19
+ # token.token # => "tok-MH3yTbcuZJ8o..."
20
+ #
21
+ # @param attribute [Symbol] The attribute to assign the token to.
22
+ # @param size [Integer] The size of the randomly generated token (default: 64).
23
+ # @param prefix [String, nil] Optional prefix to prepend to the token.
24
+ def tokenize(attribute, size: 64, prefix: nil)
25
+ before_create do
26
+ token_value = send(attribute)
27
+ next unless token_value.nil?
28
+
29
+ loop do
30
+ unique = SecureRandom.base58(size)
31
+
32
+ send("#{attribute}=", [prefix, unique].compact.join('-'))
33
+ break unless self.class.exists?(token_value)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
data/lib/toolx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Toolx
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toolx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pawel Niemczyk
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-06-24 00:00:00.000000000 Z
10
+ date: 2025-06-25 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: statesman
@@ -288,6 +288,8 @@ files:
288
288
  - lib/toolx/core/concerns/custom_identifier.rb
289
289
  - lib/toolx/core/concerns/date_time_to_boolean.rb
290
290
  - lib/toolx/core/concerns/inquirer.rb
291
+ - lib/toolx/core/concerns/keygen.rb
292
+ - lib/toolx/core/concerns/tokenizer.rb
291
293
  - lib/toolx/core/concerns/transformer.rb
292
294
  - lib/toolx/core/concerns/with_state_machine.rb
293
295
  - lib/toolx/core/env.rb