team_fastlane-domain_driven_design 1.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: 6254016e8961513cb7097633e77fdda46e6bfb849a7776dc551f6a1531846256
4
+ data.tar.gz: ce3a1a9a7cbcf13246efd889dc9af63e10f2d4bd7873b8ca170b6842376c6196
5
+ SHA512:
6
+ metadata.gz: 9a16818fc6edd7c088aa458b5f83f86f869f402f31f21b3c77d2c518ff96edda5fe6efd76320a7456372364cfa0301fdb0daa570f83da445669bd27420d3e5b8
7
+ data.tar.gz: b64e3c3d4df0ec1e3fe68ff3e92e5ff7c836e2191a398fe4cd978130b9a2d6961dfc7cbb61d3fb1b89446a1fb4e4de98f6001dd73dbc8e119de1b2faf6c868c7
data/CHANGELOG.adoc ADDED
@@ -0,0 +1,39 @@
1
+ = Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on https://keepachangelog.com[Keep a Changelog],
6
+ and this project adheres to https://semver.org[Semantic Versioning].
7
+
8
+ == Unreleased
9
+
10
+ == [1.0.0] - 2023-08-01
11
+ === Changed
12
+ Renamed and restructured for release on rubygems
13
+
14
+ == [0.0.5] - 2022-01-03
15
+ === Changed
16
+ - Small refactoring to comply to rubocop
17
+
18
+ == [0.0.4] - 2020-06-10
19
+ === Added
20
+ - A basic readme
21
+ === Changed
22
+ - Adjusted changelog more to keep-a-changelog-recommendation
23
+ - Cleanup gemspec
24
+ - Cleanup gem structure to match best practices
25
+
26
+ == [0.0.3] - 2020-05-19
27
+ === Bugfix
28
+ - Applied Rubocop to all files
29
+
30
+ == [0.0.2] - 2020-05-18
31
+ === Bugfix
32
+ - Added the possibility to require the Gem instead of the single lib files.
33
+
34
+ == [0.0.1] - 2020-05-18
35
+ === Added
36
+ - Initial Gem version extracted from the Fastlane Backend.
37
+
38
+ The format is based on https://keepachangelog.com[Keep a Changelog],
39
+ and this project adheres to https://semver.org[Semantic Versioning].
data/README.adoc ADDED
@@ -0,0 +1,7 @@
1
+ = Domain Driven Design Helper
2
+
3
+ This are some small helpers to use with a domain driven design style. Check out the code comments, these are pretty extensive.
4
+
5
+ == Installation & Usage
6
+
7
+ As described by the link:../README.adoc[main readme].
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TeamFastlane
4
+ # This is the base for all domain-driven design entities.
5
+ # A entity represents a unique object of a specific type in the domain, e.g. a customer. Entities won't be defined by
6
+ # their attributes but their unique identity.
7
+ #
8
+ # Entities are used most of the times to implement the business logic for a given domain, they don't know anything
9
+ # about outside systems (like persistence layer) and can only work with their attributes and the given parameters of
10
+ # the called method.
11
+ #
12
+ # To make use of this include it in your entity.
13
+ #
14
+ # @example How to include properly
15
+ # class TestEntity
16
+ # include DomainDrivenDesign::EntityBase
17
+ # end
18
+ #
19
+ # @ddd_base
20
+ # @author Robert Kranz
21
+ module DomainDrivenDesign
22
+ module EntityBase
23
+ extend ActiveSupport::Concern
24
+ include ActiveModel::Model
25
+ include Comparable
26
+
27
+ def <=>(other)
28
+ return id <=> other.id if respond_to?(:id)
29
+
30
+ attributes <=> other.attributes
31
+ end
32
+
33
+ def attributes
34
+ instance_values.transform_values do |value|
35
+ value.respond_to?(:attributes) ? value.attributes : value
36
+ end
37
+ end
38
+
39
+ class_methods do
40
+ def repository
41
+ @repository ||= "#{name}Repository".constantize
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TeamFastlane
4
+ # This is the base for all domain-driven design repositories.
5
+ # A repository bridges the gap between business ({EntityBase}) and persistence layer (database). It encapsulates
6
+ # storage, retrieval and search behavior for an amount of business objects.
7
+ #
8
+ # It achieves this by providing methods for object handling on the one hand and besides that also provides the mapping
9
+ # from the data structure to the business objects.
10
+ #
11
+ # This is not the right place to implement specific sql finder or similar, use the actual ActiveRecord model for this.
12
+ # Methods in here lean more to complex joins and chaining model methods together to retrieve or store its business
13
+ # objects.
14
+ #
15
+ # This is also not the place to define business logic, see {EntityBase} for this.
16
+ #
17
+ # To make use of this extend your repository with it.
18
+ #
19
+ # @example How to extend properly
20
+ # module TestRepository
21
+ # extend DomainDrivenDesign::RepositoryBase
22
+ # end
23
+ #
24
+ # @ddd_base
25
+ # @author Robert Kranz
26
+ module DomainDrivenDesign
27
+ module RepositoryBase
28
+ # Constructs an entity from the given data. The given data could either be an ActiveRecord model, or another data
29
+ # container class. Please be careful to adjust your mapping accordingly if you change the type of the data.
30
+ def build_entity(data)
31
+ entity.new map_arguments(entity_mapping, data)
32
+ end
33
+
34
+ # Represents the managed entity class, will be retrieved by reflecting over the repository name.
35
+ # For example consider this repository.
36
+ #
37
+ # module TestFeature
38
+ # module TestRepository
39
+ # extend DomainDrivenDesign::RepositoryBase
40
+ # end
41
+ # end
42
+ #
43
+ # Calling the entity method (with send cause it's private) we receive the Test entity.
44
+ # TestFeature::TestRepository.send :entity #=> TestFeature::Test
45
+ #
46
+ # It's possible to set this to something else instead, but it's highly discouraged.
47
+ def entity
48
+ @entity ||= name.gsub('Repository', '').constantize
49
+ end
50
+
51
+ def entity=(class_name)
52
+ @entity = class_name
53
+ end
54
+
55
+ protected
56
+
57
+ # Can be used to explicitly demand, that a finder method should only be called,
58
+ # if the object requested surely exists.
59
+ # For example for use cases where something should be done with an existing customer.
60
+ def ensure_existence(record)
61
+ raise ActiveRecord::RecordNotFound unless record
62
+
63
+ record
64
+ end
65
+
66
+ # This can be used to set the mapping for the {#build_entity} method or to retrieve it.
67
+ # @example Only data methods
68
+ # module TestFeature
69
+ # module TestRepository
70
+ # extend DomainDrivenDesign::RepositoryBase
71
+ #
72
+ # entity_mapping id: id,
73
+ # name: :firstname
74
+ # end
75
+ # end
76
+ #
77
+ # @example With lambdas
78
+ # module TestFeature
79
+ # module TestRepository
80
+ # extend DomainDrivenDesign::RepositoryBase
81
+ #
82
+ # entity_mapping id: id,
83
+ # name: ->(data) { data.firstname + ' ' + data.lastname }
84
+ # end
85
+ # end
86
+ #
87
+ # @see #mapping_function
88
+ # @see #map_to_entity
89
+ #
90
+ # @overload entity_mapping(entity_mapping)
91
+ # Sets a value on key
92
+ # @param entity_mapping [Hash] mapping from entity attributes to data methods or callables
93
+ # @return [Hash]
94
+ # @overload entity_mapping
95
+ # Gets the entity mapping
96
+ # @return [Hash]
97
+ def entity_mapping(entity_mapping = nil)
98
+ return @entity_mapping unless entity_mapping
99
+
100
+ @entity_mapping = entity_mapping
101
+ end
102
+
103
+ # simple mapping helper which wraps a call to the given method name in a lambda
104
+ def mapping_function(sym)
105
+ ->(data) { send sym, data }
106
+ end
107
+
108
+ # simple mapping helper which wraps a call to the given entity repository in a lambda
109
+ def map_to_entity(entity, rule)
110
+ ->(data) { entity.repository.build_entity retrieve_value(rule, data) }
111
+ end
112
+
113
+ private
114
+
115
+ def map_arguments(mapping, data_object)
116
+ mapping.transform_values { |rule| retrieve_value(rule, data_object) }
117
+ end
118
+
119
+ def retrieve_value(rule, data)
120
+ if rule.is_a? Symbol
121
+ data.method(rule).call
122
+ elsif rule.respond_to? :call
123
+ rule.call data
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TeamFastlane
4
+ module DomainDrivenDesign
5
+ VERSION = '1.0.0'
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'team_fastlane/domain_driven_design/entity_base'
4
+ require 'team_fastlane/domain_driven_design/repository_base'
5
+ require 'team_fastlane/domain_driven_design/version'
6
+
7
+ module TeamFastlane
8
+ module DomainDrivenDesign
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: team_fastlane-domain_driven_design
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Team Fastlane
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-08-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files:
18
+ - README.adoc
19
+ - CHANGELOG.adoc
20
+ files:
21
+ - CHANGELOG.adoc
22
+ - README.adoc
23
+ - lib/team_fastlane/domain_driven_design.rb
24
+ - lib/team_fastlane/domain_driven_design/entity_base.rb
25
+ - lib/team_fastlane/domain_driven_design/repository_base.rb
26
+ - lib/team_fastlane/domain_driven_design/version.rb
27
+ homepage:
28
+ licenses:
29
+ - MIT
30
+ metadata:
31
+ rubygems_mfa_required: 'true'
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '2.7'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubygems_version: 3.4.10
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: Gem for an internal project
51
+ test_files: []