rabarber 5.1.0 → 5.1.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: 874cd3840269f288baec19fd5e240afdd6b06e3e5b81d703eb30e8e62283fb32
4
- data.tar.gz: 117d060ffe53ae884b657c1d79a94d9762de1de8b6726659128d7be805c77e24
3
+ metadata.gz: 841b259e40b7e446647ee02fcca64cd183c64978c194edb6917ba344d9f12e92
4
+ data.tar.gz: 044c1aa8248f7b1b16f1c78648a0b4cafb0451f31d8fed5b72f6d3343a645c48
5
5
  SHA512:
6
- metadata.gz: c2207e66e0743b7e5a81acfcc2707d00313fa2a8e9d8e652c7f0dc41b331d8cfa0c4d3504ff5e857606666f0145023a68e8c6d961d6285d48e36c435d4597a38
7
- data.tar.gz: ea1ab97b91cb45611f4ca24a6418484a0b7634d00b0f96cec8485ba543500fc763a33f1e0cbaf7027a8a375623e91481ca1de74d47f50cf86fe5b91bfe456d0b
6
+ metadata.gz: a0880247a0c7f1af21dbb8099880d24ec200295e54f976855aac577fba55b692fee41a7ddfaf10f83848dfba20e2c0ac8289eb7bc94df21cabceb04da47925c1
7
+ data.tar.gz: 024e3093a753d53f158532c829ca245b159448d19901d884b4c09518e70b81d39d710ee0867339ca064bc0519fd06ef53a7af507149d29e80a2a2216ad92a096
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## v5.1.1
2
+
3
+ ### Misc:
4
+
5
+ - Switched to `dry-types` for input validation
6
+ - Switched to `dry-configurable` for configuration management
7
+
1
8
  ## v5.1.0
2
9
 
3
10
  ### Features:
data/README.md CHANGED
@@ -18,8 +18,8 @@ Rabarber is a role-based authorization library for Ruby on Rails that focuses on
18
18
  **Gem Usage:**
19
19
  - [Installation](#installation)
20
20
  - [Configuration](#configuration)
21
- - [Role Management](#role-management)
22
21
  - [User Role Methods](#user-role-methods)
22
+ - [Role Management](#role-management)
23
23
  - [Controller Authorization](#controller-authorization)
24
24
  - [Dynamic Rules](#dynamic-rules)
25
25
  - [Multi-tenancy / Context](#multi-tenancy--context)
@@ -27,7 +27,7 @@ Rabarber is a role-based authorization library for Ruby on Rails that focuses on
27
27
 
28
28
 
29
29
  **Community Resources:**
30
- - [Contributing](#contributing)
30
+ - [Getting Help and Contributing](#getting-help-and-contributing)
31
31
  - [License](#license)
32
32
  - [Code of Conduct](#code-of-conduct)
33
33
  - [Old Versions](#old-versions)
@@ -80,30 +80,6 @@ To clear the role cache manually:
80
80
  Rabarber::Cache.clear
81
81
  ```
82
82
 
83
- ## Role Management
84
-
85
- ### Direct Role Operations
86
-
87
- ```rb
88
- # Create a new role
89
- Rabarber::Role.add(:admin)
90
-
91
- # Rename a role
92
- Rabarber::Role.rename(:admin, :administrator)
93
- Rabarber::Role.rename(:admin, :administrator, force: true) # Force if role is assigned to users
94
-
95
- # Remove a role
96
- Rabarber::Role.remove(:admin)
97
- Rabarber::Role.remove(:admin, force: true) # Force if role is assigned to users
98
-
99
- # List available roles
100
- Rabarber::Role.names
101
- Rabarber::Role.all_names # All roles grouped by context
102
-
103
- # Get users assigned to a role
104
- Rabarber::Role.assignees(:admin)
105
- ```
106
-
107
83
  ## User Role Methods
108
84
 
109
85
  Your user model is automatically augmented with role management methods:
@@ -137,6 +113,30 @@ user.roles
137
113
  user.all_roles
138
114
  ```
139
115
 
116
+ ## Role Management
117
+
118
+ ### Direct Role Operations
119
+
120
+ ```rb
121
+ # Create a new role
122
+ Rabarber::Role.add(:admin)
123
+
124
+ # Rename a role
125
+ Rabarber::Role.rename(:admin, :administrator)
126
+ Rabarber::Role.rename(:admin, :administrator, force: true) # Force if role is assigned to users
127
+
128
+ # Remove a role
129
+ Rabarber::Role.remove(:admin)
130
+ Rabarber::Role.remove(:admin, force: true) # Force if role is assigned to users
131
+
132
+ # List available roles
133
+ Rabarber::Role.names
134
+ Rabarber::Role.all_names # All roles grouped by context
135
+
136
+ # Get users assigned to a role
137
+ Rabarber::Role.assignees(:admin)
138
+ ```
139
+
140
140
  ## Controller Authorization
141
141
 
142
142
  ### Basic Setup
@@ -182,9 +182,9 @@ class TicketsController < ApplicationController
182
182
  # Accessible to admin, manager, and support roles
183
183
  end
184
184
 
185
- grant_access action: :destroy, roles: :admin
185
+ grant_access action: :destroy, roles: :owner, context: -> { Ticket.find(params[:id]) }
186
186
  def destroy
187
- # Accessible to admin role only
187
+ # Accessible to admin and owner of the ticket
188
188
  end
189
189
  end
190
190
  ```
@@ -203,7 +203,9 @@ class InvoicesController < BaseController
203
203
 
204
204
  grant_access action: :index, roles: :manager
205
205
  grant_access action: :index, roles: :supervisor
206
- # Index is accessible to admin, accountant, manager, and supervisor
206
+ def index
207
+ # Index is accessible to admin, accountant, manager, and supervisor
208
+ end
207
209
  end
208
210
  ```
209
211
 
@@ -218,7 +220,14 @@ end
218
220
 
219
221
  class MixedController < ApplicationController
220
222
  grant_access action: :index # Unrestricted index action
223
+ def index
224
+ # Accessible to all users
225
+ end
226
+
221
227
  grant_access action: :show, roles: :member # Restricted show action
228
+ def show
229
+ # Accessible to members only
230
+ end
222
231
  end
223
232
  ```
224
233
 
@@ -242,6 +251,8 @@ class ApplicationController < ActionController::Base
242
251
  end
243
252
  ```
244
253
 
254
+ By default, Rabarber will redirect back (HTML format) or return 403 (other formats).
255
+
245
256
  ## Dynamic Rules
246
257
 
247
258
  Add conditional logic to authorization rules:
@@ -253,9 +264,15 @@ class OrdersController < ApplicationController
253
264
 
254
265
  # Proc-based conditions
255
266
  grant_access action: :show, roles: :client, if: -> { current_user.company_id == Order.find(params[:id]).company_id }
267
+ def show
268
+ # Accessible to company managers unless suspended, and to clients if the client's company matches the order's company
269
+ end
256
270
 
257
271
  # Dynamic-only rules (no roles required, can be used with custom policies)
258
272
  grant_access action: :index, if: -> { OrdersPolicy.new(current_user).can_access?(:index) }
273
+ def index
274
+ # Accessible to company managers unless suspended, and to users based on custom policy logic
275
+ end
259
276
 
260
277
  private
261
278
 
@@ -301,9 +318,15 @@ class ProjectsController < ApplicationController
301
318
 
302
319
  # Instance-based context (method)
303
320
  grant_access action: :show, roles: :member, context: :current_project
321
+ def show
322
+ # Accessible to Project admin and members of the current project
323
+ end
304
324
 
305
325
  # Instance-based context (proc)
306
326
  grant_access action: :update, roles: :owner, context: -> { Project.find(params[:id]) }
327
+ def update
328
+ # Accessible to Project admin and owner of the current project
329
+ end
307
330
 
308
331
  private
309
332
 
@@ -356,7 +379,7 @@ Use conditional rendering based on roles:
356
379
  <% end %>
357
380
  ```
358
381
 
359
- ## Contributing
382
+ ## Getting Help and Contributing
360
383
 
361
384
  ### Getting Help
362
385
  Have a question or need assistance? Open a discussion in our [discussions section](https://github.com/brownboxdev/rabarber/discussions) for:
@@ -1,36 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "singleton"
3
+ require "dry-configurable"
4
4
 
5
5
  module Rabarber
6
- class Configuration
7
- include Singleton
6
+ module Configuration
7
+ extend Dry::Configurable
8
8
 
9
- attr_reader :cache_enabled, :current_user_method
10
- attr_accessor :user_model_name
9
+ module_function
11
10
 
12
- def initialize
13
- @cache_enabled = true
14
- @current_user_method = :current_user
15
- @user_model_name = "User"
16
- end
17
-
18
- def cache_enabled=(value)
19
- @cache_enabled = Rabarber::Input::Types::Boolean.new(
20
- value, Rabarber::ConfigurationError, "Configuration `cache_enabled` must be a Boolean"
21
- ).process
22
- end
23
-
24
- def current_user_method=(method_name)
25
- @current_user_method = Rabarber::Input::Types::Symbol.new(
26
- method_name, Rabarber::ConfigurationError, "Configuration `current_user_method` must be a Symbol or a String"
27
- ).process
28
- end
11
+ setting :cache_enabled,
12
+ default: true,
13
+ reader: true,
14
+ constructor: -> (value) do
15
+ Rabarber::Inputs.process(
16
+ value,
17
+ as: :boolean,
18
+ error: Rabarber::ConfigurationError,
19
+ message: "Invalid configuration `cache_enabled`, expected a boolean, got #{value.inspect}"
20
+ )
21
+ end
22
+ setting :current_user_method,
23
+ default: :current_user,
24
+ reader: true,
25
+ constructor: -> (value) do
26
+ Rabarber::Inputs.process(
27
+ value,
28
+ as: :symbol,
29
+ error: Rabarber::ConfigurationError,
30
+ message: "Invalid configuration `current_user_method`, expected a symbol or a string, got #{value.inspect}"
31
+ )
32
+ end
33
+ setting :user_model_name,
34
+ default: "User",
35
+ reader: true,
36
+ constructor: -> (value) do
37
+ Rabarber::Inputs.process(
38
+ value,
39
+ as: :string,
40
+ error: Rabarber::ConfigurationError,
41
+ message: "Invalid configuration `user_model_name`, expected an ActiveRecord model name, got #{value.inspect}"
42
+ )
43
+ end
29
44
 
30
45
  def user_model
31
- Rabarber::Input::ArModel.new(
32
- @user_model_name, Rabarber::ConfigurationError, "Configuration `user_model_name` must be an ActiveRecord model name"
33
- ).process
46
+ Rabarber::Inputs.process(
47
+ user_model_name,
48
+ as: :model,
49
+ error: Rabarber::ConfigurationError,
50
+ message: "Invalid configuration `user_model_name`, expected an ActiveRecord model name, got #{user_model_name.inspect}"
51
+ )
34
52
  end
35
53
  end
36
54
  end
@@ -21,11 +21,34 @@ module Rabarber
21
21
  def grant_access(action: nil, roles: nil, context: nil, if: nil, unless: nil)
22
22
  Rabarber::Core::Permissions.add(
23
23
  self,
24
- Rabarber::Input::Action.new(action).process,
25
- Rabarber::Input::Roles.new(roles).process,
26
- Rabarber::Input::AuthorizationContext.new(context).process,
27
- Rabarber::Input::DynamicRule.new(binding.local_variable_get(:if)).process,
28
- Rabarber::Input::DynamicRule.new(binding.local_variable_get(:unless)).process
24
+ Rabarber::Inputs.process(
25
+ action,
26
+ as: :symbol,
27
+ optional: true,
28
+ message: "Expected a symbol or a string, got #{action.inspect}"
29
+ ),
30
+ Rabarber::Inputs.process(
31
+ roles,
32
+ as: :roles,
33
+ message: "Expected an array of symbols or strings containing only lowercase letters, numbers, and underscores, got #{roles.inspect}"
34
+ ),
35
+ Rabarber::Inputs.process(
36
+ context,
37
+ as: :authorization_context,
38
+ message: "Expected a Class, an instance of ActiveRecord model, a symbol, a string, or a proc, got #{context.inspect}"
39
+ ),
40
+ Rabarber::Inputs.process(
41
+ binding.local_variable_get(:if),
42
+ as: :dynamic_rule,
43
+ optional: true,
44
+ message: "Expected a symbol, a string, or a proc, got #{binding.local_variable_get(:if).inspect}"
45
+ ),
46
+ Rabarber::Inputs.process(
47
+ binding.local_variable_get(:unless),
48
+ as: :dynamic_rule,
49
+ optional: true,
50
+ message: "Expected a symbol, a string, or a proc, got #{binding.local_variable_get(:unless).inspect}"
51
+ )
29
52
  )
30
53
  end
31
54
  end
@@ -20,7 +20,7 @@ module Rabarber
20
20
  end
21
21
 
22
22
  def enabled?
23
- Rabarber::Configuration.instance.cache_enabled
23
+ Rabarber::Configuration.cache_enabled
24
24
  end
25
25
 
26
26
  def clear
@@ -4,12 +4,12 @@ module Rabarber
4
4
  module Core
5
5
  module Roleable
6
6
  def roleable
7
- current_roleable = send(Rabarber::Configuration.instance.current_user_method)
7
+ current_roleable = send(Rabarber::Configuration.current_user_method)
8
8
 
9
- unless current_roleable.is_a?(Rabarber::Configuration.instance.user_model)
9
+ unless current_roleable.is_a?(Rabarber::Configuration.user_model)
10
10
  raise(
11
11
  Rabarber::Error,
12
- "Expected `#{Rabarber::Configuration.instance.current_user_method}` to return an instance of #{Rabarber::Configuration.instance.user_model_name}, but got #{current_roleable.inspect}"
12
+ "Expected `#{Rabarber::Configuration.current_user_method}` to return an instance of #{Rabarber::Configuration.user_model_name}, got #{current_roleable.inspect}"
13
13
  )
14
14
  end
15
15
 
@@ -35,11 +35,12 @@ module Rabarber
35
35
  end
36
36
 
37
37
  def resolve_context(controller_instance)
38
- case context
39
- when Proc then Rabarber::Input::Context.new(controller_instance.instance_exec(&context)).process
40
- when Symbol then Rabarber::Input::Context.new(controller_instance.send(context)).process
41
- else context
42
- end
38
+ resolved_context = case context
39
+ when Proc then controller_instance.instance_exec(&context)
40
+ when Symbol then controller_instance.send(context)
41
+ else context
42
+ end
43
+ Rabarber::Inputs.process(resolved_context, as: :role_context, message: "Expected an instance of ActiveRecord model, a Class, or nil, got #{resolved_context.inspect}")
43
44
  end
44
45
  end
45
46
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-types"
4
+
5
+ module Rabarber
6
+ module Inputs
7
+ extend self
8
+
9
+ include Dry.Types()
10
+
11
+ PROC_TYPE = self::Instance(Proc)
12
+ SYMBOL_TYPE = self::Coercible::Symbol.constrained(min_size: 1)
13
+ ROLE_TYPE = self::SYMBOL_TYPE.constrained(format: /\A[a-z0-9_]+\z/)
14
+
15
+ CONTEXT_TYPE = self::Strict::Class | self::Instance(ActiveRecord::Base) | self::Hash.schema(
16
+ context_type: self::Strict::String | self::Nil,
17
+ context_id: self::Strict::String | self::Strict::Integer | self::Nil
18
+ ) | self::Nil
19
+
20
+ TYPES = {
21
+ boolean: self::Strict::Bool,
22
+ string: self::Strict::String.constrained(min_size: 1).constructor { _1.is_a?(::String) ? _1.strip : _1 },
23
+ symbol: self::SYMBOL_TYPE,
24
+ role: self::ROLE_TYPE,
25
+ roles: self::Array.of(self::ROLE_TYPE).constructor { Kernel::Array(_1) },
26
+ model: self::Strict::Class.constructor { _1.try(:safe_constantize) }.constrained(lt: ActiveRecord::Base),
27
+ dynamic_rule: self::SYMBOL_TYPE | self::PROC_TYPE,
28
+ role_context: self::CONTEXT_TYPE,
29
+ authorization_context: self::SYMBOL_TYPE | self::PROC_TYPE | self::CONTEXT_TYPE
30
+ }.freeze
31
+
32
+ def process(value, as:, optional: false, error: Rabarber::InvalidArgumentError, message: nil)
33
+ checker = type_for(as)
34
+ checker = checker.optional if optional
35
+
36
+ result = checker[value]
37
+
38
+ [:role_context, :authorization_context].include?(as) ? resolve_context(result) : result
39
+ rescue Dry::Types::CoercionError => e
40
+ raise error, message || e.message
41
+ end
42
+
43
+ private
44
+
45
+ def type_for(name) = self::TYPES.fetch(name)
46
+
47
+ def resolve_context(value)
48
+ case value
49
+ when nil
50
+ { context_type: nil, context_id: nil }
51
+ when Class
52
+ { context_type: value.to_s, context_id: nil }
53
+ when ActiveRecord::Base
54
+ raise Dry::Types::CoercionError, "instance context not persisted" unless value.persisted?
55
+
56
+ { context_type: value.class.to_s, context_id: value.public_send(value.class.primary_key) }
57
+ else
58
+ value
59
+ end
60
+ end
61
+ end
62
+ end
@@ -81,11 +81,19 @@ module Rabarber
81
81
  end
82
82
 
83
83
  def process_role_names(role_names)
84
- Rabarber::Input::Roles.new(role_names).process
84
+ Rabarber::Inputs.process(
85
+ role_names,
86
+ as: :roles,
87
+ message: "Expected an array of symbols or strings containing only lowercase letters, numbers, and underscores, got #{role_names.inspect}"
88
+ )
85
89
  end
86
90
 
87
91
  def process_context(context)
88
- Rabarber::Input::Context.new(context).process
92
+ Rabarber::Inputs.process(
93
+ context,
94
+ as: :role_context,
95
+ message: "Expected an instance of ActiveRecord model, a Class, or nil, got #{context.inspect}"
96
+ )
89
97
  end
90
98
 
91
99
  def delete_roleable_cache(contexts:)
@@ -6,7 +6,7 @@ module Rabarber
6
6
 
7
7
  belongs_to :context, polymorphic: true, optional: true
8
8
 
9
- has_and_belongs_to_many :roleables, class_name: Rabarber::Configuration.instance.user_model_name,
9
+ has_and_belongs_to_many :roleables, class_name: Rabarber::Configuration.user_model_name,
10
10
  association_foreign_key: "roleable_id",
11
11
  join_table: "rabarber_roles_roleables"
12
12
 
@@ -63,8 +63,7 @@ module Rabarber
63
63
  end
64
64
 
65
65
  def assignees(name, context: nil)
66
- find_by(name: process_role_name(name), **process_context(context))&.roleables ||
67
- Rabarber::Configuration.instance.user_model.none
66
+ find_by(name: process_role_name(name), **process_context(context))&.roleables || Rabarber::Configuration.user_model.none
68
67
  end
69
68
 
70
69
  private
@@ -76,11 +75,19 @@ module Rabarber
76
75
  end
77
76
 
78
77
  def process_role_name(name)
79
- Rabarber::Input::Role.new(name).process
78
+ Rabarber::Inputs.process(
79
+ name,
80
+ as: :role,
81
+ message: "Expected a symbol or a string containing only lowercase letters, numbers, and underscores, got #{name.inspect}"
82
+ )
80
83
  end
81
84
 
82
85
  def process_context(context)
83
- Rabarber::Input::Context.new(context).process
86
+ Rabarber::Inputs.process(
87
+ context,
88
+ as: :role_context,
89
+ message: "Expected an instance of ActiveRecord model, a Class, or nil, got #{context.inspect}"
90
+ )
84
91
  end
85
92
  end
86
93
 
@@ -18,7 +18,7 @@ module Rabarber
18
18
  end
19
19
  end
20
20
  end
21
- user_model = Rabarber::Configuration.instance.user_model
21
+ user_model = Rabarber::Configuration.user_model
22
22
  user_model.include Rabarber::HasRoles unless user_model < Rabarber::HasRoles
23
23
  end
24
24
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rabarber
4
- VERSION = "5.1.0"
4
+ VERSION = "5.1.1"
5
5
  end
data/lib/rabarber.rb CHANGED
@@ -1,22 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "rabarber/version"
4
- require_relative "rabarber/configuration"
5
4
 
6
5
  require "active_record"
7
6
  require "active_support"
8
7
 
9
- require_relative "rabarber/input/base"
10
- require_relative "rabarber/input/action"
11
- require_relative "rabarber/input/ar_model"
12
- require_relative "rabarber/input/authorization_context"
13
- require_relative "rabarber/input/context"
14
- require_relative "rabarber/input/dynamic_rule"
15
- require_relative "rabarber/input/role"
16
- require_relative "rabarber/input/roles"
17
- require_relative "rabarber/input/types/boolean"
18
- require_relative "rabarber/input/types/proc"
19
- require_relative "rabarber/input/types/symbol"
8
+ require_relative "rabarber/inputs"
9
+
10
+ require_relative "rabarber/configuration"
11
+
12
+ module Rabarber
13
+ class Error < StandardError; end
14
+ class ConfigurationError < Rabarber::Error; end
15
+ class InvalidArgumentError < Rabarber::Error; end
16
+ class NotFoundError < Rabarber::Error; end
17
+
18
+ delegate :configure, to: Rabarber::Configuration
19
+ module_function :configure
20
+ end
20
21
 
21
22
  require_relative "rabarber/core/cache"
22
23
 
@@ -32,15 +33,3 @@ require_relative "rabarber/core/permissions"
32
33
  require_relative "rabarber/core/integrity_checker"
33
34
 
34
35
  require_relative "rabarber/railtie"
35
-
36
- module Rabarber
37
- class Error < StandardError; end
38
- class ConfigurationError < Rabarber::Error; end
39
- class InvalidArgumentError < Rabarber::Error; end
40
- class NotFoundError < Rabarber::Error; end
41
-
42
- def configure
43
- yield(Rabarber::Configuration.instance)
44
- end
45
- module_function :configure
46
- end
data/rabarber.gemspec CHANGED
@@ -21,5 +21,7 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.require_paths = ["lib"]
23
23
 
24
+ spec.add_dependency "dry-configurable", "~> 1.3"
25
+ spec.add_dependency "dry-types", "~> 1.8"
24
26
  spec.add_dependency "rails", ">= 7.1", "< 8.1"
25
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rabarber
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 5.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - enjaku4
@@ -10,6 +10,34 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 1980-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-configurable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-types
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.8'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.8'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: rails
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -50,17 +78,7 @@ files:
50
78
  - lib/rabarber/core/rule.rb
51
79
  - lib/rabarber/helpers/helpers.rb
52
80
  - lib/rabarber/helpers/migration_helpers.rb
53
- - lib/rabarber/input/action.rb
54
- - lib/rabarber/input/ar_model.rb
55
- - lib/rabarber/input/authorization_context.rb
56
- - lib/rabarber/input/base.rb
57
- - lib/rabarber/input/context.rb
58
- - lib/rabarber/input/dynamic_rule.rb
59
- - lib/rabarber/input/role.rb
60
- - lib/rabarber/input/roles.rb
61
- - lib/rabarber/input/types/boolean.rb
62
- - lib/rabarber/input/types/proc.rb
63
- - lib/rabarber/input/types/symbol.rb
81
+ - lib/rabarber/inputs.rb
64
82
  - lib/rabarber/models/concerns/has_roles.rb
65
83
  - lib/rabarber/models/role.rb
66
84
  - lib/rabarber/railtie.rb
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- class Action < Rabarber::Input::Base
6
- def valid?
7
- Rabarber::Input::Types::Symbol.new(value).valid? || value.nil?
8
- end
9
-
10
- private
11
-
12
- def processed_value
13
- value&.to_sym
14
- end
15
-
16
- def default_error_message
17
- "Action name must be a Symbol or a String"
18
- end
19
- end
20
- end
21
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- class ArModel < Rabarber::Input::Base
6
- def valid?
7
- processed_value < ActiveRecord::Base
8
- rescue NameError
9
- false
10
- end
11
-
12
- private
13
-
14
- def processed_value
15
- value.constantize
16
- end
17
-
18
- def default_error_message
19
- "Value must be an ActiveRecord model"
20
- end
21
- end
22
- end
23
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- class AuthorizationContext < Rabarber::Input::Base
6
- def valid?
7
- Rabarber::Input::Context.new(value).valid? || Rabarber::Input::DynamicRule.new(value).valid?
8
- end
9
-
10
- private
11
-
12
- def processed_value
13
- case value
14
- when String then value.to_sym
15
- when Symbol, Proc then value
16
- else Rabarber::Input::Context.new(value).process
17
- end
18
- end
19
-
20
- def default_error_message
21
- "Context must be a Class, an instance of ActiveRecord model, a Symbol, a String, or a Proc"
22
- end
23
- end
24
- end
25
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- class Base
6
- attr_reader :value, :error_type, :error_message
7
-
8
- def initialize(value, error_type = Rabarber::InvalidArgumentError, error_message = nil)
9
- @value = value
10
- @error_type = error_type
11
- @error_message = error_message || default_error_message
12
- end
13
-
14
- def process
15
- valid? ? processed_value : raise_error
16
- end
17
-
18
- def valid?
19
- raise NotImplementedError
20
- end
21
-
22
- private
23
-
24
- def processed_value
25
- raise NotImplementedError
26
- end
27
-
28
- def default_error_message
29
- raise NotImplementedError
30
- end
31
-
32
- def raise_error
33
- raise error_type, error_message
34
- end
35
- end
36
- end
37
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- class Context < Rabarber::Input::Base
6
- def valid?
7
- value.nil? || value.is_a?(Class) || value.is_a?(ActiveRecord::Base) && value.persisted? || already_processed?
8
- end
9
-
10
- private
11
-
12
- def processed_value
13
- case value
14
- when nil then { context_type: nil, context_id: nil }
15
- when Class then { context_type: value.to_s, context_id: nil }
16
- when ActiveRecord::Base then { context_type: value.class.to_s, context_id: value.public_send(value.class.primary_key) }
17
- else value
18
- end
19
- end
20
-
21
- def default_error_message
22
- "Context must be a Class or an instance of ActiveRecord model"
23
- end
24
-
25
- def already_processed?
26
- case value
27
- in { context_type: NilClass | String, context_id: NilClass | String | Integer } then true
28
- else false
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- class DynamicRule < Rabarber::Input::Base
6
- def valid?
7
- Rabarber::Input::Types::Symbol.new(value).valid? || Rabarber::Input::Types::Proc.new(value).valid? || value.nil?
8
- end
9
-
10
- private
11
-
12
- def processed_value
13
- value.is_a?(String) ? value.to_sym : value
14
- end
15
-
16
- def default_error_message
17
- "Dynamic rule must be a Symbol, a String, or a Proc"
18
- end
19
- end
20
- end
21
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- class Role < Rabarber::Input::Base
6
- REGEX = /\A[a-z0-9_]+\z/
7
-
8
- def valid?
9
- Rabarber::Input::Types::Symbol.new(value).valid? && value.to_s.match?(REGEX)
10
- end
11
-
12
- private
13
-
14
- def processed_value
15
- value.to_sym
16
- end
17
-
18
- def default_error_message
19
- "Role name must be a Symbol or a String and may only contain lowercase letters, numbers, and underscores"
20
- end
21
- end
22
- end
23
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- class Roles < Rabarber::Input::Base
6
- def value
7
- Array(super)
8
- end
9
-
10
- def valid?
11
- value.all? { |role_name| Rabarber::Input::Role.new(role_name).valid? }
12
- end
13
-
14
- private
15
-
16
- def processed_value
17
- value.map(&:to_sym)
18
- end
19
-
20
- def default_error_message
21
- "Role names must be Symbols or Strings and may only contain lowercase letters, numbers, and underscores"
22
- end
23
- end
24
- end
25
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- module Types
6
- class Boolean < Rabarber::Input::Base
7
- def valid?
8
- [true, false].include?(value)
9
- end
10
-
11
- private
12
-
13
- def processed_value
14
- value
15
- end
16
-
17
- def default_error_message
18
- "Value must be a Boolean"
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- module Types
6
- class Proc < Rabarber::Input::Base
7
- def valid?
8
- value.is_a?(::Proc)
9
- end
10
-
11
- private
12
-
13
- def processed_value
14
- value
15
- end
16
-
17
- def default_error_message
18
- "Value must be a Proc"
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module Input
5
- module Types
6
- class Symbol < Rabarber::Input::Base
7
- def valid?
8
- (value.is_a?(::Symbol) || value.is_a?(String)) && value.present?
9
- end
10
-
11
- private
12
-
13
- def processed_value
14
- value.to_sym
15
- end
16
-
17
- def default_error_message
18
- "Value must be a Symbol or a String"
19
- end
20
- end
21
- end
22
- end
23
- end