foobara 0.0.59 → 0.0.60

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b7be87ca46efe6904e7dbda58946be00c552a293d46dc792cd58754f25cbdd1
4
- data.tar.gz: '099e7378170b4855e04e09cadf67e86bf98532e752dd94b4c53bc0c394ab81bb'
3
+ metadata.gz: 66d592a242dce3e961e2ced3ff1a86de06c4d2a2689aa4855ad5a4ca7c5f53e9
4
+ data.tar.gz: c8b15ee8720b452e8e1d120372d51796ac901b733907f98b60d68dec02bf0dc7
5
5
  SHA512:
6
- metadata.gz: d9aeb29f8a439ba5eeaee556aac014b9c309284232d4f729ca4c8319baf5d2a09a4859f2fb5c6abb4d8bc969ba8e0c7a1627479bf64e0bca66d63332bdeac9b8
7
- data.tar.gz: d7da4a626362ccb44a79e3ac2eba674eecb467d89f2d247578bcc5f72931a451a43cd38996c7246855eb0149a18f029bbbd0ab21e251d01a8039f1328029287f
6
+ metadata.gz: 9993251bdfc128748b97119cafd9fd6f939c1f73617d5b5b0096d9171deaf24f8a125c653160b5576d44c1422fe63e2f044b29b235a2801668502170ea7c5c0e
7
+ data.tar.gz: 8fbcc20d12ff7a3dab1d0ba92c67df095ba73979d407c167816db610bc9ade966e8c6c2bfb4effebbf0ac3b9396554a420b772ec2c6a1a7603cd466602a08aec
data/CHANGELOG.md CHANGED
@@ -1,4 +1,10 @@
1
- ## [0.0.58] - 2025-02-20
1
+ ## [0.0.60] - 2025-02-22
2
+
3
+ - Now including domain mappers in the .depends_on call is optional. If you include any of them, you must include all
4
+ of them. Otherwise, you can include none of them and then no verification of them will be performed.
5
+ - Introduce a ranking/scoring system of domain mapper matches to help with certain ambiguous situations
6
+
7
+ ## [0.0.59] - 2025-02-20
2
8
 
3
9
  - DomainMapper no longer inherits from Command. Instead, both include CommandPatternImplementation mixin
4
10
 
@@ -45,13 +45,33 @@ module Foobara
45
45
  end
46
46
  end
47
47
 
48
+ module ClassMethods
49
+ def domain_map_criteria
50
+ return @domain_map_criteria if @domain_map_criteria
51
+
52
+ has_explicit_mapper_deps = depends_on.any? do |c|
53
+ foobara_lookup_domain_mapper(c)
54
+ end
55
+
56
+ @domain_map_criteria = if has_explicit_mapper_deps
57
+ ->(mapper) { depends_on?(mapper) }
58
+ end
59
+ end
60
+ end
61
+
48
62
  include Concern
49
63
 
50
64
  def run_mapped_subcommand!(subcommand_class, unmapped_inputs = {}, to = nil)
65
+ unless subcommand_class
66
+ # :nocov:
67
+ raise ArgumentError, "subcommand_class is required"
68
+ # :nocov:
69
+ end
70
+
51
71
  mapped_something = false
52
72
  no_mapper_found = nil
53
73
 
54
- criteria = ->(mapper) { self.class.depends_on?(mapper) }
74
+ criteria = self.class.domain_map_criteria
55
75
 
56
76
  inputs_mapper = self.class.domain.lookup_matching_domain_mapper(
57
77
  from: unmapped_inputs,
@@ -88,7 +108,7 @@ module Foobara
88
108
  result_mapper = self.class.domain.lookup_matching_domain_mapper(
89
109
  from: result,
90
110
  to:,
91
- criteria: ->(domain_mapper) { self.class.depends_on?(domain_mapper) },
111
+ criteria:,
92
112
  strict: true
93
113
  )
94
114
  end
@@ -99,24 +119,26 @@ module Foobara
99
119
  end
100
120
 
101
121
  unless mapped_something
102
- mapper = self.class.domain.lookup_matching_domain_mapper(
103
- from: unmapped_inputs,
104
- to: subcommand_class,
105
- strict: true
106
- )
107
-
108
- if mapper
109
- raise ForgotToDependOnDomainMapperError, mapper
110
- end
111
-
112
- mapper = self.class.domain.lookup_matching_domain_mapper(
113
- from: subcommand_class.result_type,
114
- to:,
115
- strict: true
116
- )
117
-
118
- if mapper
119
- raise ForgotToDependOnDomainMapperError, mapper
122
+ if criteria
123
+ mapper = self.class.domain.lookup_matching_domain_mapper(
124
+ from: unmapped_inputs,
125
+ to: subcommand_class,
126
+ strict: true
127
+ )
128
+
129
+ if mapper
130
+ raise ForgotToDependOnDomainMapperError, mapper
131
+ end
132
+
133
+ mapper = self.class.domain.lookup_matching_domain_mapper(
134
+ from: subcommand_class.result_type,
135
+ to:,
136
+ strict: true
137
+ )
138
+
139
+ if mapper
140
+ raise ForgotToDependOnDomainMapperError, mapper
141
+ end
120
142
  end
121
143
 
122
144
  raise NoDomainMapperFoundError.new(subcommand_class, to)
@@ -125,12 +147,12 @@ module Foobara
125
147
  result
126
148
  end
127
149
 
128
- def domain_map(...)
129
- self.class.domain.foobara_domain_map(...)
150
+ def domain_map(*, **, &)
151
+ self.class.domain.foobara_domain_map(*, criteria: self.class.domain_map_criteria, strict: true, **, &)
130
152
  end
131
153
 
132
- def domain_map!(...)
133
- self.class.domain.foobara_domain_map!(...)
154
+ def domain_map!(*, **, &)
155
+ self.class.domain.foobara_domain_map!(*, criteria: self.class.domain_map_criteria, strict: true, **, &)
134
156
  end
135
157
  end
136
158
  end
@@ -79,6 +79,10 @@ module Foobara
79
79
  end
80
80
 
81
81
  def verify_depends_on!(subcommand_class)
82
+ unless domain_map_criteria
83
+ return if subcommand_class < DomainMapper
84
+ end
85
+
82
86
  unless depends_on?(subcommand_class)
83
87
  # :nocov:
84
88
  raise SubcommandNotRegistered, "Need to declare #{subcommand_class} on #{self} with .depends_on"
@@ -133,7 +133,7 @@ module Foobara
133
133
  super
134
134
  end
135
135
 
136
- def foobara_domain_map(value, to: nil, strict: false, **opts)
136
+ def foobara_domain_map(value, to: nil, strict: false, criteria: nil, should_raise: false, **opts)
137
137
  invalid_keys = opts.keys - [:from]
138
138
 
139
139
  if invalid_keys.any?
@@ -144,23 +144,27 @@ module Foobara
144
144
 
145
145
  from = if opts.key?(:from)
146
146
  opts[:from]
147
- elsif !strict
147
+ else
148
+ try_nil = true
148
149
  value
149
150
  end
150
151
 
151
- mapper = lookup_matching_domain_mapper(from:, to:, strict:)
152
-
153
- mapper&.map!(value)
154
- end
152
+ mapper = lookup_matching_domain_mapper(from:, to:, criteria:, strict:)
155
153
 
156
- def foobara_domain_map!(value, from: value, to: nil, strict: false)
157
- mapper = lookup_matching_domain_mapper(from:, to:, strict:)
154
+ if try_nil
155
+ from = nil
156
+ mapper = lookup_matching_domain_mapper(from:, to:, criteria:, strict:)
157
+ end
158
158
 
159
- unless mapper
159
+ if mapper
160
+ mapper.map!(value)
161
+ elsif should_raise
160
162
  raise Foobara::DomainMapperLookups::NoDomainMapperFoundError.new(from, to, value:)
161
163
  end
164
+ end
162
165
 
163
- mapper.map!(value)
166
+ def foobara_domain_map!(value, from: nil, to: nil, criteria: nil, strict: false)
167
+ foobara_domain_map(value, from:, to:, criteria:, strict:, should_raise: true)
164
168
  end
165
169
 
166
170
  def foobara_domain_name
@@ -1,4 +1,7 @@
1
1
  module Foobara
2
+ # NOTE: If you depend_on a domain mapper in a command, then you need to depend on all domain mappers
3
+ # that that command uses. Or you can just exclude all of them in which case Foobara won't enforce
4
+ # explicit depends_on of domain mappers.
2
5
  class DomainMapper
3
6
  include CommandPatternImplementation
4
7
 
@@ -38,22 +41,37 @@ module Foobara
38
41
  end
39
42
 
40
43
  def matches?(type_indicator, value)
41
- return true if type_indicator.nil? || value.nil? || type_indicator == value
44
+ match_score(type_indicator, value)&.>(0)
45
+ end
46
+
47
+ def applicable_score(from_value, to_value)
48
+ [*match_score(from_type, from_value), *match_score(to_type, to_value)].sum
49
+ end
50
+
51
+ def match_score(type_indicator, value)
52
+ return 1 if type_indicator.nil? || value.nil?
53
+ return 20 if type_indicator == value
42
54
 
43
55
  type = object_to_type(type_indicator)
44
56
 
45
- return true if type.nil? || type == value
46
- return true if type.applicable?(value) && type.process_value(value).success?
57
+ return 1 if type.nil?
58
+ return 9 if type == value
59
+
60
+ return 5 if type.applicable?(value) && type.process_value(value).success?
47
61
 
48
62
  if value.is_a?(Types::Type)
49
63
  if !value.registered? && !type.registered?
50
- value.declaration_data == type.declaration_data
64
+ if value.declaration_data == type.declaration_data
65
+ 8
66
+ end
51
67
  end
52
68
  else
53
69
  value_type = object_to_type(value)
54
70
 
55
71
  if value_type
56
- matches?(type, value_type)
72
+ if matches?(type, value_type)
73
+ 6
74
+ end
57
75
  end
58
76
  end
59
77
  end
@@ -56,7 +56,25 @@ module Foobara
56
56
  end
57
57
 
58
58
  if candidates.size > 1
59
- raise AmbiguousDomainMapperError.new(from, to, candidates)
59
+ best = []
60
+ best_score = 0
61
+
62
+ candidates.each do |mapper|
63
+ score = mapper.applicable_score(from, to)
64
+
65
+ if score > best_score
66
+ best = [mapper]
67
+ best_score = score
68
+ elsif score == best_score
69
+ best << mapper
70
+ end
71
+ end
72
+
73
+ if best.size > 1
74
+ raise AmbiguousDomainMapperError.new(from, to, candidates)
75
+ else
76
+ candidates = best
77
+ end
60
78
  end
61
79
 
62
80
  value = candidates.first
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foobara
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.59
4
+ version: 0.0.60
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-20 00:00:00.000000000 Z
10
+ date: 2025-02-21 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bigdecimal