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

Commit 26a6e95

Browse files
author
Matt Walters
committed
add support for required properties
1 parent 7e559ab commit 26a6e95

File tree

4 files changed

+59
-2
lines changed

4 files changed

+59
-2
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,25 @@ purposes; the exception is generated if `:retired_at` is set to _anything_.)
629629
You can retire events, categories, and entire versions; this system ensures the DSL continues to be a historical record
630630
of what things were in the past, as well as what they are today.
631631

632+
### Requiring Properties
633+
634+
Sometimes it is helpful to enforce the presence of certain properties. For example, imagine you are tracking views of
635+
a set of banners that advertise a set of new features. In order to determine which banners (and therefore features) are
636+
driving conversions, you need to be sure to include `:banner_id` and `:banner_size`. If there are many places in the
637+
code that can call this event, you may forget to pass along these properties. With `:required_properties` an exception
638+
is generated if the keys are not present _or if their values are blank_.
639+
640+
```ruby
641+
global_events_prefix :ab
642+
643+
version 1, "2014-02-04" do
644+
category :user do
645+
event :viewed_banner, "2014-02-04", "user creates a brand-new account", :required_properties => [ :banner_id, :banner_size ]
646+
end
647+
end
648+
```
649+
650+
632651
### Adding Notes to Events
633652

634653
You can also add notes to events. They must be tagged with the author and the time, and they can be very useful for

lib/meta_events/definition/definition_set.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module Definition
1515
class DefinitionSet
1616
class BaseError < StandardError; end
1717
class RetiredEventError < BaseError; end
18+
class RequiredPropertyMissingError < BaseError; end
1819

1920
class << self
2021
# Creates an MetaEvents::Definition::DefinitionSet. +source+ can be one of:

lib/meta_events/definition/event.rb

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,10 @@ def initialize(category, name, *args, &block)
7373
# provide for required properties, property validation, or anything else.
7474
def validate!(properties)
7575
if retired_at
76-
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."
76+
raise ::MetaEvents::Definition::DefinitionSet::RetiredEventError,
77+
"Event #{full_name} was retired at #{retired_at.inspect} (or its category or version was); you can't use it any longer."
7778
end
79+
validate_properties!(properties)
7880
end
7981

8082
# Returns, or sets, the description for an event.
@@ -142,17 +144,34 @@ def ensure_complete!
142144
raise ArgumentError, "You must record when you introduced event #{full_name}, either as an argument, in the options, or using 'introduced'" if (! @introduced)
143145
end
144146

147+
def validate_properties!(properties)
148+
properties_with_indifferent_access = properties.with_indifferent_access
149+
if @required_properties
150+
missing_properties = [ ]
151+
@required_properties.each do |required_property|
152+
if properties_with_indifferent_access[required_property].blank?
153+
missing_properties << required_property
154+
end
155+
end
156+
unless missing_properties.empty?
157+
raise ::MetaEvents::Definition::DefinitionSet::RequiredPropertyMissingError,
158+
"Event #{full_name} requires the properties #{@required_properties.join(', ')}. #{missing_properties.join(', ')} were missing or had blank values."
159+
end
160+
end
161+
end
162+
145163
# Called with the set of options (which can be empty) supplied in the constructor; responsible for applying those
146164
# to the object properly.
147165
def apply_options!(options)
148-
options.assert_valid_keys(:introduced, :desc, :description, :retired_at, :external_name)
166+
options.assert_valid_keys(:introduced, :desc, :description, :retired_at, :external_name, :required_properties)
149167

150168
introduced options[:introduced] if options[:introduced]
151169
desc options[:desc] if options[:desc]
152170
desc options[:description] if options[:description]
153171
external_name options[:external_name] if options[:external_name]
154172

155173
@retired_at = Time.parse(options[:retired_at]) if options[:retired_at]
174+
@required_properties = Array(options[:required_properties]) if options[:required_properties]
156175
end
157176

158177
# Called with the arguments (past the category and event name) supplied to the constructor; responsible for

spec/meta_events/definition/event_spec.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@
6666
allow(category).to receive(:retired_at).and_return(Time.parse("2013-02-01"))
6767
expect { instance.validate!(:foo => :bar) }.to raise_error(::MetaEvents::Definition::DefinitionSet::RetiredEventError, /2013/)
6868
end
69+
70+
it "should fail if required properties are missing" do
71+
expect { klass.new(category, :foo, "2016-1-1", "foobar", :required_properties => [ :foo ]).validate!(:baz => :bar) }.to raise_error(::MetaEvents::Definition::DefinitionSet::RequiredPropertyMissingError, /foo/)
72+
end
73+
74+
it "should fail if required properties have blank values" do
75+
expect { klass.new(category, :foo, "2016-1-1", "foobar", :required_properties => [ :foo ]).validate!(:foo => '') }.to raise_error(::MetaEvents::Definition::DefinitionSet::RequiredPropertyMissingError, /foo/)
76+
end
6977
end
7078

7179
it "should return and allow setting its description via #desc" do
@@ -143,5 +151,15 @@
143151
expect(instance.external_name).to eq("my name")
144152
end
145153
end
154+
155+
context "with required properties" do
156+
it "should work with strings and symbols" do
157+
expect do
158+
event = klass.new(category, :foo, "2016-1-1", "foobar", :required_properties => [ "string", :symbol ])
159+
event.validate!('string' => "foo", :symbol => "foo")
160+
event.validate!(:string => "foo", "symbol" => "foo")
161+
end.to_not raise_error(::MetaEvents::Definition::DefinitionSet::RequiredPropertyMissingError)
162+
end
163+
end
146164
end
147165
end

0 commit comments

Comments
 (0)