active_projection 0.1.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +3 -0
- data/app/models/active_projection/projection.rb +5 -0
- data/app/models/active_projection/projection_repository.rb +43 -0
- data/db/migrate/01_create_projections.rb +10 -0
- data/lib/active_projection.rb +16 -0
- data/lib/active_projection/autoload.rb +20 -0
- data/lib/active_projection/event_client.rb +55 -0
- data/lib/active_projection/projection_type.rb +56 -0
- data/lib/active_projection/projection_type_registry.rb +38 -0
- data/lib/active_projection/railtie.rb +8 -0
- data/lib/active_projection/server.rb +60 -0
- data/lib/active_projection/version.rb +11 -0
- data/spec/factories/event_factory.rb +8 -0
- data/spec/lib/projection_type_registry_spec.rb +22 -0
- data/spec/lib/projecton_type_spec.rb +74 -0
- data/spec/models/projection_repository_spec.rb +27 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/active_record.rb +38 -0
- metadata +206 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d9052c28e84c5b64ab1b4350b291e02077f824ec
|
4
|
+
data.tar.gz: a7ad85d0ff185230ba7d350efa4a123143e60499
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b617e60a34666ba1fb02b110113c6d94a7b72c7f91d1c2a64d4272e44e7eec28894c4a4234491638b4babccae0cf1600a22089ce8630f7c9d3e33471c2662467
|
7
|
+
data.tar.gz: 1abea3c7eb6b8921ecbf7a4c3896642dd0ac55301439dd09b5013a51c4a12f9c8713b912f36004ac15d6aad45dff4751b48f4c4dec7eb4d6f39be76d747fd867
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Andreas Reischuck
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
module ActiveProjection
|
2
|
+
class ProjectionRepository
|
3
|
+
|
4
|
+
def self.all
|
5
|
+
Projection.all
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.get_last_id(id)
|
9
|
+
@@last_id[id] ||= Projection.find(id).last_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.set_last_id(id, last_id)
|
13
|
+
Projection.find(id).update! last_id: last_id
|
14
|
+
@@last_id[id] += 1
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.set_broken(id)
|
18
|
+
@@broken[id] = false
|
19
|
+
Projection.find(id).update! solid: false
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.solid?(id)
|
23
|
+
@@broken[id] ||= Projection.find(id).solid
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.create_or_get(projection_class)
|
27
|
+
projection = Projection.where(class_name: projection_class).first
|
28
|
+
if projection.nil?
|
29
|
+
projection = Projection.create! class_name: projection_class, last_id: 0, solid: true
|
30
|
+
else
|
31
|
+
projection.update! solid: true
|
32
|
+
end
|
33
|
+
projection
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def self.initialize
|
38
|
+
end
|
39
|
+
|
40
|
+
@@last_id = {}
|
41
|
+
@@broken = {}
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_event'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
require 'active_projection/version'
|
4
|
+
|
5
|
+
module ActiveProjection
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :Autoload
|
9
|
+
autoload :EventClient
|
10
|
+
autoload :ProjectionType
|
11
|
+
autoload :ProjectionTypeRegistry
|
12
|
+
autoload :Server
|
13
|
+
|
14
|
+
autoload :Projection, (File.expand_path '../../app/models/active_projection/projection', __FILE__)
|
15
|
+
autoload :ProjectionRepository, (File.expand_path '../../app/models/active_projection/projection_repository', __FILE__)
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActiveProjection
|
2
|
+
module Autoload
|
3
|
+
def self.worker_config=(config)
|
4
|
+
dirs = []
|
5
|
+
projections_dir = "#{config[:path]}**/*.rb"
|
6
|
+
if config[:count] == 1
|
7
|
+
dirs << projections_dir
|
8
|
+
else
|
9
|
+
Dir[*projections_dir].each_with_index.map { |item, i| i % config[:count] == config[:number] ? item : nil }.compact.each do |dir|
|
10
|
+
dirs << dir
|
11
|
+
end
|
12
|
+
end
|
13
|
+
ActiveEvent::Support::Autoloader.load_from dirs
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.app_path=(path)
|
17
|
+
ActiveEvent::Support::Autoloader.load_from "#{path}/models/**/*.rb"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'bunny'
|
3
|
+
module ActiveProjection
|
4
|
+
class EventClient
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def self.start(options)
|
8
|
+
instance.start options
|
9
|
+
end
|
10
|
+
|
11
|
+
def start(options)
|
12
|
+
self.options = options
|
13
|
+
event_connection.start
|
14
|
+
begin
|
15
|
+
event_channel.queue('', auto_delete: true).bind(event_exchange).subscribe do |delivery_info, properties, body|
|
16
|
+
puts "Received #{properties.type} with #{body}"
|
17
|
+
ProjectionTypeRegistry.process(properties.headers.deep_symbolize_keys, Object.const_get(properties.type).new((JSON.parse body).deep_symbolize_keys))
|
18
|
+
end
|
19
|
+
rescue Interrupt => _
|
20
|
+
event_channel.close
|
21
|
+
event_connection.close
|
22
|
+
end
|
23
|
+
last_ids = ProjectionRepository.all.to_a.map { |p| p.last_id }
|
24
|
+
request_events_after last_ids.min || 0
|
25
|
+
event_channel.work_pool.join
|
26
|
+
end
|
27
|
+
|
28
|
+
def request_events_after(id)
|
29
|
+
resend_exchange.publish id.to_s, routing_key: 'resend'
|
30
|
+
end
|
31
|
+
|
32
|
+
def event_connection
|
33
|
+
@event_server ||= Bunny.new URI::Generic.build(options[:event_connection]).to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def event_channel
|
37
|
+
@event_channel ||= event_connection.create_channel
|
38
|
+
end
|
39
|
+
|
40
|
+
def event_exchange
|
41
|
+
@event_exchange ||= event_channel.fanout options[:event_exchange]
|
42
|
+
end
|
43
|
+
|
44
|
+
def resend_exchange
|
45
|
+
@resend_exchange ||= event_channel.direct "resend_#{options[:event_exchange]}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def options
|
49
|
+
@options
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
attr_writer :options
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveProjection
|
2
|
+
module ProjectionType
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
class WrongArgumentsCountError < StandardError
|
5
|
+
end
|
6
|
+
included do
|
7
|
+
ProjectionTypeRegistry::register(self)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
self.handlers = Hash.new do |hash, key|
|
12
|
+
hash[key] = []
|
13
|
+
end
|
14
|
+
self.class.public_instance_methods(false).each do |method_name|
|
15
|
+
method = self.class.instance_method method_name
|
16
|
+
event_type = method_name.to_s.camelcase.to_sym
|
17
|
+
raise WrongArgumentsCountError if 1 != method.arity
|
18
|
+
handlers[event_type] << method.name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def evaluate(headers)
|
23
|
+
return false unless ProjectionRepository.solid? projection_id #projection is broken and shouldn't process any incoming event
|
24
|
+
last_id = ProjectionRepository.get_last_id projection_id
|
25
|
+
case
|
26
|
+
when last_id + 1 == headers[:store_id] #process incoming event
|
27
|
+
ProjectionRepository.set_last_id projection_id, headers[:store_id]
|
28
|
+
puts "process this event"
|
29
|
+
true
|
30
|
+
when last_id >= headers[:store_id] #incoming event already processed
|
31
|
+
puts "event already processed"
|
32
|
+
false
|
33
|
+
when last_id < headers[:store_id] #incoming event is in future, so we are missing some
|
34
|
+
puts "events are missing"
|
35
|
+
ProjectionRepository.set_broken projection_id
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def invoke(event)
|
41
|
+
event_type = event.class.name.split('::').last.to_sym
|
42
|
+
return unless handlers.has_key? event_type
|
43
|
+
handlers[event_type].each do |method|
|
44
|
+
self.send method, event
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
attr_accessor :handlers
|
50
|
+
attr_writer :projection_id
|
51
|
+
|
52
|
+
def projection_id
|
53
|
+
@projection_id ||= ProjectionRepository.create_or_get(self.class.name).id
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module ActiveProjection
|
4
|
+
class ProjectionTypeRegistry
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def self.register(projection)
|
8
|
+
self.registry << projection
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.process(headers, event)
|
12
|
+
instance.process headers, event
|
13
|
+
end
|
14
|
+
|
15
|
+
def process(headers, event)
|
16
|
+
projections.each do |projection|
|
17
|
+
ActiveRecord::Base.transaction do
|
18
|
+
projection.invoke event if projection.evaluate headers
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
cattr_accessor :registry
|
26
|
+
attr_accessor :projections
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
self.projections = []
|
30
|
+
self.class.registry.freeze.each do |projection|
|
31
|
+
projections << projection.new
|
32
|
+
end
|
33
|
+
projections.freeze
|
34
|
+
end
|
35
|
+
|
36
|
+
self.registry = []
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module ActiveProjection
|
4
|
+
class Server
|
5
|
+
|
6
|
+
def self.run(options = nil)
|
7
|
+
self.new(options).run
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(new_options = nil)
|
11
|
+
self.options = new_options.deep_symbolize_keys! unless new_options.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
ActiveRecord::Base.establish_connection options[:projection_database]
|
16
|
+
EventClient.start options
|
17
|
+
end
|
18
|
+
|
19
|
+
def env
|
20
|
+
@env = ENV['PROJECTION_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
21
|
+
end
|
22
|
+
|
23
|
+
def options
|
24
|
+
@options ||= parse_options(ARGV)
|
25
|
+
end
|
26
|
+
|
27
|
+
cattr_accessor :base_path
|
28
|
+
cattr_accessor :config_file
|
29
|
+
|
30
|
+
def config_file
|
31
|
+
self.class.config_file || File.expand_path('config/disco.yml', base_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_writer :options
|
37
|
+
attr_writer :domain
|
38
|
+
|
39
|
+
def default_options
|
40
|
+
{
|
41
|
+
projection_database: {
|
42
|
+
adapter: 'sqlite3',
|
43
|
+
database: File.expand_path('db/projection.sqlite3', base_path)
|
44
|
+
},
|
45
|
+
event_connection: {
|
46
|
+
scheme: 'amqp',
|
47
|
+
userinfo: nil,
|
48
|
+
host: '127.0.0.1',
|
49
|
+
port: 9797,
|
50
|
+
},
|
51
|
+
event_exchange: 'events'
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_options(args)
|
56
|
+
options = default_options
|
57
|
+
options.merge! YAML.load_file(config_file)[env].deep_symbolize_keys! unless config_file.blank?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ActiveProjection
|
2
|
+
# Returns the version of the currently loaded ActiveProjection as a Gem::Version
|
3
|
+
def self.version
|
4
|
+
Gem::Version.new '0.1.0'
|
5
|
+
end
|
6
|
+
|
7
|
+
module VERSION #:nodoc:
|
8
|
+
MAJOR, MINOR, TINY, PRE = ActiveProjection.version.segments
|
9
|
+
STRING = ActiveProjection.version.to_s
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe ActiveProjection::ProjectionTypeRegistry do
|
4
|
+
class TestEvent
|
5
|
+
end
|
6
|
+
class TestProjection
|
7
|
+
end
|
8
|
+
before :all do
|
9
|
+
ActiveProjection::ProjectionTypeRegistry.register(TestProjection)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'initializes' do
|
13
|
+
ActiveProjection::ProjectionTypeRegistry.instance.should be
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'invokes event handlers' do
|
17
|
+
event = TestEvent.new
|
18
|
+
expect_any_instance_of(TestProjection).to receive(:evaluate).with('test').and_return(true)
|
19
|
+
expect_any_instance_of(TestProjection).to receive(:invoke).with(event)
|
20
|
+
ActiveProjection::ProjectionTypeRegistry.process('test', event)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../support/active_record'
|
3
|
+
|
4
|
+
describe ActiveProjection::ProjectionType do
|
5
|
+
it 'should register automatically' do
|
6
|
+
expect(ActiveProjection::ProjectionTypeRegistry).to receive(:register) do |arg|
|
7
|
+
arg.name.to_sym.should eq :DummyProjection
|
8
|
+
end
|
9
|
+
class DummyProjection
|
10
|
+
include ActiveProjection::ProjectionType
|
11
|
+
end
|
12
|
+
end
|
13
|
+
describe 'instance' do
|
14
|
+
class TestProjection
|
15
|
+
def test_event(event)
|
16
|
+
end
|
17
|
+
|
18
|
+
def dummy_event(event)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
class TestEvent
|
22
|
+
end
|
23
|
+
before :each do
|
24
|
+
allow(ActiveProjection::ProjectionTypeRegistry).to receive(:register)
|
25
|
+
TestProjection.send(:include, ActiveProjection::ProjectionType)
|
26
|
+
@projection = TestProjection.new
|
27
|
+
end
|
28
|
+
it 'initializes all handler' do
|
29
|
+
handlers = @projection.instance_variable_get(:@handlers)
|
30
|
+
handlers.length.should eq 2
|
31
|
+
handlers['TestEvent'].should be
|
32
|
+
handlers['DummyEvent'].should be
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'evaluate' do
|
36
|
+
before :each do
|
37
|
+
allow(@projection).to receive(:projection_id).and_return(0)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'rejects processing, if projection is broken' do
|
41
|
+
expect(ActiveProjection::ProjectionRepository).to receive(:solid?).and_return(false)
|
42
|
+
expect(ActiveProjection::ProjectionRepository).to_not receive(:get_last_id)
|
43
|
+
@projection.evaluate({store_id: 1})
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'with solid projection' do
|
47
|
+
before :each do
|
48
|
+
allow(ActiveProjection::ProjectionRepository).to receive(:solid?).and_return(true)
|
49
|
+
expect(ActiveProjection::ProjectionRepository).to receive(:get_last_id).and_return(5)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'processes event with the correct id' do
|
53
|
+
expect(ActiveProjection::ProjectionRepository).to receive(:set_last_id).with(0, 6)
|
54
|
+
expect(@projection.evaluate({store_id: 6})).to be_true
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'rejects event with last id smaller event id' do
|
58
|
+
expect(@projection.evaluate({store_id: 3})).to be_false
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'rejects event with last greater equal event id' do
|
62
|
+
expect(ActiveProjection::ProjectionRepository).to receive(:set_broken).with(0)
|
63
|
+
expect(@projection.evaluate({store_id: 7})).to be_false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'invokes all handler' do
|
69
|
+
expect(@projection).to receive(:test_event)
|
70
|
+
expect(@projection).to_not receive(:dummy_event)
|
71
|
+
@projection.invoke(TestEvent.new)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../support/active_record'
|
3
|
+
|
4
|
+
describe ActiveProjection::ProjectionRepository do
|
5
|
+
before :all do
|
6
|
+
5.times do |i|
|
7
|
+
FactoryGirl.create :projection, id: i, class_name: "TestProjection#{i}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
describe 'create_or_get' do
|
11
|
+
it 'creates a projection, if classname is not present' do
|
12
|
+
expect(ActiveProjection::ProjectionRepository.create_or_get('TestProjection5').id).to eq 5
|
13
|
+
expect(ActiveProjection::Projection.all.to_a.length).to eq 6
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'does not create a projection, if classname is present' do
|
17
|
+
expect(ActiveProjection::ProjectionRepository.create_or_get('TestProjection3').id).to eq 3
|
18
|
+
expect(ActiveProjection::Projection.all.to_a.length).to eq 5
|
19
|
+
end
|
20
|
+
end
|
21
|
+
describe 'broken' do
|
22
|
+
it 'sets solid to false' do
|
23
|
+
ActiveProjection::ProjectionRepository.set_broken 0
|
24
|
+
expect(ActiveProjection::Projection.where(id:0).first.solid).to be_false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_projection'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
|
5
|
+
|
6
|
+
ActiveRecord::Migrator.up 'db/migrate'
|
7
|
+
|
8
|
+
module ActiveModel::Validations
|
9
|
+
# Extension to enhance `should have` on AR Model instances. Calls
|
10
|
+
# model.valid? in order to prepare the object's errors object.
|
11
|
+
#
|
12
|
+
# You can also use this to specify the content of the error messages.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
#
|
16
|
+
# model.should have(:no).errors_on(:attribute)
|
17
|
+
# model.should have(1).error_on(:attribute)
|
18
|
+
# model.should have(n).errors_on(:attribute)
|
19
|
+
#
|
20
|
+
# model.errors_on(:attribute).should include("can't be blank")
|
21
|
+
def errors_on(attribute)
|
22
|
+
self.valid?
|
23
|
+
[self.errors[attribute]].flatten.compact
|
24
|
+
end
|
25
|
+
alias :error_on :errors_on
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec.configure do |config|
|
29
|
+
config.around do |example|
|
30
|
+
ActiveRecord::Base.transaction do
|
31
|
+
example.run
|
32
|
+
raise ActiveRecord::Rollback
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
require 'factory_girl'
|
38
|
+
FactoryGirl.find_definitions
|
metadata
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_projection
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andreas Reischuck
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: active_event
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>'
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.2.0
|
34
|
+
- - <
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 4.1.0
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - '>'
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 3.2.0
|
44
|
+
- - <
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 4.1.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: activemodel
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - '>'
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 3.2.0
|
54
|
+
- - <
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 4.1.0
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - '>'
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 3.2.0
|
64
|
+
- - <
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 4.1.0
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: bunny
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: bundler
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '1.3'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ~>
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '1.3'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: rake
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: rspec
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: factory_girl
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: sqlite3
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
type: :development
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
description: Projection environment for rails-disco
|
152
|
+
email: andreas.reischuck@hicknhack-software.com
|
153
|
+
executables: []
|
154
|
+
extensions: []
|
155
|
+
extra_rdoc_files: []
|
156
|
+
files:
|
157
|
+
- app/models/active_projection/projection.rb
|
158
|
+
- app/models/active_projection/projection_repository.rb
|
159
|
+
- db/migrate/01_create_projections.rb
|
160
|
+
- lib/active_projection/autoload.rb
|
161
|
+
- lib/active_projection/event_client.rb
|
162
|
+
- lib/active_projection/projection_type.rb
|
163
|
+
- lib/active_projection/projection_type_registry.rb
|
164
|
+
- lib/active_projection/railtie.rb
|
165
|
+
- lib/active_projection/server.rb
|
166
|
+
- lib/active_projection/version.rb
|
167
|
+
- lib/active_projection.rb
|
168
|
+
- README.md
|
169
|
+
- MIT-LICENSE
|
170
|
+
- spec/factories/event_factory.rb
|
171
|
+
- spec/lib/projection_type_registry_spec.rb
|
172
|
+
- spec/lib/projecton_type_spec.rb
|
173
|
+
- spec/models/projection_repository_spec.rb
|
174
|
+
- spec/spec_helper.rb
|
175
|
+
- spec/support/active_record.rb
|
176
|
+
homepage: https://github.com/hicknhack-software/rails-disco
|
177
|
+
licenses:
|
178
|
+
- MIT
|
179
|
+
metadata: {}
|
180
|
+
post_install_message:
|
181
|
+
rdoc_options: []
|
182
|
+
require_paths:
|
183
|
+
- lib
|
184
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - '>='
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
189
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - '>='
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
requirements: []
|
195
|
+
rubyforge_project:
|
196
|
+
rubygems_version: 2.0.5
|
197
|
+
signing_key:
|
198
|
+
specification_version: 4
|
199
|
+
summary: Projection related stuff (part of rails-disco)
|
200
|
+
test_files:
|
201
|
+
- spec/factories/event_factory.rb
|
202
|
+
- spec/lib/projection_type_registry_spec.rb
|
203
|
+
- spec/lib/projecton_type_spec.rb
|
204
|
+
- spec/models/projection_repository_spec.rb
|
205
|
+
- spec/spec_helper.rb
|
206
|
+
- spec/support/active_record.rb
|