foobara 0.5.3 → 0.5.5

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: 2ee98e7512333f9d3e069e3fe8a6c7cbbe2c5f27f2d918a7397cdaeed64b077f
4
- data.tar.gz: 6fd8d38c4a30d1b0721fc241b6d09ef890e719fccd795b40d8319a7d77a82c56
3
+ metadata.gz: 6527e62790180b1aeb2f98e069655d8ac72750fbff834fc63e9b75a01c35cb4e
4
+ data.tar.gz: a769dd2a642b71bd401dabe3c0917a1fa128069f2a7987ff79df633765ae93ad
5
5
  SHA512:
6
- metadata.gz: 0b9e6f6ba2685ee2462811158fefc0d30f4c83122a3701e8b5ab06e2188d1d9c3ce5775846af2a4b4e15ffb7007d19947894fd9e6d4c3a98b92d2636b5b1bbc8
7
- data.tar.gz: 14db098dc24293b84247e8a4d44913c902aae7f4058ca148698587c14c7d9f971d5d1e97b04ad94f4ae8b80007cac1b6881348c03d13b1ec41c4213b3a1c2892
6
+ metadata.gz: '0359999dd32f56220e88e3e860ff7e415a4fd2b978bf83768868b1e10b0013c9e02597731890d1a2abb2fd11c1e288e1c1e8056b3bd6bf7a11bc9589af371ae3'
7
+ data.tar.gz: 33cf7a4428854d3016c1ccda045820e6da47a268e34f5bb05505bcc878ecdeff909caf1c411505d97849f4ffd69cc6e9c1c51a046ee92f6ee7ac2afe1919b359
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # [0.5.5] - 2026-02-19
2
+
3
+ - Fix bug where WeakObjectSet#delete could fail after deactivation
4
+ - Fix bug where arrays of allowed rules run in the wrong context
5
+ - Remove awkward proc defaults from manifest
6
+
7
+ # [0.5.4] - 2026-02-16
8
+
9
+ - Fix bug where adding a desugarizer to a subclass had no effect
10
+ - Add support for requiring allow_if: by default
11
+
1
12
  # [0.5.3] - 2026-02-12
2
13
 
3
14
  - Allow registering an allowed rule on an instance of a connector not just its class
@@ -60,16 +60,17 @@ module Foobara
60
60
  possible_errors:,
61
61
  depends_on:,
62
62
  # TODO: allow inputs type to be nil or really any type?
63
- inputs_type: inputs_type&.reference_or_declaration_data || GlobalDomain.foobara_type_from_declaration(
64
- type: "::attributes",
65
- element_type_declarations: {},
66
- required: []
67
- ).declaration_data
63
+ inputs_type: inputs_type&.reference_or_declaration_data_for_manifest ||
64
+ GlobalDomain.foobara_type_from_declaration(
65
+ type: "::attributes",
66
+ element_type_declarations: {},
67
+ required: []
68
+ ).declaration_data
68
69
  ).merge(description:)
69
70
 
70
71
  if result_type
71
72
  # TODO: find a way to represent literal types like "nil"
72
- h[:result_type] = result_type.reference_or_declaration_data
73
+ h[:result_type] = result_type.reference_or_declaration_data_for_manifest
73
74
  end
74
75
 
75
76
  super.merge(h)
@@ -488,6 +488,20 @@ RSpec.describe Foobara::CommandConnector do
488
488
  expect(response.body).to eq("8")
489
489
  end
490
490
 
491
+ context "when requires_allowed_rule" do
492
+ let(:command_connector) do
493
+ described_class.new(
494
+ authenticator:,
495
+ default_serializers:,
496
+ requires_allowed_rule: true
497
+ )
498
+ end
499
+
500
+ it "gives a relevant error" do
501
+ expect { response }.to raise_error(Foobara::CommandConnector::NoAllowedRuleGivenError)
502
+ end
503
+ end
504
+
491
505
  context "with default transformers" do
492
506
  before do
493
507
  identity = proc { |x| x }
@@ -2074,14 +2088,14 @@ RSpec.describe Foobara::CommandConnector do
2074
2088
  end
2075
2089
  let(:command_connector) do
2076
2090
  rule = allowed_rule_d
2077
- command_connector_class_d.new do
2091
+ command_connector_class_d.new(requires_allowed_rule: true) do
2078
2092
  register_allowed_rule :d, rule
2079
2093
  end
2080
2094
  end
2081
2095
 
2082
2096
  it "puts the expected allowed rules on the command connector" do
2083
2097
  command_connector.connect(command_class, suffix: "A", allow_if: :a)
2084
- command_connector.connect(command_class, suffix: "B")
2098
+ command_connector.connect(command_class, suffix: "B", allow_if: :always)
2085
2099
  command_connector.connect(command_class, suffix: "C", allowed_rule: :c)
2086
2100
  command_connector.connect(command_class, suffix: "D", allowed_rule: :d)
2087
2101
 
@@ -2091,7 +2105,7 @@ RSpec.describe Foobara::CommandConnector do
2091
2105
 
2092
2106
  response = command_connector.run(full_command_name: "ComputeExponentB", action:, inputs:)
2093
2107
  expect(response.status).to be(0)
2094
- expect(response.command.allowed_rule).to be_nil
2108
+ expect(response.command.allowed_rule).to be(described_class.always_allowed_rule)
2095
2109
 
2096
2110
  response = command_connector.run(full_command_name: "ComputeExponentC", action:, inputs:)
2097
2111
  expect(response.status).to be(1)
@@ -36,13 +36,13 @@ module Foobara
36
36
  end
37
37
 
38
38
  def desugarizers
39
- @desugarizers ||= []
39
+ return @desugarizers if defined?(@desugarizers)
40
40
 
41
- if superclass == Object
42
- @desugarizers
43
- else
44
- @desugarizers + superclass.desugarizers
45
- end
41
+ @desugarizers = if superclass == Object
42
+ []
43
+ else
44
+ superclass.desugarizers.dup
45
+ end
46
46
  end
47
47
  end
48
48
  end
@@ -0,0 +1,6 @@
1
+ module Foobara
2
+ class CommandConnector
3
+ class NoAllowedRuleGivenError < StandardError
4
+ end
5
+ end
6
+ end
@@ -178,10 +178,19 @@ module Foobara
178
178
  def build_auth_mapper(to_type, &)
179
179
  TypeDeclarations::TypedTransformer.subclass(to: to_type, &).instance
180
180
  end
181
+
182
+ def always_allowed_rule
183
+ # maybe move AllowedRule to CommandConnector:: instead of
184
+ # CommandRegistry:: which is more of an implementation detail?
185
+ @always_allowed_rule ||= CommandRegistry::AllowedRule.new(
186
+ symbol: :always,
187
+ explanation: "This always passes. Used to override allowed_rule_missing."
188
+ ) { true }
189
+ end
181
190
  end
182
191
 
183
192
  attr_accessor :command_registry, :authenticator, :capture_unknown_error, :name,
184
- :auth_map
193
+ :auth_map, :requires_allowed_rule
185
194
 
186
195
  def initialize(name: nil,
187
196
  authenticator: nil,
@@ -190,6 +199,7 @@ module Foobara
190
199
  default_pre_commit_transformers: nil,
191
200
  auth_map: nil,
192
201
  current_user: nil,
202
+ requires_allowed_rule: false,
193
203
  &block)
194
204
  authenticator = self.class.to_authenticator(authenticator)
195
205
 
@@ -214,6 +224,11 @@ module Foobara
214
224
  add_default_serializer(serializer)
215
225
  end
216
226
 
227
+ if requires_allowed_rule
228
+ self.requires_allowed_rule = requires_allowed_rule
229
+ register_allowed_rule(CommandConnector.always_allowed_rule)
230
+ end
231
+
217
232
  Util.array(default_pre_commit_transformers).each do |pre_commit_transformer|
218
233
  add_default_pre_commit_transformer(pre_commit_transformer)
219
234
  end
@@ -232,6 +247,7 @@ module Foobara
232
247
  end
233
248
 
234
249
  # TODO: should this be the official way to connect a command instead of #connect ?
250
+ # Probably not. But what about #export instead?
235
251
  def command(...) = connect(...)
236
252
 
237
253
  def connect(*args, **opts)
@@ -616,6 +632,16 @@ module Foobara
616
632
  def run_command(request)
617
633
  command = request.command
618
634
 
635
+ if requires_allowed_rule
636
+ unless command.allowed_rule
637
+ raise NoAllowedRuleGivenError,
638
+ "Must connect #{command.full_command_name} with an `allowed_if:` " \
639
+ "because `requires_allowed_rule` is true. You can use `allow_if: :always` if want to always allow " \
640
+ "this command to be ran or you can also use `requires_allowed_rule: false` " \
641
+ "when creating the connector if you don't want to enforce allowed_if: for all connected commands."
642
+ end
643
+ end
644
+
619
645
  unless command.outcome
620
646
  command.run
621
647
  end
@@ -263,7 +263,7 @@ module Foobara
263
263
  procs = rules.map(&:block)
264
264
 
265
265
  block = proc do
266
- procs.any?(&:call)
266
+ procs.any? { |p| instance_exec(&p) }
267
267
  end
268
268
 
269
269
  allowed_rule = AllowedRule.new(&block)
@@ -381,7 +381,7 @@ module Foobara
381
381
  end
382
382
 
383
383
  # TODO: This should support nil as an inputs_type but it breaks other projects for now
384
- inputs_type = inputs_type_for_manifest&.reference_or_declaration_data ||
384
+ inputs_type = inputs_type_for_manifest&.reference_or_declaration_data_for_manifest ||
385
385
  { type: :attributes, element_type_declarations: {} }
386
386
 
387
387
  # TODO: handle errors_types_depended_on!
@@ -390,7 +390,7 @@ module Foobara
390
390
  result_types_depended_on:,
391
391
  types_depended_on: types,
392
392
  inputs_type:,
393
- result_type: result_type&.reference_or_declaration_data,
393
+ result_type: result_type&.reference_or_declaration_data_for_manifest,
394
394
  possible_errors: possible_errors_manifest,
395
395
  capture_unknown_error:,
396
396
  inputs_transformers:,
@@ -45,7 +45,7 @@ module Foobara
45
45
  loop do
46
46
  object_id = queue.pop
47
47
  if object_id
48
- weak_object_set.delete(object_id)
48
+ weak_object_set&.delete(object_id)
49
49
  elsif queue.closed?
50
50
  self.queue = nil
51
51
  break
@@ -420,6 +420,10 @@ module Foobara
420
420
  scoped_full_name
421
421
  end
422
422
 
423
+ def reference_or_declaration_data_for_manifest
424
+ reference_or_declaration_data(declaration_data_for_manifest)
425
+ end
426
+
423
427
  def reference_or_declaration_data(declaration_data = self.declaration_data)
424
428
  remove_sensitive = TypeDeclarations.foobara_manifest_context_remove_sensitive?
425
429
 
@@ -437,6 +441,30 @@ module Foobara
437
441
  end
438
442
  end
439
443
 
444
+ def declaration_data_for_manifest
445
+ data = declaration_data
446
+
447
+ if data.is_a?(::Hash) && data[:type] == :attributes
448
+ if data.key?(:defaults)
449
+ defaults = data[:defaults]
450
+
451
+ if defaults.is_a?(::Hash) && defaults.values.any? { it.is_a?(Proc) }
452
+ cleaned_defaults = defaults.transform_values do |value|
453
+ if value.is_a?(Proc)
454
+ "[<Lazily Set>]"
455
+ else
456
+ value
457
+ end
458
+ end
459
+
460
+ data = data.merge(defaults: cleaned_defaults)
461
+ end
462
+ end
463
+ end
464
+
465
+ data
466
+ end
467
+
440
468
  # TODO: put this somewhere else
441
469
  def foobara_manifest_reference
442
470
  scoped_full_name
@@ -462,7 +490,7 @@ module Foobara
462
490
  [possible_error.key.to_s, possible_error.foobara_manifest]
463
491
  end.sort.to_h
464
492
 
465
- declaration_data = self.declaration_data
493
+ declaration_data = declaration_data_for_manifest
466
494
 
467
495
  if remove_sensitive
468
496
  declaration_data = TypeDeclarations.remove_sensitive_types(declaration_data)
@@ -1,4 +1,6 @@
1
1
  RSpec.describe Foobara::BuiltinTypes::Attributes do
2
+ after { Foobara.reset_alls }
3
+
2
4
  let(:type) {
3
5
  Foobara::Domain.current.foobara_type_from_declaration(type_declaration)
4
6
  }
@@ -61,6 +63,26 @@ RSpec.describe Foobara::BuiltinTypes::Attributes do
61
63
  end
62
64
  end
63
65
 
66
+ context "when default is a proc" do
67
+ let(:type_declaration) do
68
+ {
69
+ type: :attributes,
70
+ element_type_declarations: {
71
+ a: :integer,
72
+ b: :integer
73
+ },
74
+ defaults: { a: -> { 10 }, b: 100 }
75
+ }
76
+ end
77
+
78
+ it "applies defaults and scrubs the value in the manifest data" do
79
+ expect(type.process_value!({})).to eq(a: 10, b: 100)
80
+
81
+ Foobara::GlobalDomain.foobara_register_type(:some_type, type)
82
+ expect(type.foobara_manifest[:declaration_data][:defaults]).to eq(a: "[<Lazily Set>]", b: 100)
83
+ end
84
+ end
85
+
64
86
  context "when defaults contains invalid attribute names" do
65
87
  let(:type_declaration) do
66
88
  {
data/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Foobara
2
2
  module Version
3
- VERSION = "0.5.3".freeze
3
+ VERSION = "0.5.5".freeze
4
4
  MINIMUM_RUBY_VERSION = ">= 3.4.0".freeze
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foobara
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi
@@ -138,6 +138,7 @@ files:
138
138
  - projects/command_connectors/src/command_connector/concerns/desugarizers.rb
139
139
  - projects/command_connectors/src/command_connector/concerns/reflection.rb
140
140
  - projects/command_connectors/src/command_connector/invalid_context_error.rb
141
+ - projects/command_connectors/src/command_connector/no_allowed_rule_given_error.rb
141
142
  - projects/command_connectors/src/command_connector/no_command_found_error.rb
142
143
  - projects/command_connectors/src/command_connector/no_command_or_type_found_error.rb
143
144
  - projects/command_connectors/src/command_connector/no_type_found_error.rb