euston 1.2.3 → 1.2.4

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/euston.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'euston'
3
- s.version = '1.2.3'
4
- s.date = '2011-10-24'
3
+ s.version = '1.2.4'
4
+ s.date = '2011-11-29'
5
5
  s.platform = RUBY_PLATFORM.to_s == 'java' ? 'java' : Gem::Platform::RUBY
6
6
  s.authors = ['Lee Henson', 'Guy Boertje']
7
7
  s.email = ['lee.m.henson@gmail.com', 'guyboertje@gmail.com']
@@ -35,6 +35,7 @@ Gem::Specification.new do |s|
35
35
  spec/aggregate_command_map_spec.rb
36
36
  spec/aggregate_root_samples.rb
37
37
  spec/aggregate_root_spec.rb
38
+ spec/command_headers_spec.rb
38
39
  spec/spec_helper.rb
39
40
  ]
40
41
  # = MANIFEST =
@@ -161,10 +161,17 @@ module Euston
161
161
 
162
162
  def deliver_message headers, message, name_method, message_kind, expected_block_kind
163
163
  name = self.class.send(name_method, headers.type, headers.version).to_sym
164
-
165
164
  if respond_to? name
166
165
  @log.debug "Calling #{name} with: #{message.inspect}"
167
- method(name).call OpenStruct.new(message).freeze
166
+ m = method(name)
167
+ case m.arity
168
+ when 2, -2
169
+ m.call OpenStruct.new(headers.to_hash).freeze, OpenStruct.new(message).freeze
170
+ when 1, -1
171
+ m.call OpenStruct.new(message).freeze
172
+ else
173
+ m.call
174
+ end
168
175
  else
169
176
  raise "Couldn't deliver #{message_kind} (#{headers.type} v#{headers.version}) to #{self.class}. Did you forget #{expected_block_kind}?"
170
177
  end
@@ -40,8 +40,7 @@ module Euston
40
40
  private
41
41
 
42
42
  def define_private_method name, &block
43
- block = method(:null_block) if block.nil?
44
- define_method name do |*args| instance_exec *args, &block end
43
+ define_method name, &(block || method(:null_block))
45
44
  end
46
45
 
47
46
  def map_command(entry_point, type, command, opts)
@@ -22,6 +22,14 @@ module Euston
22
22
  @headers[:id] = value
23
23
  end
24
24
 
25
+ def publishing_user_id
26
+ @headers[:user_id]
27
+ end
28
+
29
+ def publishing_user_id= value
30
+ @headers[:user_id] = value
31
+ end
32
+
25
33
  def read_attribute_for_validation key
26
34
  match = /^__(.*)/.match(key.to_s)
27
35
 
@@ -1,29 +1,58 @@
1
1
  module Euston
2
2
  class CommandHeaders
3
- attr_reader :id, :type, :version, :log_completion
4
3
 
5
- def initialize id, type, version, log_completion = false
6
- @id = id
7
- @type = type
8
- @version = version
9
- @log_completion = log_completion
4
+ BASE_KEYS = [:id, :type, :version]
5
+
6
+ def initialize hash
7
+ arg_errors = []
8
+ BASE_KEYS.each do |arg|
9
+ arg_errors << arg unless hash.has_key?(arg)
10
+ end
11
+ raise Errors::CommandHeadersArgumentError.new("Missing args: #{arg_errors.join(", ")}") if arg_errors.size > 0
12
+ @headers = {}.merge(hash)
13
+ @headers[:type] = @headers[:type].to_sym
14
+ @headers_keys = @headers.keys
15
+ end
16
+
17
+ def [] name
18
+ @headers[name.to_sym]
10
19
  end
11
20
 
21
+ # only use method missing for uncommon attributes
22
+ def id() @headers[:id]; end
23
+ def type() @headers[:type]; end
24
+ def version() @headers[:version]; end
25
+
12
26
  def to_hash
13
- {
14
- :id => id,
15
- :type => type,
16
- :version => version,
17
- :log_completion => log_completion
18
- }
27
+ @headers.dup
28
+ end
29
+
30
+ def ==(other)
31
+ @headers == other.to_hash
19
32
  end
20
33
 
21
34
  def self.from_hash hash
22
- self.new hash[:id], hash[:type].to_sym, hash[:version], ( hash[:log_completion] || false )
35
+ self.new hash
23
36
  end
24
37
 
25
38
  def to_s
26
39
  "#{id} #{type} (v#{version})"
27
40
  end
41
+
42
+ def method_missing(name,*args,&block)
43
+ n = name.to_sym
44
+ is_dynamic_method?(n) ? @headers[n] : super
45
+ end
46
+
47
+ # >= 1.9.2
48
+ def respond_to_missing?(name, incl_private)
49
+ is_dynamic_method?(name.to_sym) || super
50
+ end
51
+
52
+ private
53
+
54
+ def is_dynamic_method? name
55
+ (@headers_keys - BASE_KEYS).include?(name)
56
+ end
28
57
  end
29
58
  end
data/lib/euston/errors.rb CHANGED
@@ -2,5 +2,6 @@ module Euston
2
2
  module Errors
3
3
  class InvalidCommandError < StandardError; end
4
4
  class AggregateNotFoundError < StandardError; end
5
+ class CommandHeadersArgumentError < StandardError; end
5
6
  end
6
7
  end
@@ -8,7 +8,7 @@ module Euston
8
8
  end
9
9
 
10
10
  module ClassMethods
11
- def subscribes type, version = 1, opts = nil, &consumer
11
+ def subscribes type, version = 1, opts = {}, &consumer
12
12
  if self.include? Euston::AggregateRoot
13
13
  o = { :id => :id }.merge opts
14
14
 
@@ -21,8 +21,12 @@ module Euston
21
21
  end
22
22
  end
23
23
 
24
- define_method event_handler_method_name(type, version) do |*args|
25
- instance_exec *args, &consumer
24
+ method_name = event_handler_method_name type, version
25
+ define_method method_name, &consumer
26
+ new_method = instance_method method_name
27
+
28
+ define_method method_name do |*args|
29
+ new_method.bind(self).call *args
26
30
  end
27
31
  end
28
32
  end
@@ -1,3 +1,3 @@
1
1
  module Euston
2
- VERSION = "1.2.3"
2
+ VERSION = "1.2.4"
3
3
  end
@@ -6,17 +6,17 @@ module Euston
6
6
  let(:guid1) {Euston.uuid.generate}
7
7
  let(:guid2) {Euston.uuid.generate}
8
8
 
9
- let(:command_cw) { { :headers => CommandHeaders.new(Euston.uuid.generate, :create_widget, 1),
9
+ let(:command_cw) { { :headers => CommandHeaders.new(id: Euston.uuid.generate, type: 'create_widget', version: 1),
10
10
  :body => { :id => guid1} } }
11
- let(:command_iw) { { :headers => CommandHeaders.new(Euston.uuid.generate, :import_widget, 1),
11
+ let(:command_iw) { { :headers => CommandHeaders.new(id: Euston.uuid.generate, type: 'import_widget', version: 1),
12
12
  :body => { :id => guid1, :imported_count => 5 } } }
13
- let(:command_aw) { { :headers => CommandHeaders.new(Euston.uuid.generate, :log_access_to_widget, 1),
13
+ let(:command_aw) { { :headers => CommandHeaders.new(id: Euston.uuid.generate, type: 'log_access_to_widget', version: 1),
14
14
  :body => { :widget_id => guid1 } } }
15
- let(:command_cp) { { :headers => CommandHeaders.new(Euston.uuid.generate, :create_product, 1),
15
+ let(:command_cp) { { :headers => CommandHeaders.new(id: Euston.uuid.generate, type: 'create_product', version: 1),
16
16
  :body => { :id => guid2} } }
17
- let(:command_ip) { { :headers => CommandHeaders.new(Euston.uuid.generate, :import_product, 1),
17
+ let(:command_ip) { { :headers => CommandHeaders.new(id: Euston.uuid.generate, type: 'import_product', version: 1),
18
18
  :body => { :id => guid2, :imported_count => 5 } } }
19
- let(:command_ap) { { :headers => CommandHeaders.new(Euston.uuid.generate, :log_access_to_product, 1),
19
+ let(:command_ap) { { :headers => CommandHeaders.new(id: Euston.uuid.generate, type: 'log_access_to_product', version: 1),
20
20
  :body => { :product_id => guid2 } } }
21
21
 
22
22
  describe "when creating new Aggregates" do
@@ -3,20 +3,20 @@ module Euston
3
3
  class Widget
4
4
  include Euston::AggregateRoot
5
5
 
6
- created_by :create_widget do |command|
6
+ created_by :create_widget do |header, command|
7
7
  apply_event :widget_created, 1, command
8
8
  end
9
9
 
10
- created_by :import_widget do |command|
10
+ created_by :import_widget do |header, command|
11
11
  apply_event :widget_imported, 1, :access_count => (@access_count || 0) + command.imported_count
12
12
  end
13
13
 
14
- consumes :log_access_to_widget, :id => :widget_id do |command|
14
+ consumes :log_access_to_widget, :id => :widget_id do |header, command|
15
15
  apply_event :widget_access_logged, 1, :widget_id => command.widget_id,
16
16
  :access_count => @access_count + 1
17
17
  end
18
18
 
19
- applies :widget_created, 1 do |event|
19
+ applies :widget_created, 1 do
20
20
  @access_count = 0
21
21
  end
22
22
 
@@ -32,11 +32,11 @@ module Euston
32
32
  class Product
33
33
  include Euston::AggregateRoot
34
34
 
35
- created_by :create_product do |command|
35
+ created_by :create_product do |header, command|
36
36
  apply_event :product_created, 1, command
37
37
  end
38
38
 
39
- created_by :import_product do |command|
39
+ created_by :import_product do |header, command|
40
40
  apply_event :product_imported, 1, :access_count => command.imported_count
41
41
  end
42
42
 
@@ -5,7 +5,7 @@ module Euston
5
5
  context 'duplicate command consumption' do
6
6
  let(:aggregate) { Sample::Widget.new }
7
7
  let(:aggregate2) { Sample::Widget.new }
8
- let(:command) { { :headers => CommandHeaders.new(Euston.uuid.generate, :create_widget, 1),
8
+ let(:command) { { :headers => CommandHeaders.new(id: Euston.uuid.generate, type: 'create_widget', version: 1),
9
9
  :body => { :id => Euston.uuid.generate } } }
10
10
 
11
11
  it 'does not handle the same command twice' do
@@ -0,0 +1,51 @@
1
+ require File.expand_path("../spec_helper", __FILE__)
2
+
3
+ module Euston
4
+ describe 'command_headers' do
5
+ let(:header) { CommandHeaders.new(parameters) }
6
+ context 'a new command headers object' do
7
+ it 'traps incorrect construction' do
8
+ expect { CommandHeaders.new({}) }.to raise_error(Errors::CommandHeadersArgumentError)
9
+ expect { CommandHeaders.new(id: 'foo', type: 'bah') }.to raise_error(Errors::CommandHeadersArgumentError,/version/)
10
+ expect { CommandHeaders.new(type: 'bah', version: 3) }.to raise_error(Errors::CommandHeadersArgumentError,/id/)
11
+ expect { CommandHeaders.new(id: 'foo', version: 2) }.to raise_error(Errors::CommandHeadersArgumentError,/type/)
12
+ end
13
+ let(:parameters) {{ id: 'foo', type: 'bah', version: 3 }}
14
+ it 'creates one from a hash' do
15
+ CommandHeaders.from_hash(parameters).should == header
16
+ end
17
+ end
18
+ context 'accessors' do
19
+ let(:parameters) {{ id: 'foo', type: 'bah', version: 3 }}
20
+ it 'converts type to a symbol' do
21
+ header.type.should == :bah
22
+ end
23
+ it 'has various accessor methods' do
24
+ header.id.should == 'foo'
25
+ header.version.should == 3
26
+ header[:id].should == 'foo'
27
+ header[:type].should == :bah
28
+ header['version'].should == 3
29
+ end
30
+ it 'treats respond_to correctly' do
31
+ header.respond_to?(:type).should be_true
32
+ header.respond_to?(:user_id).should be_false
33
+ end
34
+ end
35
+ context 'with more than the basic attributes' do
36
+ let(:parameters) {{ id: 'foo', type: 'bah', version: 3, user_id: 'bobby123' }}
37
+ it 'allows access to the extra attributes' do
38
+ header.respond_to?(:user_id).should be_true
39
+ header.user_id.should == 'bobby123'
40
+ header[:user_id].should == 'bobby123'
41
+ end
42
+ end
43
+ context 'auxilliary methods' do
44
+ let(:parameters) {{ id: 'foo', type: 'bah', version: 3, user_id: 'bobby123' }}
45
+ it 'has methods' do
46
+ header.to_hash.should == {id: 'foo', type: :bah, version: 3, user_id: 'bobby123'}
47
+ header.to_s.should == 'foo bah (v3)'
48
+ end
49
+ end
50
+ end
51
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,8 @@
1
1
  require 'euston'
2
2
  require 'aggregate_root_samples'
3
+
4
+ def apr(what, header='')
5
+ puts '', "== #{header} =="
6
+ puts what.inspect
7
+ puts ("="*(header.size + 6)), ''
8
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: euston
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-10-24 00:00:00.000000000 Z
13
+ date: 2011-11-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activemodel
17
- requirement: &70270530479600 !ruby/object:Gem::Requirement
17
+ requirement: &70222602188740 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: 3.0.10
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70270530479600
25
+ version_requirements: *70222602188740
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activesupport
28
- requirement: &70270530478760 !ruby/object:Gem::Requirement
28
+ requirement: &70222602187880 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 3.0.10
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *70270530478760
36
+ version_requirements: *70222602187880
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: fuubar
39
- requirement: &70270530478060 !ruby/object:Gem::Requirement
39
+ requirement: &70222602187200 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ~>
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: 0.0.0
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *70270530478060
47
+ version_requirements: *70222602187200
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: rspec
50
- requirement: &70270530477300 !ruby/object:Gem::Requirement
50
+ requirement: &70222602186600 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ~>
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: 2.6.0
56
56
  type: :development
57
57
  prerelease: false
58
- version_requirements: *70270530477300
58
+ version_requirements: *70222602186600
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: uuid
61
- requirement: &70270530476640 !ruby/object:Gem::Requirement
61
+ requirement: &70222602186040 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ~>
@@ -66,7 +66,7 @@ dependencies:
66
66
  version: 2.3.0
67
67
  type: :development
68
68
  prerelease: false
69
- version_requirements: *70270530476640
69
+ version_requirements: *70222602186040
70
70
  description: ''
71
71
  email:
72
72
  - lee.m.henson@gmail.com
@@ -99,6 +99,7 @@ files:
99
99
  - spec/aggregate_command_map_spec.rb
100
100
  - spec/aggregate_root_samples.rb
101
101
  - spec/aggregate_root_spec.rb
102
+ - spec/command_headers_spec.rb
102
103
  - spec/spec_helper.rb
103
104
  homepage: http://github.com/leemhenson/euston
104
105
  licenses: []
@@ -128,4 +129,5 @@ test_files:
128
129
  - spec/aggregate_command_map_spec.rb
129
130
  - spec/aggregate_root_samples.rb
130
131
  - spec/aggregate_root_spec.rb
132
+ - spec/command_headers_spec.rb
131
133
  - spec/spec_helper.rb