eventus 0.2.0

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.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.swp
6
+ vendor/bundle
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rspec'
7
+ gem 'guard-rspec'
8
+ gem 'libnotify' if RUBY_PLATFORM =~ /linux/i
9
+ gem 'uuid'
10
+ gem 'kyotocabinet-ruby'
11
+ end
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec', :version => 2 do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+
6
+ end
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ eventus
2
+ ===
3
+
4
+ A Ruby Event Store
5
+
6
+ License
7
+ ---
8
+
9
+ Copyright (c) 2012, Jason Staten, PeerIntel
10
+
11
+ All rights reserved.
12
+
13
+ Redistribution and use in source and binary forms, with or without
14
+ modification, are permitted provided that the following conditions are met:
15
+
16
+ - Redistributions of source code must retain the above copyright notice, this
17
+ list of conditions and the following disclaimer.
18
+
19
+ - Redistributions in binary form must reproduce the above copyright notice,
20
+ this list of conditions and the following disclaimer in the documentation
21
+ and/or other materials provided with the distribution.
22
+
23
+ - Neither the name of PeerIntel nor the names of its contributors may be used
24
+ to endorse or promote products derived from this software without specific
25
+ prior written permission.
26
+
27
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
28
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
31
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
36
+ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
data/eventus.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "eventus/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "eventus"
7
+ s.version = Eventus::VERSION
8
+ s.authors = ["Jason Staten"]
9
+ s.email = ["jstaten07@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Event Store}
12
+ s.description = %q{An Event Store}
13
+
14
+ s.rubyforge_project = "eventus"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ end
@@ -0,0 +1,48 @@
1
+ module Eventus
2
+ module AggregateRoot
3
+ module ClassMethods
4
+ def find(id)
5
+ instance = self.new
6
+ stream = Eventus::Stream.new(id, persistence)
7
+ instance.populate(stream)
8
+ instance
9
+ end
10
+
11
+ def apply(event_name, &block)
12
+ raise "A block is required" unless block_given?
13
+ define_method("apply_#{event_name}", &block)
14
+ end
15
+
16
+ def persistence
17
+ @persistence ||= Eventus.persistence
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+ def populate(stream)
23
+ @stream = stream
24
+ stream.committed_events.each do |event|
25
+ apply_change event[:name], event[:body], false
26
+ end
27
+ end
28
+
29
+ def save
30
+ @stream.commit
31
+ end
32
+
33
+ protected
34
+
35
+ def apply_change(name, body=nil, is_new=true)
36
+ method_name = "apply_#{name}"
37
+ self.send method_name, body if self.respond_to?(method_name)
38
+
39
+ @stream.add({:name => name, :body => body}) if is_new
40
+ end
41
+ end
42
+
43
+ def self.included(base)
44
+ base.send :include, InstanceMethods
45
+ base.send :extend, ClassMethods
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module Eventus
2
+ class ConcurrencyError < ::StandardError; end
3
+ end
@@ -0,0 +1,42 @@
1
+ module Eventus
2
+ module Persistence
3
+ class InMemory
4
+
5
+ def initialize(options = {})
6
+ @store = {}
7
+ @serializer = options.fetch(:serializer) { Eventus::Serializers::Marshal }
8
+ @mutex = Mutex.new
9
+ end
10
+
11
+ def commit(id, start, events)
12
+ @mutex.synchronize do
13
+ pending = {}
14
+ events.each_with_index do |event, index|
15
+ key = build_key(id, start + index)
16
+ raise Eventus::ConcurrencyError if @store.include? key
17
+ value = @serializer.serialize(event)
18
+ pending[key] = value
19
+ end
20
+ @store.merge! pending
21
+ end
22
+ end
23
+
24
+ def load(id, min=nil)
25
+ @mutex.synchronize do
26
+ keys = @store.keys.select { |k| k.start_with? id }.sort
27
+
28
+ if min
29
+ min_key = build_key(id, min)
30
+ keys = keys.drop_while { |k| k != min_key }
31
+ end
32
+
33
+ keys.map { |k| @serializer.deserialize(@store[k]) }
34
+ end
35
+ end
36
+
37
+ def build_key(id, index)
38
+ id + ("_%07d" % index)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ require 'kyotocabinet'
2
+
3
+ module Eventus
4
+ module Persistence
5
+ class KyotoCabinet
6
+
7
+ def initialize(options = {})
8
+ @db = ::KyotoCabinet::DB::new
9
+ @db.open(options[:path], ::KyotoCabinet::DB::OCREATE)
10
+ @serializer = options.fetch(:serializer) { Eventus::Serializers::Marshal }
11
+ end
12
+
13
+ def commit(id, start, events)
14
+ pid = pack_hex(id)
15
+ @db.transaction do
16
+ events.each_with_index do |event, index|
17
+ key = build_key(pid, start + index)
18
+ value = @serializer.serialize(event)
19
+ raise Eventus::ConcurrencyError unless @db.add(key,value)
20
+ end
21
+ end
22
+ end
23
+
24
+ def load(id, min = nil)
25
+ pid = pack_hex(id)
26
+ keys = @db.match_prefix(pid)
27
+
28
+ if min
29
+ min_key = build_key(pid, min)
30
+ keys = keys.drop_while { |k| k != min_key }
31
+ end
32
+
33
+ @db.get_bulk(keys, false).values.map { |obj| @serializer.deserialize(obj) }
34
+ end
35
+
36
+ def pack_hex(id)
37
+ id.match(/^[0-9a-fA-F]+$/) ? [id].pack('H*') : id
38
+ end
39
+
40
+ def build_key(id, index)
41
+ id + ("_%07d" % index)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,6 @@
1
+ module Eventus
2
+ module Persistence
3
+ autoload :KyotoCabinet, 'eventus/persistence/kyotocabinet'
4
+ autoload :InMemory, 'eventus/persistence/in_memory'
5
+ end
6
+ end
@@ -0,0 +1,15 @@
1
+ module Eventus
2
+ module Serializers
3
+ module Marshal
4
+ class << self
5
+ def serialize(obj)
6
+ ::Marshal.dump obj
7
+ end
8
+
9
+ def deserialize(obj)
10
+ ::Marshal.load obj
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ require 'msgpack'
2
+
3
+ module Eventus
4
+ module Serializers
5
+ module MessagePack
6
+ class << self
7
+ def serialize(obj)
8
+ ::MessagePack.pack(obj)
9
+ end
10
+
11
+ def deserialize(obj)
12
+ ::MessagePack.unpack(obj)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ module Eventus
2
+ module Serializers
3
+ autoload :Marshal, 'eventus/serializers/marshal'
4
+ autoload :MessagePack, 'eventus/serializers/msgpack'
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ module Eventus
2
+ class Store
3
+
4
+ def initialize(persistence)
5
+ @persistence = persistence
6
+ end
7
+
8
+ def open id
9
+ @persistence.get_events(id)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,39 @@
1
+ module Eventus
2
+ class Stream
3
+
4
+ attr_reader :id, :committed_events, :uncommitted_events
5
+
6
+ def initialize(id, persistence)
7
+ @id = id
8
+ @persistence = persistence
9
+ @committed_events = []
10
+ @uncommitted_events = []
11
+ load_events @persistence.load(id)
12
+ end
13
+
14
+ def add(event)
15
+ @uncommitted_events << event
16
+ end
17
+
18
+ alias_method :<<, :add
19
+
20
+ def commit
21
+ @persistence.commit @id, version, @uncommitted_events
22
+ load_events @uncommitted_events
23
+ @uncommitted_events.clear
24
+ rescue ConcurrencyError => e
25
+ load_events @persistence.load(id, version + 1)
26
+ raise e
27
+ end
28
+
29
+ def version
30
+ @committed_events.length
31
+ end
32
+
33
+ private
34
+
35
+ def load_events(events)
36
+ events.each { |e| @committed_events << e }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module Eventus
2
+ VERSION = "0.2.0"
3
+ end
data/lib/eventus.rb ADDED
@@ -0,0 +1,17 @@
1
+ module Eventus
2
+ autoload :Serializers, 'eventus/serializers'
3
+ autoload :AggregateRoot, 'eventus/aggregate_root'
4
+
5
+ class << self
6
+
7
+ def persistence
8
+ @persistence ||= Eventus::Persistence::InMemory.new
9
+ end
10
+
11
+ def persistence=(val)
12
+ @persistence = val
13
+ end
14
+ end
15
+ end
16
+
17
+ %w{store stream version persistence errors}.each { |r| require "eventus/#{r}" }
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ class TestAgg
4
+ include Eventus::AggregateRoot
5
+
6
+ attr_accessor :loaded
7
+
8
+ def bake_cake
9
+ apply_change :cake_baked, :flavor => 'strawberry'
10
+ end
11
+
12
+ apply :dino do |e|
13
+ @loaded = true
14
+ end
15
+ end
16
+
17
+ describe Eventus::AggregateRoot do
18
+ let(:events) { [] }
19
+ let(:persistence) { stub.as_null_object }
20
+
21
+ before do
22
+ TestAgg.stub(:persistence).and_return(persistence)
23
+ end
24
+
25
+ it "should load a new aggregate from find" do
26
+ result = TestAgg.find('abc')
27
+ result.should_not be_nil
28
+ end
29
+
30
+ describe "when events exist" do
31
+ before do
32
+ persistence.should_receive(:load).with('abc').and_return(events)
33
+ events << {:name => 'dino', :body => {}}
34
+ end
35
+
36
+ it "should apply the event" do
37
+ result = TestAgg.find('abc')
38
+ result.loaded.should == true
39
+ end
40
+ end
41
+
42
+ describe "when applying a new change" do
43
+ let(:aggregate) { TestAgg.new }
44
+ let(:stream) { stub(:stream, :committed_events => []) }
45
+
46
+ before do
47
+ aggregate.populate(stream)
48
+ end
49
+
50
+ it "should be added to the stream" do
51
+ stream.should_receive(:add)
52
+ aggregate.bake_cake
53
+ end
54
+ end
55
+
56
+ describe "when saving" do
57
+ let(:aggregate) { TestAgg.new }
58
+ let(:stream) { stub(:stream, :committed_events => []) }
59
+
60
+ before do
61
+ aggregate.populate(stream)
62
+ end
63
+
64
+ it "should commit stream" do
65
+ stream.should_receive(:commit)
66
+ aggregate.save
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eventus::Persistence::InMemory do
4
+ let(:options) { {:path => '%'} }
5
+ let(:persistence) { Eventus::Persistence::InMemory.new(options) }
6
+ let(:uuid) { UUID.new }
7
+
8
+ it "should store complex objects" do
9
+ id = uuid.generate :compact
10
+ o = {'a' => 'super', 'complex' => ['object', 'with', {'nested' => ['members', 'galore', 1]}]}
11
+ persistence.commit id, 1, [o]
12
+
13
+ result = persistence.load id
14
+ result[0].should == o
15
+ end
16
+
17
+ it "should return no events when key not found" do
18
+ result = persistence.load "my_id"
19
+ result.should be_empty
20
+ end
21
+
22
+ it "should return events ordered" do
23
+ id = uuid.generate :compact
24
+ persistence.commit id, 5, ["five", "six"]
25
+ persistence.commit id, 1, ["one", "two"]
26
+ persistence.commit id, 3, ["three", "four"]
27
+ persistence.commit "other", 1, ["cake", "batter"]
28
+
29
+ result = persistence.load id
30
+ result.should == ["one", "two", "three", "four", "five", "six"]
31
+ end
32
+
33
+ describe "when events exist" do
34
+ let(:id) { uuid.generate :compact }
35
+ let(:events) { (1..20).map {|i| "Body #{i}"} }
36
+ before do
37
+ persistence.commit id, 1, events
38
+ other_events = (1..60).map {|i| "Other #{i}"}
39
+ persistence.commit uuid.generate(:compact), 1, events
40
+ end
41
+
42
+ it "should load events" do
43
+ result = persistence.load id
44
+ result.length.should == 20
45
+ end
46
+
47
+ it "should throw concurrency exception if the same event number is added" do
48
+ lambda {persistence.commit id, 3, ["This is taken"]}.should raise_error(Eventus::ConcurrencyError)
49
+ end
50
+
51
+ it "should rollback changes on concurrency error" do
52
+ persistence.commit id, 3, ["first", "second", "third"] rescue nil
53
+
54
+ result = persistence.load id
55
+ result.length.should == 20
56
+ end
57
+
58
+ it "should load all events from a minimum" do
59
+ result = persistence.load id, 10
60
+ result.length.should == 11
61
+ end
62
+ end
63
+
64
+ describe "when serialization is set" do
65
+ let(:serializer) { stub }
66
+ before do
67
+ options[:serializer] = serializer
68
+ end
69
+
70
+ it "should use serializer" do
71
+ input = "original"
72
+ ser = "i'm serialized!"
73
+
74
+ serializer.should_receive(:serialize).with(input).and_return(ser)
75
+ serializer.should_receive(:deserialize).with(ser).and_return(input)
76
+
77
+ id = uuid.generate :compact
78
+
79
+ persistence.commit id, 1, [input]
80
+ result = persistence.load id
81
+ result[0].should == input
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eventus::Persistence::KyotoCabinet do
4
+ let(:options) { {:path => '%'} }
5
+ let(:persistence) { Eventus::Persistence::KyotoCabinet.new(options) }
6
+ let(:uuid) { UUID.new }
7
+
8
+ it "should pack keys" do
9
+ 1000.times do
10
+ key = uuid.generate(:compact)
11
+ packed = persistence.pack_hex(key)
12
+ packed.unpack('H*')[0].should == key
13
+ end
14
+ end
15
+
16
+ it "should not pack non-hex strings" do
17
+ key = 'abc123q'
18
+ packed = persistence.pack_hex(key)
19
+ packed.should == key
20
+ end
21
+
22
+ it "should store complex objects" do
23
+ id = uuid.generate :compact
24
+ o = {'a' => 'super', 'complex' => ['object', 'with', {'nested' => ['members', 'galore', 1]}]}
25
+ persistence.commit id, 1, [o]
26
+
27
+ result = persistence.load id
28
+ result[0].should == o
29
+ end
30
+
31
+ it "should return no events when key not found" do
32
+ result = persistence.load "my_id"
33
+ result.should be_empty
34
+ end
35
+
36
+ it "should return events ordered" do
37
+ id = uuid.generate :compact
38
+ persistence.commit id, 5, ["five", "six"]
39
+ persistence.commit id, 1, ["one", "two"]
40
+ persistence.commit id, 3, ["three", "four"]
41
+ persistence.commit "other", 1, ["cake", "batter"]
42
+
43
+ result = persistence.load id
44
+ result.should == ["one", "two", "three", "four", "five", "six"]
45
+ end
46
+
47
+ describe "when events exist" do
48
+ let(:id) { uuid.generate :compact }
49
+ let(:events) { (1..20).map {|i| "Body #{i}"} }
50
+ before do
51
+ persistence.commit id, 1, events
52
+ other_events = (1..60).map {|i| "Other #{i}"}
53
+ persistence.commit uuid.generate(:compact), 1, events
54
+ end
55
+
56
+ it "should load events" do
57
+ result = persistence.load id
58
+ result.length.should == 20
59
+ end
60
+
61
+ it "should throw concurrency exception if the same event number is added" do
62
+ lambda {persistence.commit id, 3, ["This is taken"]}.should raise_error(Eventus::ConcurrencyError)
63
+ end
64
+
65
+ it "should rollback changes on concurrency error" do
66
+ persistence.commit id, 3, ["first", "second", "third"] rescue nil
67
+
68
+ result = persistence.load id
69
+ result.length.should == 20
70
+ end
71
+
72
+ it "should load all events from a minimum" do
73
+ result = persistence.load id, 10
74
+ result.length.should == 11
75
+ end
76
+ end
77
+
78
+ describe "when serialization is set" do
79
+ let(:serializer) { stub }
80
+ before do
81
+ options[:serializer] = serializer
82
+ end
83
+
84
+ it "should use serializer" do
85
+ input = "original"
86
+ ser = "i'm serialized!"
87
+
88
+ serializer.should_receive(:serialize).with(input).and_return(ser)
89
+ serializer.should_receive(:deserialize).with(ser).and_return(input)
90
+
91
+ id = uuid.generate :compact
92
+
93
+ persistence.commit id, 1, [input]
94
+ result = persistence.load id
95
+ result[0].should == input
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ $:.unshift File.expand_path('../../lib', __FILE__)
5
+ require 'eventus'
6
+
7
+ Bundler.require :development
8
+
9
+ Dir[File.join(File.dirname(__FILE__), 'support', '*.rb')].each { |d| require d }
10
+
11
+ RSpec.configure do |config|
12
+ config.mock_with :rspec
13
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eventus::Store do
4
+ let(:persistence) { stub(:persistence).as_null_object }
5
+ let(:store) { Eventus::Store.new(persistence) }
6
+ let(:uuid) { UUID.new }
7
+ let(:stream) { stub(:stream) }
8
+
9
+ describe "when opening an event stream" do
10
+ let(:id) { uuid.generate(:compact) }
11
+ let(:result) { store.open id }
12
+
13
+ it "should request from persistence" do
14
+ persistence.should_receive(:get_events)
15
+ result
16
+ end
17
+
18
+ it "should return a stream" do
19
+ result.should_not be_nil
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eventus::Stream do
4
+ let(:id) { UUID.generate(:compact) }
5
+ let(:stream) { Eventus::Stream.new(id, persistence) }
6
+ let(:persistence) { stub(:persistence).as_null_object }
7
+
8
+ it "should use id" do
9
+ stream.id.should == id
10
+ end
11
+
12
+ it "should have no committed events" do
13
+ stream.committed_events.should be_empty
14
+ end
15
+
16
+ it "should have no uncommitted events" do
17
+ stream.uncommitted_events.should be_empty
18
+ end
19
+
20
+ describe "when events available from persistence" do
21
+ before do
22
+ persistence.should_receive(:load).and_return([stub, stub])
23
+ end
24
+
25
+ it "should have an equal number of events" do
26
+ stream.version.should == 2
27
+ end
28
+
29
+ it "should have no uncommitted events" do
30
+ stream.uncommitted_events.should be_empty
31
+ end
32
+ end
33
+
34
+ describe "when events added" do
35
+ before do
36
+ stream << stub
37
+ stream.add stub
38
+ end
39
+
40
+ it "should have uncommitted events" do
41
+ stream.uncommitted_events.length.should == 2
42
+ end
43
+
44
+ describe "when committed" do
45
+ before do
46
+ persistence.should_receive(:commit)
47
+ stream.commit
48
+ end
49
+
50
+ it "should have committed events" do
51
+ stream.version.should == 2
52
+ end
53
+
54
+ it "should have no uncommitted events" do
55
+ stream.uncommitted_events.should be_empty
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "when a concurrency error occurs" do
61
+ before do
62
+ persistence.should_receive(:commit).and_raise(Eventus::ConcurrencyError)
63
+ stream << stub(:event)
64
+ end
65
+
66
+ it "should reraise concurrency error" do
67
+ lambda {stream.commit}.should raise_error(Eventus::ConcurrencyError)
68
+ end
69
+
70
+ it "should load latest events" do
71
+ persistence.should_receive(:load).with(id, 1).and_return([stub, stub, stub])
72
+ stream.commit rescue nil
73
+ stream.version.should == 3
74
+ end
75
+ end
76
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eventus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jason Staten
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-09 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: An Event Store
15
+ email:
16
+ - jstaten07@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - Guardfile
24
+ - README.md
25
+ - Rakefile
26
+ - eventus.gemspec
27
+ - lib/eventus.rb
28
+ - lib/eventus/aggregate_root.rb
29
+ - lib/eventus/errors.rb
30
+ - lib/eventus/persistence.rb
31
+ - lib/eventus/persistence/in_memory.rb
32
+ - lib/eventus/persistence/kyotocabinet.rb
33
+ - lib/eventus/serializers.rb
34
+ - lib/eventus/serializers/marshal.rb
35
+ - lib/eventus/serializers/msgpack.rb
36
+ - lib/eventus/store.rb
37
+ - lib/eventus/stream.rb
38
+ - lib/eventus/version.rb
39
+ - spec/aggregate_root_spec.rb
40
+ - spec/persistence/in_memory_spec.rb
41
+ - spec/persistence/kyotocabinet_spec.rb
42
+ - spec/spec_helper.rb
43
+ - spec/store_spec.rb
44
+ - spec/stream_spec.rb
45
+ homepage: ''
46
+ licenses: []
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ segments:
58
+ - 0
59
+ hash: 3611850257360750717
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ segments:
67
+ - 0
68
+ hash: 3611850257360750717
69
+ requirements: []
70
+ rubyforge_project: eventus
71
+ rubygems_version: 1.8.13
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Event Store
75
+ test_files:
76
+ - spec/aggregate_root_spec.rb
77
+ - spec/persistence/in_memory_spec.rb
78
+ - spec/persistence/kyotocabinet_spec.rb
79
+ - spec/spec_helper.rb
80
+ - spec/store_spec.rb
81
+ - spec/stream_spec.rb