pragma-operation 1.6.3 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -8
- data/README.md +164 -3
- data/lib/pragma/operation.rb +14 -4
- data/lib/pragma/operation/base.rb +2 -247
- data/lib/pragma/operation/error.rb +27 -0
- data/lib/pragma/operation/response.rb +102 -0
- data/lib/pragma/operation/response/bad_request.rb +16 -0
- data/lib/pragma/operation/response/created.rb +13 -0
- data/lib/pragma/operation/response/forbidden.rb +19 -0
- data/lib/pragma/operation/response/no_content.rb +13 -0
- data/lib/pragma/operation/response/not_found.rb +19 -0
- data/lib/pragma/operation/response/ok.rb +13 -0
- data/lib/pragma/operation/response/unprocessable_entity.rb +23 -0
- data/lib/pragma/operation/version.rb +2 -1
- data/pragma-operation.gemspec +16 -19
- metadata +15 -55
- data/doc/01-basic-usage.md +0 -264
- data/doc/02-contracts.md +0 -154
- data/doc/03-policies.md +0 -179
- data/doc/04-decorators.md +0 -50
- data/lib/pragma/operation/authorization.rb +0 -130
- data/lib/pragma/operation/decoration.rb +0 -76
- data/lib/pragma/operation/validation.rb +0 -146
@@ -1,76 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module Pragma
|
3
|
-
module Operation
|
4
|
-
# Provides integration with {https://github.com/pragmarb/pragma-decorator Pragma::Decorator}.
|
5
|
-
#
|
6
|
-
# @author Alessandro Desantis
|
7
|
-
module Decoration
|
8
|
-
def self.included(base)
|
9
|
-
base.extend ClassMethods
|
10
|
-
base.include InstanceMethods
|
11
|
-
end
|
12
|
-
|
13
|
-
module ClassMethods # :nodoc:
|
14
|
-
# Sets the decorator to use for decorating this operation.
|
15
|
-
#
|
16
|
-
# @param klass [Class] a subclass of +Pragma::Decorator::Base+
|
17
|
-
#
|
18
|
-
# @yield A block which will be called with the operation's context which should return
|
19
|
-
# the decorator class. The block can also return +nil+ if decoration should be skipped.
|
20
|
-
def decorator(klass = nil, &block)
|
21
|
-
if !klass && !block_given?
|
22
|
-
fail ArgumentError, 'You must pass either a decorator class or a block'
|
23
|
-
end
|
24
|
-
|
25
|
-
@decorator = klass || block
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns the decorator class.
|
29
|
-
#
|
30
|
-
# @return [Class]
|
31
|
-
def decorator_klass
|
32
|
-
@decorator
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
module InstanceMethods # :nodoc:
|
37
|
-
# Builds the decorator for the given resource, using the previously defined decorator class.
|
38
|
-
#
|
39
|
-
# This is just an instance-level alias of {.build_decorator}. You should use this from
|
40
|
-
# inside the operation.
|
41
|
-
#
|
42
|
-
# @param resource [Object]
|
43
|
-
#
|
44
|
-
# @return [Pragma::Decorator::Base]
|
45
|
-
#
|
46
|
-
# @see #decorate
|
47
|
-
def build_decorator(resource)
|
48
|
-
resource = resource.to_a if resource.is_a?(Enumerable)
|
49
|
-
compute_decorator_klass.represent(resource)
|
50
|
-
end
|
51
|
-
|
52
|
-
# If a decorator is defined, acts as an alias for {#build_decorator}. If not, simply returns
|
53
|
-
# the provided resource.
|
54
|
-
# @param decoratable [Object]
|
55
|
-
#
|
56
|
-
# @return [Pragma::Decorator::Base|Object]
|
57
|
-
#
|
58
|
-
# @see #build_decorator
|
59
|
-
def decorate(decoratable)
|
60
|
-
return decoratable unless compute_decorator_klass
|
61
|
-
build_decorator(decoratable)
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def compute_decorator_klass
|
67
|
-
if self.class.decorator_klass.is_a?(Proc)
|
68
|
-
self.class.decorator_klass.call(context)
|
69
|
-
else
|
70
|
-
self.class.decorator_klass
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,146 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module Pragma
|
3
|
-
module Operation
|
4
|
-
# Provides integration with {https://github.com/pragmarb/pragma-contract Pragma::Contract}.
|
5
|
-
#
|
6
|
-
# @author Alessandro Desantis
|
7
|
-
module Validation
|
8
|
-
def self.included(base)
|
9
|
-
base.extend ClassMethods
|
10
|
-
base.include InstanceMethods
|
11
|
-
end
|
12
|
-
|
13
|
-
module ClassMethods # :nodoc:
|
14
|
-
# Sets the contract to use for validating this operation.
|
15
|
-
#
|
16
|
-
# @param klass [Class] a subclass of +Pragma::Contract::Base+
|
17
|
-
#
|
18
|
-
# @yield A block which will be called with the operation's context which should return
|
19
|
-
# the contract class. The block can also return +nil+ if validation should be skipped.
|
20
|
-
def contract(klass = nil, &block)
|
21
|
-
if !klass && !block_given?
|
22
|
-
fail ArgumentError, 'You must pass either a contract class or a block'
|
23
|
-
end
|
24
|
-
|
25
|
-
@contract = klass || block
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns the contract class.
|
29
|
-
#
|
30
|
-
# @return [Class|Proc]
|
31
|
-
def contract_klass
|
32
|
-
@contract
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
module InstanceMethods # :nodoc:
|
37
|
-
# Builds the contract for the given resource, using the previously defined contract class.
|
38
|
-
#
|
39
|
-
# This is just an instance-level alias of {.build_contract}. You should use this from inside
|
40
|
-
# the operation.
|
41
|
-
#
|
42
|
-
# @param resource [Object]
|
43
|
-
#
|
44
|
-
# @return [Pragma::Contract::Base]
|
45
|
-
#
|
46
|
-
# @see .contract
|
47
|
-
def build_contract(resource)
|
48
|
-
contract_klass = compute_contract_klass(resource)
|
49
|
-
return resource unless contract_klass
|
50
|
-
|
51
|
-
contract_klass.new(resource)
|
52
|
-
end
|
53
|
-
|
54
|
-
# Validates this operation on the provided contract or resource.
|
55
|
-
#
|
56
|
-
# If no contract has been defined for this operation, tries to call +#validate+ on the
|
57
|
-
# resource. If the resource does not respond to +#validate+, returns true.
|
58
|
-
#
|
59
|
-
# @param validatable [Object|Pragma::Contract::Base] contract or resource
|
60
|
-
#
|
61
|
-
# @return [Boolean] whether the operation is valid
|
62
|
-
def validate(validatable)
|
63
|
-
# rubocop:disable Metrics/LineLength
|
64
|
-
contract = if Object.const_defined?('Pragma::Contract::Base') && validatable.is_a?(Pragma::Contract::Base)
|
65
|
-
validatable
|
66
|
-
else
|
67
|
-
build_contract(validatable)
|
68
|
-
end
|
69
|
-
# rubocop:enable Metrics/LineLength
|
70
|
-
|
71
|
-
if contract.is_a?(Pragma::Contract::Base)
|
72
|
-
contract.validate(params)
|
73
|
-
else
|
74
|
-
contract.respond_to?(:validate) ? contract.validate : true
|
75
|
-
end.tap do |result|
|
76
|
-
after_validation(result)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# Validates this operation on the provided contract or resource. If the operation is not
|
81
|
-
# valid, responds with 422 Unprocessable Entity and an error body and halts the execution.
|
82
|
-
#
|
83
|
-
# @param validatable [Object|Pragma::Contract::Base] contract or resource
|
84
|
-
def validate!(validatable)
|
85
|
-
# rubocop:disable Metrics/LineLength
|
86
|
-
contract = if Object.const_defined?('Pragma::Contract::Base') && validatable.is_a?(Pragma::Contract::Base)
|
87
|
-
validatable
|
88
|
-
else
|
89
|
-
build_contract(validatable)
|
90
|
-
end
|
91
|
-
# rubocop:enable Metrics/LineLength
|
92
|
-
|
93
|
-
respond_with_validation_errors!(contract) unless validate(contract)
|
94
|
-
end
|
95
|
-
|
96
|
-
# Runs after validation is done.
|
97
|
-
#
|
98
|
-
# @param result [Boolean] the result of the validation
|
99
|
-
def after_validation(result)
|
100
|
-
end
|
101
|
-
|
102
|
-
# Sets a response suitable for reporting validation errors.
|
103
|
-
#
|
104
|
-
# The response will be a 422 Unprocessable Entity, contain the +error_type+, +error_message+
|
105
|
-
# and +meta+ keys. +meta.errors+ will contain the validation errors.
|
106
|
-
#
|
107
|
-
# @param validatable [Object] a validatable object
|
108
|
-
def respond_with_validation_errors(validatable)
|
109
|
-
respond_with validation_errors_response(validatable)
|
110
|
-
end
|
111
|
-
|
112
|
-
# Same as {#respond_with_validation_errors}, but also halts the execution of the operation.
|
113
|
-
#
|
114
|
-
# @param validatable [Object] a validatable object
|
115
|
-
#
|
116
|
-
# @see #respond_with_validation_errors
|
117
|
-
def respond_with_validation_errors!(validatable)
|
118
|
-
respond_with! validation_errors_response(validatable)
|
119
|
-
end
|
120
|
-
|
121
|
-
private
|
122
|
-
|
123
|
-
def validation_errors_response(validatable)
|
124
|
-
{
|
125
|
-
status: :unprocessable_entity,
|
126
|
-
resource: {
|
127
|
-
error_type: :contract_not_respected,
|
128
|
-
error_message: 'The contract for this operation was not respected.',
|
129
|
-
meta: {
|
130
|
-
errors: validatable.errors.messages
|
131
|
-
}
|
132
|
-
}
|
133
|
-
}
|
134
|
-
end
|
135
|
-
|
136
|
-
def compute_contract_klass(_resource)
|
137
|
-
if self.class.contract_klass.is_a?(Proc)
|
138
|
-
self.class.contract_klass.call(context)
|
139
|
-
else
|
140
|
-
self.class.contract_klass
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|