nucleus-core 0.1.4 → 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/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
|
[](https://rubygems.org/gems/nucleus-core)
|
4
4
|
[](https://app.circleci.com/pipelines/github/dodgerogers/nucleus-core?branch=main)
|
5
5
|
[](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
|