Skip to content
This repository has been archived by the owner on Dec 22, 2023. It is now read-only.

Commit

Permalink
add support for required properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt Walters committed Jan 14, 2016
1 parent 7e559ab commit 26a6e95
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 2 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,25 @@ purposes; the exception is generated if `:retired_at` is set to _anything_.)
You can retire events, categories, and entire versions; this system ensures the DSL continues to be a historical record
of what things were in the past, as well as what they are today.

### Requiring Properties

Sometimes it is helpful to enforce the presence of certain properties. For example, imagine you are tracking views of
a set of banners that advertise a set of new features. In order to determine which banners (and therefore features) are
driving conversions, you need to be sure to include `:banner_id` and `:banner_size`. If there are many places in the
code that can call this event, you may forget to pass along these properties. With `:required_properties` an exception
is generated if the keys are not present _or if their values are blank_.

```ruby
global_events_prefix :ab

version 1, "2014-02-04" do
category :user do
event :viewed_banner, "2014-02-04", "user creates a brand-new account", :required_properties => [ :banner_id, :banner_size ]
end
end
```


### Adding Notes to Events

You can also add notes to events. They must be tagged with the author and the time, and they can be very useful for
Expand Down
1 change: 1 addition & 0 deletions lib/meta_events/definition/definition_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
23 changes: 21 additions & 2 deletions lib/meta_events/definition/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -142,17 +144,34 @@ 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]
desc options[:description] if options[:description]
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
Expand Down
18 changes: 18 additions & 0 deletions spec/meta_events/definition/event_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

0 comments on commit 26a6e95

Please sign in to comment.