diff --git a/lib/meta_events/definition/definition_set.rb b/lib/meta_events/definition/definition_set.rb index b6c5583..b81a308 100644 --- a/lib/meta_events/definition/definition_set.rb +++ b/lib/meta_events/definition/definition_set.rb @@ -15,6 +15,7 @@ module Definition class DefinitionSet class BaseError < StandardError; end class RetiredEventError < BaseError; end + class RequiredPropertyMissingError < BaseError; end class << self # Creates an MetaEvents::Definition::DefinitionSet. +source+ can be one of: diff --git a/lib/meta_events/definition/event.rb b/lib/meta_events/definition/event.rb index 5eb72dc..10466b5 100644 --- a/lib/meta_events/definition/event.rb +++ b/lib/meta_events/definition/event.rb @@ -73,8 +73,10 @@ def initialize(category, name, *args, &block) # provide for required properties, property validation, or anything else. def validate!(properties) if retired_at - raise ::MetaEvents::Definition::DefinitionSet::RetiredEventError, "Event #{full_name} was retired at #{retired_at.inspect} (or its category or version was); you can't use it any longer." + raise ::MetaEvents::Definition::DefinitionSet::RetiredEventError, + "Event #{full_name} was retired at #{retired_at.inspect} (or its category or version was); you can't use it any longer." end + validate_properties!(properties) end # Returns, or sets, the description for an event. @@ -142,10 +144,26 @@ def ensure_complete! raise ArgumentError, "You must record when you introduced event #{full_name}, either as an argument, in the options, or using 'introduced'" if (! @introduced) end + def validate_properties!(properties) + properties_with_indifferent_access = properties.with_indifferent_access + if @required_properties + missing_properties = [ ] + @required_properties.each do |required_property| + if properties_with_indifferent_access[required_property].blank? + missing_properties << required_property + end + end + unless missing_properties.empty? + raise ::MetaEvents::Definition::DefinitionSet::RequiredPropertyMissingError, + "Event #{full_name} requires the properties #{@required_properties.join(', ')}. #{missing_properties.join(', ')} were missing or had blank values." + end + end + end + # Called with the set of options (which can be empty) supplied in the constructor; responsible for applying those # to the object properly. def apply_options!(options) - options.assert_valid_keys(:introduced, :desc, :description, :retired_at, :external_name) + options.assert_valid_keys(:introduced, :desc, :description, :retired_at, :external_name, :required_properties) introduced options[:introduced] if options[:introduced] desc options[:desc] if options[:desc] @@ -153,6 +171,7 @@ def apply_options!(options) external_name options[:external_name] if options[:external_name] @retired_at = Time.parse(options[:retired_at]) if options[:retired_at] + @required_properties = Array(options[:required_properties]) if options[:required_properties] end # Called with the arguments (past the category and event name) supplied to the constructor; responsible for diff --git a/spec/meta_events/definition/event_spec.rb b/spec/meta_events/definition/event_spec.rb index 4336968..953d297 100644 --- a/spec/meta_events/definition/event_spec.rb +++ b/spec/meta_events/definition/event_spec.rb @@ -66,6 +66,14 @@ allow(category).to receive(:retired_at).and_return(Time.parse("2013-02-01")) expect { instance.validate!(:foo => :bar) }.to raise_error(::MetaEvents::Definition::DefinitionSet::RetiredEventError, /2013/) end + + it "should fail if required properties are missing" do + expect { klass.new(category, :foo, "2016-1-1", "foobar", :required_properties => [ :foo ]).validate!(:baz => :bar) }.to raise_error(::MetaEvents::Definition::DefinitionSet::RequiredPropertyMissingError, /foo/) + end + + it "should fail if required properties have blank values" do + expect { klass.new(category, :foo, "2016-1-1", "foobar", :required_properties => [ :foo ]).validate!(:foo => '') }.to raise_error(::MetaEvents::Definition::DefinitionSet::RequiredPropertyMissingError, /foo/) + end end it "should return and allow setting its description via #desc" do @@ -143,5 +151,15 @@ expect(instance.external_name).to eq("my name") end end + + context "with required properties" do + it "should work with strings and symbols" do + expect do + event = klass.new(category, :foo, "2016-1-1", "foobar", :required_properties => [ "string", :symbol ]) + event.validate!('string' => "foo", :symbol => "foo") + event.validate!(:string => "foo", "symbol" => "foo") + end.to_not raise_error(::MetaEvents::Definition::DefinitionSet::RequiredPropertyMissingError) + end + end end end