rabarber 5.0.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 +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +194 -384
- data/lib/rabarber/configuration.rb +43 -25
- data/lib/rabarber/controllers/concerns/authorization.rb +31 -8
- data/lib/rabarber/core/cache.rb +1 -1
- data/lib/rabarber/core/roleable.rb +3 -3
- data/lib/rabarber/core/rule.rb +6 -5
- data/lib/rabarber/inputs.rb +62 -0
- data/lib/rabarber/models/concerns/has_roles.rb +24 -6
- data/lib/rabarber/models/role.rb +12 -10
- data/lib/rabarber/railtie.rb +1 -1
- data/lib/rabarber/version.rb +1 -1
- data/lib/rabarber.rb +13 -24
- data/rabarber.gemspec +2 -0
- metadata +30 -12
- data/lib/rabarber/input/action.rb +0 -21
- data/lib/rabarber/input/ar_model.rb +0 -23
- data/lib/rabarber/input/authorization_context.rb +0 -25
- data/lib/rabarber/input/base.rb +0 -37
- data/lib/rabarber/input/context.rb +0 -33
- data/lib/rabarber/input/dynamic_rule.rb +0 -21
- data/lib/rabarber/input/role.rb +0 -23
- data/lib/rabarber/input/roles.rb +0 -25
- data/lib/rabarber/input/types/boolean.rb +0 -23
- data/lib/rabarber/input/types/proc.rb +0 -23
- data/lib/rabarber/input/types/symbol.rb +0 -23
@@ -1,36 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "dry-configurable"
|
4
4
|
|
5
5
|
module Rabarber
|
6
|
-
|
7
|
-
|
6
|
+
module Configuration
|
7
|
+
extend Dry::Configurable
|
8
8
|
|
9
|
-
|
10
|
-
attr_accessor :user_model_name
|
9
|
+
module_function
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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::
|
32
|
-
|
33
|
-
|
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
|
@@ -9,23 +9,46 @@ module Rabarber
|
|
9
9
|
def with_authorization(options = {})
|
10
10
|
before_action :with_authorization, **options
|
11
11
|
rescue ArgumentError => e
|
12
|
-
raise Rabarber::
|
12
|
+
raise Rabarber::InvalidArgumentError, e.message
|
13
13
|
end
|
14
14
|
|
15
15
|
def skip_authorization(options = {})
|
16
16
|
skip_before_action :with_authorization, **options
|
17
17
|
rescue ArgumentError => e
|
18
|
-
raise Rabarber::
|
18
|
+
raise Rabarber::InvalidArgumentError, e.message
|
19
19
|
end
|
20
20
|
|
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::
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
@@ -39,7 +62,7 @@ module Rabarber
|
|
39
62
|
end
|
40
63
|
|
41
64
|
def when_unauthorized
|
42
|
-
request.format.html? ? redirect_back(fallback_location: root_path) : head(:
|
65
|
+
request.format.html? ? redirect_back(fallback_location: root_path) : head(:forbidden)
|
43
66
|
end
|
44
67
|
end
|
45
68
|
end
|
data/lib/rabarber/core/cache.rb
CHANGED
@@ -4,12 +4,12 @@ module Rabarber
|
|
4
4
|
module Core
|
5
5
|
module Roleable
|
6
6
|
def roleable
|
7
|
-
current_roleable = send(Rabarber::Configuration.
|
7
|
+
current_roleable = send(Rabarber::Configuration.current_user_method)
|
8
8
|
|
9
|
-
unless current_roleable.is_a?(Rabarber::Configuration.
|
9
|
+
unless current_roleable.is_a?(Rabarber::Configuration.user_model)
|
10
10
|
raise(
|
11
11
|
Rabarber::Error,
|
12
|
-
"Expected `#{Rabarber::Configuration.
|
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
|
|
data/lib/rabarber/core/rule.rb
CHANGED
@@ -35,11 +35,12 @@ module Rabarber
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def resolve_context(controller_instance)
|
38
|
-
case context
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
@@ -40,7 +40,7 @@ module Rabarber
|
|
40
40
|
)
|
41
41
|
|
42
42
|
if roles_to_assign.any?
|
43
|
-
delete_roleable_cache(
|
43
|
+
delete_roleable_cache(contexts: [processed_context])
|
44
44
|
rabarber_roles << roles_to_assign
|
45
45
|
end
|
46
46
|
|
@@ -56,13 +56,23 @@ module Rabarber
|
|
56
56
|
)
|
57
57
|
|
58
58
|
if roles_to_revoke.any?
|
59
|
-
delete_roleable_cache(
|
59
|
+
delete_roleable_cache(contexts: [processed_context])
|
60
60
|
self.rabarber_roles -= roles_to_revoke
|
61
61
|
end
|
62
62
|
|
63
63
|
roles(context: processed_context)
|
64
64
|
end
|
65
65
|
|
66
|
+
def revoke_all_roles
|
67
|
+
return if rabarber_roles.none?
|
68
|
+
|
69
|
+
contexts = all_roles.keys.map { process_context(_1) }
|
70
|
+
|
71
|
+
rabarber_roles.clear
|
72
|
+
|
73
|
+
delete_roleable_cache(contexts:)
|
74
|
+
end
|
75
|
+
|
66
76
|
private
|
67
77
|
|
68
78
|
def create_new_roles(role_names, context:)
|
@@ -71,15 +81,23 @@ module Rabarber
|
|
71
81
|
end
|
72
82
|
|
73
83
|
def process_role_names(role_names)
|
74
|
-
Rabarber::
|
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
|
+
)
|
75
89
|
end
|
76
90
|
|
77
91
|
def process_context(context)
|
78
|
-
Rabarber::
|
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
|
+
)
|
79
97
|
end
|
80
98
|
|
81
|
-
def delete_roleable_cache(
|
82
|
-
Rabarber::Core::Cache.delete([roleable_id,
|
99
|
+
def delete_roleable_cache(contexts:)
|
100
|
+
Rabarber::Core::Cache.delete(*contexts.map { [roleable_id, _1] }, [roleable_id, :all])
|
83
101
|
end
|
84
102
|
|
85
103
|
def roleable_id
|
data/lib/rabarber/models/role.rb
CHANGED
@@ -4,14 +4,9 @@ module Rabarber
|
|
4
4
|
class Role < ActiveRecord::Base
|
5
5
|
self.table_name = "rabarber_roles"
|
6
6
|
|
7
|
-
validates :name, presence: true,
|
8
|
-
uniqueness: { scope: [:context_type, :context_id] },
|
9
|
-
format: { with: Rabarber::Input::Role::REGEX },
|
10
|
-
strict: true
|
11
|
-
|
12
7
|
belongs_to :context, polymorphic: true, optional: true
|
13
8
|
|
14
|
-
has_and_belongs_to_many :roleables, class_name: Rabarber::Configuration.
|
9
|
+
has_and_belongs_to_many :roleables, class_name: Rabarber::Configuration.user_model_name,
|
15
10
|
association_foreign_key: "roleable_id",
|
16
11
|
join_table: "rabarber_roles_roleables"
|
17
12
|
|
@@ -68,8 +63,7 @@ module Rabarber
|
|
68
63
|
end
|
69
64
|
|
70
65
|
def assignees(name, context: nil)
|
71
|
-
find_by(name: process_role_name(name), **process_context(context))&.roleables ||
|
72
|
-
Rabarber::Configuration.instance.user_model.none
|
66
|
+
find_by(name: process_role_name(name), **process_context(context))&.roleables || Rabarber::Configuration.user_model.none
|
73
67
|
end
|
74
68
|
|
75
69
|
private
|
@@ -81,11 +75,19 @@ module Rabarber
|
|
81
75
|
end
|
82
76
|
|
83
77
|
def process_role_name(name)
|
84
|
-
Rabarber::
|
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
|
+
)
|
85
83
|
end
|
86
84
|
|
87
85
|
def process_context(context)
|
88
|
-
Rabarber::
|
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
|
+
)
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
data/lib/rabarber/railtie.rb
CHANGED
data/lib/rabarber/version.rb
CHANGED
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/
|
10
|
-
|
11
|
-
require_relative "rabarber/
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
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.
|
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/
|
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
|
data/lib/rabarber/input/base.rb
DELETED
@@ -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
|