clean-architecture 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []