cuprum-rails 0.1.0 → 0.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 +4 -4
- data/CHANGELOG.md +145 -0
- data/DEVELOPMENT.md +20 -0
- data/README.md +356 -63
- data/lib/cuprum/rails/action.rb +32 -16
- data/lib/cuprum/rails/actions/create.rb +62 -15
- data/lib/cuprum/rails/actions/destroy.rb +23 -7
- data/lib/cuprum/rails/actions/edit.rb +23 -7
- data/lib/cuprum/rails/actions/index.rb +30 -10
- data/lib/cuprum/rails/actions/middleware/associations/cache.rb +112 -0
- data/lib/cuprum/rails/actions/middleware/associations/find.rb +23 -0
- data/lib/cuprum/rails/actions/middleware/associations/parent.rb +70 -0
- data/lib/cuprum/rails/actions/middleware/associations/query.rb +140 -0
- data/lib/cuprum/rails/actions/middleware/associations.rb +12 -0
- data/lib/cuprum/rails/actions/middleware/log_request.rb +126 -0
- data/lib/cuprum/rails/actions/middleware/log_result.rb +51 -0
- data/lib/cuprum/rails/actions/middleware/resources/find.rb +44 -0
- data/lib/cuprum/rails/actions/middleware/resources/query.rb +91 -0
- data/lib/cuprum/rails/actions/middleware/resources.rb +11 -0
- data/lib/cuprum/rails/actions/middleware.rb +13 -0
- data/lib/cuprum/rails/actions/new.rb +16 -4
- data/lib/cuprum/rails/actions/parameter_validation.rb +60 -0
- data/lib/cuprum/rails/actions/resource_action.rb +119 -42
- data/lib/cuprum/rails/actions/show.rb +23 -7
- data/lib/cuprum/rails/actions/update.rb +70 -22
- data/lib/cuprum/rails/actions.rb +11 -7
- data/lib/cuprum/rails/collection.rb +27 -47
- data/lib/cuprum/rails/command.rb +3 -1
- data/lib/cuprum/rails/commands/destroy_one.rb +10 -6
- data/lib/cuprum/rails/commands/find_many.rb +8 -1
- data/lib/cuprum/rails/commands/find_matching.rb +1 -1
- data/lib/cuprum/rails/commands/find_one.rb +8 -0
- data/lib/cuprum/rails/commands/insert_one.rb +17 -6
- data/lib/cuprum/rails/commands/update_one.rb +16 -5
- data/lib/cuprum/rails/constraints/parameters_contract.rb +14 -0
- data/lib/cuprum/rails/constraints.rb +10 -0
- data/lib/cuprum/rails/controller.rb +12 -2
- data/lib/cuprum/rails/controllers/action.rb +100 -0
- data/lib/cuprum/rails/controllers/class_methods/actions.rb +33 -7
- data/lib/cuprum/rails/controllers/class_methods/configuration.rb +36 -0
- data/lib/cuprum/rails/controllers/class_methods/middleware.rb +88 -0
- data/lib/cuprum/rails/controllers/class_methods/validations.rb +2 -2
- data/lib/cuprum/rails/controllers/configuration.rb +41 -1
- data/lib/cuprum/rails/controllers/middleware.rb +59 -0
- data/lib/cuprum/rails/controllers.rb +2 -0
- data/lib/cuprum/rails/errors/invalid_parameters.rb +55 -0
- data/lib/cuprum/rails/errors/invalid_statement.rb +11 -0
- data/lib/cuprum/rails/errors/missing_parameter.rb +42 -0
- data/lib/cuprum/rails/errors/resource_error.rb +46 -0
- data/lib/cuprum/rails/errors.rb +6 -1
- data/lib/cuprum/rails/map_errors.rb +29 -1
- data/lib/cuprum/rails/query.rb +1 -1
- data/lib/cuprum/rails/repository.rb +12 -25
- data/lib/cuprum/rails/request.rb +149 -60
- data/lib/cuprum/rails/resource.rb +119 -85
- data/lib/cuprum/rails/responders/base_responder.rb +78 -0
- data/lib/cuprum/rails/responders/html/plural_resource.rb +9 -39
- data/lib/cuprum/rails/responders/html/rendering.rb +81 -0
- data/lib/cuprum/rails/responders/html/resource.rb +107 -0
- data/lib/cuprum/rails/responders/html/singular_resource.rb +9 -38
- data/lib/cuprum/rails/responders/html.rb +2 -0
- data/lib/cuprum/rails/responders/html_responder.rb +8 -52
- data/lib/cuprum/rails/responders/json/resource.rb +3 -3
- data/lib/cuprum/rails/responders/json_responder.rb +31 -16
- data/lib/cuprum/rails/responders/matching.rb +29 -27
- data/lib/cuprum/rails/responders/serialization.rb +11 -9
- data/lib/cuprum/rails/responders.rb +1 -0
- data/lib/cuprum/rails/responses/head_response.rb +24 -0
- data/lib/cuprum/rails/responses/html/redirect_back_response.rb +55 -0
- data/lib/cuprum/rails/responses/html/redirect_response.rb +19 -4
- data/lib/cuprum/rails/responses/html/render_response.rb +17 -5
- data/lib/cuprum/rails/responses/html.rb +6 -2
- data/lib/cuprum/rails/responses.rb +1 -0
- data/lib/cuprum/rails/result.rb +36 -0
- data/lib/cuprum/rails/routes.rb +36 -23
- data/lib/cuprum/rails/rspec/contract_helpers.rb +57 -0
- data/lib/cuprum/rails/rspec/contracts/action_contracts.rb +754 -0
- data/lib/cuprum/rails/rspec/contracts/actions/create_contracts.rb +289 -0
- data/lib/cuprum/rails/rspec/contracts/actions/destroy_contracts.rb +164 -0
- data/lib/cuprum/rails/rspec/contracts/actions/edit_contracts.rb +73 -0
- data/lib/cuprum/rails/rspec/contracts/actions/index_contracts.rb +108 -0
- data/lib/cuprum/rails/rspec/contracts/actions/new_contracts.rb +111 -0
- data/lib/cuprum/rails/rspec/contracts/actions/show_contracts.rb +72 -0
- data/lib/cuprum/rails/rspec/contracts/actions/update_contracts.rb +263 -0
- data/lib/cuprum/rails/rspec/contracts/actions.rb +8 -0
- data/lib/cuprum/rails/rspec/contracts/command_contracts.rb +479 -0
- data/lib/cuprum/rails/rspec/contracts/responder_contracts.rb +232 -0
- data/lib/cuprum/rails/rspec/contracts/routes_contracts.rb +363 -0
- data/lib/cuprum/rails/rspec/contracts/serializers_contracts.rb +70 -0
- data/lib/cuprum/rails/rspec/contracts.rb +8 -0
- data/lib/cuprum/rails/rspec/matchers/be_a_result_matcher.rb +64 -0
- data/lib/cuprum/rails/rspec/matchers.rb +41 -0
- data/lib/cuprum/rails/serializers/base_serializer.rb +60 -0
- data/lib/cuprum/rails/serializers/context.rb +84 -0
- data/lib/cuprum/rails/serializers/json/active_record_serializer.rb +2 -2
- data/lib/cuprum/rails/serializers/json/array_serializer.rb +9 -8
- data/lib/cuprum/rails/serializers/json/attributes_serializer.rb +95 -172
- data/lib/cuprum/rails/serializers/json/error_serializer.rb +2 -2
- data/lib/cuprum/rails/serializers/json/hash_serializer.rb +9 -8
- data/lib/cuprum/rails/serializers/json/identity_serializer.rb +3 -3
- data/lib/cuprum/rails/serializers/json/properties_serializer.rb +252 -0
- data/lib/cuprum/rails/serializers/json.rb +2 -1
- data/lib/cuprum/rails/serializers.rb +3 -1
- data/lib/cuprum/rails/version.rb +1 -1
- data/lib/cuprum/rails.rb +19 -16
- metadata +73 -131
- data/lib/cuprum/rails/controller_action.rb +0 -121
- data/lib/cuprum/rails/errors/missing_parameters.rb +0 -33
- data/lib/cuprum/rails/errors/missing_primary_key.rb +0 -46
- data/lib/cuprum/rails/errors/undefined_permitted_attributes.rb +0 -34
- data/lib/cuprum/rails/rspec/command_contract.rb +0 -460
- data/lib/cuprum/rails/rspec/define_route_contract.rb +0 -84
- data/lib/cuprum/rails/serializers/json/serializer.rb +0 -66
@@ -5,13 +5,18 @@ require 'cuprum/rails/responses/html'
|
|
5
5
|
module Cuprum::Rails::Responses::Html
|
6
6
|
# Encapsulates an HTML response that redirects to a given path.
|
7
7
|
class RedirectResponse
|
8
|
-
# @param
|
9
|
-
# @param
|
10
|
-
|
8
|
+
# @param flash [Hash] the flash messages to set.
|
9
|
+
# @param path [String] the path or url to redirect to.
|
10
|
+
# @param status [Integer] the HTTP status of the response.
|
11
|
+
def initialize(path, flash: {}, status: 302)
|
12
|
+
@flash = flash
|
11
13
|
@path = path
|
12
14
|
@status = status
|
13
15
|
end
|
14
16
|
|
17
|
+
# @return [Hash] the flash messages to set.
|
18
|
+
attr_reader :flash
|
19
|
+
|
15
20
|
# @return [String] the path or url to redirect to.
|
16
21
|
attr_reader :path
|
17
22
|
|
@@ -20,10 +25,20 @@ module Cuprum::Rails::Responses::Html
|
|
20
25
|
|
21
26
|
# Calls the renderer's #redirect_to method with the path and status.
|
22
27
|
#
|
23
|
-
# @param renderer [#redirect_to] The
|
28
|
+
# @param renderer [#redirect_to] The tontext for executing the response,
|
24
29
|
# such as a Rails controller.
|
25
30
|
def call(renderer)
|
31
|
+
assign_flash(renderer)
|
32
|
+
|
26
33
|
renderer.redirect_to(path, status: status)
|
27
34
|
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def assign_flash(renderer)
|
39
|
+
flash.each do |key, value|
|
40
|
+
renderer.flash[key] = value
|
41
|
+
end
|
42
|
+
end
|
28
43
|
end
|
29
44
|
end
|
@@ -5,12 +5,14 @@ require 'cuprum/rails/responses/html'
|
|
5
5
|
module Cuprum::Rails::Responses::Html
|
6
6
|
# Encapsulates an HTML response that renders a given template.
|
7
7
|
class RenderResponse
|
8
|
-
# @param assigns [Hash]
|
9
|
-
# @param
|
10
|
-
# @param
|
11
|
-
# @param
|
12
|
-
|
8
|
+
# @param assigns [Hash] variables to assign when rendering the template.
|
9
|
+
# @param flash [Hash] the flash messages to set.
|
10
|
+
# @param layout [String] the layout to render.
|
11
|
+
# @param status [Integer] the HTTP status of the response.
|
12
|
+
# @param template [String, Symbol] the template to render.
|
13
|
+
def initialize(template, assigns: {}, flash: {}, layout: nil, status: 200)
|
13
14
|
@assigns = assigns
|
15
|
+
@flash = flash
|
14
16
|
@layout = layout
|
15
17
|
@status = status
|
16
18
|
@template = template
|
@@ -19,6 +21,9 @@ module Cuprum::Rails::Responses::Html
|
|
19
21
|
# @return [Hash] variables to assign when rendering the template.
|
20
22
|
attr_reader :assigns
|
21
23
|
|
24
|
+
# @return [Hash] the flash messages to set.
|
25
|
+
attr_reader :flash
|
26
|
+
|
22
27
|
# @return [String] the layout to render.
|
23
28
|
attr_reader :layout
|
24
29
|
|
@@ -33,6 +38,7 @@ module Cuprum::Rails::Responses::Html
|
|
33
38
|
# @param renderer [#render] The context for executing the response, such as
|
34
39
|
# a Rails controller.
|
35
40
|
def call(renderer)
|
41
|
+
assign_flash(renderer)
|
36
42
|
assign_variables(renderer)
|
37
43
|
|
38
44
|
options = { status: status }
|
@@ -43,6 +49,12 @@ module Cuprum::Rails::Responses::Html
|
|
43
49
|
|
44
50
|
private
|
45
51
|
|
52
|
+
def assign_flash(renderer)
|
53
|
+
flash.each do |key, value|
|
54
|
+
renderer.flash.now[key] = value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
46
58
|
def assign_variables(renderer)
|
47
59
|
assigns.each do |key, value|
|
48
60
|
renderer.instance_variable_set("@#{key}", value)
|
@@ -5,7 +5,11 @@ require 'cuprum/rails/responses'
|
|
5
5
|
module Cuprum::Rails::Responses
|
6
6
|
# Namespace for response objects, which encapsulate Html responses.
|
7
7
|
module Html
|
8
|
-
autoload :
|
9
|
-
|
8
|
+
autoload :RedirectBackResponse,
|
9
|
+
'cuprum/rails/responses/html/redirect_back_response'
|
10
|
+
autoload :RedirectResponse,
|
11
|
+
'cuprum/rails/responses/html/redirect_response'
|
12
|
+
autoload :RenderResponse,
|
13
|
+
'cuprum/rails/responses/html/render_response'
|
10
14
|
end
|
11
15
|
end
|
@@ -5,6 +5,7 @@ require 'cuprum/rails'
|
|
5
5
|
module Cuprum::Rails
|
6
6
|
# Namespace for response objects, which encapsulate server responses.
|
7
7
|
module Responses
|
8
|
+
autoload :HeadResponse, 'cuprum/rails/responses/head_response'
|
8
9
|
autoload :Html, 'cuprum/rails/responses/html'
|
9
10
|
autoload :JsonResponse, 'cuprum/rails/responses/json_response'
|
10
11
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails'
|
4
|
+
|
5
|
+
module Cuprum::Rails
|
6
|
+
# Result class representing the result of calling an action.
|
7
|
+
#
|
8
|
+
# In addition to the standard properties inherited from Cuprum::Result, each
|
9
|
+
# Cuprum::Rails::Result also includes a #metadata property. This represents
|
10
|
+
# secondary information about the result that may be relevant for rendering or
|
11
|
+
# displaying the data, but is not part of the requested value. For example.
|
12
|
+
# information about the current controller would be metadata, as would the
|
13
|
+
# current authentication session.
|
14
|
+
class Result < Cuprum::Result
|
15
|
+
# @param value [Object] the value returned by calling the action.
|
16
|
+
# @param error [Cuprum::Error] the error (if any) generated when the action
|
17
|
+
# was called.
|
18
|
+
# @param metadata [Hash{Symbol => Object}] the request or action metadata.
|
19
|
+
# @param status [String, Symbol, nil] the status of the result. Must be
|
20
|
+
# :success, :failure, or nil.
|
21
|
+
def initialize(error: nil, metadata: {}, status: nil, value: nil)
|
22
|
+
super(error: error, status: status, value: value)
|
23
|
+
|
24
|
+
@metadata = metadata
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Hash{Symbol => Object}] the request or action metadata.
|
28
|
+
attr_reader :metadata
|
29
|
+
|
30
|
+
# @return [Hash{Symbol => Object}] a Hash representation of the result.
|
31
|
+
def properties
|
32
|
+
super().merge(metadata: metadata)
|
33
|
+
end
|
34
|
+
alias to_h properties
|
35
|
+
end
|
36
|
+
end
|
data/lib/cuprum/rails/routes.rb
CHANGED
@@ -4,7 +4,7 @@ require 'cuprum/rails'
|
|
4
4
|
|
5
5
|
module Cuprum::Rails
|
6
6
|
# Represent the routes available for a given resource.
|
7
|
-
class Routes
|
7
|
+
class Routes # rubocop:disable Metrics/ClassLength
|
8
8
|
# Error class when a wildcard value is missing for a route.
|
9
9
|
class MissingWildcardError < StandardError; end
|
10
10
|
|
@@ -37,18 +37,18 @@ module Cuprum::Rails
|
|
37
37
|
private
|
38
38
|
|
39
39
|
def define_collection_route(action_name, original_path)
|
40
|
-
define_method :"#{action_name}_path" do
|
40
|
+
define_method :"#{action_name}_path" do |**wildcards|
|
41
41
|
path = resolve_base_path(original_path)
|
42
42
|
|
43
|
-
insert_wildcards(path)
|
43
|
+
insert_wildcards(path, **wildcards)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
def define_member_route(action_name, original_path)
|
48
|
-
define_method :"#{action_name}_path" do |entity|
|
48
|
+
define_method :"#{action_name}_path" do |entity = nil, **wildcards|
|
49
49
|
path = resolve_base_path(original_path)
|
50
50
|
|
51
|
-
insert_wildcards(path, entity)
|
51
|
+
insert_wildcards(path, entity, **wildcards)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -75,10 +75,12 @@ module Cuprum::Rails
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
# @param base_path [String]
|
79
|
-
|
80
|
-
|
81
|
-
@
|
78
|
+
# @param base_path [String] the relative path of the resource.
|
79
|
+
# @param parent_path [String] the path to the parent resource, if any.
|
80
|
+
def initialize(base_path:, parent_path: nil, &block)
|
81
|
+
@base_path = base_path
|
82
|
+
@parent_path = parent_path
|
83
|
+
@wildcards = {}
|
82
84
|
|
83
85
|
singleton_class.instance_exec(&block) if block_given?
|
84
86
|
end
|
@@ -91,7 +93,9 @@ module Cuprum::Rails
|
|
91
93
|
|
92
94
|
# @return [String] the path to the parent resource index.
|
93
95
|
def parent_path
|
94
|
-
|
96
|
+
return '/' if @parent_path.nil?
|
97
|
+
|
98
|
+
insert_wildcards(@parent_path)
|
95
99
|
end
|
96
100
|
|
97
101
|
# @return [String] the root path for the application.
|
@@ -120,15 +124,15 @@ module Cuprum::Rails
|
|
120
124
|
|
121
125
|
private
|
122
126
|
|
123
|
-
def insert_wildcards(path,
|
127
|
+
def insert_wildcards(path, value_or_entity = nil, **wildcards)
|
128
|
+
wildcards = wildcards.merge('id' => value_or_entity) if value_or_entity
|
129
|
+
|
124
130
|
path
|
125
131
|
.split('/')
|
126
132
|
.map do |segment|
|
127
133
|
next segment unless segment.start_with?(':')
|
128
134
|
|
129
|
-
|
130
|
-
|
131
|
-
resolve_wildcard(segment)
|
135
|
+
resolve_wildcard(segment, **wildcards)
|
132
136
|
end
|
133
137
|
.join('/')
|
134
138
|
end
|
@@ -141,24 +145,33 @@ module Cuprum::Rails
|
|
141
145
|
"#{base_path}/#{path}"
|
142
146
|
end
|
143
147
|
|
144
|
-
def resolve_primary_key(
|
145
|
-
raise MissingWildcardError, 'missing wildcard :id' if
|
148
|
+
def resolve_primary_key(value_or_entity)
|
149
|
+
raise MissingWildcardError, 'missing wildcard :id' if value_or_entity.nil?
|
150
|
+
|
151
|
+
unless value_or_entity.class.respond_to?(:primary_key)
|
152
|
+
return value_or_entity
|
153
|
+
end
|
146
154
|
|
147
|
-
primary_key =
|
155
|
+
primary_key = value_or_entity.class.primary_key
|
148
156
|
|
149
|
-
|
157
|
+
value_or_entity[primary_key]
|
150
158
|
end
|
151
159
|
|
152
|
-
def resolve_wildcard(segment)
|
160
|
+
def resolve_wildcard(segment, **wildcards)
|
161
|
+
wildcards = self.wildcards.merge(wildcards)
|
162
|
+
value = wildcard_value(segment, **wildcards)
|
163
|
+
|
164
|
+
resolve_primary_key(value)
|
165
|
+
end
|
166
|
+
|
167
|
+
def wildcard_value(segment, **wildcards)
|
153
168
|
wildcard = segment[1..] # :something_id to something_id
|
154
169
|
|
155
|
-
return wildcards[wildcard] if wildcards.
|
170
|
+
return wildcards[wildcard] if wildcards.key?(wildcard)
|
156
171
|
|
157
172
|
wildcard = segment[1...-3] # :something_id to something
|
158
173
|
|
159
|
-
if wildcards.
|
160
|
-
return resolve_primary_key(wildcards[wildcard])
|
161
|
-
end
|
174
|
+
return wildcards[wildcard] if wildcards.key?(wildcard)
|
162
175
|
|
163
176
|
raise MissingWildcardError, "missing wildcard #{segment}"
|
164
177
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cuprum::Rails::RSpec
|
4
|
+
# Helper methods for defining RSpec contracts.
|
5
|
+
module ContractHelpers
|
6
|
+
class << self
|
7
|
+
# Resolves a configuration option.
|
8
|
+
#
|
9
|
+
# If the configured value is a Proc, the Proc is executed in the context
|
10
|
+
# of the example group and the resulting value returned. Otherwise,
|
11
|
+
# returns the configured value, or the given default if the configured
|
12
|
+
# value is nil.
|
13
|
+
#
|
14
|
+
# @param value [Object] The configured value for the option.
|
15
|
+
# @param context [RSpec::SleepingKingStudios::ExampleGroup] The example
|
16
|
+
# group used as a context if the configured value is a Proc.
|
17
|
+
# @param default [Object] An optional default value if the configured
|
18
|
+
# value is nil.
|
19
|
+
def option_with_default(value, context:, default: nil)
|
20
|
+
# :nocov:
|
21
|
+
case value
|
22
|
+
when Proc
|
23
|
+
return context.instance_exec(&value) if value.arity.zero?
|
24
|
+
|
25
|
+
context.instance_exec(default, &value)
|
26
|
+
when nil
|
27
|
+
default
|
28
|
+
else
|
29
|
+
value
|
30
|
+
end
|
31
|
+
# :nocov:
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Resolves a configuration option.
|
36
|
+
#
|
37
|
+
# If the configured value is a Proc, the Proc is executed in the context of
|
38
|
+
# the example group and the resulting value returned. Otherwise, returns the
|
39
|
+
# configured value, or the given default if the configured value is nil.
|
40
|
+
#
|
41
|
+
# @param value [Object] The configured value for the option.
|
42
|
+
# @param context [RSpec::SleepingKingStudios::ExampleGroup] The example
|
43
|
+
# group used as a context if the configured value is a Proc.
|
44
|
+
# @param default [Object] An optional default value if the configured value
|
45
|
+
# is nil.
|
46
|
+
def option_with_default(value, context: nil, default: nil)
|
47
|
+
# :nocov:
|
48
|
+
Cuprum::Rails::RSpec::ContractHelpers
|
49
|
+
.option_with_default(
|
50
|
+
value,
|
51
|
+
context: context || self,
|
52
|
+
default: default
|
53
|
+
)
|
54
|
+
# :nocov:
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|