foobara 0.0.58 → 0.0.60

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73dea1ae2bd36b295db67678c8d5717458a386b0a1bd11fbf5fffd4adf117a6a
4
- data.tar.gz: 1b99f0f9e5294302d13061240696c05d7c6542291aaaec8f6049c8f5eef69800
3
+ metadata.gz: 66d592a242dce3e961e2ced3ff1a86de06c4d2a2689aa4855ad5a4ca7c5f53e9
4
+ data.tar.gz: c8b15ee8720b452e8e1d120372d51796ac901b733907f98b60d68dec02bf0dc7
5
5
  SHA512:
6
- metadata.gz: b03089aee29a4d85bebc9dccbe8bfe32b3891fa81689fda604f28ab0d3c9909f516b34f73c6370bea9c3b4da3a49569cd9da57319245b482ada56142b0b8bf05
7
- data.tar.gz: 931145ba8982bb71388135b95262b321f9b0ac3f1b9dc77ee8cd64e5f701083e0f46fb0332bb5844fb642ddfcebe268c3e6e12888a67f08f82fa574788b00a18
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,5 +1,5 @@
1
1
  module Foobara
2
- class DomainMapper < Foobara::Command
2
+ class DomainMapper
3
3
  class << self
4
4
  def install!
5
5
  Namespace.global.foobara_add_category_for_subclass_of(:domain_mapper, self)
@@ -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.58
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