foobara 0.0.36 → 0.0.37
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +11 -1
- data/projects/command/src/concerns/domain_mappers.rb +2 -2
- data/projects/domain/lib/foobara/domain.rb +0 -6
- data/projects/domain/src/domain_module_extension.rb +6 -14
- data/projects/domain_mapper/lib/foobara/domain_mapper.rb +10 -0
- data/projects/domain_mapper/src/domain_mapper.rb +106 -0
- data/projects/{domain/src/domain_mapper/registry.rb → domain_mapper/src/domain_mapper_lookups.rb} +17 -19
- data/projects/foobara/lib/foobara/all.rb +3 -3
- metadata +6 -4
- data/projects/domain/src/domain_mapper.rb +0 -166
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b44ab7dcd4b578702ab3f310f19a631fc804b06d46c804212b700f1cda1ef98f
|
4
|
+
data.tar.gz: e45e7c10ae665a2e4fd3a06c366018466ec26c7b31615ff9b9dca79dac42ea1d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c68ee020e1185a6446d4880a1b8557809a82bcb46cf2ad4309dcf965d850e9803cf2da8669a8d45a4a7cc5be2801756c581f4b9ca1c1696dd521f807c95618cc
|
7
|
+
data.tar.gz: 4846196d83db2d9fc9ab0b56e20092eda1abf8c4722a1f7a5dfc1c05c31981696b4f5787708252931c36f127edf745795e4386197810fbc42b55b56fd8ad3c37
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1518,8 +1518,18 @@ Note that we can automatically map `animal` to CreateCapybara inputs by calling
|
|
1518
1518
|
Let's play with it:
|
1519
1519
|
|
1520
1520
|
```irb
|
1521
|
-
|
1521
|
+
> basil = FoobaraDemo::CapyCafe::ImportAnimal.run!(animal: { species: :capybara, first_name: "Basil", last_name: "Doe", birthday: "1000-01-01" })
|
1522
|
+
==> <Capybara:3>
|
1523
|
+
> basil.age
|
1524
|
+
==> 1024
|
1525
|
+
> basil.id
|
1526
|
+
==> 3
|
1527
|
+
> FoobaraDemo::CapyCafe::IncrementAge.run!(capybara: basil)
|
1528
|
+
==> <Capybara:3>
|
1529
|
+
> FoobaraDemo::CapyCafe::FindCapybara.run!(id: basil).age
|
1530
|
+
==> 1025
|
1522
1531
|
```
|
1532
|
+
|
1523
1533
|
TODO
|
1524
1534
|
|
1525
1535
|
### Code Generators
|
@@ -23,13 +23,13 @@ module Foobara
|
|
23
23
|
result = run_subcommand!(subcommand_class, inputs)
|
24
24
|
|
25
25
|
if has_result_type
|
26
|
-
result_mapper = self.class.domain.
|
26
|
+
result_mapper = self.class.domain.lookup_matching_domain_mapper!(
|
27
27
|
from: result,
|
28
28
|
to: result_type,
|
29
29
|
strict: true
|
30
30
|
)
|
31
31
|
|
32
|
-
result = result_mapper.map(result)
|
32
|
+
result = result_mapper.map!(result)
|
33
33
|
end
|
34
34
|
|
35
35
|
result
|
@@ -14,12 +14,6 @@ module Foobara
|
|
14
14
|
Namespace.global.foobara_add_category(:organization) { is_a?(Module) && foobara_organization? }
|
15
15
|
Namespace.global.foobara_add_category(:domain) { is_a?(Module) && foobara_domain? }
|
16
16
|
end
|
17
|
-
|
18
|
-
def reset_all
|
19
|
-
if Foobara::DomainMapper.instance_variable_defined?(:@foobara_domain_mappers_to_process)
|
20
|
-
Foobara::DomainMapper.remove_instance_variable(:@foobara_domain_mappers_to_process)
|
21
|
-
end
|
22
|
-
end
|
23
17
|
end
|
24
18
|
end
|
25
19
|
end
|
@@ -148,27 +148,19 @@ module Foobara
|
|
148
148
|
value
|
149
149
|
end
|
150
150
|
|
151
|
-
mapper =
|
151
|
+
mapper = lookup_matching_domain_mapper(from:, to:, strict:)
|
152
152
|
|
153
|
-
mapper&.
|
153
|
+
mapper&.map!(value)
|
154
154
|
end
|
155
155
|
|
156
156
|
def foobara_domain_map!(value, from: value, to: nil, strict: false)
|
157
|
-
mapper =
|
157
|
+
mapper = lookup_matching_domain_mapper(from:, to:, strict:)
|
158
|
+
|
158
159
|
unless mapper
|
159
|
-
raise Foobara::
|
160
|
+
raise Foobara::DomainMapperLookups::NoDomainMapperFoundError.new(from, to, value:)
|
160
161
|
end
|
161
162
|
|
162
|
-
mapper.
|
163
|
-
end
|
164
|
-
|
165
|
-
def foobara_domain_mapper(mapper)
|
166
|
-
foobara_domain_mapper_registry(skip_check: true).register(mapper)
|
167
|
-
end
|
168
|
-
|
169
|
-
def foobara_domain_mapper_registry(skip_check: false)
|
170
|
-
Foobara::DomainMapper.foobara_process_domain_mappers unless skip_check
|
171
|
-
@foobara_domain_mapper_registry ||= DomainMapper::Registry.new
|
163
|
+
mapper.map!(value)
|
172
164
|
end
|
173
165
|
|
174
166
|
def foobara_domain_name
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Foobara
|
2
|
+
# TODO: would be nice to inherit from something other than Command. Can we hoist a bunch of common behavior up
|
3
|
+
# out of Command into some other class maybe called Service or Runnable or something?
|
4
|
+
class DomainMapper < Foobara::Command
|
5
|
+
class << self
|
6
|
+
def map(value)
|
7
|
+
new(from: value).run
|
8
|
+
end
|
9
|
+
|
10
|
+
def map!(value)
|
11
|
+
new(from: value).run!
|
12
|
+
end
|
13
|
+
|
14
|
+
# A bit hacky because Command only supports attributes inputs at the moment, ugg.
|
15
|
+
def from(...)
|
16
|
+
from_type = args_to_type(...)
|
17
|
+
|
18
|
+
inputs do
|
19
|
+
from from_type, :required
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to(...)
|
24
|
+
result_type = args_to_type(...)
|
25
|
+
result(result_type)
|
26
|
+
end
|
27
|
+
|
28
|
+
def from_type
|
29
|
+
inputs_type.element_types[:from]
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_type
|
33
|
+
result_type
|
34
|
+
end
|
35
|
+
|
36
|
+
def applicable?(from_value, to_value)
|
37
|
+
matches?(from_type, from_value) && matches?(to_type, to_value)
|
38
|
+
end
|
39
|
+
|
40
|
+
def matches?(type_indicator, value)
|
41
|
+
return true if type_indicator.nil? || value.nil? || type_indicator == value
|
42
|
+
|
43
|
+
type = object_to_type(type_indicator)
|
44
|
+
|
45
|
+
return true if type.nil? || type == value
|
46
|
+
return true if type.applicable?(value) && type.process_value(value).success?
|
47
|
+
|
48
|
+
if value.is_a?(Types::Type)
|
49
|
+
if !value.registered? && !type.registered?
|
50
|
+
value.declaration_data == type.declaration_data
|
51
|
+
end
|
52
|
+
else
|
53
|
+
value_type = object_to_type(value)
|
54
|
+
|
55
|
+
if value_type
|
56
|
+
matches?(type, value_type)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# TODO: should this be somewhere more general-purpose?
|
62
|
+
def args_to_type(*args, **opts, &block)
|
63
|
+
if args.size == 1 && opts.empty? && block.nil?
|
64
|
+
object_to_type(args.first)
|
65
|
+
else
|
66
|
+
domain.foobara_type_from_declaration(*args, **opts, &block)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def object_to_type(object)
|
71
|
+
if object
|
72
|
+
if object.is_a?(::Class)
|
73
|
+
if object < Foobara::Model
|
74
|
+
object.model_type
|
75
|
+
elsif object < Foobara::Command
|
76
|
+
object.inputs_type
|
77
|
+
else
|
78
|
+
domain.foobara_type_from_declaration(object)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
case object
|
82
|
+
when Types::Type
|
83
|
+
object
|
84
|
+
when ::Symbol
|
85
|
+
domain.foobara_lookup_type!(object)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def execute
|
93
|
+
map
|
94
|
+
end
|
95
|
+
|
96
|
+
def from
|
97
|
+
inputs[:from]
|
98
|
+
end
|
99
|
+
|
100
|
+
def map
|
101
|
+
# :nocov:
|
102
|
+
raise "subclass responsibility"
|
103
|
+
# :nocov:
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/projects/{domain/src/domain_mapper/registry.rb → domain_mapper/src/domain_mapper_lookups.rb}
RENAMED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Foobara
|
2
|
-
|
2
|
+
module DomainMapperLookups
|
3
3
|
class NoDomainMapperFoundError < StandardError
|
4
4
|
attr_accessor :value, :from, :to, :has_value
|
5
5
|
|
@@ -25,30 +25,28 @@ module Foobara
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
class
|
29
|
-
|
30
|
-
attr_accessor :candidates, :from, :to
|
28
|
+
class AmbiguousDomainMapperError < StandardError
|
29
|
+
attr_accessor :candidates, :from, :to
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
def initialize(from, to, candidates)
|
32
|
+
self.to = to
|
33
|
+
self.from = from
|
34
|
+
self.candidates = [*candidates].flatten
|
36
35
|
|
37
|
-
|
38
|
-
end
|
36
|
+
super("#{candidates.size} ambiguous candidates found.")
|
39
37
|
end
|
38
|
+
end
|
40
39
|
|
41
|
-
|
42
|
-
mappers << mapper
|
43
|
-
end
|
40
|
+
include Concern
|
44
41
|
|
45
|
-
|
46
|
-
|
42
|
+
module ClassMethods
|
43
|
+
def lookup_matching_domain_mapper!(from: nil, to: nil, strict: false)
|
44
|
+
result = lookup_matching_domain_mapper(from:, to:, strict:)
|
47
45
|
|
48
46
|
result || raise(NoDomainMapperFoundError.new(from, to))
|
49
47
|
end
|
50
48
|
|
51
|
-
def
|
49
|
+
def lookup_matching_domain_mapper(from: nil, to: nil, strict: false)
|
52
50
|
candidates = mappers.select do |mapper|
|
53
51
|
mapper.applicable?(from, to)
|
54
52
|
end
|
@@ -63,15 +61,15 @@ module Foobara
|
|
63
61
|
|
64
62
|
unless strict
|
65
63
|
if from
|
66
|
-
|
64
|
+
lookup_matching_domain_mapper(from: nil, to:)
|
67
65
|
elsif to
|
68
|
-
|
66
|
+
lookup_matching_domain_mapper(from:, to: nil)
|
69
67
|
end
|
70
68
|
end
|
71
69
|
end
|
72
70
|
|
73
71
|
def mappers
|
74
|
-
@mappers ||=
|
72
|
+
@mappers ||= foobara_all_domain_mapper
|
75
73
|
end
|
76
74
|
end
|
77
75
|
end
|
@@ -18,12 +18,11 @@ module Foobara
|
|
18
18
|
"state_machine",
|
19
19
|
"namespace"
|
20
20
|
|
21
|
-
project "domain"
|
22
|
-
|
23
21
|
# various components of the foobara framework that have some level of coupling.
|
24
22
|
# for example, Error in common knows about (or could be implemented to know about)
|
25
23
|
# type declarations to expose its context type.
|
26
|
-
projects "
|
24
|
+
projects "domain",
|
25
|
+
"common",
|
27
26
|
"value",
|
28
27
|
"types",
|
29
28
|
"type_declarations",
|
@@ -32,6 +31,7 @@ module Foobara
|
|
32
31
|
"detached_entity",
|
33
32
|
"entity",
|
34
33
|
"command",
|
34
|
+
"domain_mapper",
|
35
35
|
"persistence",
|
36
36
|
"in_memory_crud_driver_minimal",
|
37
37
|
"in_memory_crud_driver",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foobara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.37
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: foobara-util
|
@@ -193,8 +193,6 @@ files:
|
|
193
193
|
- projects/detached_entity/src/extensions/type_declarations/handlers/extend_detached_entity_type_declaration/validate_primary_key_references_attribute.rb
|
194
194
|
- projects/domain/lib/foobara/domain.rb
|
195
195
|
- projects/domain/src/domain.rb
|
196
|
-
- projects/domain/src/domain_mapper.rb
|
197
|
-
- projects/domain/src/domain_mapper/registry.rb
|
198
196
|
- projects/domain/src/domain_module_extension.rb
|
199
197
|
- projects/domain/src/extensions/foobara.rb
|
200
198
|
- projects/domain/src/global_domain.rb
|
@@ -204,6 +202,9 @@ files:
|
|
204
202
|
- projects/domain/src/module_extension.rb
|
205
203
|
- projects/domain/src/organization.rb
|
206
204
|
- projects/domain/src/organization_module_extension.rb
|
205
|
+
- projects/domain_mapper/lib/foobara/domain_mapper.rb
|
206
|
+
- projects/domain_mapper/src/domain_mapper.rb
|
207
|
+
- projects/domain_mapper/src/domain_mapper_lookups.rb
|
207
208
|
- projects/entity/lib/foobara/entity.rb
|
208
209
|
- projects/entity/src/concerns/attribute_helpers.rb
|
209
210
|
- projects/entity/src/concerns/attributes.rb
|
@@ -393,6 +394,7 @@ require_paths:
|
|
393
394
|
- "./projects/delegate/lib"
|
394
395
|
- "./projects/detached_entity/lib"
|
395
396
|
- "./projects/domain/lib"
|
397
|
+
- "./projects/domain_mapper/lib"
|
396
398
|
- "./projects/entity/lib"
|
397
399
|
- "./projects/enumerated/lib"
|
398
400
|
- "./projects/foobara/lib"
|
@@ -1,166 +0,0 @@
|
|
1
|
-
module Foobara
|
2
|
-
class DomainMapper
|
3
|
-
class << self
|
4
|
-
def call(value)
|
5
|
-
instance.call(value)
|
6
|
-
end
|
7
|
-
|
8
|
-
def from(*args)
|
9
|
-
if args.empty?
|
10
|
-
@from
|
11
|
-
else
|
12
|
-
if args.size > 1
|
13
|
-
# :nocov:
|
14
|
-
raise ArgumentError, "only one argument allowed"
|
15
|
-
# :nocov:
|
16
|
-
end
|
17
|
-
|
18
|
-
@from = args.first
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def to(*args)
|
23
|
-
if args.empty?
|
24
|
-
@to
|
25
|
-
else
|
26
|
-
if args.size > 1
|
27
|
-
# :nocov:
|
28
|
-
raise ArgumentError, "only one argument allowed"
|
29
|
-
# :nocov:
|
30
|
-
end
|
31
|
-
|
32
|
-
@to = args.first
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def from_type
|
37
|
-
return @from_type if defined?(@from_type)
|
38
|
-
|
39
|
-
@from_type = object_to_type(from)
|
40
|
-
end
|
41
|
-
|
42
|
-
def to_type
|
43
|
-
return @to_type if defined?(@to_type)
|
44
|
-
|
45
|
-
@to_type = object_to_type(to)
|
46
|
-
end
|
47
|
-
|
48
|
-
def instance
|
49
|
-
@instance ||= new
|
50
|
-
end
|
51
|
-
|
52
|
-
def inherited(subclass)
|
53
|
-
foobara_domain_mapper_to_process(subclass.instance)
|
54
|
-
|
55
|
-
super
|
56
|
-
end
|
57
|
-
|
58
|
-
def foobara_domain_mapper_to_process(mapper)
|
59
|
-
foobara_domain_mappers_to_process << mapper
|
60
|
-
end
|
61
|
-
|
62
|
-
def foobara_domain_mappers_to_process
|
63
|
-
@foobara_domain_mappers_to_process ||= []
|
64
|
-
end
|
65
|
-
|
66
|
-
def foobara_process_domain_mappers
|
67
|
-
if defined?(@foobara_domain_mappers_to_process)
|
68
|
-
@foobara_domain_mappers_to_process.each do |mapper|
|
69
|
-
mapper.domain.foobara_domain_mapper(mapper)
|
70
|
-
end
|
71
|
-
remove_instance_variable(:@foobara_domain_mappers_to_process)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def domain
|
76
|
-
candidate = self
|
77
|
-
|
78
|
-
loop do
|
79
|
-
candidate = Util.module_for(candidate)
|
80
|
-
|
81
|
-
if candidate.nil?
|
82
|
-
# :nocov:
|
83
|
-
raise "Domain mapper must be scoped within a domain but #{self.class.name} is not in a domain"
|
84
|
-
# :nocov:
|
85
|
-
elsif candidate.foobara_domain?
|
86
|
-
return candidate
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def matches?(type_indicator, value)
|
92
|
-
return true if type_indicator.nil? || value.nil? || type_indicator == value
|
93
|
-
|
94
|
-
type = object_to_type(type_indicator)
|
95
|
-
|
96
|
-
return true if type.nil? || type == value
|
97
|
-
return true if type.applicable?(value) && type.process_value(value).success?
|
98
|
-
|
99
|
-
if value.is_a?(Types::Type)
|
100
|
-
if !value.registered? && !type.registered?
|
101
|
-
value.declaration_data == type.declaration_data
|
102
|
-
end
|
103
|
-
else
|
104
|
-
value_type = object_to_type(value)
|
105
|
-
|
106
|
-
if value_type
|
107
|
-
matches?(type, value_type)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def object_to_type(object)
|
113
|
-
if object
|
114
|
-
if object.is_a?(::Class)
|
115
|
-
if object < Foobara::Model
|
116
|
-
object.model_type
|
117
|
-
elsif object < Foobara::Command
|
118
|
-
object.inputs_type
|
119
|
-
else
|
120
|
-
domain.foobara_type_from_declaration(object)
|
121
|
-
end
|
122
|
-
else
|
123
|
-
case object
|
124
|
-
when Types::Type
|
125
|
-
object
|
126
|
-
when ::Symbol
|
127
|
-
domain.foobara_lookup_type!(object)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def from_type
|
135
|
-
self.class.from_type
|
136
|
-
end
|
137
|
-
|
138
|
-
def to_type
|
139
|
-
self.class.to_type
|
140
|
-
end
|
141
|
-
|
142
|
-
def call(from_value)
|
143
|
-
from_value = from_type.process_value!(from_value)
|
144
|
-
|
145
|
-
mapped_value = map(from_value)
|
146
|
-
|
147
|
-
to_type.process_value!(mapped_value)
|
148
|
-
end
|
149
|
-
|
150
|
-
# TODO: can we make _from_value passed to #initialize instead? That way it doesn't have to be passed around
|
151
|
-
# between various helper methods
|
152
|
-
def map(_from_value)
|
153
|
-
# :nocov:
|
154
|
-
raise "subclass repsonsibility"
|
155
|
-
# :nocov:
|
156
|
-
end
|
157
|
-
|
158
|
-
def applicable?(from_value, to_value)
|
159
|
-
self.class.matches?(from_type, from_value) && self.class.matches?(to_type, to_value)
|
160
|
-
end
|
161
|
-
|
162
|
-
def domain
|
163
|
-
self.class.domain
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|