nucleus-core 0.1.4 → 0.1.5
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 +8 -8
- data/lib/nucleus_core/extensions/utils.rb +88 -0
- data/lib/nucleus_core/policy.rb +1 -1
- data/lib/nucleus_core/responder.rb +10 -12
- data/lib/nucleus_core/response_adapter.rb +1 -1
- data/lib/nucleus_core/version.rb +1 -1
- data/lib/nucleus_core.rb +9 -8
- metadata +3 -4
- data/lib/nucleus_core/extensions/array.rb +0 -11
- data/lib/nucleus_core/extensions/rack.rb +0 -86
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16856ef31bb784d60c0245dc2b64688edffafedc629346e4b0aa5ad85c67f03b
|
4
|
+
data.tar.gz: 6132356105d16688ba22fcb6ab4827727584660867ffd07b37f2c559d6a365c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d77daf39dac0313f1fae986f124394e3f1af56fb1c0a8324a2054398d9c43715df25513a3cc568150ae5eed87bdabd8def043f6542fccce443334b2ee5fdc8b
|
7
|
+
data.tar.gz: 7a233128785f6359cd01c351c6fc3633de18af631ea022aa42e73e978c37a59fecab0eaa770d482257ee6c4042182555f94a3ecc3058819df769b2ec2a12bc25
|
data/README.md
CHANGED
@@ -4,18 +4,18 @@
|
|
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
|
-
NucleusCore Core is a
|
7
|
+
NucleusCore Core is a set of components which express and orchestrate business logic separatley to the framework.
|
8
8
|
|
9
|
-
## This gem is still very much in development.
|
9
|
+
## This gem is still very much in development. See `nucleus-rails` for Rails usage.
|
10
10
|
|
11
11
|
Here are the classes NucleusCore exposes, they have preordained responsibilities, can be composed together, and tested simply in isolation from the framework.
|
12
12
|
|
13
|
-
- Policy (Authorization) - Can this user perform this process?
|
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.
|
13
|
+
- **Policy (Authorization)** - Can this user perform this process?
|
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.
|
19
19
|
|
20
20
|
Below is an example using NucleusCore Core with Rails:
|
21
21
|
|
@@ -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
|
data/lib/nucleus_core/policy.rb
CHANGED
@@ -11,7 +11,7 @@ module NucleusCore
|
|
11
11
|
policy_methods.each do |policy_method_and_args|
|
12
12
|
next if send(*policy_method_and_args)
|
13
13
|
|
14
|
-
name =
|
14
|
+
name = Utils.wrap(policy_method_and_args).first
|
15
15
|
message = "You do not have access to: #{name}"
|
16
16
|
|
17
17
|
raise NucleusCore::NotAuthorized, message
|
@@ -10,12 +10,12 @@ module NucleusCore
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def set_request_format(request=nil)
|
13
|
-
@request_format = request&.to_sym ||
|
13
|
+
@request_format = request&.to_sym || NucleusCore.configuration.default_response_format
|
14
14
|
end
|
15
15
|
|
16
16
|
# rubocop:disable Naming/AccessorMethodName
|
17
17
|
def set_response_adapter(response_adapter)
|
18
|
-
@response_adapter = response_adapter
|
18
|
+
@response_adapter = response_adapter || NucleusCore.configuration.response_adapter
|
19
19
|
end
|
20
20
|
# rubocop:enable Naming/AccessorMethodName
|
21
21
|
|
@@ -101,18 +101,16 @@ module NucleusCore
|
|
101
101
|
|
102
102
|
# rubocop:disable Lint/DuplicateBranch
|
103
103
|
def exception_to_status(exception)
|
104
|
-
config = exception_map
|
105
|
-
|
106
104
|
case exception
|
107
|
-
when NucleusCore::NotFound, *
|
105
|
+
when NucleusCore::NotFound, *exceptions.not_found
|
108
106
|
:not_found
|
109
|
-
when NucleusCore::BadRequest, *
|
107
|
+
when NucleusCore::BadRequest, *exceptions.bad_request
|
110
108
|
:bad_request
|
111
|
-
when NucleusCore::NotAuthorized, *
|
109
|
+
when NucleusCore::NotAuthorized, *exceptions.forbidden
|
112
110
|
:forbidden
|
113
|
-
when NucleusCore::Unprocessable, *
|
111
|
+
when NucleusCore::Unprocessable, *exceptions.unprocessable
|
114
112
|
:unprocessable_entity
|
115
|
-
when NucleusCore::BaseException, *
|
113
|
+
when NucleusCore::BaseException, *exceptions.server_error
|
116
114
|
:internal_server_error
|
117
115
|
else
|
118
116
|
:internal_server_error
|
@@ -125,11 +123,11 @@ module NucleusCore
|
|
125
123
|
end
|
126
124
|
|
127
125
|
def logger(object, log_level=:info)
|
128
|
-
NucleusCore.configuration
|
126
|
+
NucleusCore.configuration&.logger&.send(log_level, object)
|
129
127
|
end
|
130
128
|
|
131
|
-
def
|
132
|
-
NucleusCore.configuration.
|
129
|
+
def exceptions
|
130
|
+
NucleusCore.configuration.exceptions
|
133
131
|
end
|
134
132
|
end
|
135
133
|
end
|
@@ -17,7 +17,7 @@ class NucleusCore::ResponseAdapter < NucleusCore::BasicObject
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def status_code(status=nil)
|
20
|
-
status =
|
20
|
+
status = Utils.status_code(status)
|
21
21
|
default_status = 200
|
22
22
|
|
23
23
|
status.zero? ? default_status : status
|
data/lib/nucleus_core/version.rb
CHANGED
data/lib/nucleus_core.rb
CHANGED
@@ -24,8 +24,8 @@ module NucleusCore
|
|
24
24
|
class BadRequest < BaseException; end
|
25
25
|
|
26
26
|
class Configuration
|
27
|
-
|
28
|
-
|
27
|
+
attr_accessor :response_adapter, :default_response_format, :logger
|
28
|
+
attr_reader :exceptions
|
29
29
|
|
30
30
|
RESPONSE_ADAPTER_METHODS = %i[
|
31
31
|
render_json render_xml render_text render_pdf render_csv render_nothing set_header
|
@@ -33,11 +33,12 @@ module NucleusCore
|
|
33
33
|
|
34
34
|
def initialize
|
35
35
|
@logger = nil
|
36
|
-
@
|
36
|
+
@exceptions = format_exceptions
|
37
|
+
@default_response_format = :json
|
37
38
|
end
|
38
39
|
|
39
|
-
def
|
40
|
-
@
|
40
|
+
def exceptions=(args={})
|
41
|
+
@exceptions = format_exceptions(args)
|
41
42
|
end
|
42
43
|
|
43
44
|
private
|
@@ -50,13 +51,13 @@ module NucleusCore
|
|
50
51
|
|
51
52
|
def format_exceptions(exceptions={})
|
52
53
|
exception_defaults = ERROR_STATUSES.reduce({}) { |acc, ex| acc.merge(ex => nil) }
|
53
|
-
|
54
|
+
exceptions = (exceptions || exception_defaults)
|
54
55
|
.slice(*exception_defaults.keys)
|
55
56
|
.reduce({}) do |acc, (key, value)|
|
56
|
-
acc.merge(key =>
|
57
|
+
acc.merge(key => Utils.wrap(value))
|
57
58
|
end
|
58
59
|
|
59
|
-
objectify(
|
60
|
+
objectify(exceptions)
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
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.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dodgerogers
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-02-
|
11
|
+
date: 2023-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -151,8 +151,7 @@ files:
|
|
151
151
|
- lib/nucleus_core/aggregate.rb
|
152
152
|
- lib/nucleus_core/basic_object.rb
|
153
153
|
- lib/nucleus_core/cli.rb
|
154
|
-
- lib/nucleus_core/extensions/
|
155
|
-
- lib/nucleus_core/extensions/rack.rb
|
154
|
+
- lib/nucleus_core/extensions/utils.rb
|
156
155
|
- lib/nucleus_core/operation.rb
|
157
156
|
- lib/nucleus_core/policy.rb
|
158
157
|
- lib/nucleus_core/repository.rb
|
@@ -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
|