hubbado-policy 1.1.1 → 1.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: 92b2d2ebfeca29045209e9ac790024cfe3be4d6646be7ace9f3678684808cad6
4
- data.tar.gz: 88b9eb114f043c6b8f948fb780446566bf4a73771aabc96a9becfb670374a701
3
+ metadata.gz: 10ac3df17852150db0027d21e4fda49038083e6d825e41227a225864322df576
4
+ data.tar.gz: 0d303a7756e82512635a6a323939df1f794766cef2182cf405f07e72b96ad4d9
5
5
  SHA512:
6
- metadata.gz: b28dc471aa7bcbee6db421e41cb4664423a6c58d31ab17e6deb2ae55d0a53fbf1b8c00e5a2ef96c34bd46d325fac68b5fb77fe0c88e59f0ca28eb2359affac28
7
- data.tar.gz: 29670f1bb98582426e288fd290091d20ac8bf7ee9606a61f6de6b20a869794342c7646bc630c41bea8c0af1217033612c5455ea32b04aee05c8aa082546455e7
6
+ metadata.gz: 83232ddd7a934bf3a3381dccfe785be182ef6d03e2fd519bc006f1a17a07c0006b87c1d0e4dd58d442b5739350edf0e6f0ae9153a88676da3a5fcb74f8b5e94f
7
+ data.tar.gz: 8086d8d2ecbbe4df566560a0d36ebad2c1010b000d70c10bb703fc6c0b0d6c1ea5fd7a8017c70dd940951676090b2afa5ab10b80e02274e109e1152a5c4da231
data/CHANGELOG.md CHANGED
@@ -5,14 +5,32 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.0] - 2025-05-27
9
+
10
+ ### Added
11
+
12
+ - Policy control is improved:
13
+ - When using a policy control you could permit or deny with a method
14
+ ```ruby
15
+ mimic_policy = Control::Policies::ArticlePolicy.example
16
+ mimic_policy.permit(:view)
17
+ # or
18
+ mimic_policy.deny(:view)
19
+ mimic_policy.deny(:view, :a_reason) # with a reason
20
+ mimic_policy.deny(:view, data: :custom_data) # with data
21
+ mimic_policy.deny(:view, :a_reason, data: :custom_data) # or both
22
+ ```
23
+
8
24
  ## [1.1.1] - 2025-05-26
9
25
 
10
26
  ### Fixed
27
+
11
28
  - Railtie is corrected with an initializer to load I18n locales correctly.
12
29
 
13
30
  ## [1.1.0] - 2025-05-20
14
31
 
15
32
  ### Added
33
+
16
34
  - Control to mimic policies
17
35
 
18
36
  ## [1.0.1] - 2025-05-20
@@ -22,6 +40,7 @@ Bump because rubygems does not allow repushing the same version even if it is ya
22
40
  ## [1.0.0] - 2025-05-20
23
41
 
24
42
  ### Added
43
+
25
44
  - Initial release of the hubbado-policy gem
26
45
  - `Policy` class with DSL for defining authorization rules
27
46
  - `Result` class to represent policy outcomes
@@ -31,6 +50,7 @@ Bump because rubygems does not allow repushing the same version even if it is ya
31
50
  - Full compatibility with the eventide-project/dependency gem
32
51
 
33
52
  ### Documentation
53
+
34
54
  - Comprehensive README with usage examples
35
55
  - Detailed explanations of all major components
36
56
  - Rails integration guide
data/README.md CHANGED
@@ -152,11 +152,24 @@ module Control
152
152
  end
153
153
 
154
154
  mimic_policy = Control::Policies::ArticlePolicy.example
155
- mimic_policy.view? # returns the value from the real policy
156
-
155
+ mimic_policy.view? # returns false (denied by default)
157
156
 
157
+ # Override specific policies
158
158
  mimic_policy = Control::Policies::ArticlePolicy.example(view: ArticlePolicy.denied)
159
159
  mimic_policy.view? # returns false
160
+
161
+ # Control policy behavior with permit/deny methods
162
+ mimic_policy = Control::Policies::ArticlePolicy.example
163
+ mimic_policy.permit(:view)
164
+ mimic_policy.view? # returns true
165
+
166
+ mimic_policy.deny(:view)
167
+ mimic_policy.view? # returns false
168
+
169
+ # Deny with reason and data
170
+ mimic_policy.deny(:view, :not_authorized)
171
+ mimic_policy.deny(:view, data: { reason: "custom data" })
172
+ mimic_policy.deny(:view, :not_authorized, data: { user_id: 123 })
160
173
  ```
161
174
 
162
175
  ## Result Objects
@@ -190,18 +203,55 @@ end
190
203
  - `message` - Returns the localized error message
191
204
  - `data` - Returns any additional context data
192
205
 
206
+ ### Error Handling
207
+
208
+ Policies validate their inputs and will raise errors for invalid usage:
209
+
210
+ ```ruby
211
+ # Will raise "User not provided" error
212
+ ArticlePolicy.build(nil, article)
213
+
214
+ # Control policies raise UnkownPolicy for invalid policy names
215
+ mimic_policy = Control::Policies::ArticlePolicy.example
216
+ mimic_policy.permit(:invalid_policy) # raises UnkownPolicy
217
+ ```
218
+
219
+ ### Accessing Result Data
220
+
221
+ When policies return additional context data, you can access it through the result:
222
+
223
+ ```ruby
224
+ # In your policy
225
+ define_policy :edit do
226
+ return denied(:quota_exceeded, data: { limit: 10, current: 12 }) if over_quota?
227
+ permitted
228
+ end
229
+
230
+ # Using the result
231
+ result = policy.edit
232
+ if result.denied?
233
+ puts result.message # "You have exceeded your quota"
234
+ puts result.data[:limit] # 10
235
+ puts result.data[:current] # 12
236
+ end
237
+ ```
238
+
193
239
  ## Scope Objects
194
240
 
195
241
  Scope objects filter collections based on what a user is authorized to access.
196
242
 
197
243
  ### Basic Usage
198
244
 
245
+ Scope objects require two template methods to be implemented in subclasses:
246
+
199
247
  ```ruby
200
248
  class ArticleScope < Hubbado::Policy::Scope
249
+ # Required: Define the base collection to filter
201
250
  def self.default_scope
202
251
  Article.all
203
252
  end
204
253
 
254
+ # Required: Implement the filtering logic
205
255
  def resolve(record, scope, **options)
206
256
  return scope if record.admin?
207
257
 
@@ -213,6 +263,14 @@ end
213
263
  visible_articles = ArticleScope.call(current_user)
214
264
  ```
215
265
 
266
+ **Required Methods:**
267
+ - `default_scope` - Class method that returns the base collection to filter
268
+ - `resolve(record, scope, **options)` - Instance method that applies filtering logic
269
+
270
+ Both methods must be implemented or a `MethodMissing` error will be raised.
271
+
272
+ **Important:** Like policies, use `Scope.call()` instead of manual instantiation to ensure the `configure` method is called if defined.
273
+
216
274
  ### Custom Scopes
217
275
 
218
276
  You can pass custom base scopes:
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "hubbado-policy"
3
- s.version = "1.1.1"
3
+ s.version = "1.2.0"
4
4
  s.summary = "A lightweight, flexible policy framework for Ruby applications"
5
5
 
6
6
  s.authors = ["Hubbado Devs"]
@@ -2,6 +2,8 @@ module Hubbado
2
2
  module Policy
3
3
  module Controls
4
4
  class Policy
5
+ UnkownPolicy = Class.new(StandardError)
6
+
5
7
  def self.mimic(policy_class)
6
8
  policy_class.policies.each do |policy|
7
9
  send(:attr_writer, policy)
@@ -14,6 +16,22 @@ module Hubbado
14
16
  send(policy).permitted?
15
17
  end
16
18
  end
19
+
20
+ define_method :permit do |policy|
21
+ unless policy_class.instance_variable_get("@policies").include?(policy)
22
+ raise UnkownPolicy
23
+ end
24
+
25
+ send("#{policy}=", policy_class.permitted)
26
+ end
27
+
28
+ define_method :deny do |policy, reason = nil, data: nil|
29
+ unless policy_class.instance_variable_get("@policies").include?(policy)
30
+ raise UnkownPolicy
31
+ end
32
+
33
+ send("#{policy}=", policy_class.denied(reason, data: data))
34
+ end
17
35
  end
18
36
 
19
37
  def initialize(policies = {})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hubbado-policy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hubbado Devs