sandthorn_event_filter 0.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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +49 -0
- data/LICENSE.txt +22 -0
- data/README.md +60 -0
- data/Rakefile +13 -0
- data/lib/sandthorn_event_filter/event.rb +38 -0
- data/lib/sandthorn_event_filter/filter.rb +77 -0
- data/lib/sandthorn_event_filter/matchers/aggregate_type_matcher.rb +15 -0
- data/lib/sandthorn_event_filter/matchers/attribute_changed_matcher.rb +17 -0
- data/lib/sandthorn_event_filter/matchers/block_matcher.rb +15 -0
- data/lib/sandthorn_event_filter/matchers/event_name_matcher.rb +15 -0
- data/lib/sandthorn_event_filter/matchers/extract.rb +51 -0
- data/lib/sandthorn_event_filter/matchers/identity_matcher.rb +9 -0
- data/lib/sandthorn_event_filter/matchers/matcher.rb +20 -0
- data/lib/sandthorn_event_filter/matchers/matcher_collection.rb +36 -0
- data/lib/sandthorn_event_filter/matchers/not_matcher.rb +10 -0
- data/lib/sandthorn_event_filter/matchers/sequence_number_matcher.rb +16 -0
- data/lib/sandthorn_event_filter/version.rb +3 -0
- data/lib/sandthorn_event_filter.rb +7 -0
- data/sandthorn_event_filter.gemspec +32 -0
- data/spec/data/events.rb +28 -0
- data/spec/event_spec.rb +38 -0
- data/spec/filter_spec.rb +151 -0
- data/spec/matchers/attribute_changed_matcher_spec.rb +48 -0
- data/spec/matchers/block_matcher_spec.rb +26 -0
- data/spec/matchers/class_matcher_spec.rb +37 -0
- data/spec/matchers/event_name_matcher_spec.rb +36 -0
- data/spec/matchers/extract_spec.rb +60 -0
- data/spec/matchers/matcher_collection_spec.rb +47 -0
- data/spec/matchers/sequence_number_matcher_spec.rb +31 -0
- data/spec/spec_helper.rb +17 -0
- metadata +200 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1078458dda85cc9f4050925f006b34f2e1ee39b8
|
4
|
+
data.tar.gz: dacd493ed0495b299a8ee86a0c64caf9801a5592
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8ea5d12b472ae9e4f81d6f921b4839e3f2392bfc5c458529f3b38fed03294ce06dd01cd3a83415217a5ad21a020c2141efc1f593fcfd81c788615ab9c7d13d2f
|
7
|
+
data.tar.gz: 72cd5e9767b0a2c50be2dcdd12619928470209b38c7fc33cd60038215c960d72ef127e3573d127d9e7e6fd002964176d1f6774012ab0b143b35fef94cdaec2d6
|
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
/.idea/
|
12
|
+
|
13
|
+
## Documentation cache and generated files:
|
14
|
+
/.yardoc/
|
15
|
+
/_yardoc/
|
16
|
+
/doc/
|
17
|
+
/rdoc/
|
18
|
+
|
19
|
+
## Environment normalisation:
|
20
|
+
/.bundle/
|
21
|
+
/lib/bundler/man/
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sandthorn_event_filter (0.0.1)
|
5
|
+
hamster
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
autotest-standalone (4.5.11)
|
11
|
+
coderay (1.1.0)
|
12
|
+
diff-lcs (1.2.5)
|
13
|
+
dotenv (0.11.1)
|
14
|
+
dotenv-deployment (~> 0.0.2)
|
15
|
+
dotenv-deployment (0.0.2)
|
16
|
+
gem-release (0.7.3)
|
17
|
+
hamster (0.4.3)
|
18
|
+
method_source (0.8.2)
|
19
|
+
pry (0.10.0)
|
20
|
+
coderay (~> 1.1.0)
|
21
|
+
method_source (~> 0.8.1)
|
22
|
+
slop (~> 3.4)
|
23
|
+
rake (10.3.2)
|
24
|
+
rspec (3.0.0)
|
25
|
+
rspec-core (~> 3.0.0)
|
26
|
+
rspec-expectations (~> 3.0.0)
|
27
|
+
rspec-mocks (~> 3.0.0)
|
28
|
+
rspec-core (3.0.3)
|
29
|
+
rspec-support (~> 3.0.0)
|
30
|
+
rspec-expectations (3.0.3)
|
31
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
32
|
+
rspec-support (~> 3.0.0)
|
33
|
+
rspec-mocks (3.0.3)
|
34
|
+
rspec-support (~> 3.0.0)
|
35
|
+
rspec-support (3.0.3)
|
36
|
+
slop (3.6.0)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
autotest-standalone
|
43
|
+
bundler (~> 1.6)
|
44
|
+
dotenv
|
45
|
+
gem-release
|
46
|
+
pry
|
47
|
+
rake
|
48
|
+
rspec
|
49
|
+
sandthorn_event_filter!
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Jesper Josefsson
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
[](https://travis-ci.org/Sandthorn/sandthorn_event_filter)
|
2
|
+
|
3
|
+
# SandthornEventFilter
|
4
|
+
|
5
|
+
SandthornEventFilter is a library for creating composable event filters.
|
6
|
+
They are composable in the following senses:
|
7
|
+
|
8
|
+
- chained filters get boiled down to a single expression, meaning we can filter in just one pass
|
9
|
+
- filters are immutable and can be extended with further chaining
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'event_filter'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install event_filter
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
The basic way to use a Filter is to wrap an array of Events:
|
28
|
+
|
29
|
+
filter = SandthornEventFilter::Filter.new(my_events)
|
30
|
+
|
31
|
+
You can always call `.events` to get the filtered events:
|
32
|
+
|
33
|
+
# This filter is empty, and will return the original events
|
34
|
+
filter.events
|
35
|
+
# => [...]
|
36
|
+
|
37
|
+
You can also enumerate on the filter directly:
|
38
|
+
|
39
|
+
filter.each { |event| puts event.inspect }
|
40
|
+
|
41
|
+
`extract` returns a new filter that extracts the chosen events:
|
42
|
+
|
43
|
+
new_events = filter.extract(events: "new", types: MyAggregate, after_sequence_number: 100)
|
44
|
+
new_events.events
|
45
|
+
# => events that match the criteria
|
46
|
+
|
47
|
+
`remove` returns a new filter with removes the chosen events:
|
48
|
+
|
49
|
+
except_new = filter.remove(events: "new")
|
50
|
+
except_new.events
|
51
|
+
# => events except those with event name "new"
|
52
|
+
|
53
|
+
`select` and `reject` behave as you would expect, except they return a new filter instance.
|
54
|
+
|
55
|
+
You can also create a filter chain without supplying initial events, and apply that chain to any
|
56
|
+
array of events.
|
57
|
+
|
58
|
+
filter = Filter.new.reject(events: "new")
|
59
|
+
filter.apply(my_array_of_events)
|
60
|
+
# => [ ... array ... ]
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'sandthorn_event_filter'
|
3
|
+
require 'dotenv/tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
task default: :spec
|
9
|
+
|
10
|
+
desc "Open an irb session preloaded with this library"
|
11
|
+
task :console do
|
12
|
+
sh "irb -rubygems -I lib -r sandthorn_event_filter.rb"
|
13
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
module SandthornEventFilter
|
3
|
+
class Event < SimpleDelegator
|
4
|
+
# Wraps raw event data and encapsulates knowledge about it
|
5
|
+
# Makes sure the event is in canonical form
|
6
|
+
# Delegates to the raw data hash, so you can still do Event.new(data)[:foo]
|
7
|
+
|
8
|
+
def attribute_changed?(attribute)
|
9
|
+
input_attributes = Array(attribute)
|
10
|
+
changed_attributes.any? do |attr|
|
11
|
+
input_attributes.include?(attr)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def changed_attributes
|
16
|
+
attribute_deltas.map do |delta|
|
17
|
+
delta[:attribute_name]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def attribute_deltas
|
22
|
+
self.fetch(:event_args, {}).fetch(:attribute_deltas, [])
|
23
|
+
end
|
24
|
+
|
25
|
+
def aggregate_type
|
26
|
+
self[:aggregate_type]
|
27
|
+
end
|
28
|
+
|
29
|
+
def name
|
30
|
+
self[:event_name]
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
alias_method :wrap, :new
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'sandthorn_event_filter/matchers/matcher_collection'
|
2
|
+
require 'sandthorn_event_filter/matchers/matcher'
|
3
|
+
require 'sandthorn_event_filter/matchers/extract'
|
4
|
+
require 'sandthorn_event_filter/matchers/attribute_changed_matcher'
|
5
|
+
require 'sandthorn_event_filter/matchers/not_matcher'
|
6
|
+
require 'sandthorn_event_filter/matchers/identity_matcher'
|
7
|
+
require 'sandthorn_event_filter/matchers/aggregate_type_matcher'
|
8
|
+
require 'sandthorn_event_filter/matchers/event_name_matcher'
|
9
|
+
require 'sandthorn_event_filter/matchers/block_matcher'
|
10
|
+
require 'sandthorn_event_filter/matchers/sequence_number_matcher'
|
11
|
+
|
12
|
+
module SandthornEventFilter
|
13
|
+
class Filter
|
14
|
+
# = Filter
|
15
|
+
# A composable event filter.
|
16
|
+
# Filters can be chained at will, but the actual filtering won't be done
|
17
|
+
# until a method is called that needs actual data.
|
18
|
+
#
|
19
|
+
# Filter methods (+remove+, +extract+, +select+, +reject+) return new instances of Filter, and do not affect
|
20
|
+
# the original filter.
|
21
|
+
#
|
22
|
+
# NOTE:
|
23
|
+
# This class expects well-formed events as input, and does nothing to transform events.
|
24
|
+
# TODO: throw error for malformed events? Or at least emit warning?
|
25
|
+
extend Forwardable
|
26
|
+
include Enumerable
|
27
|
+
|
28
|
+
def_delegators :events, :each, :last, :length, :empty?, :[]
|
29
|
+
|
30
|
+
attr_reader :matchers, :original_events
|
31
|
+
|
32
|
+
def initialize(events = [], matchers = Matchers::MatcherCollection.new)
|
33
|
+
@matchers = matchers
|
34
|
+
@original_events = events
|
35
|
+
end
|
36
|
+
|
37
|
+
def events
|
38
|
+
if @matchers.any?
|
39
|
+
@filtered_events ||= apply(original_events)
|
40
|
+
else
|
41
|
+
@original_events
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def extract(*args)
|
46
|
+
matcher = Matchers::Extract.new(*args)
|
47
|
+
add_matcher(matcher)
|
48
|
+
end
|
49
|
+
|
50
|
+
# A remove matcher is a negated extract matcher
|
51
|
+
def remove(*args)
|
52
|
+
matcher = Matchers::NotMatcher.new(Matchers::Extract.new(*args))
|
53
|
+
add_matcher(matcher)
|
54
|
+
end
|
55
|
+
|
56
|
+
def select(&block)
|
57
|
+
matcher = Matchers::BlockMatcher.new(&block)
|
58
|
+
add_matcher(matcher)
|
59
|
+
end
|
60
|
+
|
61
|
+
def reject(&block)
|
62
|
+
matcher = Matchers::NotMatcher.new(Matchers::BlockMatcher.new(&block))
|
63
|
+
add_matcher(matcher)
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_matcher(matcher)
|
67
|
+
# This works because .add returns a new MatcherCollection
|
68
|
+
new_matchers = @matchers.add(matcher)
|
69
|
+
self.class.new(original_events, new_matchers)
|
70
|
+
end
|
71
|
+
|
72
|
+
def apply(events)
|
73
|
+
@matchers.apply(events)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SandthornEventFilter
|
2
|
+
module Matchers
|
3
|
+
class AttributeChangedMatcher < Matcher
|
4
|
+
|
5
|
+
attr_reader :attributes
|
6
|
+
|
7
|
+
def initialize(attributes)
|
8
|
+
@attributes = Array(attributes)
|
9
|
+
end
|
10
|
+
|
11
|
+
def match?(event)
|
12
|
+
SandthornEventFilter::Event.wrap(event).attribute_changed?(attributes)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SandthornEventFilter
|
2
|
+
module Matchers
|
3
|
+
class EventNameMatcher < Matcher
|
4
|
+
|
5
|
+
def initialize(types)
|
6
|
+
@types = Array(types)
|
7
|
+
end
|
8
|
+
|
9
|
+
def match?(event)
|
10
|
+
@types.any? { |type| event[:event_name].to_s == type.to_s }
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module SandthornEventFilter
|
2
|
+
module Matchers
|
3
|
+
class Extract < Matcher
|
4
|
+
# = Extract
|
5
|
+
# Extract is basically an AND matcher.
|
6
|
+
# Given some matching criteria, it will construct submatchers,
|
7
|
+
# for example creating a ClassMatcher if provided with classes.
|
8
|
+
# Events match an Extract matcher if all of its submatchers match the event.
|
9
|
+
def match?(event)
|
10
|
+
submatchers_match?(event)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def submatchers_match?(event)
|
16
|
+
submatchers.all? { |submatcher| submatcher.match?(event) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def submatchers
|
20
|
+
@submatchers ||= construct_submatchers
|
21
|
+
end
|
22
|
+
|
23
|
+
def construct_submatchers
|
24
|
+
matchers = []
|
25
|
+
add_class_matcher(matchers, options)
|
26
|
+
add_event_name_matcher(matchers, options)
|
27
|
+
add_changed_attributes_matcher(matchers, options)
|
28
|
+
matchers
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_class_matcher(matchers, options)
|
32
|
+
if types = options[:types]
|
33
|
+
matchers << AggregateTypeMatcher.new(types)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_event_name_matcher(matchers, options)
|
38
|
+
if names = options[:events]
|
39
|
+
matchers << EventNameMatcher.new(names)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_changed_attributes_matcher(matchers, options)
|
44
|
+
if attributes = options[:changed_attributes]
|
45
|
+
matchers << AttributeChangedMatcher.new(attributes)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SandthornEventFilter
|
2
|
+
module Matchers
|
3
|
+
class Matcher
|
4
|
+
# = Matcher
|
5
|
+
# Abstract class.
|
6
|
+
# Matches an event. Must implement a +match?+ method.
|
7
|
+
# Used to filter collections of events.
|
8
|
+
attr_reader :options
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def match?(event)
|
15
|
+
raise NotImplementedError, "subclasses should override"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'hamster/list'
|
3
|
+
|
4
|
+
module SandthornEventFilter
|
5
|
+
module Matchers
|
6
|
+
class MatcherCollection
|
7
|
+
# = MatcherCollection
|
8
|
+
# A collection of Matchers which can be applied to a collection of events.
|
9
|
+
extend Forwardable
|
10
|
+
attr_reader :matchers
|
11
|
+
def_delegators :@matchers, :any?
|
12
|
+
|
13
|
+
def initialize(matchers = Hamster.list)
|
14
|
+
@matchers = matchers
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns all events that match all of the matchers in the collection
|
18
|
+
def apply(events)
|
19
|
+
events.select { |event| matchers.all? { |matcher| matcher.match?(event) } }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns a new instance of MatcherCollection, with the new matchers added.
|
23
|
+
# Since @matchers is a persistent, immutable Hamster::List,
|
24
|
+
# adding all new matchers and sending the resulting list to the
|
25
|
+
# new instance is safe.
|
26
|
+
def add(input_matchers)
|
27
|
+
input_matchers = Array(input_matchers)
|
28
|
+
matchers = input_matchers.reduce(@matchers) do |matcher_collection, matcher|
|
29
|
+
matcher_collection.cons(matcher)
|
30
|
+
end
|
31
|
+
self.class.new(matchers)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SandthornEventFilter
|
2
|
+
module Matchers
|
3
|
+
class SequenceNumberMatcher < Matcher
|
4
|
+
|
5
|
+
attr_reader :sequence_number
|
6
|
+
|
7
|
+
def initialize(sequence_number)
|
8
|
+
@sequence_number = sequence_number
|
9
|
+
end
|
10
|
+
|
11
|
+
def match?(event)
|
12
|
+
event[:sequence_number] > sequence_number
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sandthorn_event_filter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sandthorn_event_filter"
|
8
|
+
spec.version = SandthornEventFilter::VERSION
|
9
|
+
spec.authors = ["Jesper Josefsson"]
|
10
|
+
spec.email = ["jesper.josefsson@gmail.com"]
|
11
|
+
spec.summary = %q{Composable filters for Sandthorn Events}
|
12
|
+
spec.homepage = "https://github.com/Sandthorn"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
# added by upptec_create_gem
|
21
|
+
spec.add_development_dependency "pry"
|
22
|
+
spec.add_development_dependency "rspec"
|
23
|
+
spec.add_development_dependency "gem-release"
|
24
|
+
spec.add_development_dependency "autotest-standalone"
|
25
|
+
spec.add_development_dependency "dotenv"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
|
30
|
+
spec.add_runtime_dependency "hamster"
|
31
|
+
|
32
|
+
end
|
data/spec/data/events.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module SandthornEventFilter
|
4
|
+
module Fixtures
|
5
|
+
EVENTS =
|
6
|
+
[{:aggregate_type=>"SandthornProduct", :aggregate_version=>1, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>1, :event_name=>"new", :timestamp=>Time.parse('2014-04-08 12:22:09 UTC'), :event_args=>{:method_name=>"new", :method_args=>[{"name"=>"Morgan", "price"=>"666", "stock_status"=>"instock"}], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>nil, :new_value=>"Morgan"}, {:attribute_name=>"price", :old_value=>nil, :new_value=>"666"}, {:attribute_name=>"stock_status", :old_value=>nil, :new_value=>"instock"}, {:attribute_name=>"active", :old_value=>nil, :new_value=>true}, {:attribute_name=>"aggregate_id", :old_value=>nil, :new_value=>"da932773-dd06-43dc-8c0c-61837f009226"}]}},
|
7
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>2, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>2, :event_name=>"name_updated", :timestamp=>Time.parse('2014-04-08 12:22:17 UTC'), :event_args=>{:method_name=>"name_updated", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>"Morgan", :new_value=>"Morgan Hallgren"}]}},
|
8
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>3, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>3, :event_name=>"price_updated", :timestamp=>Time.parse('2014-04-08 12:22:19 UTC'), :event_args=>{:method_name=>"price_updated", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"price", :old_value=>"666", :new_value=>"999"}]}},
|
9
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>4, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>4, :event_name=>"product_discontinued", :timestamp=>Time.parse('2014-04-08 12:22:20 UTC'), :event_args=>{:method_name=>"product_discontinued", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"stock_status", :old_value=>"instock", :new_value=>"discontinued"}]}},
|
10
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>5, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>5, :event_name=>"price_updated", :timestamp=>Time.parse('2014-04-08 13:35:29 UTC'), :event_args=>{:method_name=>"price_updated", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"price", :old_value=>"999", :new_value=>"1000"}]}},
|
11
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>6, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>6, :event_name=>"price_updated", :timestamp=>Time.parse('2014-04-08 13:40:28 UTC'), :event_args=>{:method_name=>"price_updated", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"price", :old_value=>"1000", :new_value=>"1001"}]}},
|
12
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>7, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>7, :event_name=>"product_on_sale", :timestamp=>Time.parse('2014-04-09 09:14:45 UTC'), :event_args=>{:method_name=>"product_on_sale", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>"Morgan Hallgren", :new_value=>"ON SALE!!!! Morgan Hallgren"}, {:attribute_name=>"price", :old_value=>"1001", :new_value=>0}, {:attribute_name=>"on_sale", :old_value=>false, :new_value=>true}]}},
|
13
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>8, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>8, :event_name=>"removed_from_sale", :timestamp=>Time.parse('2014-04-09 09:15:03 UTC'), :event_args=>{:method_name=>"removed_from_sale", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>"ON SALE!!!! Morgan Hallgren", :new_value=>"Morgan Hallgren"}, {:attribute_name=>"on_sale", :old_value=>true, :new_value=>false}]}},
|
14
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>9, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>9, :event_name=>"price_updated", :timestamp=>Time.parse('2014-04-09 09:15:06 UTC'), :event_args=>{:method_name=>"price_updated", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"price", :old_value=>0, :new_value=>100}]}},
|
15
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>10, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>10, :event_name=>"product_on_sale", :timestamp=>Time.parse('2014-04-09 09:15:11 UTC'), :event_args=>{:method_name=>"product_on_sale", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>"Morgan Hallgren", :new_value=>"ON SALE!!!! Morgan Hallgren"}, {:attribute_name=>"price", :old_value=>100, :new_value=>80}, {:attribute_name=>"on_sale", :old_value=>false, :new_value=>true}]}},
|
16
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>11, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>11, :event_name=>"product_out_of_stock", :timestamp=>Time.parse('2014-04-09 19:45:38 UTC'), :event_args=>{:method_name=>"product_out_of_stock", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"stock_status", :old_value=>"discontinued", :new_value=>"outofstock"}]}},
|
17
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>12, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>12, :event_name=>"removed_from_sale", :timestamp=>Time.parse('2014-04-09 19:45:53 UTC'), :event_args=>{:method_name=>"removed_from_sale", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>"ON SALE!!!! Morgan Hallgren", :new_value=>"Morgan Hallgren"}, {:attribute_name=>"price", :old_value=>80, :new_value=>100}, {:attribute_name=>"on_sale", :old_value=>true, :new_value=>false}]}},
|
18
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>13, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>13, :event_name=>"price_updated", :timestamp=>Time.parse('2014-04-10 14:03:28 UTC'), :event_args=>{:method_name=>"price_updated", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"price", :old_value=>100, :new_value=>111}]}},
|
19
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>14, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>14, :event_name=>"stock_status_updated", :timestamp=>Time.parse('2014-04-10 14:03:28 UTC'), :event_args=>{:method_name=>"stock_status_updated", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"stock_status", :old_value=>"outofstock", :new_value=>nil}]}},
|
20
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>15, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>15, :event_name=>"stock_status_updated", :timestamp=>Time.parse('2014-04-10 21:32:30 UTC'), :event_args=>{:method_name=>"stock_status_updated", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"stock_status", :old_value=>nil, :new_value=>"discontinued"}]}},
|
21
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>16, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>16, :event_name=>"product_on_sale", :timestamp=>Time.parse('2014-04-10 21:32:55 UTC'), :event_args=>{:method_name=>"product_on_sale", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>"Morgan Hallgren", :new_value=>"ON SALE!!!! Morgan Hallgren"}, {:attribute_name=>"price", :old_value=>111, :new_value=>88}, {:attribute_name=>"on_sale", :old_value=>false, :new_value=>true}]}},
|
22
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>17, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>17, :event_name=>"removed_from_sale", :timestamp=>Time.parse('2014-04-10 21:32:56 UTC'), :event_args=>{:method_name=>"removed_from_sale", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>"ON SALE!!!! Morgan Hallgren", :new_value=>"Morgan Hallgren"}, {:attribute_name=>"price", :old_value=>88, :new_value=>110}, {:attribute_name=>"on_sale", :old_value=>true, :new_value=>false}]}},
|
23
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>18, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>18, :event_name=>"product_on_sale", :timestamp=>Time.parse('2014-04-10 21:32:57 UTC'), :event_args=>{:method_name=>"product_on_sale", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>"Morgan Hallgren", :new_value=>"ON SALE!!!! Morgan Hallgren"}, {:attribute_name=>"price", :old_value=>110, :new_value=>88}, {:attribute_name=>"on_sale", :old_value=>false, :new_value=>true}]}},
|
24
|
+
{:aggregate_type=>"SandthornProduct", :aggregate_version=>19, :aggregate_id=>"da932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>19, :event_name=>"removed_from_sale", :timestamp=>Time.parse('2014-04-10 21:32:58 UTC'), :event_args=>{:method_name=>"removed_from_sale", :method_args=>[], :attribute_deltas=>[{:attribute_name=>"name", :old_value=>"ON SALE!!!! Morgan Hallgren", :new_value=>"Morgan Hallgren"}, {:attribute_name=>"price", :old_value=>88, :new_value=>110}, {:attribute_name=>"on_sale", :old_value=>true, :new_value=>false}]}},
|
25
|
+
{:aggregate_type=>"SandthornTest", :aggregate_version=>1, :aggregate_id=>"xa932773-dd06-43dc-8c0c-61837f009226", :sequence_number=>20, :event_name=>"new", :timestamp=>Time.parse('2014-04-10 21:32:59 UTC'), :event_args=>{:attribute_deltas=>[{:attribute_name=>"name", :old_value=>"Morgan Hallgren", :new_value=>"ON SALE!!!! Morgan Hallgren"}, {:attribute_name=>"price", :old_value=>110, :new_value=>88}, {:attribute_name=>"on_sale", :old_value=>false, :new_value=>true}]}}
|
26
|
+
]
|
27
|
+
end
|
28
|
+
end
|
data/spec/event_spec.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module SandthornEventFilter
|
4
|
+
describe Event do
|
5
|
+
let(:event) { Event.wrap(Fixtures::EVENTS.first) }
|
6
|
+
let(:deltas) do [
|
7
|
+
{:attribute_name => "name", :old_value => nil, :new_value => "Morgan"},
|
8
|
+
{:attribute_name => "price", :old_value => nil, :new_value => "666"},
|
9
|
+
{:attribute_name => "stock_status", :old_value => nil, :new_value => "instock"},
|
10
|
+
{:attribute_name => "active", :old_value => nil, :new_value => true},
|
11
|
+
{:attribute_name => "aggregate_id", :old_value => nil, :new_value => "da932773-dd06-43dc-8c0c-61837f009226"}]
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#attribute_changed?" do
|
15
|
+
context "when the attribute is included in the attribute deltas" do
|
16
|
+
it "should return true" do
|
17
|
+
deltas.map { |delta| delta[:attribute_name] }.each do |attribute|
|
18
|
+
expect(event.attribute_changed?(attribute)).to be_truthy
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when the attribute is bogus" do
|
24
|
+
it "should return false" do
|
25
|
+
expect(event.attribute_changed?("foo")).to be_falsey
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#attribute_deltas" do
|
31
|
+
it "should return the deltas" do
|
32
|
+
expect(event.attribute_deltas).to eq(deltas)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|