eventus 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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