nucleus-core 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +149 -110
- data/lib/nucleus_core/exceptions/bad_request.rb +3 -0
- data/lib/nucleus_core/exceptions/base.rb +1 -0
- data/lib/nucleus_core/exceptions/not_authorized.rb +3 -0
- data/lib/nucleus_core/exceptions/not_found.rb +3 -0
- data/lib/nucleus_core/exceptions/unprocessable.rb +3 -0
- data/lib/nucleus_core/extensions/utils.rb +88 -0
- data/lib/nucleus_core/request_adapter.rb +23 -0
- data/lib/nucleus_core/responder.rb +35 -52
- data/lib/nucleus_core/response_adapters/csv_response.rb +13 -0
- data/lib/nucleus_core/response_adapters/json_response.rb +9 -0
- data/lib/nucleus_core/response_adapters/no_response.rb +9 -0
- data/lib/nucleus_core/response_adapters/pdf_response.rb +13 -0
- data/lib/nucleus_core/response_adapters/response_adapter.rb +32 -0
- data/lib/nucleus_core/response_adapters/text_response.rb +9 -0
- data/lib/nucleus_core/response_adapters/xml_response.rb +9 -0
- data/lib/nucleus_core/{basic_object.rb → simple_object.rb} +8 -5
- data/lib/nucleus_core/version.rb +1 -1
- data/lib/nucleus_core/views/error_view.rb +2 -1
- data/lib/nucleus_core/views/view.rb +3 -1
- data/lib/nucleus_core.rb +22 -35
- metadata +28 -20
- data/lib/nucleus_core/aggregate.rb +0 -1
- data/lib/nucleus_core/extensions/array.rb +0 -11
- data/lib/nucleus_core/extensions/rack.rb +0 -86
- data/lib/nucleus_core/policy.rb +0 -21
- data/lib/nucleus_core/repository.rb +0 -6
- data/lib/nucleus_core/response_adapter.rb +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05f1cb3a1cdbe91b800911bb9f62b22496be36e29d620847f955ea52e823b166
|
4
|
+
data.tar.gz: 95d2d4eeab4797441ddff2473f29a61c37b49adbec2168599cd67e3ef3803502
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d8948f0e23f0724b396d3888a06cd515b36427b540e706330de247a12d713407d1b053bad5c49fe85bed7cbe49756cec28c20f62bd51273a39c25f30d4535ff
|
7
|
+
data.tar.gz: 8e6ea5ea9ca756d24c73c11186651687bb5eea6acc817f13c5c44e2b7a023684a290972ca71b209c3ad19ef2dcc49ad5bb5bb8333ba2cfe6251758cc4e956c2c
|
data/README.md
CHANGED
@@ -1,143 +1,170 @@
|
|
1
|
-
#
|
1
|
+
# Nucleus Core
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/nucleus-core.svg)](https://rubygems.org/gems/nucleus-core)
|
4
4
|
[![Circle](https://circleci.com/gh/dodgerogers/nucleus-core/tree/main.svg?style=shield)](https://app.circleci.com/pipelines/github/dodgerogers/nucleus-core?branch=main)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/dodgerogers/nucleus-core/badges/gpa.svg)](https://codeclimate.com/github/dodgerogers/nucleus-core)
|
6
6
|
|
7
|
-
|
7
|
+
- [Overview](#overview)
|
8
|
+
- [Components](#components)
|
9
|
+
- [Supported Frameworks](#supported-frameworks)
|
10
|
+
- [Quick start](#quick-start)
|
11
|
+
- [Best practices](#best-practices)
|
12
|
+
- [Support](#support)
|
13
|
+
- [License](#license)
|
14
|
+
- [Code of conduct](#code-of-conduct)
|
15
|
+
- [Contribution guide](#contribution-guide)
|
16
|
+
|
17
|
+
## Overview
|
18
|
+
|
19
|
+
Nucleus Core defines a boundary between your business logic, and a framework.
|
8
20
|
|
9
|
-
##
|
21
|
+
## Components
|
10
22
|
|
11
|
-
|
23
|
+
**Responder** - The boundary which passes request parameters to your business logic, then renders a response (requires framework request, and response adapaters).\
|
24
|
+
**Operations** - Service implementation that executes one side effect.\
|
25
|
+
**Workflows** - Service orchestration which composes complex, multi stage processes.\
|
26
|
+
**Views** - Presentation objects which render multiple formats.
|
12
27
|
|
13
|
-
|
14
|
-
- Operation (Services) - Executes a single unit of business logic, or side effect (ScheduleAppointment, CancelOrder, UpdateAddress).
|
15
|
-
- Workflow (Service Orchestration) - Excecutes multiple units of work, and side effects (ApproveLoan, TakePayment, CancelFulfillments).
|
16
|
-
- View (Presentation) - A presentation object which can render to multiple formats.
|
17
|
-
- Repository (Data access) - Interacts with data sources to hide the implementation details to callers, and return Aggregates. Data sources could be an API, ActiveRecord, SQL, a local file, etc.
|
18
|
-
- Aggregate (Domain/business Object) - Maps data from the data source to an object the aplication defines, known as an anti corruption layer.
|
28
|
+
## Supported Frameworks
|
19
29
|
|
20
|
-
|
30
|
+
These packages implement request, and response adapters for their respective framework.
|
31
|
+
|
32
|
+
- [nucleus-rails](https://rubygems.org/gems/nucleus-rails).
|
33
|
+
|
34
|
+
## Getting started
|
35
|
+
|
36
|
+
1. Install the gem
|
37
|
+
|
38
|
+
```
|
39
|
+
$ gem install nuclueus-core
|
40
|
+
```
|
41
|
+
|
42
|
+
2. Initialize, and configure `NucleusCore`
|
21
43
|
|
22
44
|
```ruby
|
23
|
-
|
24
|
-
class PaymentsController < ApplicationController
|
25
|
-
include NucleusCore::Responder
|
45
|
+
require "nucleus-core"
|
26
46
|
|
27
|
-
|
28
|
-
|
29
|
-
|
47
|
+
NucleusCore.configure do |config|
|
48
|
+
config.logger = Logger.new($stdout)
|
49
|
+
config.default_response_format = :json
|
50
|
+
config.exceptions = {
|
51
|
+
not_found: ActiveRecord::RecordNotFound,
|
52
|
+
unprocessible: [ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved],
|
53
|
+
bad_request: Apipie::ParamError,
|
54
|
+
unauthorized: Pundit::NotAuthorizedError
|
55
|
+
}
|
56
|
+
end
|
57
|
+
```
|
30
58
|
|
31
|
-
|
59
|
+
3. Create a class that implements the rendering methods below. Class, or instance methods can be used, make sure to initialize the responder accordingly.
|
32
60
|
|
33
|
-
|
61
|
+
```ruby
|
62
|
+
class ResponderAdapter
|
63
|
+
# entity: Nucleus::ResponseAdapter
|
34
64
|
|
35
|
-
|
36
|
-
end
|
65
|
+
def render_json(entity)
|
37
66
|
end
|
38
67
|
|
39
|
-
|
40
|
-
|
41
|
-
def policy
|
42
|
-
Policy.new(current_user)
|
68
|
+
def render_xml(entity)
|
43
69
|
end
|
44
70
|
|
45
|
-
def
|
46
|
-
params.slice(:cart_id)
|
71
|
+
def render_pdf(entity)
|
47
72
|
end
|
48
|
-
end
|
49
73
|
|
50
|
-
|
51
|
-
class HandleCheckoutWorkflow < NucleusCore::Workflow
|
52
|
-
def define
|
53
|
-
start_node(continue: :calculate_amount)
|
54
|
-
register_node(
|
55
|
-
state: :calculate_amount,
|
56
|
-
operation: FetchShoppingCart,
|
57
|
-
determine_signal: ->(context) { context.cart.total > 10 ? :discount : :pay },
|
58
|
-
signals: { discount: :apply_discount, pay: :take_payment }
|
59
|
-
)
|
60
|
-
register_node(
|
61
|
-
state: :apply_discount,
|
62
|
-
operation: ApplyDiscountToShoppingCart,
|
63
|
-
signals: { continue: :take_payment }
|
64
|
-
)
|
65
|
-
register_node(
|
66
|
-
state: :take_payment,
|
67
|
-
operation: ->(context) { context.paid = context.cart.paid },
|
68
|
-
determine_signal: ->(_) { :completed }
|
69
|
-
)
|
70
|
-
register_node(
|
71
|
-
state: :completed,
|
72
|
-
determine_signal: ->(_) { :wait }
|
73
|
-
)
|
74
|
+
def render_csv(entity)
|
74
75
|
end
|
75
|
-
end
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
def call
|
80
|
-
cart = ShoppingCartRepository.find(context.cart_id)
|
77
|
+
def render_text(entity)
|
78
|
+
end
|
81
79
|
|
82
|
-
|
83
|
-
rescue NucleusCore::NotFound => e
|
84
|
-
context.fail!(e.message, exception: e)
|
80
|
+
def render_nothing(entity)
|
85
81
|
end
|
86
82
|
end
|
83
|
+
```
|
87
84
|
|
88
|
-
|
89
|
-
class ShoppingCartRepository < NucleusCore::Repository
|
90
|
-
def self.find(cart_id)
|
91
|
-
cart = ShoppingCart.find(cart_id)
|
85
|
+
4. Create a class that implements `call` which returns a hash of request details. `format` and `parameters` are required, but there others can be returned.
|
92
86
|
|
93
|
-
|
94
|
-
|
95
|
-
|
87
|
+
```ruby
|
88
|
+
class RequestAdapter
|
89
|
+
def call(args={})
|
90
|
+
{ format: args[:format], parameters: args[:params], ...}
|
96
91
|
end
|
92
|
+
end
|
93
|
+
```
|
97
94
|
|
98
|
-
|
99
|
-
cart = find(cart_id, percentage=0.5)
|
95
|
+
4. Implement your business logic using Operations, and orchestrate more complex proceedures with Workflows.
|
100
96
|
|
101
|
-
|
97
|
+
`operations/fetch_order.rb`
|
102
98
|
|
103
|
-
|
99
|
+
```ruby
|
100
|
+
class Operations::FetchOrder < NucleusCore::Operation
|
101
|
+
def call
|
102
|
+
context.order = find_order(context.id)
|
104
103
|
rescue NucleusCore::NotFound => e
|
105
|
-
|
104
|
+
context.fail!(e.message, exception: e)
|
106
105
|
end
|
107
106
|
end
|
107
|
+
```
|
108
108
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
109
|
+
`operations/apply_order_discount.rb`
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
class Operations::ApplyOrderDiscount < NucleusCore::Operation
|
113
|
+
def call
|
114
|
+
discount = context.discount || 0.25
|
115
|
+
order = update_order(context.order, discount: discount)
|
113
116
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
super(id: cart.id, total: cart.total, paid: cart.paid, created_at: cart.created_at)
|
117
|
+
context.order = order
|
118
|
+
rescue NucleusCore::NotFound, NucleusCore::Unprocessable => e
|
119
|
+
context.fail!(e.message, exception: e)
|
118
120
|
end
|
119
121
|
end
|
122
|
+
```
|
120
123
|
|
121
|
-
|
122
|
-
class ApplyDiscountToShoppingCart < NucleusCore::Operation
|
123
|
-
def call
|
124
|
-
cart = ShoppingCartRepository.discount(context.cart_id, 0.75)
|
124
|
+
`workflows/fulfill_order.rb`
|
125
125
|
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
```ruby
|
127
|
+
class Workflows::FulfillOrder < NucleusCore::Workflow
|
128
|
+
def define
|
129
|
+
start_node(continue: :apply_discount?)
|
130
|
+
register_node(
|
131
|
+
state: :apply_discount?,
|
132
|
+
operation: Operations::FetchOrder,
|
133
|
+
determine_signal: ->(context) { context.order.total > 10 ? :discount : :pay },
|
134
|
+
signals: { discount: :discount_order, pay: :take_payment }
|
135
|
+
)
|
136
|
+
register_node(
|
137
|
+
state: :discount_order,
|
138
|
+
operation: Operations::ApplyOrderDiscount,
|
139
|
+
signals: { continue: :take_payment }
|
140
|
+
)
|
141
|
+
register_node(
|
142
|
+
state: :take_payment,
|
143
|
+
operation: ->(context) { context.paid = context.order.pay! },
|
144
|
+
signals: { continue: :completed }
|
145
|
+
)
|
146
|
+
register_node(
|
147
|
+
state: :completed,
|
148
|
+
determine_signal: ->(_) { :wait }
|
149
|
+
)
|
129
150
|
end
|
130
151
|
end
|
152
|
+
```
|
131
153
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
154
|
+
5. Define your view, and it's responses.
|
155
|
+
|
156
|
+
`views/order.rb`
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
class Views::Order < NucleusCore::View
|
160
|
+
def initialize(order)
|
161
|
+
super(id: order.id, price: "$#{order.total}", paid: order.paid, created_at: order.created_at)
|
136
162
|
end
|
137
163
|
|
138
164
|
def json_response
|
139
165
|
content = {
|
140
166
|
payment: {
|
167
|
+
id: id,
|
141
168
|
price: price,
|
142
169
|
paid: paid,
|
143
170
|
created_at: created_at,
|
@@ -149,38 +176,50 @@ class NucleusCore::PaymentView < NucleusCore::View
|
|
149
176
|
end
|
150
177
|
|
151
178
|
def pdf_response
|
152
|
-
|
179
|
+
pdf = generate_pdf(id, price, paid)
|
153
180
|
|
154
|
-
NucleusCore::PdfResponse.new(content:
|
155
|
-
end
|
156
|
-
|
157
|
-
private def generate_pdf_string(price, paid)
|
158
|
-
# pdf string genration...
|
181
|
+
NucleusCore::PdfResponse.new(content: pdf)
|
159
182
|
end
|
160
183
|
end
|
161
184
|
```
|
162
185
|
|
163
|
-
|
186
|
+
4. Initialize the responder with your adapters, then call your business logic, and return a view.
|
164
187
|
|
165
|
-
|
166
|
-
- [Support](#support)
|
167
|
-
- [License](#license)
|
168
|
-
- [Code of conduct](#code-of-conduct)
|
169
|
-
- [Contribution guide](#contribution-guide)
|
188
|
+
`controllers/orders_controller.rb`
|
170
189
|
|
171
|
-
|
190
|
+
```ruby
|
191
|
+
class OrdersController
|
192
|
+
before_action do
|
193
|
+
@responder = Nucleus::Responder.new(
|
194
|
+
response_adapter: ResponseAdapter.new,
|
195
|
+
request_adapter: RequestAdapter.new
|
196
|
+
)
|
172
197
|
|
173
|
-
|
174
|
-
|
175
|
-
|
198
|
+
@request = {
|
199
|
+
format: request.format,
|
200
|
+
parameters: request.params
|
201
|
+
}
|
202
|
+
end
|
176
203
|
|
177
|
-
|
178
|
-
|
204
|
+
def create
|
205
|
+
@responder.execute(@request) do |req|
|
206
|
+
context, _process = Workflows::FulfillOrder.call(context: req.parameters)
|
207
|
+
|
208
|
+
return Views::Order.new(order: context.order) if context.success?
|
209
|
+
|
210
|
+
return context
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
179
214
|
```
|
180
215
|
|
216
|
+
5. Then tell us about it!
|
217
|
+
|
218
|
+
---
|
219
|
+
|
181
220
|
## Support
|
182
221
|
|
183
|
-
If you want to report a bug, or have ideas, feedback or questions about the gem, [let me know via GitHub issues](https://github.com/dodgerogers/nucleus_core/issues/new) and
|
222
|
+
If you want to report a bug, or have ideas, feedback or questions about the gem, [let me know via GitHub issues](https://github.com/dodgerogers/nucleus_core/issues/new) and we will do our best to provide a helpful answer.
|
184
223
|
|
185
224
|
## License
|
186
225
|
|
@@ -0,0 +1 @@
|
|
1
|
+
class NucleusCore::BaseException < StandardError; end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Rack::Utils patch for status code
|
2
|
+
class Utils
|
3
|
+
HTTP_STATUS_CODES = {
|
4
|
+
100 => "Continue",
|
5
|
+
101 => "Switching Protocols",
|
6
|
+
102 => "Processing",
|
7
|
+
103 => "Early Hints",
|
8
|
+
200 => "OK",
|
9
|
+
201 => "Created",
|
10
|
+
202 => "Accepted",
|
11
|
+
203 => "Non-Authoritative Information",
|
12
|
+
204 => "No Content",
|
13
|
+
205 => "Reset Content",
|
14
|
+
206 => "Partial Content",
|
15
|
+
207 => "Multi-Status",
|
16
|
+
208 => "Already Reported",
|
17
|
+
226 => "IM Used",
|
18
|
+
300 => "Multiple Choices",
|
19
|
+
301 => "Moved Permanently",
|
20
|
+
302 => "Found",
|
21
|
+
303 => "See Other",
|
22
|
+
304 => "Not Modified",
|
23
|
+
305 => "Use Proxy",
|
24
|
+
306 => "(Unused)",
|
25
|
+
307 => "Temporary Redirect",
|
26
|
+
308 => "Permanent Redirect",
|
27
|
+
400 => "Bad Request",
|
28
|
+
401 => "Unauthorized",
|
29
|
+
402 => "Payment Required",
|
30
|
+
403 => "Forbidden",
|
31
|
+
404 => "Not Found",
|
32
|
+
405 => "Method Not Allowed",
|
33
|
+
406 => "Not Acceptable",
|
34
|
+
407 => "Proxy Authentication Required",
|
35
|
+
408 => "Request Timeout",
|
36
|
+
409 => "Conflict",
|
37
|
+
410 => "Gone",
|
38
|
+
411 => "Length Required",
|
39
|
+
412 => "Precondition Failed",
|
40
|
+
413 => "Payload Too Large",
|
41
|
+
414 => "URI Too Long",
|
42
|
+
415 => "Unsupported Media Type",
|
43
|
+
416 => "Range Not Satisfiable",
|
44
|
+
417 => "Expectation Failed",
|
45
|
+
421 => "Misdirected Request",
|
46
|
+
422 => "Unprocessable Entity",
|
47
|
+
423 => "Locked",
|
48
|
+
424 => "Failed Dependency",
|
49
|
+
425 => "Too Early",
|
50
|
+
426 => "Upgrade Required",
|
51
|
+
428 => "Precondition Required",
|
52
|
+
429 => "Too Many Requests",
|
53
|
+
431 => "Request Header Fields Too Large",
|
54
|
+
451 => "Unavailable for Legal Reasons",
|
55
|
+
500 => "Internal Server Error",
|
56
|
+
501 => "Not Implemented",
|
57
|
+
502 => "Bad Gateway",
|
58
|
+
503 => "Service Unavailable",
|
59
|
+
504 => "Gateway Timeout",
|
60
|
+
505 => "HTTP Version Not Supported",
|
61
|
+
506 => "Variant Also Negotiates",
|
62
|
+
507 => "Insufficient Storage",
|
63
|
+
508 => "Loop Detected",
|
64
|
+
509 => "Bandwidth Limit Exceeded",
|
65
|
+
510 => "Not Extended",
|
66
|
+
511 => "Network Authentication Required"
|
67
|
+
}.freeze
|
68
|
+
|
69
|
+
SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map do |code, message|
|
70
|
+
[message.downcase.gsub(/\s|-|'/, "_").to_sym, code]
|
71
|
+
end.flatten]
|
72
|
+
|
73
|
+
def self.status_code(status)
|
74
|
+
if status.is_a?(Symbol)
|
75
|
+
return SYMBOL_TO_STATUS_CODE.fetch(status) do
|
76
|
+
raise ArgumentError, "Unrecognized status code #{status.inspect}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
status.to_i
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.wrap(object)
|
84
|
+
return [] if object.nil?
|
85
|
+
|
86
|
+
object.is_a?(Array) ? object : [object]
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "nucleus_core/simple_object"
|
2
|
+
|
3
|
+
module NucleusCore
|
4
|
+
class RequestAdapter < NucleusCore::SimpleObject
|
5
|
+
def initialize(attrs=nil)
|
6
|
+
attrs ||= {}
|
7
|
+
attributes = defaults
|
8
|
+
.merge(attrs)
|
9
|
+
.slice(*defaults.keys)
|
10
|
+
|
11
|
+
super(attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def defaults
|
17
|
+
{
|
18
|
+
format: NucleusCore.configuration.default_response_format,
|
19
|
+
parameters: {}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,27 +1,22 @@
|
|
1
1
|
require "set"
|
2
2
|
|
3
3
|
module NucleusCore
|
4
|
-
|
5
|
-
|
4
|
+
class Responder
|
5
|
+
attr_accessor :response_adapter, :request_adapter, :request_context
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
set_response_adapter(response_adapter)
|
10
|
-
end
|
11
|
-
|
12
|
-
def set_request_format(request=nil)
|
13
|
-
@request_format = request&.to_sym || :json
|
14
|
-
end
|
15
|
-
|
16
|
-
# rubocop:disable Naming/AccessorMethodName
|
17
|
-
def set_response_adapter(response_adapter)
|
7
|
+
def initialize(request_adapter: nil, response_adapter: nil)
|
8
|
+
@request_adapter = request_adapter
|
18
9
|
@response_adapter = response_adapter
|
10
|
+
@request_context = nil
|
19
11
|
end
|
20
|
-
# rubocop:enable Naming/AccessorMethodName
|
21
12
|
|
22
13
|
# rubocop:disable Lint/RescueException:
|
23
|
-
def
|
24
|
-
|
14
|
+
def execute(raw_request_context=nil, &block)
|
15
|
+
return if block.nil?
|
16
|
+
|
17
|
+
request_context_attrs = request_adapter&.call(raw_request_context) || {}
|
18
|
+
@request_context = NucleusCore::RequestAdapter.new(request_context_attrs)
|
19
|
+
entity = execute_block(@request_context, &block)
|
25
20
|
|
26
21
|
render_entity(entity)
|
27
22
|
rescue Exception => e
|
@@ -29,49 +24,36 @@ module NucleusCore
|
|
29
24
|
end
|
30
25
|
# rubocop:enable Lint/RescueException:
|
31
26
|
|
32
|
-
def handle_exception(exception)
|
33
|
-
logger(exception)
|
34
|
-
|
35
|
-
status = exception_to_status(exception)
|
36
|
-
attrs = { message: exception.message, status: status }
|
37
|
-
error = NucleusCore::ErrorView.new(attrs)
|
38
|
-
|
39
|
-
render_entity(error)
|
40
|
-
end
|
41
|
-
|
42
27
|
# Calling `return` in a block/proc returns from the outer calling scope as well.
|
43
28
|
# Lambdas do not have this limitation. So we convert the proc returned
|
44
29
|
# from a block method into a lambda to avoid 'return' exiting the method early.
|
45
30
|
# https://stackoverflow.com/questions/2946603/ruby-convert-proc-to-lambda
|
46
|
-
def
|
31
|
+
def execute_block(request, &block)
|
47
32
|
define_singleton_method(:_proc_to_lambda_, &block)
|
48
33
|
|
49
|
-
method(:_proc_to_lambda_).to_proc.call
|
34
|
+
method(:_proc_to_lambda_).to_proc.call(request)
|
50
35
|
end
|
51
36
|
|
52
37
|
def render_entity(entity)
|
53
38
|
return handle_context(entity) if entity.is_a?(NucleusCore::Operation::Context)
|
54
|
-
return render_response(entity) if subclass_of(entity, NucleusCore::ResponseAdapter)
|
55
39
|
return render_view(entity) if subclass_of(entity, NucleusCore::View)
|
40
|
+
return render_response(entity) if subclass_of(entity, NucleusCore::ResponseAdapter)
|
56
41
|
end
|
57
42
|
|
58
43
|
def handle_context(context)
|
59
44
|
return render_nothing(context) if context.success?
|
60
45
|
return handle_exception(context.exception) if context.exception
|
61
46
|
|
62
|
-
|
63
|
-
attrs = { message: message, status: :unprocessable_entity }
|
64
|
-
error_view = NucleusCore::ErrorView.new(attrs)
|
47
|
+
view = NucleusCore::ErrorView.new(message: context.message, status: :unprocessable_entity)
|
65
48
|
|
66
|
-
render_view(
|
49
|
+
render_view(view)
|
67
50
|
end
|
68
51
|
|
69
52
|
def render_view(view)
|
70
|
-
|
71
|
-
|
72
|
-
format_response = view.send(format_rendering) if renders_format
|
53
|
+
render_to_format = "#{request_context.format}_response".to_sym
|
54
|
+
format_response = view.send(render_to_format) if view.respond_to?(render_to_format)
|
73
55
|
|
74
|
-
raise NucleusCore::BadRequest, "
|
56
|
+
raise NucleusCore::BadRequest, "`#{request_context.format}` is not supported" if format_response.nil?
|
75
57
|
|
76
58
|
render_response(format_response)
|
77
59
|
end
|
@@ -79,7 +61,7 @@ module NucleusCore
|
|
79
61
|
def render_response(entity)
|
80
62
|
render_headers(entity.headers)
|
81
63
|
|
82
|
-
|
64
|
+
render_method = {
|
83
65
|
NucleusCore::JsonResponse => :render_json,
|
84
66
|
NucleusCore::XmlResponse => :render_xml,
|
85
67
|
NucleusCore::PdfResponse => :render_pdf,
|
@@ -88,7 +70,16 @@ module NucleusCore
|
|
88
70
|
NucleusCore::NoResponse => :render_nothing
|
89
71
|
}.fetch(entity.class, nil)
|
90
72
|
|
91
|
-
response_adapter&.send(
|
73
|
+
response_adapter&.send(render_method, entity)
|
74
|
+
end
|
75
|
+
|
76
|
+
def handle_exception(exception)
|
77
|
+
logger(exception)
|
78
|
+
|
79
|
+
status = exception_to_status(exception)
|
80
|
+
view = NucleusCore::ErrorView.new(message: exception.message, status: status)
|
81
|
+
|
82
|
+
render_view(view)
|
92
83
|
end
|
93
84
|
|
94
85
|
def render_headers(headers={})
|
@@ -99,26 +90,22 @@ module NucleusCore
|
|
99
90
|
end
|
100
91
|
end
|
101
92
|
|
102
|
-
# rubocop:disable Lint/DuplicateBranch
|
103
93
|
def exception_to_status(exception)
|
104
|
-
|
94
|
+
exceptions = NucleusCore.configuration.exceptions
|
105
95
|
|
106
96
|
case exception
|
107
|
-
when NucleusCore::NotFound, *
|
97
|
+
when NucleusCore::NotFound, *exceptions.not_found
|
108
98
|
:not_found
|
109
|
-
when NucleusCore::BadRequest, *
|
99
|
+
when NucleusCore::BadRequest, *exceptions.bad_request
|
110
100
|
:bad_request
|
111
|
-
when NucleusCore::NotAuthorized, *
|
101
|
+
when NucleusCore::NotAuthorized, *exceptions.forbidden
|
112
102
|
:forbidden
|
113
|
-
when NucleusCore::Unprocessable, *
|
103
|
+
when NucleusCore::Unprocessable, *exceptions.unprocessable
|
114
104
|
:unprocessable_entity
|
115
|
-
when NucleusCore::BaseException, *config.server_error
|
116
|
-
:internal_server_error
|
117
105
|
else
|
118
106
|
:internal_server_error
|
119
107
|
end
|
120
108
|
end
|
121
|
-
# rubocop:enable Lint/DuplicateBranch
|
122
109
|
|
123
110
|
def subclass_of(entity, *classes)
|
124
111
|
Set[*entity.class.ancestors].intersect?(classes.to_set)
|
@@ -127,9 +114,5 @@ module NucleusCore
|
|
127
114
|
def logger(object, log_level=:info)
|
128
115
|
NucleusCore.configuration.logger&.send(log_level, object)
|
129
116
|
end
|
130
|
-
|
131
|
-
def exception_map
|
132
|
-
NucleusCore.configuration.exceptions_map
|
133
|
-
end
|
134
117
|
end
|
135
118
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "nucleus_core/response_adapters/response_adapter"
|
2
|
+
|
3
|
+
class NucleusCore::CsvResponse < NucleusCore::ResponseAdapter
|
4
|
+
def initialize(attrs={})
|
5
|
+
attrs = attrs.merge(
|
6
|
+
disposition: "attachment",
|
7
|
+
filename: attrs.fetch(:filename) { "response.csv" },
|
8
|
+
type: "text/csv; charset=UTF-8;"
|
9
|
+
)
|
10
|
+
|
11
|
+
super(attrs)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "nucleus_core/response_adapters/response_adapter"
|
2
|
+
|
3
|
+
class NucleusCore::PdfResponse < NucleusCore::ResponseAdapter
|
4
|
+
def initialize(attrs={})
|
5
|
+
attrs = attrs.merge(
|
6
|
+
disposition: "inline",
|
7
|
+
filename: attrs.fetch(:filename) { "response.pdf" },
|
8
|
+
type: "application/pdf"
|
9
|
+
)
|
10
|
+
|
11
|
+
super(attrs)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "nucleus_core/simple_object"
|
2
|
+
|
3
|
+
class NucleusCore::ResponseAdapter < NucleusCore::SimpleObject
|
4
|
+
def initialize(attrs={})
|
5
|
+
attributes = defaults
|
6
|
+
.merge(attrs)
|
7
|
+
.slice(*defaults.keys)
|
8
|
+
.tap do |hash|
|
9
|
+
hash[:status] = status_code(hash[:status])
|
10
|
+
end
|
11
|
+
|
12
|
+
super(attributes)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def defaults
|
18
|
+
{
|
19
|
+
content: nil,
|
20
|
+
headers: nil,
|
21
|
+
status: nil,
|
22
|
+
location: nil
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def status_code(status=nil)
|
27
|
+
status = Utils.status_code(status)
|
28
|
+
default_status = 200
|
29
|
+
|
30
|
+
status.zero? ? default_status : status
|
31
|
+
end
|
32
|
+
end
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module NucleusCore
|
2
|
-
class
|
2
|
+
class SimpleObject
|
3
|
+
attr_reader :__attributes__
|
4
|
+
|
3
5
|
def initialize(attrs={})
|
6
|
+
@__attributes__ = {}
|
7
|
+
|
4
8
|
attrs.each_pair do |key, value|
|
5
9
|
define_singleton_method(key.to_s) do
|
6
10
|
instance_variable_get("@#{key}")
|
@@ -8,17 +12,16 @@ module NucleusCore
|
|
8
12
|
|
9
13
|
define_singleton_method("#{key}=") do |val|
|
10
14
|
instance_variable_set("@#{key}", val)
|
15
|
+
@__attributes__[key] = val
|
11
16
|
end
|
12
17
|
|
13
18
|
instance_variable_set("@#{key}", value)
|
19
|
+
@__attributes__[key] = value
|
14
20
|
end
|
15
21
|
end
|
16
22
|
|
17
23
|
def to_h
|
18
|
-
|
19
|
-
.reduce({}) do |acc, var|
|
20
|
-
acc.merge(var.to_s.delete("@") => instance_variable_get(var))
|
21
|
-
end
|
24
|
+
__attributes__
|
22
25
|
end
|
23
26
|
end
|
24
27
|
end
|
data/lib/nucleus_core/version.rb
CHANGED
data/lib/nucleus_core.rb
CHANGED
@@ -2,61 +2,48 @@ require "ostruct"
|
|
2
2
|
require "json"
|
3
3
|
require "set"
|
4
4
|
|
5
|
-
|
5
|
+
extensions = File.join(__dir__, "nucleus_core", "extensions", "*.rb")
|
6
|
+
exceptions = File.join(__dir__, "nucleus_core", "exceptions", "*.rb")
|
7
|
+
views = File.join(__dir__, "nucleus_core", "views", "*.rb")
|
8
|
+
response_adapters = File.join(__dir__, "nucleus_core", "response_adapters", "*.rb")
|
9
|
+
[extensions, exceptions, views, response_adapters].each do |dir|
|
10
|
+
Dir[dir].sort.each { |f| require f }
|
11
|
+
end
|
6
12
|
|
7
13
|
module NucleusCore
|
8
14
|
autoload :CLI, "nucleus_core/cli"
|
9
15
|
autoload :VERSION, "nucleus_core/version"
|
10
|
-
autoload :BasicObject, "nucleus_core/basic_object"
|
11
|
-
autoload :View, "nucleus_core/views/view"
|
12
|
-
autoload :ErrorView, "nucleus_core/views/error_view"
|
13
|
-
autoload :ResponseAdapter, "nucleus_core/response_adapter"
|
14
|
-
autoload :Aggregate, "nucleus_core/aggregate"
|
15
|
-
autoload :Policy, "nucleus_core/policy"
|
16
16
|
autoload :Operation, "nucleus_core/operation"
|
17
17
|
autoload :Workflow, "nucleus_core/workflow"
|
18
18
|
autoload :Responder, "nucleus_core/responder"
|
19
|
-
|
20
|
-
|
21
|
-
class NotAuthorized < BaseException; end
|
22
|
-
class NotFound < BaseException; end
|
23
|
-
class Unprocessable < BaseException; end
|
24
|
-
class BadRequest < BaseException; end
|
19
|
+
autoload :RequestAdapter, "nucleus_core/request_adapter"
|
20
|
+
autoload :SimpleObject, "nucleus_core/basic_object"
|
25
21
|
|
26
22
|
class Configuration
|
27
|
-
|
28
|
-
|
23
|
+
attr_accessor :default_response_format, :logger
|
24
|
+
attr_reader :exceptions
|
29
25
|
|
30
|
-
|
31
|
-
render_json render_xml render_text render_pdf render_csv render_nothing set_header
|
32
|
-
].freeze
|
26
|
+
ERROR_STATUSES = %i[not_found bad_request unauthorized unprocessable].freeze
|
33
27
|
|
34
28
|
def initialize
|
35
29
|
@logger = nil
|
36
|
-
@
|
30
|
+
@exceptions = format_exceptions
|
31
|
+
@default_response_format = :json
|
37
32
|
end
|
38
33
|
|
39
|
-
def
|
40
|
-
@
|
34
|
+
def exceptions=(args={})
|
35
|
+
@exceptions = format_exceptions(args)
|
41
36
|
end
|
42
37
|
|
43
38
|
private
|
44
39
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
def format_exceptions(exceptions={})
|
52
|
-
exception_defaults = ERROR_STATUSES.reduce({}) { |acc, ex| acc.merge(ex => nil) }
|
53
|
-
exceptions_map = (exceptions || exception_defaults)
|
54
|
-
.slice(*exception_defaults.keys)
|
55
|
-
.reduce({}) do |acc, (key, value)|
|
56
|
-
acc.merge(key => Array.wrap(value))
|
57
|
-
end
|
40
|
+
def format_exceptions(args={})
|
41
|
+
exceptions = ERROR_STATUSES
|
42
|
+
.reduce({}) { |acc, name| acc.merge(name => nil) }
|
43
|
+
.merge(args)
|
44
|
+
.transform_values { |values| Utils.wrap(values) }
|
58
45
|
|
59
|
-
|
46
|
+
OpenStruct.new(exceptions)
|
60
47
|
end
|
61
48
|
end
|
62
49
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nucleus-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dodgerogers
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-02-
|
11
|
+
date: 2023-02-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -70,16 +70,16 @@ dependencies:
|
|
70
70
|
name: rubocop
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 1.
|
75
|
+
version: 1.45.1
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 1.
|
82
|
+
version: 1.45.1
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rubocop-minitest
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,14 +114,14 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - '='
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 1.
|
117
|
+
version: 1.16.0
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - '='
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 1.
|
124
|
+
version: 1.16.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: rubocop-rake
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,7 +136,7 @@ dependencies:
|
|
136
136
|
- - '='
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.6.0
|
139
|
-
description:
|
139
|
+
description:
|
140
140
|
email:
|
141
141
|
- dodgerogers@hotmail.com
|
142
142
|
executables:
|
@@ -148,16 +148,24 @@ files:
|
|
148
148
|
- README.md
|
149
149
|
- exe/nucleus
|
150
150
|
- lib/nucleus_core.rb
|
151
|
-
- lib/nucleus_core/aggregate.rb
|
152
|
-
- lib/nucleus_core/basic_object.rb
|
153
151
|
- lib/nucleus_core/cli.rb
|
154
|
-
- lib/nucleus_core/
|
155
|
-
- lib/nucleus_core/
|
152
|
+
- lib/nucleus_core/exceptions/bad_request.rb
|
153
|
+
- lib/nucleus_core/exceptions/base.rb
|
154
|
+
- lib/nucleus_core/exceptions/not_authorized.rb
|
155
|
+
- lib/nucleus_core/exceptions/not_found.rb
|
156
|
+
- lib/nucleus_core/exceptions/unprocessable.rb
|
157
|
+
- lib/nucleus_core/extensions/utils.rb
|
156
158
|
- lib/nucleus_core/operation.rb
|
157
|
-
- lib/nucleus_core/
|
158
|
-
- lib/nucleus_core/repository.rb
|
159
|
+
- lib/nucleus_core/request_adapter.rb
|
159
160
|
- lib/nucleus_core/responder.rb
|
160
|
-
- lib/nucleus_core/
|
161
|
+
- lib/nucleus_core/response_adapters/csv_response.rb
|
162
|
+
- lib/nucleus_core/response_adapters/json_response.rb
|
163
|
+
- lib/nucleus_core/response_adapters/no_response.rb
|
164
|
+
- lib/nucleus_core/response_adapters/pdf_response.rb
|
165
|
+
- lib/nucleus_core/response_adapters/response_adapter.rb
|
166
|
+
- lib/nucleus_core/response_adapters/text_response.rb
|
167
|
+
- lib/nucleus_core/response_adapters/xml_response.rb
|
168
|
+
- lib/nucleus_core/simple_object.rb
|
161
169
|
- lib/nucleus_core/version.rb
|
162
170
|
- lib/nucleus_core/views/error_view.rb
|
163
171
|
- lib/nucleus_core/views/view.rb
|
@@ -171,7 +179,7 @@ metadata:
|
|
171
179
|
source_code_uri: https://github.com/dodgerogers/nucleus-core
|
172
180
|
homepage_uri: https://github.com/dodgerogers/nucleus-core
|
173
181
|
rubygems_mfa_required: 'true'
|
174
|
-
post_install_message:
|
182
|
+
post_install_message:
|
175
183
|
rdoc_options: []
|
176
184
|
require_paths:
|
177
185
|
- lib
|
@@ -186,8 +194,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
194
|
- !ruby/object:Gem::Version
|
187
195
|
version: '0'
|
188
196
|
requirements: []
|
189
|
-
rubygems_version: 3.
|
190
|
-
signing_key:
|
197
|
+
rubygems_version: 3.0.3.1
|
198
|
+
signing_key:
|
191
199
|
specification_version: 4
|
192
200
|
summary: A Ruby business logic framework
|
193
201
|
test_files: []
|
@@ -1 +0,0 @@
|
|
1
|
-
class NucleusCore::Aggregate < NucleusCore::BasicObject; end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
# Rack::Utils patch for status code
|
2
|
-
module NucleusCore
|
3
|
-
module Rack
|
4
|
-
class Utils
|
5
|
-
HTTP_STATUS_CODES = {
|
6
|
-
100 => "Continue",
|
7
|
-
101 => "Switching Protocols",
|
8
|
-
102 => "Processing",
|
9
|
-
103 => "Early Hints",
|
10
|
-
200 => "OK",
|
11
|
-
201 => "Created",
|
12
|
-
202 => "Accepted",
|
13
|
-
203 => "Non-Authoritative Information",
|
14
|
-
204 => "No Content",
|
15
|
-
205 => "Reset Content",
|
16
|
-
206 => "Partial Content",
|
17
|
-
207 => "Multi-Status",
|
18
|
-
208 => "Already Reported",
|
19
|
-
226 => "IM Used",
|
20
|
-
300 => "Multiple Choices",
|
21
|
-
301 => "Moved Permanently",
|
22
|
-
302 => "Found",
|
23
|
-
303 => "See Other",
|
24
|
-
304 => "Not Modified",
|
25
|
-
305 => "Use Proxy",
|
26
|
-
306 => "(Unused)",
|
27
|
-
307 => "Temporary Redirect",
|
28
|
-
308 => "Permanent Redirect",
|
29
|
-
400 => "Bad Request",
|
30
|
-
401 => "Unauthorized",
|
31
|
-
402 => "Payment Required",
|
32
|
-
403 => "Forbidden",
|
33
|
-
404 => "Not Found",
|
34
|
-
405 => "Method Not Allowed",
|
35
|
-
406 => "Not Acceptable",
|
36
|
-
407 => "Proxy Authentication Required",
|
37
|
-
408 => "Request Timeout",
|
38
|
-
409 => "Conflict",
|
39
|
-
410 => "Gone",
|
40
|
-
411 => "Length Required",
|
41
|
-
412 => "Precondition Failed",
|
42
|
-
413 => "Payload Too Large",
|
43
|
-
414 => "URI Too Long",
|
44
|
-
415 => "Unsupported Media Type",
|
45
|
-
416 => "Range Not Satisfiable",
|
46
|
-
417 => "Expectation Failed",
|
47
|
-
421 => "Misdirected Request",
|
48
|
-
422 => "Unprocessable Entity",
|
49
|
-
423 => "Locked",
|
50
|
-
424 => "Failed Dependency",
|
51
|
-
425 => "Too Early",
|
52
|
-
426 => "Upgrade Required",
|
53
|
-
428 => "Precondition Required",
|
54
|
-
429 => "Too Many Requests",
|
55
|
-
431 => "Request Header Fields Too Large",
|
56
|
-
451 => "Unavailable for Legal Reasons",
|
57
|
-
500 => "Internal Server Error",
|
58
|
-
501 => "Not Implemented",
|
59
|
-
502 => "Bad Gateway",
|
60
|
-
503 => "Service Unavailable",
|
61
|
-
504 => "Gateway Timeout",
|
62
|
-
505 => "HTTP Version Not Supported",
|
63
|
-
506 => "Variant Also Negotiates",
|
64
|
-
507 => "Insufficient Storage",
|
65
|
-
508 => "Loop Detected",
|
66
|
-
509 => "Bandwidth Limit Exceeded",
|
67
|
-
510 => "Not Extended",
|
68
|
-
511 => "Network Authentication Required"
|
69
|
-
}.freeze
|
70
|
-
|
71
|
-
SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map do |code, message|
|
72
|
-
[message.downcase.gsub(/\s|-|'/, "_").to_sym, code]
|
73
|
-
end.flatten]
|
74
|
-
|
75
|
-
def self.status_code(status)
|
76
|
-
if status.is_a?(Symbol)
|
77
|
-
return SYMBOL_TO_STATUS_CODE.fetch(status) do
|
78
|
-
raise ArgumentError, "Unrecognized status code #{status.inspect}"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
status.to_i
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
data/lib/nucleus_core/policy.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module NucleusCore
|
2
|
-
class Policy
|
3
|
-
attr_reader :user, :record
|
4
|
-
|
5
|
-
def initialize(user, record=nil)
|
6
|
-
@user = user
|
7
|
-
@record = record
|
8
|
-
end
|
9
|
-
|
10
|
-
def enforce!(*policy_methods)
|
11
|
-
policy_methods.each do |policy_method_and_args|
|
12
|
-
next if send(*policy_method_and_args)
|
13
|
-
|
14
|
-
name = Array.wrap(policy_method_and_args).first
|
15
|
-
message = "You do not have access to: #{name}"
|
16
|
-
|
17
|
-
raise NucleusCore::NotAuthorized, message
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
class NucleusCore::ResponseAdapter < NucleusCore::BasicObject
|
2
|
-
def initialize(attrs={})
|
3
|
-
attributes = defaults
|
4
|
-
.merge(attrs)
|
5
|
-
.slice(*defaults.keys)
|
6
|
-
.tap do |hash|
|
7
|
-
hash[:status] = status_code(hash[:status])
|
8
|
-
end
|
9
|
-
|
10
|
-
super(attributes)
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def defaults
|
16
|
-
{ content: "", headers: {}, status: 200, location: nil }
|
17
|
-
end
|
18
|
-
|
19
|
-
def status_code(status=nil)
|
20
|
-
status = NucleusCore::Rack::Utils.status_code(status)
|
21
|
-
default_status = 200
|
22
|
-
|
23
|
-
status.zero? ? default_status : status
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class NucleusCore::NoResponse < NucleusCore::ResponseAdapter
|
28
|
-
def initialize(attrs={})
|
29
|
-
attrs = attrs.merge(content: nil, type: "text/html; charset=utf-8")
|
30
|
-
|
31
|
-
super(attrs)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class NucleusCore::TextResponse < NucleusCore::ResponseAdapter
|
36
|
-
def initialize(attrs={})
|
37
|
-
attrs = attrs.merge(type: "application/text")
|
38
|
-
|
39
|
-
super(attrs)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
class NucleusCore::JsonResponse < NucleusCore::ResponseAdapter
|
44
|
-
def initialize(attrs={})
|
45
|
-
attrs = attrs.merge(type: "application/json")
|
46
|
-
|
47
|
-
super(attrs)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
class NucleusCore::XmlResponse < NucleusCore::ResponseAdapter
|
52
|
-
def initialize(attrs={})
|
53
|
-
attrs = attrs.merge(type: "application/xml")
|
54
|
-
|
55
|
-
super(attrs)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
class NucleusCore::CsvResponse < NucleusCore::ResponseAdapter
|
60
|
-
def initialize(attrs={})
|
61
|
-
attrs = attrs.merge(
|
62
|
-
disposition: "attachment",
|
63
|
-
filename: attrs.fetch(:filename) { "response.csv" },
|
64
|
-
type: "text/csv; charset=UTF-8;"
|
65
|
-
)
|
66
|
-
|
67
|
-
super(attrs)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
class NucleusCore::PdfResponse < NucleusCore::ResponseAdapter
|
72
|
-
def initialize(attrs={})
|
73
|
-
attrs = attrs.merge(
|
74
|
-
disposition: "inline",
|
75
|
-
filename: attrs.fetch(:filename) { "response.pdf" },
|
76
|
-
type: "application/pdf"
|
77
|
-
)
|
78
|
-
|
79
|
-
super(attrs)
|
80
|
-
end
|
81
|
-
end
|