clean-architecture 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9c12933e54f79e602a9aa26cc2f959e1ce7decd0
4
- data.tar.gz: bf30e8c044d46f04e02028b53375b492af95b033
3
+ metadata.gz: 5c49173a8914ea9260202535efe792a4a678619d
4
+ data.tar.gz: 508d35b34541f7b631cf1ea8fd994b4b20e08927
5
5
  SHA512:
6
- metadata.gz: 638aeb1b5ab5435392e652472aec5ffc05d3055bc0a3d2862c2e222ffa676be53729fdd48c0589a7e3b376b6c4245f723f45e31519ac4cea2a17d47c96c2922d
7
- data.tar.gz: b6c3a7b94a70c92b38833c2d5de6f11f728042382da0fcbc67ea7a53ace3c69a79611ba3a3c0879b0c404a56078203bbf3c2cfdbeb8d0f93c7501367af00f350
6
+ metadata.gz: 9cf655b8ae3fddb3071fb12b817b4b3e08863a34e0007a06d15c814c3cbde3d43057f62dca01ade1bfe02aed5634850e5b2852d6c9647a83055f598494cb6ec4
7
+ data.tar.gz: b92ebb0350cd0d79ed012c0318560bfef0148fa5669a6e4837f1c7f48a87611e44dafea1b6cfa75dc228946e28c34e42b44572f3a4c9c238b9e626d372c3203f
data/.reek.yml ADDED
@@ -0,0 +1,32 @@
1
+ ---
2
+ detectors:
3
+ IrresponsibleModule:
4
+ enabled: false
5
+ TooManyStatements:
6
+ enabled: true
7
+ max_statements: 10
8
+ NilCheck:
9
+ enabled: false
10
+ directories:
11
+ app/controllers:
12
+ NestedIterators:
13
+ max_allowed_nesting: 2
14
+ UnusedPrivateMethod:
15
+ enabled: false
16
+ app/helpers:
17
+ UtilityFunction:
18
+ enabled: false
19
+ exclude_paths:
20
+ - app/assets
21
+ - bin
22
+ - client/node_modules
23
+ - config
24
+ - coverage
25
+ - data
26
+ - db
27
+ - dw
28
+ - log
29
+ - phrase
30
+ - public
31
+ - tmp
32
+ - vendor
data/.rubocop.yml CHANGED
@@ -1,29 +1,19 @@
1
1
  ---
2
2
  Documentation:
3
3
  Enabled: false
4
- Rails:
5
- Enabled: true
6
4
  AllCops:
7
5
  Include:
8
- - app/**/*.rb
9
6
  - lib/**/*.rb
10
7
  - spec/**/*.rb
11
8
  Exclude:
12
- - app/assets/**/*
13
9
  - bin/**/*
14
- - client/node_modules/**/*
15
10
  - config/**/*
16
11
  - coverage/**/*
17
- - data/**/*
18
- - db/**/*
19
- - db_*/**/*
20
- - dw/**/*
21
12
  - log/**/*
22
- - phrase/**/*
23
13
  - public/**/*
24
14
  - tmp/**/*
25
15
  - vendor/**/*
26
- TargetRubyVersion: 2.3
16
+ TargetRubyVersion: 2.4
27
17
  Metrics/LineLength:
28
18
  Max: 100
29
19
  Layout/MultilineMethodCallIndentation:
@@ -42,6 +32,8 @@ RSpec/NestedGroups:
42
32
  Max: 10
43
33
  RSpec/MessageExpectation:
44
34
  Enabled: false
35
+ RSpec/MissingExampleGroupArgument:
36
+ Enabled: false
45
37
  require:
46
38
  - rubocop-rspec
47
39
  - test_prof/rubocop
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ 0.2.0
2
+
3
+ * Add Entities::FailureDetails and support for it in the various Serializers
4
+ * Strategies::ActorGetsAuthorizedThenDoesWork returns Entities::FailureDetails when authorization
5
+ fails
6
+
1
7
  0.1.0
2
8
 
3
9
  * Add Adapters::AttributeHashBase
data/Gemfile.lock CHANGED
@@ -1,9 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- clean-architecture (0.1.0)
4
+ clean-architecture (0.2.0)
5
5
  dry-matcher (~> 0.0)
6
6
  dry-monads (~> 1.0)
7
+ dry-struct (~> 0.0)
8
+ dry-types (~> 0.0)
7
9
  duckface-interfaces (~> 0.0)
8
10
 
9
11
  GEM
@@ -25,14 +27,36 @@ GEM
25
27
  thread_safe (~> 0.3, >= 0.3.1)
26
28
  diff-lcs (1.3)
27
29
  docile (1.3.1)
30
+ dry-configurable (0.7.0)
31
+ concurrent-ruby (~> 1.0)
32
+ dry-container (0.6.0)
33
+ concurrent-ruby (~> 1.0)
34
+ dry-configurable (~> 0.1, >= 0.1.3)
28
35
  dry-core (0.4.7)
29
36
  concurrent-ruby (~> 1.0)
30
37
  dry-equalizer (0.2.1)
38
+ dry-inflector (0.1.2)
39
+ dry-logic (0.4.2)
40
+ dry-container (~> 0.2, >= 0.2.6)
41
+ dry-core (~> 0.2)
42
+ dry-equalizer (~> 0.2)
31
43
  dry-matcher (0.7.0)
32
- dry-monads (1.0.1)
44
+ dry-monads (1.1.0)
33
45
  concurrent-ruby (~> 1.0)
34
46
  dry-core (~> 0.4, >= 0.4.4)
35
47
  dry-equalizer
48
+ dry-struct (0.5.1)
49
+ dry-core (~> 0.4, >= 0.4.3)
50
+ dry-equalizer (~> 0.2)
51
+ dry-types (~> 0.13)
52
+ ice_nine (~> 0.11)
53
+ dry-types (0.13.2)
54
+ concurrent-ruby (~> 1.0)
55
+ dry-container (~> 0.3)
56
+ dry-core (~> 0.4, >= 0.4.4)
57
+ dry-equalizer (~> 0.2)
58
+ dry-inflector (~> 0.1, >= 0.1.2)
59
+ dry-logic (~> 0.4, >= 0.4.2)
36
60
  duckface-interfaces (0.0.2)
37
61
  em-websocket (0.5.1)
38
62
  eventmachine (>= 0.12.9)
@@ -92,7 +116,7 @@ GEM
92
116
  rb-inotify (0.9.10)
93
117
  ffi (>= 0.5.0, < 2)
94
118
  rb-readline (0.5.5)
95
- reek (5.0.2)
119
+ reek (5.2.0)
96
120
  codeclimate-engine-rb (~> 0.4.0)
97
121
  kwalify (~> 0.7.0)
98
122
  parser (>= 2.5.0.0, < 2.6, != 2.5.1.1)
@@ -103,14 +127,14 @@ GEM
103
127
  rspec-mocks (~> 3.8.0)
104
128
  rspec-core (3.8.0)
105
129
  rspec-support (~> 3.8.0)
106
- rspec-expectations (3.8.1)
130
+ rspec-expectations (3.8.2)
107
131
  diff-lcs (>= 1.2.0, < 2.0)
108
132
  rspec-support (~> 3.8.0)
109
133
  rspec-mocks (3.8.0)
110
134
  diff-lcs (>= 1.2.0, < 2.0)
111
135
  rspec-support (~> 3.8.0)
112
136
  rspec-support (3.8.0)
113
- rubocop (0.58.2)
137
+ rubocop (0.59.2)
114
138
  jaro_winkler (~> 1.5.1)
115
139
  parallel (~> 1.10)
116
140
  parser (>= 2.5, != 2.5.1.1)
@@ -118,7 +142,7 @@ GEM
118
142
  rainbow (>= 2.2.2, < 4.0)
119
143
  ruby-progressbar (~> 1.7)
120
144
  unicode-display_width (~> 1.0, >= 1.0.1)
121
- rubocop-rspec (1.29.0)
145
+ rubocop-rspec (1.30.0)
122
146
  rubocop (>= 0.58.0)
123
147
  ruby-progressbar (1.10.0)
124
148
  ruby_dep (1.5.0)
@@ -143,12 +167,12 @@ PLATFORMS
143
167
  ruby
144
168
 
145
169
  DEPENDENCIES
146
- bundler (>= 1.13)
170
+ bundler (~> 1.13)
147
171
  clean-architecture!
148
172
  guard-livereload
149
173
  guard-rspec
150
174
  pry-byebug
151
- rake (>= 10.0)
175
+ rake (~> 12.0)
152
176
  rb-fsevent
153
177
  rb-readline
154
178
  reek
@@ -160,4 +184,4 @@ DEPENDENCIES
160
184
  timecop
161
185
 
162
186
  BUNDLED WITH
163
- 1.16.3
187
+ 1.16.4
data/README.md CHANGED
@@ -23,10 +23,11 @@ and decisions about I/O can be deferred until the last possible moment. It relie
23
23
  [duckface-interfaces](https://github.com/samuelgiles/duckface) gem to enforce interface
24
24
  implementation.
25
25
 
26
- ### Use cases as an organisational principle
26
+ ## Clean architecture principles
27
27
 
28
- Uncle Bob suggests that your source code organisation should allow developers to easily find a
29
- listing of all use cases your application provides. Here's an example of how this might look in a
28
+ ### Screaming architecture - use cases as an organisational principle
29
+
30
+ Uncle Bob suggests that your source code organisation should allow developers to easily find a listing of all use cases your application provides. Here's an example of how this might look in a
30
31
  Rails application.
31
32
 
32
33
  ```
@@ -38,7 +39,96 @@ Rails application.
38
39
  - ...
39
40
  ```
40
41
 
41
- ### Clean architecture principles
42
+ Note that the use case name contains:
43
+
44
+ - the user role
45
+ - the action
46
+ - the (sometimes implied) subject
47
+
48
+ ### Design principles
49
+
50
+ #### SRP - The Single Responsibility principle
51
+
52
+ > A function should do one, and only one, thing
53
+
54
+ We satisfy the SRP by following these rules:
55
+
56
+ - An **adapter** is solely responsible for presenting the properties of a business object, or a small number of business objects, in a known interface
57
+ - A **command** is solely responsible for completing an atomic I/O operation
58
+ - An **entity** is solely responsible for representing, in memory, a business object whos properties do not come from a single source
59
+ - An **interface** is a module that represents a contract between two classes
60
+ - A **serializer** is solely responsible for taking a business object and turning it into a representation made up of purely primitive values
61
+ - A **strategy** is an algorithm used by commands to compose atomic I/O operations
62
+ - A **use case** is solely responsible for checking whether an actor has permissions to perform a command, and executing that command if so
63
+ - A **validator** is solely responsible for validating a business object and returning a validation result
64
+
65
+ #### OCP - The Open/Closed Principle, LSP - The Liskov Substitution Principle and DIP - The Dependency Inversion Principle
66
+
67
+ > A software artefact should be open for extension but closed for modification
68
+
69
+ > A caller should not have to know the type of an object to interact with it
70
+
71
+ > Always depend on or derive from a stable abstraction, rather than a volatile concrete class
72
+
73
+ We satisfy the OCP, LSP & DIP by following these rules:
74
+
75
+ - We create a clean boundary between our business logic, our persistence layer and our application-specific classes using interfaces
76
+ - We use interfaces wherever possible, allowing concrete implementations of those interfaces to be extended without breaking the contract
77
+ - We write unit tests against interfaces, never against concrete implementations (unless interfaces don't exist)
78
+
79
+ #### ISP - The Interface Segregation Principle
80
+
81
+ > Where some actors only use a subset of methods available from an interface, the interface should be split into sub-interfaces supporting each type of caller
82
+
83
+ We satisfy the ISP by following these rules:
84
+
85
+ - Each functional area of our code is split into folders (under `lib` in Rails projects)
86
+ - Each functional area defines its own interfaces
87
+ - Interfaces are not shared between functional areas
88
+
89
+ ### Component cohesion
90
+
91
+ #### REP - The Reuse/Release Equivalence Principle, CCP - The Common Closure Principle & CRP - The Common Reuse Principle
92
+
93
+ > Classes and modules that are grouped together into a component should be releasable together
94
+
95
+ > Gather into components those changes the change for the same reasons and at the same times.
96
+
97
+ > Classes and modules that tend to be reused together should be placed in the same component
98
+
99
+ We satisfy the REP, CCP and CRP by:
100
+
101
+ - Having team discussions whenever we make decisions about what a new functional area should be called and what it should contain
102
+ - Ensuring that none of our functional areas make direct reference back to the parent application
103
+ - Splitting functional areas out into gems when those functional areas change at a different rate than the rest of the codebase
104
+ - Splitting functional areas out into standalone applications when it makes sense to do so
105
+
106
+ ### Component coupling
107
+
108
+ #### ADP - The Acyclic Dependencies Principle
109
+
110
+ > Don't create circular dependencies
111
+
112
+ I don't think I need to explain this. Just don't do it. I like explicitly including dependencies using `require` because it actually prevents you from doing this. Rails, in so many ways, makes one lazy.
113
+
114
+ #### SDP - The Stable Dependencies Principle
115
+
116
+ > A component always have less things depending on it than it depends on
117
+
118
+ We satisfy the SDP by:
119
+
120
+ - Putting sensible abstractions in place that adhere to the Single Responsibility principle
121
+ - Not sharing abstractions and entities between multiple functional areas
122
+
123
+ #### SAP - The Stable Abstractions Principle
124
+
125
+ > A component should be as abstract as it is stable
126
+
127
+ We satisfy the SAP by:
128
+
129
+ - Thinking hard about the methods and parameters we specify in our interfaces. Are they solving for a general problem? Are we likely to have to change them when requirements change, and how we can avoid that?
130
+
131
+ ## Practical suggestions for implementation
42
132
 
43
133
  * The code that manages your inputs (e.g. a Rails controller) instantiates a persistence layer
44
134
  object
@@ -21,6 +21,8 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_dependency 'dry-matcher', '~> 0.0'
23
23
  spec.add_dependency 'dry-monads', '~> 1.0'
24
+ spec.add_dependency 'dry-struct', '~> 0.0'
25
+ spec.add_dependency 'dry-types', '~> 0.0'
24
26
  spec.add_dependency 'duckface-interfaces', '~> 0.0'
25
27
 
26
28
  spec.add_development_dependency 'bundler', '~> 1.13'
@@ -5,8 +5,10 @@
5
5
  require 'clean_architecture/adapters/all'
6
6
  require 'clean_architecture/entities/all'
7
7
  require 'clean_architecture/interfaces/all'
8
+ require 'clean_architecture/matchers/all'
8
9
  require 'clean_architecture/queries/all'
9
10
  require 'clean_architecture/serializers/all'
10
11
  require 'clean_architecture/strategies/all'
11
12
 
13
+ require 'clean_architecture/types'
12
14
  require 'clean_architecture/version'
@@ -2,6 +2,7 @@
2
2
 
3
3
  # THIS FILE IS AUTOGENERATED AND SHOULD NOT BE MANUALLY MODIFIED
4
4
 
5
+ require 'clean_architecture/entities/failure_details'
5
6
  require 'clean_architecture/entities/targeted_parameters'
6
7
  require 'clean_architecture/entities/untargeted_parameters'
7
8
  require 'clean_architecture/entities/use_case_history_entry'
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'clean_architecture/types'
4
+ require 'dry/struct'
5
+
6
+ module CleanArchitecture
7
+ module Entities
8
+ class FailureDetails < Dry::Struct
9
+ FailureTypes = Types::Strict::String.enum(
10
+ 'error',
11
+ 'expectation_failed',
12
+ 'not_found',
13
+ 'unauthorized'
14
+ )
15
+
16
+ attribute :type, FailureTypes
17
+ attribute :message, Types::Strict::String
18
+ attribute :other_properties, Types::Strict::Hash
19
+ end
20
+ end
21
+ end
@@ -4,6 +4,7 @@ require 'dry-monads'
4
4
  require 'dry/matcher/result_matcher'
5
5
  require 'duckface'
6
6
  require 'clean_architecture/interfaces/use_case_history_entry'
7
+ require 'clean_architecture/matchers/use_case_result'
7
8
 
8
9
  module CleanArchitecture
9
10
  module Entities
@@ -23,9 +24,9 @@ module CleanArchitecture
23
24
  end
24
25
 
25
26
  def failure_messages
26
- Dry::Matcher::ResultMatcher.call(@use_case_result) do |matcher|
27
+ Matchers::UseCaseResult.call(@use_case_result) do |matcher|
27
28
  matcher.success { nil }
28
- matcher.failure { |value| value }
29
+ matcher.failure(&:message)
29
30
  end
30
31
  end
31
32
 
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # THIS FILE IS AUTOGENERATED AND SHOULD NOT BE MANUALLY MODIFIED
4
+
5
+ require 'clean_architecture/matchers/use_case_result'
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-matcher'
4
+
5
+ module CleanArchitecture
6
+ module Matchers
7
+ class UseCaseResult
8
+ def self.call(result, &block)
9
+ new.matcher.call(result, &block)
10
+ end
11
+
12
+ def matcher
13
+ Dry::Matcher.new(success: success_case, failure: failure_case)
14
+ end
15
+
16
+ private
17
+
18
+ def success_case
19
+ Dry::Matcher::Case.new(
20
+ match: ->(value) { value.is_a?(Dry::Monads::Success) },
21
+ resolve: ->(value) { value.value! }
22
+ )
23
+ end
24
+
25
+ def failure_case
26
+ Dry::Matcher::Case.new(
27
+ match: ->(value) { value.is_a?(Dry::Monads::Failure) },
28
+ resolve: ->(value) { resolve_failure_value(value) }
29
+ )
30
+ end
31
+
32
+ def resolve_failure_value(value)
33
+ failure = value.failure
34
+ case failure
35
+ when String
36
+ Entities::FailureDetails.new(message: failure, other_properties: {}, type: 'error')
37
+ when Entities::FailureDetails
38
+ failure
39
+ else
40
+ raise 'Unexpected failure value - must be String or Entities::FailureDetails'
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -2,4 +2,5 @@
2
2
 
3
3
  # THIS FILE IS AUTOGENERATED AND SHOULD NOT BE MANUALLY MODIFIED
4
4
 
5
+ require 'clean_architecture/queries/http_failure_code'
5
6
  require 'clean_architecture/queries/http_success_code'
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CleanArchitecture
4
+ module Queries
5
+ class HttpFailureCode
6
+ def initialize(failure_details_type)
7
+ @failure_details_type = failure_details_type
8
+ end
9
+
10
+ def to_sym
11
+ code = FAILURE_DETAILS_TYPE_TO_STATUS_CODE[@failure_details_type.to_s.downcase]
12
+ if code.nil?
13
+ raise NotImplementedError,
14
+ "cannot determine failure code for failure details type #{@failure_details_type}"
15
+ end
16
+
17
+ code
18
+ end
19
+
20
+ private
21
+
22
+ FAILURE_DETAILS_TYPE_TO_STATUS_CODE = {
23
+ 'error' => :internal_server_error,
24
+ 'expectation_failed' => :expectation_failed,
25
+ 'not_found' => :not_found,
26
+ 'unauthorized' => :unauthorized
27
+ }.freeze
28
+ end
29
+ end
30
+ end
@@ -8,10 +8,11 @@ module CleanArchitecture
8
8
  end
9
9
 
10
10
  def to_sym
11
- code = HTTP_METHOD_TO_SUCCESS_CODE[@http_method]
11
+ code = HTTP_METHOD_TO_SUCCESS_CODE[@http_method.to_s.upcase]
12
12
  if code.nil?
13
13
  raise NotImplementedError, "cannot determine success code for HTTP method #{@http_method}"
14
14
  end
15
+
15
16
  code
16
17
  end
17
18
 
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/matcher/result_matcher'
3
+ require 'clean_architecture/entities/failure_details'
4
+ require 'clean_architecture/matchers/use_case_result'
4
5
  require 'clean_architecture/queries/http_success_code'
6
+ require 'clean_architecture/queries/http_failure_code'
5
7
 
6
8
  module CleanArchitecture
7
9
  module Serializers
@@ -12,13 +14,22 @@ module CleanArchitecture
12
14
  end
13
15
 
14
16
  def to_h
15
- Dry::Matcher::ResultMatcher.call(@result) do |matcher|
16
- matcher.success do |data|
17
- { status: Queries::HttpSuccessCode.new(@http_method).to_sym, data: data }
18
- end
19
- matcher.failure { |error_message| { status: :error, error: error_message } }
17
+ Matchers::UseCaseResult.call(@result) do |matcher|
18
+ matcher.success { |data| success_html_response(data) }
19
+ matcher.failure { |failure_details| failure_html_response(failure_details) }
20
20
  end
21
21
  end
22
+
23
+ private
24
+
25
+ def success_html_response(data)
26
+ { status: Queries::HttpSuccessCode.new(@http_method).to_sym, data: data }
27
+ end
28
+
29
+ def failure_html_response(failure_details)
30
+ status = Queries::HttpFailureCode.new(failure_details.type).to_sym
31
+ { status: status, error: failure_details.message }
32
+ end
22
33
  end
23
34
  end
24
35
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-monads'
4
- require 'dry/matcher/result_matcher'
3
+ require 'clean_architecture/entities/failure_details'
4
+ require 'clean_architecture/matchers/use_case_result'
5
+ require 'clean_architecture/queries/http_failure_code'
5
6
  require 'clean_architecture/queries/http_success_code'
6
7
 
7
8
  module CleanArchitecture
@@ -23,22 +24,20 @@ module CleanArchitecture
23
24
  private
24
25
 
25
26
  def http_status_code
26
- Dry::Matcher::ResultMatcher.call(@result) do |matcher|
27
+ Matchers::UseCaseResult.call(@result) do |matcher|
27
28
  matcher.success { Queries::HttpSuccessCode.new(@http_method).to_sym }
28
- matcher.failure do
29
- if result_is_authorization_failure?
30
- :unauthorized
31
- else
32
- :expectation_failed
33
- end
29
+ matcher.failure do |failure_value|
30
+ Queries::HttpFailureCode.new(failure_value.type).to_sym
34
31
  end
35
32
  end
36
33
  end
37
34
 
38
35
  def json
39
- Dry::Matcher::ResultMatcher.call(@result) do |matcher|
36
+ Matchers::UseCaseResult.call(@result) do |matcher|
40
37
  matcher.success { success_payload }
41
- matcher.failure { |failure_message| error_payload(failure_message) }
38
+ matcher.failure do |failure_details|
39
+ { jsonapi: json_api_version_hash, errors: [failure_details.message] }
40
+ end
42
41
  end
43
42
  end
44
43
 
@@ -49,20 +48,9 @@ module CleanArchitecture
49
48
  }
50
49
  end
51
50
 
52
- def error_payload(failure_message)
53
- {
54
- jsonapi: json_api_version_hash,
55
- errors: [failure_message]
56
- }
57
- end
58
-
59
51
  def json_api_version_hash
60
52
  { version: @success_payload.version }
61
53
  end
62
-
63
- def result_is_authorization_failure?
64
- !@result.failure.index('Unauthorized: ').nil?
65
- end
66
54
  end
67
55
  end
68
56
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'dry/monads/all'
4
+ require 'clean_architecture/entities/failure_details'
4
5
  require 'clean_architecture/interfaces/strategy'
5
6
 
6
7
  module CleanArchitecture
@@ -17,12 +18,18 @@ module CleanArchitecture
17
18
 
18
19
  def_delegator :@sub_strategy, :parameters
19
20
 
21
+ UNAUTHORIZED_FAILURE_DETAILS = Entities::FailureDetails.new(
22
+ message: 'Unauthorized',
23
+ other_properties: {},
24
+ type: 'unauthorized'
25
+ )
26
+
20
27
  def result
21
28
  @result ||= begin
22
29
  if @authorization_check.authorized?
23
30
  @sub_strategy.result
24
31
  else
25
- Dry::Monads::Failure('Unauthorized')
32
+ Dry::Monads::Failure(UNAUTHORIZED_FAILURE_DETAILS)
26
33
  end
27
34
  end
28
35
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-types'
4
+
5
+ module Types
6
+ include Dry::Types.module
7
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CleanArchitecture
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clean-architecture
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bellroy Tech Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-28 00:00:00.000000000 Z
11
+ date: 2018-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-matcher
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-struct
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dry-types
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: duckface-interfaces
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -104,6 +132,7 @@ files:
104
132
  - ".gitignore"
105
133
  - ".overcommit.yml"
106
134
  - ".reek"
135
+ - ".reek.yml"
107
136
  - ".rspec"
108
137
  - ".rubocop.yml"
109
138
  - ".ruby-version"
@@ -120,6 +149,7 @@ files:
120
149
  - lib/clean_architecture/adapters/attribute_hash_base.rb
121
150
  - lib/clean_architecture/all.rb
122
151
  - lib/clean_architecture/entities/all.rb
152
+ - lib/clean_architecture/entities/failure_details.rb
123
153
  - lib/clean_architecture/entities/targeted_parameters.rb
124
154
  - lib/clean_architecture/entities/untargeted_parameters.rb
125
155
  - lib/clean_architecture/entities/use_case_history_entry.rb
@@ -137,7 +167,10 @@ files:
137
167
  - lib/clean_architecture/interfaces/use_case_actor.rb
138
168
  - lib/clean_architecture/interfaces/use_case_history_entry.rb
139
169
  - lib/clean_architecture/interfaces/use_case_target.rb
170
+ - lib/clean_architecture/matchers/all.rb
171
+ - lib/clean_architecture/matchers/use_case_result.rb
140
172
  - lib/clean_architecture/queries/all.rb
173
+ - lib/clean_architecture/queries/http_failure_code.rb
141
174
  - lib/clean_architecture/queries/http_success_code.rb
142
175
  - lib/clean_architecture/serializers/all.rb
143
176
  - lib/clean_architecture/serializers/html_response_from_result.rb
@@ -146,6 +179,7 @@ files:
146
179
  - lib/clean_architecture/strategies/actor_gets_authorized_then_does_work.rb
147
180
  - lib/clean_architecture/strategies/all.rb
148
181
  - lib/clean_architecture/strategies/with_audit_trail.rb
182
+ - lib/clean_architecture/types.rb
149
183
  - lib/clean_architecture/version.rb
150
184
  homepage: https://bellroy.com
151
185
  licenses: []