diff --git a/lib/resource_registry/capabilities/capability_config.rb b/lib/resource_registry/capabilities/capability_config.rb index 611130b..92b89f0 100644 --- a/lib/resource_registry/capabilities/capability_config.rb +++ b/lib/resource_registry/capabilities/capability_config.rb @@ -14,13 +14,39 @@ module CapabilityConfig # Class methods interface for capability configuration module ClassMethods extend T::Sig + extend T::Generic extend T::Helpers abstract! + has_attached_class! + # The key of the capability, this key will be used to take it from yaml configuration sig { abstract.returns(Symbol) } def key end + + sig { params(resource: Resource).returns(T::Boolean) } + def resource_capability?(resource:) + resource.capabilities.key?(key) + end + + sig do + params(resource: Resource).returns( + T.nilable(T.attached_class) + ) + end + def resource_capability(resource:) + return unless resource_capability?(resource:) + + T.cast(resource.capabilities[key], T.attached_class) + end + + sig do + params(resource: Resource).returns(T.attached_class) + end + def resource_capability!(resource:) + T.must(resource_capability(resource: )) + end end requires_ancestor { Object } diff --git a/lib/resource_registry/resource.rb b/lib/resource_registry/resource.rb index bd14260..966244c 100644 --- a/lib/resource_registry/resource.rb +++ b/lib/resource_registry/resource.rb @@ -140,7 +140,7 @@ def build_dto(verb, **parameters) T::Class[T.type_parameter(:CapabilityConfig)], # Referencing `ClassMethods` here is not ideal but it seems Sorbet # provides no other mechanism to do this - Capabilities::CapabilityConfig::ClassMethods, + Capabilities::CapabilityConfig::ClassMethods[T.untyped], T::Class[Capabilities::CapabilityConfig] ) ) @@ -161,7 +161,7 @@ def capability_by_key(key) params( feature: T.all( - Capabilities::CapabilityConfig::ClassMethods, + Capabilities::CapabilityConfig::ClassMethods[T.untyped], T::Class[Capabilities::CapabilityConfig] ) ).returns(T::Boolean) @@ -178,7 +178,7 @@ def capability?(feature) T::Class[T.type_parameter(:CapabilityConfig)], # Referencing ClassMethods here is not ideal but it seems Sorbet # provides no other mechanism to do this - Capabilities::CapabilityConfig::ClassMethods, + Capabilities::CapabilityConfig::ClassMethods[T.untyped], T::Class[Capabilities::CapabilityConfig] ) ) diff --git a/spec/resource_registry/capabilities/capability_config_spec.rb b/spec/resource_registry/capabilities/capability_config_spec.rb new file mode 100644 index 0000000..2cc8bfa --- /dev/null +++ b/spec/resource_registry/capabilities/capability_config_spec.rb @@ -0,0 +1,55 @@ +# typed: false + +require "spec_helper" +require_relative "../../../lib/resource_registry/capabilities/capability_config" + +class DummyCapability < T::Struct + include ResourceRegistry::Capabilities::CapabilityConfig + + def self.key + :dummy_capability + end +end + +RSpec.describe ResourceRegistry::Capabilities::CapabilityConfig do + let(:schema) do + SchemaRegistry::Schema.new( + name: "dummy", + namespace: "dummies", + properties: [ + SchemaRegistry::Property.new( + name: "foo", + types: [SchemaRegistry::PropertyType::String], + required: true + ) + ] + ) + end + let(:capabilities) { { dummy_capability: DummyCapability.new } } + let(:resource) do + ResourceRegistry::Resource.new( + repository_raw: DummyRepo.to_s, + capabilities:, + verbs: { + }, + schema: + ) + end + + it "should return resource's capability" do + expect(DummyCapability.resource_capability?(resource:)).to be true + expect(DummyCapability.resource_capability(resource:)).to be_a(DummyCapability) + expect(DummyCapability.resource_capability!(resource:)).to be_a(DummyCapability) + end + + context 'without the capability' do + let(:capabilities) { {} } + + it "should return resource's capability" do + expect(DummyCapability.resource_capability?(resource:)).to be false + expect(DummyCapability.resource_capability(resource:)).to be_nil + end + end +end + +