diff --git a/lib/r3x/workflow.rb b/lib/r3x/workflow.rb index 9b7cddc..32f45d1 100644 --- a/lib/r3x/workflow.rb +++ b/lib/r3x/workflow.rb @@ -1,5 +1,7 @@ module R3x module Workflow + KNOWN_CAPABILITIES = Set.new(%i[networking filesystem shell]).freeze + module Dsl extend ActiveSupport::Concern @@ -7,6 +9,7 @@ module Dsl def inherited(subclass) super subclass._triggers = TriggerManager::Collection.new + subclass._capabilities = Set.new end def workflow_key @@ -19,6 +22,25 @@ def trigger(type, **options) _triggers.add(trigger_instance) end + def uses(*capabilities) + incoming = Set.new(capabilities.flatten.compact.map(&:to_sym)) + unknown = incoming - KNOWN_CAPABILITIES + raise ArgumentError, "Unknown capabilities: #{unknown.to_a.join(", ")}. Known: #{KNOWN_CAPABILITIES.to_a.join(", ")}" if unknown.any? + + duplicates = incoming & _capabilities + raise ArgumentError, "Capability already declared: #{duplicates.to_a.join(", ")}" if duplicates.any? + + _capabilities.merge(incoming) + end + + def capabilities + _capabilities.dup + end + + def uses?(capability) + _capabilities.include?(capability.to_sym) + end + # Returns all triggers, with a default Manual trigger if none declared def triggers triggers = _triggers.to_a @@ -38,6 +60,7 @@ def triggers_by_key end attr_accessor :_triggers + attr_accessor :_capabilities end end end diff --git a/test/lib/r3x/workflow_test.rb b/test/lib/r3x/workflow_test.rb index 0672798..9918c95 100644 --- a/test/lib/r3x/workflow_test.rb +++ b/test/lib/r3x/workflow_test.rb @@ -101,6 +101,50 @@ def self.name assert_equal [ :schedule ], triggers.map(&:type) end + test "uses declares workflow capabilities" do + klass = Class.new(R3x::Workflow::Base) do + def self.name + "Workflows::NetworkedWorkflow" + end + + uses :networking + end + + assert_equal Set.new([ :networking ]), klass.capabilities + assert klass.uses?(:networking) + refute klass.uses?(:filesystem) + end + + test "uses raises on duplicate capability" do + klass = Class.new(R3x::Workflow::Base) do + def self.name + "Workflows::DuplicateCap" + end + + uses :networking + end + + error = assert_raises(ArgumentError) do + klass.uses(:networking) + end + + assert_match "Capability already declared", error.message + end + + test "uses raises on unknown capability" do + error = assert_raises(ArgumentError) do + Class.new(R3x::Workflow::Base) do + def self.name + "Workflows::BadCap" + end + + uses :hacking + end + end + + assert_match "Unknown capabilities: hacking", error.message + end + test "trigger :schedule rejects blank cron (empty string and whitespace)" do [ "",