clean-architecture 0.0.1
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 +7 -0
- data/.gitignore +1 -0
- data/.overcommit.yml +41 -0
- data/.reek +16 -0
- data/.rspec +2 -0
- data/.rubocop.yml +57 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +24 -0
- data/Gemfile.lock +160 -0
- data/Guardfile +111 -0
- data/README.md +17 -0
- data/Rakefile +8 -0
- data/clean-architecture.gemspec +29 -0
- data/generate_require_files.rb +49 -0
- data/lib/clean-architecture.rb +3 -0
- data/lib/clean_architecture/all.rb +11 -0
- data/lib/clean_architecture/entities/all.rb +7 -0
- data/lib/clean_architecture/entities/targeted_parameters.rb +20 -0
- data/lib/clean_architecture/entities/untargeted_parameters.rb +18 -0
- data/lib/clean_architecture/entities/use_case_history_entry.rb +52 -0
- data/lib/clean_architecture/interfaces/all.rb +17 -0
- data/lib/clean_architecture/interfaces/authorization_check.rb +15 -0
- data/lib/clean_architecture/interfaces/authorization_parameters.rb +18 -0
- data/lib/clean_architecture/interfaces/base_parameters.rb +23 -0
- data/lib/clean_architecture/interfaces/command.rb +23 -0
- data/lib/clean_architecture/interfaces/jsonable.rb +15 -0
- data/lib/clean_architecture/interfaces/persistence.rb +15 -0
- data/lib/clean_architecture/interfaces/strategy.rb +17 -0
- data/lib/clean_architecture/interfaces/success_payload.rb +19 -0
- data/lib/clean_architecture/interfaces/targeted_parameters.rb +18 -0
- data/lib/clean_architecture/interfaces/use_case.rb +23 -0
- data/lib/clean_architecture/interfaces/use_case_actor.rb +19 -0
- data/lib/clean_architecture/interfaces/use_case_history_entry.rb +39 -0
- data/lib/clean_architecture/interfaces/use_case_target.rb +23 -0
- data/lib/clean_architecture/queries/all.rb +5 -0
- data/lib/clean_architecture/queries/http_success_code.rb +28 -0
- data/lib/clean_architecture/serializers/all.rb +6 -0
- data/lib/clean_architecture/serializers/html_response_from_result.rb +23 -0
- data/lib/clean_architecture/serializers/json_response_from_result.rb +67 -0
- data/lib/clean_architecture/strategies/actor_gets_authorized_then_does_work.rb +30 -0
- data/lib/clean_architecture/strategies/all.rb +6 -0
- data/lib/clean_architecture/strategies/with_audit_trail.rb +40 -0
- data/lib/clean_architecture/version.rb +5 -0
- metadata +170 -0
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'clean_architecture/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'clean-architecture'
|
9
|
+
spec.version = CleanArchitecture::VERSION
|
10
|
+
spec.authors = ['Bellroy Tech Team']
|
11
|
+
spec.email = ['tech@bellroy.com']
|
12
|
+
|
13
|
+
spec.summary = 'Bellroy Clean Architecture Framework'
|
14
|
+
spec.description = 'An attempt at building a reusable Clean Architecture framework for Ruby'
|
15
|
+
spec.homepage = 'https://bellroy.com'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_dependency 'dry-matcher'
|
23
|
+
spec.add_dependency 'dry-monads'
|
24
|
+
spec.add_dependency 'duckface-interfaces'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '>= 1.13'
|
27
|
+
spec.add_development_dependency 'rake', '>= 10.0'
|
28
|
+
spec.add_development_dependency 'rspec', '>= 3.0'
|
29
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
def directories_in(root)
|
4
|
+
Dir.entries(root).sort.select do |entry|
|
5
|
+
fully_qualified_entry = File.join(root, entry)
|
6
|
+
File.directory?(fully_qualified_entry) && !['.', '..'].include?(entry.to_s)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def files_in(root)
|
11
|
+
Dir.entries(root).sort.reject do |entry|
|
12
|
+
fully_qualified_entry = File.join(root, entry)
|
13
|
+
File.directory?(fully_qualified_entry) || entry.to_s == 'all.rb' || entry[-3..-1] != '.rb'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def recursive_files_in(root)
|
18
|
+
full_paths = Dir.glob(File.join(root, '**', '*')).sort.reject do |entry|
|
19
|
+
fully_qualified_entry = File.join(root, entry)
|
20
|
+
File.directory?(fully_qualified_entry) || entry[-7..-1] == '/all.rb' || entry[-3..-1] != '.rb'
|
21
|
+
end
|
22
|
+
|
23
|
+
remove_path = root.split('/')[0..-2].join('/') + '/'
|
24
|
+
full_paths.map { |full_path| full_path.gsub(remove_path, '') }
|
25
|
+
end
|
26
|
+
|
27
|
+
def write_require_file(root, require_prefix, require_directories, require_files)
|
28
|
+
require_file_path = File.join(root, 'all.rb')
|
29
|
+
File.open(require_file_path, 'w') do |file|
|
30
|
+
file.write("# frozen_string_literal: true\n\n")
|
31
|
+
file.write("# THIS FILE IS AUTOGENERATED AND SHOULD NOT BE MANUALLY MODIFIED\n\n")
|
32
|
+
require_directories.each do |require_directory|
|
33
|
+
file.write("require '#{require_prefix}/#{require_directory}/all'\n")
|
34
|
+
end
|
35
|
+
file.write("\n") unless require_directories.empty?
|
36
|
+
require_files.each { |require_file| file.write("require '#{require_prefix}/#{require_file[0..-4]}'\n") }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
lib_directories = ['clean_architecture']
|
41
|
+
lib_directories.each do |lib_directory|
|
42
|
+
root = File.join(__dir__, 'lib', lib_directory)
|
43
|
+
subdirectories = directories_in(root)
|
44
|
+
write_require_file(root, lib_directory, subdirectories, files_in(root))
|
45
|
+
subdirectories.each do |subdirectory|
|
46
|
+
fully_qualified_directory = File.join(root, subdirectory)
|
47
|
+
write_require_file(fully_qualified_directory, lib_directory, [], recursive_files_in(fully_qualified_directory))
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# THIS FILE IS AUTOGENERATED AND SHOULD NOT BE MANUALLY MODIFIED
|
4
|
+
|
5
|
+
require 'clean_architecture/interfaces/all'
|
6
|
+
require 'clean_architecture/entities/all'
|
7
|
+
require 'clean_architecture/queries/all'
|
8
|
+
require 'clean_architecture/serializers/all'
|
9
|
+
require 'clean_architecture/strategies/all'
|
10
|
+
|
11
|
+
require 'clean_architecture/version'
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# THIS FILE IS AUTOGENERATED AND SHOULD NOT BE MANUALLY MODIFIED
|
4
|
+
|
5
|
+
require 'clean_architecture/entities/targeted_parameters'
|
6
|
+
require 'clean_architecture/entities/untargeted_parameters'
|
7
|
+
require 'clean_architecture/entities/use_case_history_entry'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CleanArchitecture
|
4
|
+
module Entities
|
5
|
+
class TargetedParameters
|
6
|
+
attr_reader :actor, :extra_parameters_hash, :persistence, :target, :settings
|
7
|
+
|
8
|
+
implements_interface Interfaces::TargetedParameters
|
9
|
+
implements_interface Interfaces::AuthorizationParameters
|
10
|
+
|
11
|
+
def initialize(actor, target, extra_parameters_hash, persistence, settings)
|
12
|
+
@actor = actor
|
13
|
+
@target = target
|
14
|
+
@extra_parameters_hash = extra_parameters_hash
|
15
|
+
@persistence = persistence
|
16
|
+
@settings = settings
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CleanArchitecture
|
4
|
+
module Entities
|
5
|
+
class UntargetedParameters
|
6
|
+
attr_reader :actor, :extra_parameters_hash, :persistence, :settings
|
7
|
+
|
8
|
+
implements_interface Interfaces::BaseParameters
|
9
|
+
|
10
|
+
def initialize(actor, extra_parameters_hash, persistence, settings)
|
11
|
+
@actor = actor
|
12
|
+
@extra_parameters_hash = extra_parameters_hash
|
13
|
+
@persistence = persistence
|
14
|
+
@settings = settings
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry-monads'
|
4
|
+
require 'dry/matcher/result_matcher'
|
5
|
+
require 'duckface'
|
6
|
+
|
7
|
+
module CleanArchitecture
|
8
|
+
module Entities
|
9
|
+
class UseCaseHistoryEntry
|
10
|
+
implements_interface Interfaces::UseCaseHistoryEntry
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
def initialize(use_case_class, use_case_parameters, use_case_result, use_case_target)
|
14
|
+
@use_case_class = use_case_class
|
15
|
+
@use_case_parameters = use_case_parameters
|
16
|
+
@use_case_result = use_case_result
|
17
|
+
@use_case_target = use_case_target
|
18
|
+
end
|
19
|
+
|
20
|
+
def extra_parameters_hash
|
21
|
+
@use_case_parameters.extra_parameters_hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def failure_messages
|
25
|
+
Dry::Matcher::ResultMatcher.call(@use_case_result) do |matcher|
|
26
|
+
matcher.success { nil }
|
27
|
+
matcher.failure { |value| value }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def prior_target_state
|
32
|
+
@use_case_target.attribute_hash
|
33
|
+
end
|
34
|
+
|
35
|
+
def succeeded?
|
36
|
+
@use_case_result.success?
|
37
|
+
end
|
38
|
+
|
39
|
+
def target_identifier
|
40
|
+
@use_case_target.identifier
|
41
|
+
end
|
42
|
+
|
43
|
+
def use_case_class_name
|
44
|
+
@use_case_class.name
|
45
|
+
end
|
46
|
+
|
47
|
+
def user_identifier
|
48
|
+
@use_case_parameters.actor.user_identifier
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# THIS FILE IS AUTOGENERATED AND SHOULD NOT BE MANUALLY MODIFIED
|
4
|
+
|
5
|
+
require 'clean_architecture/interfaces/authorization_check'
|
6
|
+
require 'clean_architecture/interfaces/authorization_parameters'
|
7
|
+
require 'clean_architecture/interfaces/base_parameters'
|
8
|
+
require 'clean_architecture/interfaces/command'
|
9
|
+
require 'clean_architecture/interfaces/jsonable'
|
10
|
+
require 'clean_architecture/interfaces/persistence'
|
11
|
+
require 'clean_architecture/interfaces/strategy'
|
12
|
+
require 'clean_architecture/interfaces/success_payload'
|
13
|
+
require 'clean_architecture/interfaces/targeted_parameters'
|
14
|
+
require 'clean_architecture/interfaces/use_case'
|
15
|
+
require 'clean_architecture/interfaces/use_case_actor'
|
16
|
+
require 'clean_architecture/interfaces/use_case_history_entry'
|
17
|
+
require 'clean_architecture/interfaces/use_case_target'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'clean_architecture/interfaces/base_parameters'
|
4
|
+
require 'duckface'
|
5
|
+
|
6
|
+
module CleanArchitecture
|
7
|
+
module Interfaces
|
8
|
+
module AuthorizationParameters
|
9
|
+
extend Duckface::ActsAsInterface
|
10
|
+
|
11
|
+
include BaseParameters
|
12
|
+
|
13
|
+
def actor
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'duckface'
|
4
|
+
|
5
|
+
module CleanArchitecture
|
6
|
+
module Interfaces
|
7
|
+
module BaseParameters
|
8
|
+
extend Duckface::ActsAsInterface
|
9
|
+
|
10
|
+
def extra_parameters_hash
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
def persistence
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
def settings
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'duckface'
|
4
|
+
|
5
|
+
module CleanArchitecture
|
6
|
+
module Interfaces
|
7
|
+
module Command
|
8
|
+
extend Duckface::ActsAsInterface
|
9
|
+
|
10
|
+
def initialize(_parameters)
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
def parameters
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
def result
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'duckface'
|
4
|
+
|
5
|
+
module CleanArchitecture
|
6
|
+
module Interfaces
|
7
|
+
module Persistence
|
8
|
+
extend Duckface::ActsAsInterface
|
9
|
+
|
10
|
+
def create_use_case_history_entry(_use_case_history_entry)
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CleanArchitecture
|
4
|
+
module Interfaces
|
5
|
+
module Strategy
|
6
|
+
extend Duckface::ActsAsInterface
|
7
|
+
|
8
|
+
def parameters
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
def result
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'duckface'
|
4
|
+
|
5
|
+
module CleanArchitecture
|
6
|
+
module Interfaces
|
7
|
+
module SuccessPayload
|
8
|
+
extend Duckface::ActsAsInterface
|
9
|
+
|
10
|
+
def data_hash
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
def version
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'clean_architecture/interfaces/base_parameters'
|
4
|
+
require 'duckface'
|
5
|
+
|
6
|
+
module CleanArchitecture
|
7
|
+
module Interfaces
|
8
|
+
module TargetedParameters
|
9
|
+
extend Duckface::ActsAsInterface
|
10
|
+
|
11
|
+
include BaseParameters
|
12
|
+
|
13
|
+
def target
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'duckface'
|
4
|
+
|
5
|
+
module CleanArchitecture
|
6
|
+
module Interfaces
|
7
|
+
module UseCase
|
8
|
+
extend Duckface::ActsAsInterface
|
9
|
+
|
10
|
+
def initialize(_parameters)
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
def parameters
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
def result
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'duckface'
|
4
|
+
|
5
|
+
module CleanArchitecture
|
6
|
+
module Interfaces
|
7
|
+
module UseCaseActor
|
8
|
+
extend Duckface::ActsAsInterface
|
9
|
+
|
10
|
+
def authorized?(_action, _target)
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
def user_identifier
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|