active_event 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_event/event.rb +15 -0
- data/app/models/active_event/event_repository.rb +11 -0
- data/db/migrate/00_create_domain_events.rb +9 -0
- data/lib/active_event/autoload.rb +11 -0
- data/lib/active_event/command.rb +28 -0
- data/lib/active_event/domain.rb +42 -0
- data/lib/active_event/event_server.rb +63 -0
- data/lib/active_event/event_type.rb +29 -0
- data/lib/active_event/support/attr_initializer.rb +74 -0
- data/lib/active_event/support/attr_setter.rb +29 -0
- data/lib/active_event/support/autoloader.rb +9 -0
- data/lib/active_event/validations.rb +17 -0
- data/lib/active_event/validations_registry.rb +18 -0
- data/lib/active_event/version.rb +11 -0
- data/lib/active_event.rb +26 -0
- data/spec/factories/event_factory.rb +9 -0
- data/spec/lib/command_spec.rb +14 -0
- data/spec/lib/domain_spec.rb +20 -0
- data/spec/lib/event_server_spec.rb +27 -0
- data/spec/lib/event_type_spec.rb +38 -0
- data/spec/lib/support/attr_initializer_spec.rb +55 -0
- data/spec/lib/support/attr_setter_spec.rb +61 -0
- data/spec/models/event_spec.rb +20 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/active_record.rb +38 -0
- metadata +204 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5a686659ed279d8bc3e3547139ea2b01c637b8d4
|
4
|
+
data.tar.gz: c61ec7d584bf564fb12bb5250af1298dfd40efc6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 624483b1eb07a2a56fa84baa1306d1d5a3e591b055afd059efae69f1fcf6df930754dd419cbc74c84ad1fc4efbd8e3968b05bd0d1c0ca58873e8970b79993ec8
|
7
|
+
data.tar.gz: 0035b8d841c4862928e9022c0ec448fa25cd380aa1b37bd25e19131dee5cea4e83f554e64ddae866c4b64cddefb950d507738a5eff5ae80490abf727a824405c
|
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,15 @@
|
|
1
|
+
module ActiveEvent
|
2
|
+
class Event < ActiveRecord::Base
|
3
|
+
self.table_name = 'domain_events'
|
4
|
+
serialize :data, JSON
|
5
|
+
|
6
|
+
# events are only created inside the domain
|
7
|
+
def readonly?
|
8
|
+
persisted?
|
9
|
+
end
|
10
|
+
|
11
|
+
def event_type
|
12
|
+
ActiveEvent::EventType.create_instance(event, data)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module ActiveEvent
|
4
|
+
class CommandInvalid < Exception
|
5
|
+
attr_reader :record
|
6
|
+
|
7
|
+
def initialize(record)
|
8
|
+
self.record = record
|
9
|
+
super 'invalid command'
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
attr_writer :record
|
15
|
+
end
|
16
|
+
|
17
|
+
module Command
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
include ActiveEvent::Support::AttrSetter
|
20
|
+
include ActiveModel::Validations
|
21
|
+
|
22
|
+
def is_valid_do(&block)
|
23
|
+
valid = valid?
|
24
|
+
block.call() if valid
|
25
|
+
valid
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'drb/drb'
|
3
|
+
|
4
|
+
module ActiveEvent
|
5
|
+
module Domain
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include Singleton # singleton is not a concern - include directly into class
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
super
|
14
|
+
# DRb.start_service # should not be necessary
|
15
|
+
self.server = DRbObject.new_with_uri self.class.server_uri
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_command(command)
|
19
|
+
server.run_command command
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_accessor :server
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
def run_command(command)
|
28
|
+
self.instance.run_command command
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_accessor :server_uri
|
32
|
+
|
33
|
+
def self.extended(base)
|
34
|
+
base.server_uri = 'druby://127.0.0.1:8787'
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_config(protocol: 'druby', host: 'localhost', port: 8787)
|
38
|
+
self.server_uri = "#{protocol}://#{host}:#{port}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'bunny'
|
3
|
+
module ActiveEvent
|
4
|
+
class EventServer
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def self.publish(event)
|
8
|
+
type = event.class.name
|
9
|
+
body = event.to_json
|
10
|
+
instance.event_exchange.publish body, type: type, headers: event.store_infos
|
11
|
+
puts "Published #{type} with #{body}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.start(options)
|
15
|
+
instance.start options
|
16
|
+
end
|
17
|
+
|
18
|
+
def start(options)
|
19
|
+
self.options = options
|
20
|
+
event_connection.start
|
21
|
+
listen_for_resend_requests
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.resend_events_after(id)
|
25
|
+
events = EventRepository.after_id(id).to_a
|
26
|
+
events.each do |e|
|
27
|
+
event = EventType.create_instance(e.event, e.data.deep_symbolize_keys)
|
28
|
+
event.add_store_infos store_id: e.id
|
29
|
+
self.publish event
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def listen_for_resend_requests
|
34
|
+
event_channel.queue('', auto_delete: true).bind(resend_exchange, routing_key: 'resend').subscribe do |delivery_info, properties, id|
|
35
|
+
puts "received resend request with id #{id}"
|
36
|
+
self.class.resend_events_after id
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def event_connection
|
41
|
+
@event_server ||= Bunny.new URI::Generic.build(options[:event_connection]).to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
def event_channel
|
45
|
+
@event_channel ||= event_connection.create_channel
|
46
|
+
end
|
47
|
+
|
48
|
+
def event_exchange
|
49
|
+
@event_exchange ||= event_channel.fanout options[:event_exchange]
|
50
|
+
end
|
51
|
+
|
52
|
+
def resend_exchange
|
53
|
+
@resend_exchange ||= event_channel.direct "resend_#{options[:event_exchange]}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def options
|
57
|
+
@options
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
attr_writer :options
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ActiveEvent
|
2
|
+
module EventType
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include ActiveEvent::Support::AttrInitializer
|
5
|
+
|
6
|
+
def event_type
|
7
|
+
self.class.name
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.create_instance(type, data)
|
11
|
+
Object.const_get(type).new(data)
|
12
|
+
rescue NameError
|
13
|
+
require 'ostruct'
|
14
|
+
OpenStruct.new(data.merge(event_type: type.to_s)).freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_store_infos(hash)
|
18
|
+
store_infos.merge! hash
|
19
|
+
end
|
20
|
+
|
21
|
+
def store_infos
|
22
|
+
@store_infos ||= {}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
attr_writer :store_infos
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module ActiveEvent::Support
|
2
|
+
class ForbiddenAttributesError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class UnknownAttributeError < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Allows to initialize attributes with a hash
|
9
|
+
#
|
10
|
+
# example:
|
11
|
+
# class RgbColor
|
12
|
+
# include ActiveEvent::AttrInitializer
|
13
|
+
# attributes :r, :g, :b
|
14
|
+
# end
|
15
|
+
# green = RgbColor.new r: 250, g: 20, b: 20
|
16
|
+
module AttrInitializer
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
def initialize(*args)
|
20
|
+
hash = (args.last.is_a?(Hash) ? args.pop : {})
|
21
|
+
super
|
22
|
+
check_attributes hash
|
23
|
+
init_attributes hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def freeze
|
27
|
+
attributes.freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
def attributes_except(*args)
|
31
|
+
attributes.reject { |k,_| args.include? k }
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_hash
|
35
|
+
attributes.dup
|
36
|
+
end
|
37
|
+
|
38
|
+
module ClassMethods
|
39
|
+
def self.extended(base)
|
40
|
+
base.attribute_keys = []
|
41
|
+
end
|
42
|
+
|
43
|
+
attr_accessor :attribute_keys
|
44
|
+
|
45
|
+
def attributes(*args)
|
46
|
+
self.attribute_keys += args
|
47
|
+
args.each do |attr|
|
48
|
+
define_method attr, -> { attributes[attr] }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
attr_accessor :attributes
|
56
|
+
|
57
|
+
def init_attributes(attributes)
|
58
|
+
self.attributes = attributes.dup
|
59
|
+
freeze
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def check_attributes(attributes)
|
65
|
+
return if attributes.blank?
|
66
|
+
if attributes.respond_to?(:permitted?) and not attributes.permitted?
|
67
|
+
raise ActiveEvent::Support::ForbiddenAttributesError
|
68
|
+
end
|
69
|
+
(attributes.keys - self.class.attribute_keys).each do |k|
|
70
|
+
raise ActiveEvent::Support::UnknownAttributeError, "unknown attribute: #{k}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ActiveEvent::Support
|
2
|
+
# Allows to initialize and set attributes with a hash
|
3
|
+
#
|
4
|
+
# example:
|
5
|
+
# class RgbColor
|
6
|
+
# include ActiveEvent::AttrSetter
|
7
|
+
# attributes :r, :g, :b
|
8
|
+
# end
|
9
|
+
# green = RgbColor.new r: 250, g: 20, b: 20
|
10
|
+
# green.r = 255
|
11
|
+
module AttrSetter
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
include ActiveEvent::Support::AttrInitializer
|
14
|
+
|
15
|
+
# override to skip the freezing!
|
16
|
+
def init_attributes(attributes)
|
17
|
+
self.attributes = attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def attributes(*args)
|
22
|
+
super
|
23
|
+
args.each do |attr|
|
24
|
+
define_method "#{attr}=", -> (value) { attributes[attr] = value }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveEvent
|
2
|
+
module Validations
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include ActiveModel::Validations
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
super
|
8
|
+
base.extend const_get("RegisterMethods")
|
9
|
+
end
|
10
|
+
|
11
|
+
module RegisterMethods
|
12
|
+
def validation_target(target)
|
13
|
+
ValidationsRegistry.register self, target
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ActiveEvent
|
2
|
+
class ValidationsRegistry
|
3
|
+
|
4
|
+
def self.register(validations, target)
|
5
|
+
self.bindings << {validation: validations, target: target}
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.build
|
9
|
+
self.bindings.freeze.each do |binding|
|
10
|
+
Object.const_get(binding[:target].to_s).send :include, binding[:validation]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
cattr_accessor :bindings
|
16
|
+
self.bindings = []
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ActiveEvent
|
2
|
+
# Returns the version of the currently loaded ActiveEvent 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 = ActiveEvent.version.segments
|
9
|
+
STRING = ActiveEvent.version.to_s
|
10
|
+
end
|
11
|
+
end
|
data/lib/active_event.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
require 'active_event/version'
|
4
|
+
|
5
|
+
module ActiveEvent
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :Autoload
|
9
|
+
autoload :Command
|
10
|
+
autoload :Domain
|
11
|
+
autoload :EventServer
|
12
|
+
autoload :EventType
|
13
|
+
autoload :Validations
|
14
|
+
autoload :ValidationsRegistry
|
15
|
+
|
16
|
+
module Support
|
17
|
+
extend ActiveSupport::Autoload
|
18
|
+
|
19
|
+
autoload :AttrInitializer
|
20
|
+
autoload :AttrSetter
|
21
|
+
autoload :Autoloader
|
22
|
+
end
|
23
|
+
|
24
|
+
autoload :Event, (File.expand_path '../../app/models/active_event/event', __FILE__)
|
25
|
+
autoload :EventRepository, (File.expand_path '../../app/models/active_event/event_repository', __FILE__)
|
26
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe ActiveEvent::Command do
|
4
|
+
class TestCommand
|
5
|
+
include ActiveEvent::Command
|
6
|
+
attributes :r, :g, :b
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'create instance' do
|
10
|
+
it 'can create an instance' do
|
11
|
+
expect { TestCommand.new r: 10 }.to be
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe ActiveEvent::Domain do
|
4
|
+
class TestDomain
|
5
|
+
include ActiveEvent::Domain
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'connect and run command' do
|
9
|
+
before :each do
|
10
|
+
@command = Object.new
|
11
|
+
@drb_object = double 'drb_object'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'sends command over instance' do
|
15
|
+
expect(DRbObject).to receive(:new_with_uri).with(TestDomain.server_uri).and_return(@drb_object)
|
16
|
+
expect(@drb_object).to receive(:run_command).with(@command)
|
17
|
+
TestDomain.run_command(@command)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
describe ActiveEvent::EventServer do
|
3
|
+
class TestEvent
|
4
|
+
end
|
5
|
+
before :all do
|
6
|
+
@server = ActiveEvent::EventServer.instance
|
7
|
+
@event = TestEvent.new
|
8
|
+
end
|
9
|
+
it 'resends requests' do
|
10
|
+
allow(@event).to receive(:event)
|
11
|
+
allow(@event).to receive(:id)
|
12
|
+
allow(@event).to receive(:data).and_return({})
|
13
|
+
expect(ActiveEvent::EventType).to receive(:create_instance).twice.and_return(Object)
|
14
|
+
expect(Object).to receive(:add_store_infos).twice
|
15
|
+
expect(ActiveEvent::EventRepository).to receive(:after_id).and_return([@event, @event])
|
16
|
+
expect(@server.class).to receive(:publish).twice
|
17
|
+
@server.class.resend_events_after 1
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'publishes an event' do
|
21
|
+
allow(@server).to receive(:event_exchange).and_return(Object)
|
22
|
+
expect(@server.event_exchange).to receive(:publish).with("Test2", {:type => "TestEvent", :headers => "Test"})
|
23
|
+
expect(@event).to receive(:store_infos).and_return('Test')
|
24
|
+
expect(@event).to receive(:to_json).and_return('Test2')
|
25
|
+
@server.class.publish(@event)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe ActiveEvent::EventType do
|
4
|
+
class RgbColorEvent
|
5
|
+
include ActiveEvent::EventType
|
6
|
+
attributes :r, :g, :b
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'create instance' do
|
10
|
+
it 'can create an instance' do
|
11
|
+
expect { ActiveEvent::EventType.create_instance :RgbColorEvent, r: 10 }.to be
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'can create events of any kind' do
|
15
|
+
expect { ActiveEvent::EventType.create_instance :RandomEvent, r: 10 }.to be
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'regular instance' do
|
20
|
+
before :all do
|
21
|
+
@color = RgbColorEvent.new r: 10, g: 20, b: 30
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'can report type' do
|
25
|
+
@color.event_type.should == 'RgbColorEvent'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'unknown instance' do
|
30
|
+
before :all do
|
31
|
+
@random = ActiveEvent::EventType.create_instance :RandomEvent, r: 10
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'can report type' do
|
35
|
+
@random.event_type.should == 'RandomEvent'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe ActiveEvent::Support::AttrInitializer do
|
4
|
+
class RgbColor
|
5
|
+
include ActiveEvent::Support::AttrInitializer
|
6
|
+
attributes :r, :g, :b
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'constructor' do
|
10
|
+
it 'works for no args' do
|
11
|
+
expect { RgbColor.new }.to be
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'works for defined attributes' do
|
15
|
+
expect { RgbColor.new r: 10, g: 20 }.to be
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'fails for undeclared attributes' do
|
19
|
+
expect { RgbColor.new z: 10 }.to raise_error(ActiveEvent::Support::UnknownAttributeError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'fails for unauthorized hash' do
|
23
|
+
class CheckedHash < Hash
|
24
|
+
def permitted?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
expect { RgbColor.new(CheckedHash.new.merge! r: 1) }.to raise_error(ActiveEvent::Support::ForbiddenAttributesError)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'instance' do
|
33
|
+
before :all do
|
34
|
+
@color = RgbColor.new r: 10, g: 20
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'can retrieve attributes' do
|
38
|
+
@color.r.should == 10
|
39
|
+
@color.g.should == 20
|
40
|
+
@color.b.should be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'can filter attributes' do
|
44
|
+
@color.attributes_except(:r).should eq(g: 20)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'can convert to hash' do
|
48
|
+
@color.to_hash.should eq(r: 10, g: 20)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'is read only' do
|
52
|
+
expect { @color.r = 20 }.to raise_error
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe ActiveEvent::Support::AttrSetter do
|
4
|
+
class MutableRgbColor
|
5
|
+
include ActiveEvent::Support::AttrSetter
|
6
|
+
attributes :r, :g, :b
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'constructor' do
|
10
|
+
it 'works for no args' do
|
11
|
+
expect { MutableRgbColor.new }.to be
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'works for defined attributes' do
|
15
|
+
expect { MutableRgbColor.new r: 10, g: 20 }.to be
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'fails for undeclared attributes' do
|
19
|
+
expect { MutableRgbColor.new z: 10 }.to raise_error(ActiveEvent::Support::UnknownAttributeError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'fails for unauthorized hash' do
|
23
|
+
class CheckedHash < Hash
|
24
|
+
def permitted?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
expect { MutableRgbColor.new(CheckedHash.new.merge! r: 1) }.to raise_error(ActiveEvent::Support::ForbiddenAttributesError)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'instance' do
|
33
|
+
before :all do
|
34
|
+
@color = MutableRgbColor.new r: 10, g: 20
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'can retrieve attributes' do
|
38
|
+
@color.r.should == 10
|
39
|
+
@color.g.should == 20
|
40
|
+
@color.b.should be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'can filter attributes' do
|
44
|
+
@color.attributes_except(:r).should eq(g: 20)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'can convert to hash' do
|
48
|
+
@color.to_hash.should eq(r: 10, g: 20)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'is not automatically frozen' do
|
52
|
+
@color.frozen?.should be_false
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'allows write' do
|
56
|
+
@color.r = 20
|
57
|
+
@color.r.should == 20
|
58
|
+
@color.r = 10
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../support/active_record'
|
3
|
+
|
4
|
+
describe ActiveEvent::EventRepository do
|
5
|
+
describe 'instance' do
|
6
|
+
before :all do
|
7
|
+
5.times do |i|
|
8
|
+
FactoryGirl.create :event, id: (5 - i)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'gives all events ordered by event id' do
|
13
|
+
ActiveEvent::EventRepository.ordered.map { |event| event.id }.should eq [1,2,3,4,5]
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'gives newer events' do
|
17
|
+
ActiveEvent::EventRepository.after_id(3).map { |event| event.id }.should eq [4,5]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_event'
|
@@ -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,204 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_event
|
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: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>'
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.2.0
|
20
|
+
- - <
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 4.1.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - '>'
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.0
|
30
|
+
- - <
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 4.1.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: activemodel
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '>'
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 3.2.0
|
40
|
+
- - <
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 4.1.0
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - '>'
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 3.2.0
|
50
|
+
- - <
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 4.1.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: bunny
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: bundler
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ~>
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '1.3'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ~>
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '1.3'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rake
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: rspec
|
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: factory_girl
|
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: sqlite3
|
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
|
+
description: Event server, validations, commands and events for rails-disco
|
138
|
+
email: andreas.reischuck@hicknhack-software.com
|
139
|
+
executables: []
|
140
|
+
extensions: []
|
141
|
+
extra_rdoc_files: []
|
142
|
+
files:
|
143
|
+
- app/models/active_event/event.rb
|
144
|
+
- app/models/active_event/event_repository.rb
|
145
|
+
- db/migrate/00_create_domain_events.rb
|
146
|
+
- lib/active_event/autoload.rb
|
147
|
+
- lib/active_event/command.rb
|
148
|
+
- lib/active_event/domain.rb
|
149
|
+
- lib/active_event/event_server.rb
|
150
|
+
- lib/active_event/event_type.rb
|
151
|
+
- lib/active_event/support/attr_initializer.rb
|
152
|
+
- lib/active_event/support/attr_setter.rb
|
153
|
+
- lib/active_event/support/autoloader.rb
|
154
|
+
- lib/active_event/validations.rb
|
155
|
+
- lib/active_event/validations_registry.rb
|
156
|
+
- lib/active_event/version.rb
|
157
|
+
- lib/active_event.rb
|
158
|
+
- README.md
|
159
|
+
- MIT-LICENSE
|
160
|
+
- spec/factories/event_factory.rb
|
161
|
+
- spec/lib/command_spec.rb
|
162
|
+
- spec/lib/domain_spec.rb
|
163
|
+
- spec/lib/event_server_spec.rb
|
164
|
+
- spec/lib/event_type_spec.rb
|
165
|
+
- spec/lib/support/attr_initializer_spec.rb
|
166
|
+
- spec/lib/support/attr_setter_spec.rb
|
167
|
+
- spec/models/event_spec.rb
|
168
|
+
- spec/spec_helper.rb
|
169
|
+
- spec/support/active_record.rb
|
170
|
+
homepage: https://github.com/hicknhack-software/rails-disco
|
171
|
+
licenses:
|
172
|
+
- MIT
|
173
|
+
metadata: {}
|
174
|
+
post_install_message:
|
175
|
+
rdoc_options: []
|
176
|
+
require_paths:
|
177
|
+
- lib
|
178
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - '>='
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - '>='
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
requirements: []
|
189
|
+
rubyforge_project:
|
190
|
+
rubygems_version: 2.0.5
|
191
|
+
signing_key:
|
192
|
+
specification_version: 4
|
193
|
+
summary: Simple event sourcing stuff (part of rails-disco)
|
194
|
+
test_files:
|
195
|
+
- spec/factories/event_factory.rb
|
196
|
+
- spec/lib/command_spec.rb
|
197
|
+
- spec/lib/domain_spec.rb
|
198
|
+
- spec/lib/event_server_spec.rb
|
199
|
+
- spec/lib/event_type_spec.rb
|
200
|
+
- spec/lib/support/attr_initializer_spec.rb
|
201
|
+
- spec/lib/support/attr_setter_spec.rb
|
202
|
+
- spec/models/event_spec.rb
|
203
|
+
- spec/spec_helper.rb
|
204
|
+
- spec/support/active_record.rb
|