diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ca1f19..afa54a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,9 @@ Unfortunately it comes with a couple of BREAKING changes: contract expects the event type to be a fully classified class name (subclass of Event) and will attempt to factor one. The second argument is no longer a world (Hash) but - a context instance to attach to the event (a dup is made). + a context instance to attach to the event. A context fork + is made, using the event context data passed through the + Context h_factory (if event contains context info). * `Startback::Engine` constructor takes ServerEngine options under a `:server_engine` key (was the options themselves). diff --git a/lib/startback/context.rb b/lib/startback/context.rb index 02fc713..cfc46d9 100644 --- a/lib/startback/context.rb +++ b/lib/startback/context.rb @@ -112,6 +112,13 @@ def to_json(*args, &bl) to_h.to_json(*args, &bl) end + def fork(h = nil) + dup.tap{|duped| + self.class.h_factor!(duped, h) if h + yield(duped) if block_given? + } + end + def dup super.tap{|c| c.send(:clean_factored!) diff --git a/lib/startback/event.rb b/lib/startback/event.rb index 1c9e3f2..4f3a359 100644 --- a/lib/startback/event.rb +++ b/lib/startback/event.rb @@ -23,6 +23,7 @@ def initialize(type, data, context = nil) def self.json(src, context) parsed = JSON.parse(src) klass = Kernel.const_get(parsed['type']) + context = context.fork(parsed['context']) if context klass.new(parsed['type'], parsed['data'], context) end diff --git a/lib/startback/event/engine.rb b/lib/startback/event/engine.rb index b0db797..7355cb1 100644 --- a/lib/startback/event/engine.rb +++ b/lib/startback/event/engine.rb @@ -86,7 +86,7 @@ def create_agents end def factor_event(event_data) - Event.json(event_data, context.dup) + Event.json(event_data, context) end class Runner diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 78237c3..fc7ced6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,6 +11,26 @@ module SpecHelpers c.include SpecHelpers end +class SubContext < Startback::Context + attr_accessor :foo + h_factory do |c,h| + c.foo = h["foo"] + end + h_dump do |h| + h.merge!("foo" => foo) + end +end + +class SubContext + attr_accessor :bar + h_factory do |c,h| + c.bar = h["bar"] + end + h_dump do |h| + h.merge!("bar" => bar) + end +end + class User class Changed < Startback::Event end diff --git a/spec/unit/context/test_dup.rb b/spec/unit/context/test_dup.rb index 8f02ff7..9bdc771 100644 --- a/spec/unit/context/test_dup.rb +++ b/spec/unit/context/test_dup.rb @@ -3,12 +3,8 @@ module Startback describe Context, "dup" do - class Subcontext < Context - attr_accessor :foo - end - let(:context) { - Subcontext.new.tap{|s| s.foo = "bar" } + SubContext.new.tap{|s| s.foo = "bar" } } class ContextRelatedAbstraction @@ -27,7 +23,7 @@ def initialize(context) expect(x).not_to be(context) } expect(seen).to be(got) - expect(got).to be_a(Subcontext) + expect(got).to be_a(SubContext) expect(got).not_to be(context) expect(got.foo).to eql("bar") end @@ -43,4 +39,4 @@ def initialize(context) end end -end \ No newline at end of file +end diff --git a/spec/unit/context/test_fork.rb b/spec/unit/context/test_fork.rb new file mode 100644 index 0000000..940c618 --- /dev/null +++ b/spec/unit/context/test_fork.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +module Startback + describe Context, "fork" do + + it 'is a simple dup without args' do + context = SubContext.new + context.foo = ['hello'] + + forked = context.fork + puts "Forked: #{forked.inspect}" + expect(fork).not_to be(context) + expect(forked.foo).to eql(['hello']) + expect(forked.foo).to be(context.foo) + end + + it 'yields the context if a block is provided' do + context = SubContext.new + + seen = false + context.fork({ 'foo' => 'hello' }) do |forked| + expect(fork).not_to be(context) + expect(forked.foo).to eql('hello') + seen = true + end + expect(seen).to eql(true) + end + + it 'uses the factory on the hash provided' do + context = SubContext.new + + forked = context.fork({ 'foo' => 'hello' }) + expect(fork).not_to be(context) + expect(forked.foo).to eql('hello') + end + + end +end diff --git a/spec/unit/context/test_h_factory.rb b/spec/unit/context/test_h_factory.rb index f45ab19..180bdcc 100644 --- a/spec/unit/context/test_h_factory.rb +++ b/spec/unit/context/test_h_factory.rb @@ -7,26 +7,6 @@ module Startback expect(Context.new.to_json).to eql("{}") end - class SubContext < Context - attr_accessor :foo - h_factory do |c,h| - c.foo = h["foo"] - end - h_dump do |h| - h.merge!("foo" => foo) - end - end - - class SubContext - attr_accessor :bar - h_factory do |c,h| - c.bar = h["bar"] - end - h_dump do |h| - h.merge!("bar" => bar) - end - end - it 'allows installing factories' do expect(Context.h_factories).to be_empty expect(SubContext.h_factories.size).to eql(2) diff --git a/spec/unit/test_event.rb b/spec/unit/test_event.rb index 87ffbf6..9d4ea7c 100644 --- a/spec/unit/test_event.rb +++ b/spec/unit/test_event.rb @@ -50,8 +50,11 @@ module Startback end it 'accepts an explicit context as second argument' do - evt = Event.json(JSON_SRC, 12) - expect(evt.context).to eql(12) + c = SubContext.new.tap{|x| x.foo = 'hello' } + evt = Event.json(JSON_SRC, c) + expect(evt.context).not_to be(c) + expect(evt.context).to be_a(SubContext) + expect(evt.context.foo).to eql('hello') end end