boxenn 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fbc20a9c92ec4119ce2cf95528c76cd9b63a182f17a2681255e217ff626ae64a
4
+ data.tar.gz: 6e81cb746c69f65167d31a7bd488667a32b0afe46351be116ac43651885d45ea
5
+ SHA512:
6
+ metadata.gz: 16299c51f0c34f72bf2301f4ff875e81ee3aef50491fc807fdb8107dad4982973054fd7ac531f3428b0c61852e3a46a9012d3861153ec0e7fbae89dc984848cb
7
+ data.tar.gz: 346fbe465196695f5395910d7f8166ec095f3893f4349bf36571553429461c5bc2b979f25c6c998cbacd13b5fe441375e4ea3df9a3dade7951b2eea0c3c7ea38
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 sunnyfounder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # Boxenn
2
+
3
+ ![Gem Version](https://badge.fury.io/rb/boxenn.svg)
4
+ ![CI Status](https://github.com/sunnyfounder/boxenn/actions/workflows/ci.yml/badge.svg)
5
+ [![codecov](https://codecov.io/gh/sunnyfounder/boxenn/branch/main/graph/badge.svg?token=IC8NGTNYIZ)](https://codecov.io/gh/sunnyfounder/boxenn)
6
+
7
+ A DDD-oriented infrastructure for ruby/rails projects based on the dry-rb ecosystem.
8
+
9
+ ## Installation
10
+ Add this line to your application's Gemfile\
11
+ `gem 'boxenn'`\
12
+ And then execute:\
13
+ `$ bundle install`
14
+
15
+ ## Examples
16
+ * [Working With Sidekiq](examples/sidekiq/README.md)
17
+
18
+ ## License
19
+
20
+ See `LICENSE` file.
data/boxenn.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'boxenn/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'boxenn'
7
+ spec.version = Boxenn::VERSION.dup
8
+ spec.license = 'MIT'
9
+ spec.summary = 'A ddd-oriented infrastructure for ruby/rails projects based on the dry-rb ecosystem.'
10
+ spec.authors = ['Michael Fu', 'Oscar', 'Joseph']
11
+ spec.email = ['oscarada87@gmail.com']
12
+ spec.files = Dir['CHANGELOG.md', 'LICENSE', 'README.md', 'boxenn.gemspec', 'lib/**/*']
13
+ spec.homepage = 'https://github.com/sunnyfounder/boxenn'
14
+ spec.required_ruby_version = '>= 2.6.0'
15
+ spec.require_paths = ['lib']
16
+
17
+ spec.add_runtime_dependency 'dry-initializer', '~> 3.0'
18
+ spec.add_runtime_dependency 'dry-monads', '~> 1.3'
19
+ spec.add_runtime_dependency 'dry-struct', '~> 1.3.0'
20
+ spec.add_runtime_dependency 'wisper', '2.0.0'
21
+ spec.metadata['rubygems_mfa_required'] = 'true'
22
+ end
@@ -0,0 +1,22 @@
1
+ require 'dry-struct'
2
+ require_relative '../initializer/dry_types'
3
+
4
+ require 'boxenn/errors'
5
+
6
+ module Boxenn
7
+ class Entity < Dry::Struct
8
+ alias assign_attributes new
9
+
10
+ def self.primary_keys
11
+ raise UndefinePrimaryKeys.new(class_name: self.class.name)
12
+ end
13
+
14
+ def primary_keys_hash
15
+ if self.class.primary_keys.all? { |s| attributes.key? s }
16
+ attributes.slice(*self.class.primary_keys)
17
+ else
18
+ raise UnassignPrimaryKeys.new(class_name: self.class.name)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ module Boxenn
2
+ class InvalidPrimaryKey < StandardError
3
+ def initialize(**args)
4
+ super(_message(**args))
5
+ end
6
+
7
+ private
8
+
9
+ def _message(class_name:, provided:, required:)
10
+ if required - provided
11
+ "Primary Key #{required - provided} is missing for class #{class_name.inspect}"
12
+ else
13
+ "#{provided - required} is not a primary key for class #{class_name.inspect}"
14
+ end
15
+ end
16
+ end
17
+
18
+ class UndefinePrimaryKeys < StandardError
19
+ def initialize(**args)
20
+ super(_message(**args))
21
+ end
22
+
23
+ private
24
+
25
+ def _message(class_name:)
26
+ "Primary Key needs to be defined in #{class_name.inspect}"
27
+ end
28
+ end
29
+
30
+ class UnassignPrimaryKeys < StandardError
31
+ def initialize(**args)
32
+ super(_message(**args))
33
+ end
34
+
35
+ private
36
+
37
+ def _message(class_name:)
38
+ "Primary Key needs to be assigned in #{class_name.inspect}"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ require 'dry/initializer'
2
+
3
+ module Boxenn
4
+ module Repositories
5
+ class Factory
6
+ extend Dry::Initializer
7
+
8
+ param :entity, default: proc {}
9
+
10
+ def build
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def primary_keys
15
+ entity.primary_keys
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ require 'dry/initializer'
2
+
3
+ module Boxenn
4
+ module Repositories
5
+ class Query
6
+ extend Dry::Initializer
7
+
8
+ param :relation, default: proc {}
9
+
10
+ def collect
11
+ raise NotImplementedError
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Boxenn
2
+ module Repositories
3
+ class RecordMapper
4
+ def build
5
+ raise NotImplementedError
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ require 'dry/initializer'
2
+
3
+ module Boxenn
4
+ module Repositories
5
+ class SourceWrapper
6
+ extend Dry::Initializer
7
+
8
+ param :source, default: proc {}
9
+
10
+ def find_by(primary_keys)
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def save(primary_keys, attributes)
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def destroy(primary_keys_hash)
19
+ raise NotImplementedError
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,63 @@
1
+ require 'dry/initializer'
2
+
3
+ require 'boxenn/errors'
4
+
5
+ module Boxenn
6
+ class Repository
7
+ extend Dry::Initializer
8
+
9
+ option :source_wrapper, default: -> {}
10
+
11
+ option :factory, default: -> {}
12
+
13
+ option :record_mapper, default: -> {}
14
+
15
+ def find_by_identity(**attributes)
16
+ non_primary_keys_provided = (attributes.keys - factory.primary_keys).empty? && (factory.primary_keys - attributes.keys).empty?
17
+ raise InvalidPrimaryKey.new(class_name: self.class.name, provided: attributes.keys, required: factory.primary_keys) unless non_primary_keys_provided
18
+
19
+ record = retrieve_record(attributes)
20
+ record.nil? ? nil : build(record)
21
+ end
22
+
23
+ def find_by_query(query)
24
+ records = query.collect
25
+ records.map { |record| build(record) }
26
+ end
27
+
28
+ def save(entities)
29
+ Array(entities).each do |entity|
30
+ attributes = adapt(entity.to_h)
31
+ identity = adapt(entity.primary_keys_hash)
32
+ save_record(identity, attributes)
33
+ end
34
+ end
35
+
36
+ def destroy(entities)
37
+ Array(entities).each do |entity|
38
+ identity = adapt(entity.primary_keys_hash)
39
+ source_wrapper.destroy(identity)
40
+ end
41
+ end
42
+
43
+ protected
44
+
45
+ def retrieve_record(**attributes)
46
+ hash = attributes.slice(*factory.primary_keys)
47
+ pk_hash = adapt(hash)
48
+ record = source_wrapper.find_by(pk_hash)
49
+ end
50
+
51
+ def save_record(primary_keys, attributes)
52
+ source_wrapper.save(primary_keys, attributes)
53
+ end
54
+
55
+ def build(record)
56
+ factory.build(record)
57
+ end
58
+
59
+ def adapt(hash)
60
+ record_mapper.build(hash)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,30 @@
1
+ require 'ostruct'
2
+ require 'dry/monads/all'
3
+ require 'wisper'
4
+ require 'dry/initializer'
5
+
6
+ module Boxenn
7
+ ##
8
+ # 這個類別是在 Domain(Use case) 層中負責處理業務邏輯的基礎類別
9
+
10
+ class UseCase
11
+ extend Dry::Initializer
12
+ include Wisper::Publisher
13
+ include Dry::Monads
14
+ include Dry::Monads::Do
15
+
16
+ def call(*args)
17
+ Success(yield(steps(*args)))
18
+ rescue Dry::Monads::Do::Halt
19
+ raise
20
+ rescue StandardError => e
21
+ Failure.new([e], trace: e.backtrace.first)
22
+ end
23
+
24
+ protected
25
+
26
+ def steps
27
+ raise NotImplementedError
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Boxenn
2
+ VERSION = '3.0.0'.freeze
3
+ end
data/lib/boxenn.rb ADDED
@@ -0,0 +1,2 @@
1
+ module Boxenn
2
+ end
@@ -0,0 +1,5 @@
1
+ require 'dry-types'
2
+
3
+ module Types
4
+ include Dry.Types()
5
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: boxenn
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Fu
8
+ - Oscar
9
+ - Joseph
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2022-01-21 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dry-initializer
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '3.0'
29
+ - !ruby/object:Gem::Dependency
30
+ name: dry-monads
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '1.3'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '1.3'
43
+ - !ruby/object:Gem::Dependency
44
+ name: dry-struct
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 1.3.0
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: 1.3.0
57
+ - !ruby/object:Gem::Dependency
58
+ name: wisper
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - '='
62
+ - !ruby/object:Gem::Version
63
+ version: 2.0.0
64
+ type: :runtime
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - '='
69
+ - !ruby/object:Gem::Version
70
+ version: 2.0.0
71
+ description:
72
+ email:
73
+ - oscarada87@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - LICENSE
79
+ - README.md
80
+ - boxenn.gemspec
81
+ - lib/boxenn.rb
82
+ - lib/boxenn/entity.rb
83
+ - lib/boxenn/errors.rb
84
+ - lib/boxenn/repositories/factory.rb
85
+ - lib/boxenn/repositories/query.rb
86
+ - lib/boxenn/repositories/record_mapper.rb
87
+ - lib/boxenn/repositories/source_wrapper.rb
88
+ - lib/boxenn/repository.rb
89
+ - lib/boxenn/use_case.rb
90
+ - lib/boxenn/version.rb
91
+ - lib/initializer/dry_types.rb
92
+ homepage: https://github.com/sunnyfounder/boxenn
93
+ licenses:
94
+ - MIT
95
+ metadata:
96
+ rubygems_mfa_required: 'true'
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: 2.6.0
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubygems_version: 3.0.8
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: A ddd-oriented infrastructure for ruby/rails projects based on the dry-rb
116
+ ecosystem.
117
+ test_files: []