meta_events 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,253 @@
1
+ require 'meta_events'
2
+
3
+ describe MetaEvents::ControllerMethods do
4
+ before :each do
5
+ @definition_set = MetaEvents::Definition::DefinitionSet.new(:global_events_prefix => "xy") do
6
+ version 1, '2014-01-31' do
7
+ category :foo do
8
+ event :bar, '2014-01-31', 'this is bar'
9
+ event :baz, '2014-01-31', 'this is baz'
10
+ end
11
+ end
12
+ end
13
+ @tracker = ::MetaEvents::Tracker.new("abc123", nil, :definitions => @definition_set, :implicit_properties => { :imp1 => 'imp1val1' })
14
+
15
+ @klass = Class.new do
16
+ class << self
17
+ def helper_method(*args)
18
+ @_helper_methods ||= [ ]
19
+ @_helper_methods += args
20
+ end
21
+
22
+ def helper_methods_registered
23
+ @_helper_methods
24
+ end
25
+ end
26
+
27
+ def link_to(*args, &block)
28
+ @_link_to_calls ||= [ ]
29
+ @_link_to_calls << args + [ block ]
30
+ "link_to_call_#{@_link_to_calls.length}"
31
+ end
32
+
33
+ def link_to_calls
34
+ @_link_to_calls
35
+ end
36
+
37
+ attr_accessor :meta_events_tracker
38
+
39
+ include MetaEvents::ControllerMethods
40
+ include MetaEvents::Helpers
41
+ end
42
+
43
+ @obj = @klass.new
44
+ @obj.meta_events_tracker = @tracker
45
+ end
46
+
47
+ it "should register the proper helper methods" do
48
+ expect(@klass.helper_methods_registered.map(&:to_s).sort).to eq(
49
+ [ :meta_events_define_frontend_event, :meta_events_defined_frontend_events, :meta_events_tracker ].map(&:to_s).sort)
50
+ end
51
+
52
+ describe "frontend-event registration" do
53
+ def expect_defined_event(name, event_name, properties, options = { })
54
+ expected_distinct_id = options[:distinct_id] || 'abc123'
55
+ expect(@obj.meta_events_defined_frontend_events[name]).to eq({
56
+ :distinct_id => expected_distinct_id,
57
+ :event_name => event_name,
58
+ :properties => properties
59
+ })
60
+
61
+ js = @obj.meta_events_frontend_events_javascript
62
+ expect(js).to match(/MetaEvents\.registerFrontendEvent\s*\(\s*["']#{name}["']/i)
63
+ js =~ /["']#{name}["']\s*,\s*(.*?)\s*\)\s*\;/i
64
+ matched = $1
65
+ hash = JSON.parse($1)
66
+ expect(hash).to eq('distinct_id' => expected_distinct_id, 'event_name' => event_name, 'properties' => properties)
67
+ end
68
+
69
+ it "should work fine if there are no registered events" do
70
+ expect(@obj.meta_events_defined_frontend_events).to eq({ })
71
+ expect(@obj.meta_events_frontend_events_javascript).to eq("")
72
+ end
73
+
74
+ it "should not let you register a nonexistent event" do
75
+ expect { @obj.meta_events_define_frontend_event(:foo, :quux) }.to raise_error(ArgumentError, /quux/i)
76
+ end
77
+
78
+ it "should let you alias the event to anything you want" do
79
+ @obj.meta_events_define_frontend_event(:foo, :bar, { :aaa => 'bbb' }, :name => 'zyxwvu')
80
+ expect_defined_event('zyxwvu', 'xy1_foo_bar', { 'imp1' => 'imp1val1', 'aaa' => 'bbb' })
81
+ end
82
+
83
+ it "should let you override the tracker if you want" do
84
+ ds2 = MetaEvents::Definition::DefinitionSet.new(:global_events_prefix => "ab") do
85
+ version 2, '2014-01-31' do
86
+ category :aaa do
87
+ event :bbb, '2014-01-31', 'this is bar'
88
+ end
89
+ end
90
+ end
91
+ t2 = ::MetaEvents::Tracker.new("def345", nil, :definitions => ds2, :version => 2)
92
+
93
+ @obj.meta_events_define_frontend_event(:aaa, :bbb, { }, :tracker => t2)
94
+ expect_defined_event('aaa_bbb', 'ab2_aaa_bbb', { }, { :distinct_id => 'def345' })
95
+ end
96
+
97
+ it "should let you overwrite implicit properties and do hash expansion" do
98
+ @obj.meta_events_define_frontend_event(:foo, :bar, { :imp1 => 'imp1val2', :a => { :b => 'c', :d => 'e' } })
99
+ expect_defined_event('foo_bar', 'xy1_foo_bar', { 'imp1' => 'imp1val2', 'a_b' => 'c', 'a_d' => 'e' })
100
+ end
101
+
102
+ context "with one simple defined event" do
103
+ before :each do
104
+ @obj.meta_events_define_frontend_event(:foo, :bar, { :quux => 123 })
105
+ end
106
+
107
+ it "should output that event (only) in the JavaScript and via meta_events_define_frontend_event" do
108
+ expect(@obj.meta_events_defined_frontend_events.keys).to eq(%w{foo_bar})
109
+ expect_defined_event('foo_bar', 'xy1_foo_bar', { 'quux' => 123, 'imp1' => 'imp1val1' })
110
+ end
111
+
112
+ it "should overwrite the event if a new one is registered" do
113
+ @obj.meta_events_define_frontend_event(:foo, :baz, { :marph => 345 }, :name => 'foo_bar')
114
+ expect_defined_event('foo_bar', 'xy1_foo_baz', { 'marph' => 345, 'imp1' => 'imp1val1' })
115
+ end
116
+ end
117
+
118
+ context "with three defined events" do
119
+ before :each do
120
+ @obj.meta_events_define_frontend_event(:foo, :bar, { :quux => 123 })
121
+ @obj.meta_events_define_frontend_event(:foo, :bar, { :quux => 345 }, { :name => :voodoo })
122
+ @obj.meta_events_define_frontend_event(:foo, :baz, { :marph => 'whatever' })
123
+ end
124
+
125
+ it "should output all the events in the JavaScript and via meta_events_define_frontend_event" do
126
+ expect(@obj.meta_events_defined_frontend_events.keys.sort).to eq(%w{foo_bar foo_baz voodoo}.sort)
127
+ expect_defined_event('foo_bar', 'xy1_foo_bar', { 'quux' => 123, 'imp1' => 'imp1val1' })
128
+ expect_defined_event('voodoo', 'xy1_foo_bar', { 'quux' => 345, 'imp1' => 'imp1val1' })
129
+ expect_defined_event('foo_baz', 'xy1_foo_baz', { 'marph' => 'whatever', 'imp1' => 'imp1val1' })
130
+ end
131
+ end
132
+ end
133
+
134
+ describe "auto-tracking" do
135
+ def meta4(h)
136
+ @obj.meta_events_tracking_attributes_for(h, @tracker)
137
+ end
138
+
139
+ it "should return the input attributes unchanged if there is no :meta_event" do
140
+ input = { :foo => 'bar', :bar => 'baz' }
141
+ expect(meta4(input)).to be(input)
142
+ end
143
+
144
+ it "should fail if :meta_event is not a Hash" do
145
+ expect { meta4(:meta_event => 'bonk') }.to raise_error(ArgumentError)
146
+ end
147
+
148
+ it "should fail if :meta_event contains unknown keys" do
149
+ me = { :category => 'foo', :event => 'bar', :properties => { }, :extra => 'whatever' }
150
+ expect { meta4(:meta_event => me) }.to raise_error(ArgumentError)
151
+ end
152
+
153
+ it "should fail if there is no :category" do
154
+ me = { :event => 'bar', :properties => { } }
155
+ expect { meta4(:meta_event => me) }.to raise_error(ArgumentError)
156
+ end
157
+
158
+ it "should fail if there is no :event" do
159
+ me = { :category => 'foo', :properties => { } }
160
+ expect { meta4(:meta_event => me) }.to raise_error(ArgumentError)
161
+ end
162
+
163
+ def expect_meta4(input, classes, event_name, properties, options = { })
164
+ attrs = meta4(input)
165
+
166
+ expected_prefix = options[:prefix] || "mejtp"
167
+ expect(attrs['class']).to eq(classes)
168
+
169
+ expect(attrs["data-#{expected_prefix}_evt"]).to eq(event_name)
170
+ prps = JSON.parse(attrs["data-#{expected_prefix}_prp"])
171
+ expect(prps).to eq(properties)
172
+
173
+ remaining = attrs.dup
174
+ remaining.delete("data-#{expected_prefix}_evt")
175
+ remaining.delete("data-#{expected_prefix}_prp")
176
+
177
+ remaining
178
+ end
179
+
180
+ it "should add class, evt, and prp correctly, and remove :meta_event" do
181
+ me = { :category => 'foo', :event => 'bar', :properties => { :something => 'awesome' } }
182
+ remaining = expect_meta4({ :meta_event => me }, %w{mejtp_trk}, 'xy1_foo_bar', { 'something' => 'awesome', 'imp1' => 'imp1val1' })
183
+ expect(remaining['data']).to be_nil
184
+ end
185
+
186
+ it "should combine the class with an existing class string" do
187
+ me = { :category => 'foo', :event => 'bar', :properties => { :something => 'awesome' } }
188
+ remaining = expect_meta4({ :meta_event => me, :class => 'bonko baz' }, [ 'bonko baz', 'mejtp_trk' ], 'xy1_foo_bar', { 'something' => 'awesome', 'imp1' => 'imp1val1' })
189
+ expect(remaining['data']).to be_nil
190
+ end
191
+
192
+ it "should combine the class with an existing class array" do
193
+ me = { :category => 'foo', :event => 'bar', :properties => { :something => 'awesome' } }
194
+ remaining = expect_meta4({ :meta_event => me, :class => %w{bonko baz} }, %w{bonko baz mejtp_trk}, 'xy1_foo_bar', { 'something' => 'awesome', 'imp1' => 'imp1val1' })
195
+ expect(remaining['data']).to be_nil
196
+ end
197
+
198
+ it "should preserve existing attributes" do
199
+ me = { :category => 'foo', :event => 'bar', :properties => { :something => 'awesome' } }
200
+ remaining = expect_meta4({ :meta_event => me, :yo => 'there' }, %w{mejtp_trk}, 'xy1_foo_bar', { 'something' => 'awesome', 'imp1' => 'imp1val1' })
201
+ expect(remaining['data']).to be_nil
202
+ expect(remaining[:yo]).to eq('there')
203
+ end
204
+
205
+ it "should preserve existing data attributes" do
206
+ me = { :category => 'foo', :event => 'bar', :properties => { :something => 'awesome' } }
207
+ remaining = expect_meta4({ :meta_event => me, :data => { :foo => 'bar', :bar => 'baz' } }, %w{mejtp_trk}, 'xy1_foo_bar', { 'something' => 'awesome', 'imp1' => 'imp1val1' })
208
+ expect(remaining['data']).to eq({ 'foo' => 'bar', 'bar' => 'baz' })
209
+ end
210
+
211
+ it "should preserve existing data attributes that aren't a Hash" do
212
+ me = { :category => 'foo', :event => 'bar', :properties => { :something => 'awesome' } }
213
+ remaining = expect_meta4({ :meta_event => me, :data => "whatever", :'data-foo' => 'bar' }, %w{mejtp_trk}, 'xy1_foo_bar', { 'something' => 'awesome', 'imp1' => 'imp1val1' })
214
+ expect(remaining['data']).to eq('whatever')
215
+ expect(remaining['data-foo']).to eq('bar')
216
+ end
217
+
218
+ it "should let you change the tracking prefix" do
219
+ MetaEvents::Helpers.meta_events_javascript_tracking_prefix 'foo'
220
+ begin
221
+ me = { :category => 'foo', :event => 'bar', :properties => { :something => 'awesome' } }
222
+ remaining = expect_meta4({ :meta_event => me }, %w{foo_trk}, 'xy1_foo_bar', { 'something' => 'awesome', 'imp1' => 'imp1val1' }, { :prefix => 'foo' })
223
+ expect(remaining['data']).to be_nil
224
+ ensure
225
+ MetaEvents::Helpers.meta_events_javascript_tracking_prefix 'mejtp'
226
+ end
227
+ end
228
+
229
+ describe "#meta_events_tracked_link_to" do
230
+ it "should raise if there is no :meta_event" do
231
+ expect { @obj.meta_events_tracked_link_to("foobar", "barfoo") }.to raise_error(ArgumentError)
232
+ end
233
+
234
+ it "should call through to #link_to properly for a simple case" do
235
+ retval = @obj.meta_events_tracked_link_to("foobar", "barfoo", { :meta_event => { :category => :foo, :event => :bar, :properties => { :a => :b }} })
236
+ expect(retval).to eq("link_to_call_1")
237
+
238
+ calls = @obj.link_to_calls
239
+ expect(calls.length).to eq(1)
240
+
241
+ call = calls[0]
242
+ expect(call.length).to eq(4)
243
+ expect(call[0]).to eq("foobar")
244
+ expect(call[1]).to eq("barfoo")
245
+ expect(call[2].keys.sort).to eq(%w{class data-mejtp_evt data-mejtp_prp}.sort)
246
+ expect(call[2]['class']).to eq([ 'mejtp_trk' ])
247
+ expect(call[2]['data-mejtp_evt']).to eq('xy1_foo_bar')
248
+ prp = JSON.parse(call[2]['data-mejtp_prp'])
249
+ expect(prp).to eq({ 'imp1' => 'imp1val1', 'a' => 'b' })
250
+ end
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,102 @@
1
+ require "meta_events"
2
+
3
+ describe ::MetaEvents::Definition::Category do
4
+ let(:version) do
5
+ out = double("version")
6
+ allow(out).to receive(:kind_of?).with(::MetaEvents::Definition::Version).and_return(true)
7
+ allow(out).to receive(:prefix).with().and_return("vp_")
8
+ out
9
+ end
10
+ let(:klass) { ::MetaEvents::Definition::Category }
11
+
12
+ it "should normalize any name passed in" do
13
+ expect(klass.normalize_name(:foo)).to eq(:foo)
14
+ expect(klass.normalize_name(' foo ')).to eq(:foo)
15
+ expect(klass.normalize_name(:FoO)).to eq(:foo)
16
+ expect(klass.normalize_name(' FoO ')).to eq(:foo)
17
+
18
+ expect { klass.normalize_name(nil) }.to raise_error(ArgumentError)
19
+ expect { klass.normalize_name("") }.to raise_error(ArgumentError)
20
+ end
21
+
22
+ it "should validate its arguments on construction" do
23
+ expect { klass.new(double("whatever"), :foo) }.to raise_error(ArgumentError)
24
+ expect { klass.new(version, nil) }.to raise_error(ArgumentError)
25
+ expect { klass.new(version, :foo, :bar => :baz) }.to raise_error(ArgumentError, /bar/i)
26
+
27
+ # Ruby 1.8.x's Time.parse method will accept "foo" for Time.parse and just return Time.now --
28
+ # which is deeply unfortunate, but there's really no good way around it.
29
+ unless RUBY_VERSION =~ /^1\.8\./
30
+ expect { klass.new(version, :foo, :retired_at => "foo") }.to raise_error(ArgumentError)
31
+ end
32
+ end
33
+
34
+ it "should run its block in its own context" do
35
+ expect_any_instance_of(klass).to receive(:foobar).once.with(:bonk)
36
+ klass.new(version, :foo) { foobar(:bonk) }
37
+ end
38
+
39
+ context "with an instance" do
40
+ let(:instance) { klass.new(version, :foo) }
41
+ let(:event) do
42
+ out = double("event")
43
+ allow(out).to receive(:name).with().and_return(:baz)
44
+ out
45
+ end
46
+
47
+ it "should allow creating an Event" do
48
+ blk = lambda { :whatever }
49
+ expect(::MetaEvents::Definition::Event).to receive(:new).once.with(instance, :quux, :a, :b, :c => :d).and_return(event)
50
+ instance.event(:quux, :a, :b, :c => :d)
51
+ end
52
+
53
+ it "should return the prefix correctly" do
54
+ expect(instance.prefix).to eq("vp_foo_")
55
+ end
56
+
57
+ context "with an event" do
58
+ before :each do
59
+ expect(::MetaEvents::Definition::Event).to receive(:new).once.with(instance, :quux, :a, :b, :c => :d).and_return(event)
60
+ instance.event(:quux, :a, :b, :c => :d)
61
+ end
62
+
63
+ it "should not allow creating two Events with the same name" do
64
+ event_2 = double("event-2")
65
+ allow(event_2).to receive(:name).with().and_return(:baz)
66
+ expect(::MetaEvents::Definition::Event).to receive(:new).once.with(instance, :marph, :www).and_return(event_2)
67
+
68
+ expect { instance.event(:marph, :www) }.to raise_error(ArgumentError, /baz/)
69
+ end
70
+
71
+ it "should allow retrieving the event, and normalize names" do
72
+ expect(instance.event_named(:baz)).to be(event)
73
+ expect(instance.event_named(:BaZ)).to be(event)
74
+ expect(instance.event_named(' BaZ ')).to be(event)
75
+ end
76
+
77
+ it "should raise if you ask for an event that doesn't exist" do
78
+ expect { instance.event_named(:doesnotexist) }.to raise_error(ArgumentError)
79
+ end
80
+ end
81
+
82
+ it "should return the correct value for #retired_at" do
83
+ allow(version).to receive(:retired_at).with().and_return(nil)
84
+ expect(instance.retired_at).to be_nil
85
+
86
+ expect(klass.new(version, :foo, :retired_at => "2014-06-21").retired_at).to eq(Time.parse("2014-06-21"))
87
+
88
+ allow(version).to receive(:retired_at).with().and_return(Time.parse("2014-02-01"))
89
+ expect(klass.new(version, :foo).retired_at).to eq(Time.parse("2014-02-01"))
90
+ expect(klass.new(version, :foo, :retired_at => "2014-06-21").retired_at).to eq(Time.parse("2014-02-01"))
91
+ expect(klass.new(version, :foo, :retired_at => "2013-06-21").retired_at).to eq(Time.parse("2013-06-21"))
92
+ end
93
+
94
+ it "should turn itself into a string reasonably" do
95
+ allow(version).to receive(:to_s).with().and_return("boogabooga")
96
+
97
+ expect(instance.to_s).to match(/category/i)
98
+ expect(instance.to_s).to match(/foo/i)
99
+ expect(instance.to_s).to match(/boogabooga/i)
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,142 @@
1
+ describe ::MetaEvents::Definition::DefinitionSet do
2
+ let(:klass) { ::MetaEvents::Definition::DefinitionSet }
3
+ let(:instance) { klass.new(:global_events_prefix => "foo") }
4
+
5
+ describe "construction" do
6
+ it "should require a global prefix for construction" do
7
+ expect { klass.new }.to raise_error(ArgumentError)
8
+ end
9
+
10
+ it "should allow creation with a Symbol for the prefix" do
11
+ klass.new(:global_events_prefix => :bar).global_events_prefix.should == 'bar'
12
+ end
13
+
14
+ it "should allow creation without a block" do
15
+ expect { klass.new(:global_events_prefix => 'foo') }.not_to raise_error
16
+ end
17
+
18
+ it "should evaluate its block in the context of the object" do
19
+ x = nil
20
+ klass.new(:global_events_prefix => 'abc') { x = global_events_prefix }
21
+ expect(x).to eq('abc')
22
+ end
23
+
24
+ it "should validate its options" do
25
+ expect { klass.new(:foo => 'bar') }.to raise_error(ArgumentError, /foo/i)
26
+ end
27
+
28
+ it "should allow declaring the global_events_prefix in the block" do
29
+ x = klass.new { global_events_prefix "baz" }
30
+ expect(x.global_events_prefix).to eq("baz")
31
+ end
32
+
33
+ it "should be able to create itself from an IO" do
34
+ require 'stringio'
35
+ io = StringIO.new(<<-EOS)
36
+ global_events_prefix :abq
37
+
38
+ version 1, '2014-02-15' do
39
+ category :foo do
40
+ event :bar, '2014-02-16', 'something great'
41
+ end
42
+ end
43
+ EOS
44
+ set = klass.new(:definition_text => io)
45
+ expect(set.global_events_prefix).to eq('abq')
46
+ expect(set.fetch_event(1, :foo, :bar)).to be_kind_of(::MetaEvents::Definition::Event)
47
+ expect { set.fetch_event(1, :foo, :baz) }.to raise_error
48
+ end
49
+
50
+ it "should be able to create itself from a file" do
51
+ require 'tempfile'
52
+
53
+ f = Tempfile.new('definition_set_spec')
54
+ begin
55
+ f.puts <<-EOS
56
+ global_events_prefix :abq
57
+
58
+ version 1, '2014-02-15' do
59
+ category :foo do
60
+ event :bar, '2014-02-16', 'something great'
61
+ end
62
+ end
63
+ EOS
64
+ f.close
65
+
66
+ set = klass.new(:definition_text => f.path)
67
+ expect(set.global_events_prefix).to eq('abq')
68
+ expect(set.fetch_event(1, :foo, :bar)).to be_kind_of(::MetaEvents::Definition::Event)
69
+ expect { set.fetch_event(1, :foo, :baz) }.to raise_error
70
+ ensure
71
+ f.close
72
+ f.unlink
73
+ end
74
+ end
75
+ end
76
+
77
+ it "should create a new version and pass options properly" do
78
+ version = double("version")
79
+ allow(version).to receive(:number).with().and_return(234)
80
+
81
+ passed_block = nil
82
+ expect(::MetaEvents::Definition::Version).to receive(:new).once.with(instance, 123, 'foobar', { :a => :b }) { |&block| passed_block = block; version }
83
+
84
+ instance.version(123, 'foobar', { :a => :b }) { :the_right_block }
85
+ expect(passed_block.call).to eq(:the_right_block)
86
+
87
+ expect { instance.fetch_version(123) }.to raise_error(ArgumentError)
88
+ expect(instance.fetch_version(234)).to be(version)
89
+ end
90
+
91
+ it "should return its prefix" do
92
+ instance.global_events_prefix.should == 'foo'
93
+ end
94
+
95
+ it "should raise if there is a version conflict" do
96
+ version_1 = double("version-1")
97
+ allow(version_1).to receive(:number).with().and_return(234)
98
+ expect(::MetaEvents::Definition::Version).to receive(:new).once.with(instance, 123, 'foobar', { }).and_return(version_1)
99
+
100
+ instance.version(123, 'foobar')
101
+
102
+ version_2 = double("version-2")
103
+ allow(version_2).to receive(:number).with().and_return(234)
104
+ expect(::MetaEvents::Definition::Version).to receive(:new).once.with(instance, 345, 'barfoo', { }).and_return(version_2)
105
+
106
+ expect { instance.version(345, 'barfoo') }.to raise_error(/already.*234/)
107
+ end
108
+
109
+ context "with two versions" do
110
+ before :each do
111
+ @version_1 = double("version-1")
112
+ allow(@version_1).to receive(:number).with().and_return(1)
113
+ expect(::MetaEvents::Definition::Version).to receive(:new).once.with(instance, 1, 'foo', { }).and_return(@version_1)
114
+
115
+ instance.version(1, 'foo')
116
+
117
+ @version_2 = double("version-2")
118
+ allow(@version_2).to receive(:number).with().and_return(2)
119
+ expect(::MetaEvents::Definition::Version).to receive(:new).once.with(instance, 2, 'bar', { }).and_return(@version_2)
120
+
121
+ instance.version(2, 'bar')
122
+ end
123
+
124
+ it "should return the version on #fetch_version" do
125
+ instance.fetch_version(1).should be(@version_1)
126
+ instance.fetch_version(2).should be(@version_2)
127
+ end
128
+
129
+ it "should raise if asked for a version it doesn't have" do
130
+ expect { instance.fetch_version(3) }.to raise_error(ArgumentError)
131
+ end
132
+
133
+ it "should delegate to the version on #fetch_event" do
134
+ expect(@version_1).to receive(:fetch_event).once.with(:bar, :baz).and_return(:quux)
135
+ expect(instance.fetch_event(1, :bar, :baz)).to eq(:quux)
136
+ end
137
+
138
+ it "should raise if asked for an event in a version it doesn't have" do
139
+ expect { instance.fetch_event(3, :foo, :bar) }.to raise_error(ArgumentError)
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,146 @@
1
+ describe ::MetaEvents::Definition::Event do
2
+ let(:klass) { ::MetaEvents::Definition::Event }
3
+
4
+ it "should normalize the name properly" do
5
+ expect { klass.normalize_name(nil) }.to raise_error(ArgumentError)
6
+ expect { klass.normalize_name("") }.to raise_error(ArgumentError)
7
+ expect(klass.normalize_name(:foo)).to eq(:foo)
8
+ expect(klass.normalize_name(:' FoO')).to eq(:foo)
9
+ expect(klass.normalize_name(" FOo ")).to eq(:foo)
10
+ expect(klass.normalize_name("foo")).to eq(:foo)
11
+ end
12
+
13
+ let(:category) do
14
+ out = double("category")
15
+ allow(out).to receive(:kind_of?).with(::MetaEvents::Definition::Category).and_return(true)
16
+ allow(out).to receive(:name).with().and_return(:catname)
17
+ allow(out).to receive(:retired_at).with().and_return(nil)
18
+ allow(out).to receive(:prefix).with().and_return("cp_")
19
+ allow(out).to receive(:to_s).with().and_return("cat_to_s")
20
+ out
21
+ end
22
+
23
+ it "should validate its basic arguments properly" do
24
+ expect { klass.new(double("not-a-category"), :foo, "2014-01-01", "something") }.to raise_error(ArgumentError)
25
+ expect { klass.new(category, nil, "2014-01-01", "something") }.to raise_error(ArgumentError)
26
+ expect { klass.new(category, :foo, "2014-01-01", "something", :bonk => :baz) }.to raise_error(ArgumentError, /bonk/i)
27
+
28
+ # Ruby 1.8.x's Time.parse method will accept "foo" for Time.parse and just return Time.now --
29
+ # which is deeply unfortunate, but there's really no good way around it.
30
+ unless RUBY_VERSION =~ /^1\.8\./
31
+ expect { klass.new(category, :foo, "unparseable", "something") }.to raise_error(ArgumentError)
32
+ expect { klass.new(category, :foo, :desc => "something", :introduced => "unparseable") }.to raise_error(ArgumentError)
33
+ end
34
+ end
35
+
36
+ it "should fail if you don't set introduced or desc" do
37
+ expect { klass.new(category, :foo, :introduced => '2014-01-01' ) }.to raise_error(ArgumentError)
38
+ expect { klass.new(category, :foo, :desc => 'something' ) }.to raise_error(ArgumentError)
39
+ expect { klass.new(category, :foo, :desc => '' ) }.to raise_error(ArgumentError)
40
+ end
41
+
42
+ it "should let you set introduced via all three mechanisms" do
43
+ expect(klass.new(category, :foo, "2014-01-01", "foobar").introduced).to eq(Time.parse('2014-01-01'))
44
+ expect(klass.new(category, :foo, nil, "foobar", :introduced => '2014-01-01').introduced).to eq(Time.parse('2014-01-01'))
45
+ expect(klass.new(category, :foo, nil, "foobar") { introduced '2014-01-01' }.introduced).to eq(Time.parse('2014-01-01'))
46
+ end
47
+
48
+ it "should let you set desc via all three mechanisms" do
49
+ expect(klass.new(category, :foo, "2014-01-01", "foobar").desc).to eq("foobar")
50
+ expect(klass.new(category, :foo, "2014-01-01", :desc => 'foobar').desc).to eq("foobar")
51
+ expect(klass.new(category, :foo, "2014-01-01", :description => 'foobar').desc).to eq("foobar")
52
+ expect(klass.new(category, :foo, "2014-01-01") { desc 'foobar' }.desc).to eq("foobar")
53
+ end
54
+
55
+ context "with an instance" do
56
+ let(:instance) { klass.new(category, :foo, "2014-01-01", "foobar") }
57
+
58
+ describe "validation" do
59
+ it "should not fail by default" do
60
+ expect { instance.validate!(:foo => :bar) }.not_to raise_error
61
+ end
62
+
63
+ it "should fail if it's been retired" do
64
+ expect { klass.new(category, :foo, "2014-01-01", "foobar", :retired_at => "2013-06-01").validate!(:foo => :bar) }.to raise_error(::MetaEvents::Definition::DefinitionSet::RetiredEventError, /2013/)
65
+ end
66
+
67
+ it "should fail if its category has been retired" do
68
+ allow(category).to receive(:retired_at).and_return(Time.parse("2013-02-01"))
69
+ expect { instance.validate!(:foo => :bar) }.to raise_error(::MetaEvents::Definition::DefinitionSet::RetiredEventError, /2013/)
70
+ end
71
+ end
72
+
73
+ it "should return and allow setting its description via #desc" do
74
+ expect(instance.desc).to eq("foobar")
75
+ instance.desc "barbaz"
76
+ expect(instance.desc).to eq("barbaz")
77
+ end
78
+
79
+ it "should return and allow setting its introduction time via #introduced" do
80
+ expect(instance.introduced).to eq(Time.parse("2014-01-01"))
81
+ instance.introduced "2015-06-30"
82
+ expect(instance.introduced).to eq(Time.parse("2015-06-30"))
83
+ end
84
+
85
+ it "should return its category" do
86
+ expect(instance.category).to eq(category)
87
+ end
88
+
89
+ it "should return its name" do
90
+ expect(instance.name).to eq(:foo)
91
+ end
92
+
93
+ it "should return its category name" do
94
+ expect(instance.category_name).to eq(:catname)
95
+ end
96
+
97
+ it "should return its full name" do
98
+ expect(instance.full_name).to eq("cp_foo")
99
+ end
100
+
101
+ it "should return the right value for #retired_at" do
102
+ expect(instance.retired_at).to be_nil
103
+ expect(klass.new(category, :foo, "2014-01-01", "foobar", :retired_at => "2013-06-01").retired_at).to eq(Time.parse("2013-06-01"))
104
+
105
+ allow(category).to receive(:retired_at).with().and_return(Time.parse("2013-04-01"))
106
+ expect(klass.new(category, :foo, "2014-01-01", "foobar", :retired_at => "2013-06-01").retired_at).to eq(Time.parse("2013-04-01"))
107
+ expect(klass.new(category, :foo, "2014-01-01", "foobar", :retired_at => "2013-02-01").retired_at).to eq(Time.parse("2013-02-01"))
108
+ expect(klass.new(category, :foo, "2014-01-01", "foobar").retired_at).to eq(Time.parse("2013-04-01"))
109
+ end
110
+
111
+ it "should become a string" do
112
+ expect(instance.to_s).to match(/foo/i)
113
+ expect(instance.to_s).to match(/cat_to_s/i)
114
+ end
115
+
116
+ it "should require valid data for #note" do
117
+ expect { instance.note("", "me", "something here") }.to raise_error(ArgumentError)
118
+
119
+ # Ruby 1.8.x's Time.parse method will accept "foo" for Time.parse and just return Time.now --
120
+ # which is deeply unfortunate, but there's really no good way around it.
121
+ unless RUBY_VERSION =~ /^1\.8\./
122
+ expect { instance.note("foobar", "me", "something here") }.to raise_error(ArgumentError)
123
+ end
124
+
125
+ expect { instance.note("2014-01-01", "", "something here") }.to raise_error(ArgumentError)
126
+ expect { instance.note("2014-01-01", "me", "") }.to raise_error(ArgumentError)
127
+ end
128
+
129
+ it "should allow you to add notes, and return them" do
130
+ instance.note("2014-01-01", "me", "this is cool")
131
+ instance.note("2013-02-27", "someone else", "whatever")
132
+
133
+ expect(instance.notes.length).to eq(2)
134
+
135
+ note_1 = instance.notes[0]
136
+ expect(note_1[:when_left]).to eq(Time.parse("2014-01-01"))
137
+ expect(note_1[:who]).to eq("me")
138
+ expect(note_1[:text]).to eq("this is cool")
139
+
140
+ note_2 = instance.notes[1]
141
+ expect(note_2[:when_left]).to eq(Time.parse("2013-02-27"))
142
+ expect(note_2[:who]).to eq("someone else")
143
+ expect(note_2[:text]).to eq("whatever")
144
+ end
145
+ end
146
+ end