clean-architecture 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|