pragma-operation 1.6.3 → 2.0.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 +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
|