startback 0.12.1 → 0.13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '085ac55f8fc68a8b8806570359e68ae9cba48a0c0cef83645bfb9f7133fb38ce'
4
- data.tar.gz: 231685b5e7c8c53a3cb086bbdc8ef6728132a942a47b59e6ac5c1ca6560b2725
3
+ metadata.gz: 5b7ccc8dd2081ba0dffda6092a2dbb2a345b01e6b7231aee41aa506e85949a4a
4
+ data.tar.gz: c53f396f235226bbbfd336c872a5e1334708e1dcc6ca62d456d7b969bf7baad2
5
5
  SHA512:
6
- metadata.gz: 3c12830f86d5e0a067b801ebc752c894d7abec27c9745bb8eb307eee010a049275b49f3bfa1f55a1b7bf168c9fc3222b7039f6dc243f96c5268d369b625eabb3
7
- data.tar.gz: dedb51337c356d9208ea727155c978dd6e937c2d8016189c17c606820975e81d1ede4e004a22878e8060dd58cd84280a4119f1a1996dae5c26bbdfc660009029
6
+ metadata.gz: c5c4b8ecc4045efd18f206217ddc201c869929e1951e981bf07fae0a9ff710d60d00b444f871bac7096a8ee48f7b05f0d95498f58c3d737be5a5b08e3a626707
7
+ data.tar.gz: d193c22d134a0f57403433a6e4f0279d74ca17aaf7d99278664a86c5a3d2118d7a926bc7a95957ad2e4bbe90a8fafb82f549a938e73d3996204aa98f0b19c4fc
@@ -0,0 +1,43 @@
1
+ module Startback
2
+ class Context
3
+ module HFactory
4
+
5
+ def h(hash)
6
+ h_factor!(self.new, hash)
7
+ end
8
+
9
+ def h_factor!(context, hash)
10
+ h_factories.each do |f|
11
+ f.call(context, hash)
12
+ end
13
+ context
14
+ end
15
+
16
+ def h_factories
17
+ @h_factories ||= []
18
+ end
19
+
20
+ def h_factory(&factory)
21
+ h_factories << factory
22
+ end
23
+
24
+ ###
25
+
26
+ def h_dump!(context, hash = {})
27
+ h_dumpers.each do |d|
28
+ context.instance_exec(hash, &d)
29
+ end
30
+ hash
31
+ end
32
+
33
+ def h_dumpers
34
+ @h_dumpers ||= []
35
+ end
36
+
37
+ def h_dump(&dumper)
38
+ h_dumpers << dumper
39
+ end
40
+
41
+ end # module HFactory
42
+ end # class Context
43
+ end # module Startback
@@ -1,7 +1,8 @@
1
1
  module Startback
2
2
  #
3
3
  # Defines an execution context for Startback applications, and provides
4
- # a cached factory for related abstractions (see `factor`).
4
+ # a cached factory for related abstractions (see `factor`), and an
5
+ # extensible world, statically and dynamically.
5
6
  #
6
7
  # In web application, an instance of a context can be set on the Rack
7
8
  # environment, using Context::Middleware.
@@ -48,46 +49,36 @@ module Startback
48
49
  # convert them to wathever log format is necessary.
49
50
  attr_accessor :logger
50
51
 
51
- # Implementation of the `h` information contract
52
- class << self
52
+ require_relative 'context/h_factory'
53
+ extend(Context::HFactory)
53
54
 
54
- def h(hash)
55
- h_factor!(self.new, hash)
56
- end
57
-
58
- def h_factor!(context, hash)
59
- h_factories.each do |f|
60
- f.call(context, hash)
61
- end
62
- context
63
- end
64
-
65
- def h_factories
66
- @h_factories ||= []
67
- end
55
+ def initialize
56
+ super
57
+ yield(self) if block_given?
58
+ end
68
59
 
69
- def h_factory(&factory)
70
- h_factories << factory
71
- end
60
+ attr_writer :_world
61
+ protected :_world=
72
62
 
73
- ###
63
+ def self.world(who, &block)
64
+ @_world ||= Support::World.new
65
+ @_world = @_world.factory(who, &block)
66
+ end
74
67
 
75
- def h_dump!(context, hash = {})
76
- h_dumpers.each do |d|
77
- context.instance_exec(hash, &d)
78
- end
79
- hash
80
- end
68
+ def self.factor_world(context)
69
+ @_world ||= Support::World.new
70
+ @_world.with_scope(context)
71
+ end
81
72
 
82
- def h_dumpers
83
- @h_dumpers ||= []
84
- end
73
+ def world
74
+ @_world ||= self.class.factor_world(self)
75
+ end
85
76
 
86
- def h_dump(&dumper)
87
- h_dumpers << dumper
77
+ def with_world(world)
78
+ dup do |ctx|
79
+ ctx._world = self.world.with(world)
88
80
  end
89
-
90
- end # class << self
81
+ end
91
82
 
92
83
  # Factors an instance of `clazz`, which must be a Context-related
93
84
  # abstraction (i.e. its constructor takes the context as last parameters).
@@ -112,6 +103,13 @@ module Startback
112
103
  to_h.to_json(*args, &bl)
113
104
  end
114
105
 
106
+ def fork(h = nil)
107
+ dup.tap{|duped|
108
+ self.class.h_factor!(duped, h) if h
109
+ yield(duped) if block_given?
110
+ }
111
+ end
112
+
115
113
  def dup
116
114
  super.tap{|c|
117
115
  c.send(:clean_factored!)
@@ -16,9 +16,12 @@ module Startback
16
16
 
17
17
  def initialize(engine)
18
18
  @engine = engine
19
+ @context = nil
19
20
  install_listeners
20
21
  end
21
22
  attr_reader :engine
23
+ attr_accessor :context
24
+ protected :context=
22
25
 
23
26
  protected
24
27
 
@@ -40,7 +43,7 @@ module Startback
40
43
  def async(exchange, queue)
41
44
  bus.async.listen(exchange, queue) do |event_data|
42
45
  event = engine.factor_event(event_data)
43
- dup.call(event)
46
+ with_context(event.context).call(event)
44
47
  end
45
48
  end
46
49
 
@@ -50,7 +53,7 @@ module Startback
50
53
  def sync(exchange, queue)
51
54
  bus.listen(exchange, queue) do |event_data|
52
55
  event = engine.factor_event(event_data)
53
- dup.call(event)
56
+ with_context(event.context).call(event)
54
57
  end
55
58
  end
56
59
 
@@ -68,6 +71,14 @@ module Startback
68
71
  raise NotImplementedError
69
72
  end
70
73
 
74
+ def with_context(context)
75
+ dup.tap{|a| a.send(:context=, context) }
76
+ end
77
+
78
+ def operation_world(op)
79
+ super(op).merge(context: context)
80
+ end
81
+
71
82
  end # class Agent
72
83
  end # class Event
73
84
  end # module Starback
@@ -86,7 +86,7 @@ module Startback
86
86
  end
87
87
 
88
88
  def factor_event(event_data)
89
- Event.json(event_data, context.dup)
89
+ Event.json(event_data, context)
90
90
  end
91
91
 
92
92
  class Runner
@@ -21,8 +21,11 @@ module Startback
21
21
  attr_reader :context, :type, :data
22
22
 
23
23
  def self.json(src, context)
24
+ return src if src.is_a?(Event)
25
+
24
26
  parsed = JSON.parse(src)
25
27
  klass = Kernel.const_get(parsed['type'])
28
+ context = context.fork(parsed['context']) if context
26
29
  klass.new(parsed['type'], parsed['data'], context)
27
30
  end
28
31
 
@@ -0,0 +1,6 @@
1
+ module Startback
2
+ class Model
3
+ include Support::DataObject
4
+
5
+ end # class Model
6
+ end # module Startback
@@ -37,6 +37,11 @@ module Startback
37
37
  attr_accessor :world
38
38
  protected :world=
39
39
 
40
+ def initialize(input = {})
41
+ @input = input
42
+ end
43
+ attr_reader :input
44
+
40
45
  def bind(world)
41
46
  return self unless world
42
47
  self.world = world
@@ -0,0 +1,11 @@
1
+ module Startback
2
+ class Services
3
+ include Startback::Errors
4
+
5
+ def initialize(context)
6
+ @context = context
7
+ end
8
+ attr_reader :context
9
+
10
+ end # class Services
11
+ end # module Startback
@@ -0,0 +1,71 @@
1
+ module Startback
2
+ module Support
3
+ module DataObject
4
+
5
+ def initialize(data = {})
6
+ @_data = data.dup.freeze
7
+ end
8
+
9
+ attr_writer :_data
10
+ protected :_data=
11
+
12
+ def method_missing(name, *args, &bl)
13
+ return super unless args.empty? && bl.nil?
14
+ return super unless pair = _data_key_for(name)
15
+
16
+ pair.last ? !!@_data[pair.first] : @_data[pair.first]
17
+ end
18
+
19
+ def [](name)
20
+ return nil unless pair = _data_key_for(name, false, false)
21
+
22
+ @_data[pair.first]
23
+ end
24
+
25
+ def respond_to?(name)
26
+ super || !_data_key_for(name).nil?
27
+ end
28
+
29
+ def to_data
30
+ @_data
31
+ end
32
+ alias :to_h :to_data
33
+
34
+ def to_json(*args, &bl)
35
+ to_data.to_json(*args, &bl)
36
+ end
37
+
38
+ private
39
+
40
+ def _data_key_for(key, try_camelize = _data_allow_camelize, try_query = _data_allow_query)
41
+ if @_data.key?(key)
42
+ [key, false]
43
+ elsif @_data.key?(key.to_s)
44
+ [key.to_s, false]
45
+ elsif key.is_a?(String) && @_data.key?(key.to_sym)
46
+ [key.to_sym, false]
47
+ elsif try_camelize
48
+ cam = key.to_s.gsub(/_([a-z])/){ $1.upcase }.to_sym
49
+ _data_key_for(cam, false, true)
50
+ elsif try_query && key.to_s =~ /\?$/
51
+ got = _data_key_for(key[0...-1].to_sym, false, false)
52
+ got ? [got.first, true] : _data_key_not_found(key)
53
+ else
54
+ _data_key_not_found(key)
55
+ end
56
+ end
57
+
58
+ def _data_allow_camelize
59
+ true
60
+ end
61
+
62
+ def _data_allow_query
63
+ true
64
+ end
65
+
66
+ def _data_key_not_found(key)
67
+ nil
68
+ end
69
+ end # module DataObject
70
+ end # module Support
71
+ end # module Startback
@@ -0,0 +1,54 @@
1
+ module Startback
2
+ module Support
3
+ class World
4
+ include DataObject
5
+
6
+ attr_accessor :_factory
7
+ protected :_factory=
8
+
9
+ def factory(who, &block)
10
+ dup.tap do |x|
11
+ x._factory = (self._factory || {}).merge(who => block)
12
+ end
13
+ end
14
+
15
+ attr_accessor :_scope
16
+ protected :_scope=
17
+
18
+ def with_scope(scope)
19
+ dup.tap do |x|
20
+ x._scope = scope
21
+ end
22
+ end
23
+
24
+ def with(hash)
25
+ dup.tap do |x|
26
+ x._data = to_data.merge(hash)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def _data_allow_camelize
33
+ false
34
+ end
35
+
36
+ def _data_allow_query
37
+ false
38
+ end
39
+
40
+ def _data_key_not_found(key)
41
+ raise Startback::Error, "Scope must be defined" unless s = _scope
42
+
43
+ block = (_factory || {})[key]
44
+ if block
45
+ factored = s.instance_exec(&block)
46
+ @_data = @_data.dup.merge(key => factored).freeze
47
+ [key, false]
48
+ else
49
+ nil
50
+ end
51
+ end
52
+ end # class World
53
+ end # module Support
54
+ end # module Startback
@@ -22,3 +22,5 @@ require_relative 'support/hooks'
22
22
  require_relative 'support/operation_runner'
23
23
  require_relative 'support/transaction_policy'
24
24
  require_relative 'support/transaction_manager'
25
+ require_relative 'support/data_object'
26
+ require_relative 'support/world'
@@ -1,8 +1,8 @@
1
1
  module Startback
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 12
5
- TINY = 1
4
+ MINOR = 13
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
data/lib/startback.rb CHANGED
@@ -32,8 +32,10 @@ module Startback
32
32
  require_relative 'startback/ext'
33
33
  require_relative 'startback/errors'
34
34
  require_relative 'startback/support'
35
+ require_relative 'startback/model'
35
36
  require_relative 'startback/context'
36
37
  require_relative 'startback/operation'
38
+ require_relative 'startback/services'
37
39
 
38
40
  # Logger instance to use for the application
39
41
  LOGGER = ::Startback::Support::Logger.new
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,8 @@
1
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
1
  require 'startback'
3
2
  require 'startback/event'
4
3
  require 'startback/support/fake_logger'
5
4
  require 'rack/test'
5
+ require 'ostruct'
6
6
 
7
7
  module SpecHelpers
8
8
  end
@@ -11,6 +11,38 @@ RSpec.configure do |c|
11
11
  c.include SpecHelpers
12
12
  end
13
13
 
14
+ class SubContext < Startback::Context
15
+
16
+ attr_accessor :foo
17
+
18
+ h_factory do |c,h|
19
+ c.foo = h["foo"]
20
+ end
21
+
22
+ h_dump do |h|
23
+ h.merge!("foo" => foo)
24
+ end
25
+
26
+ world(:partner) do
27
+ Object.new
28
+ end
29
+
30
+ end
31
+
32
+ class SubContext
33
+
34
+ attr_accessor :bar
35
+
36
+ h_factory do |c,h|
37
+ c.bar = h["bar"]
38
+ end
39
+
40
+ h_dump do |h|
41
+ h.merge!("bar" => bar)
42
+ end
43
+
44
+ end
45
+
14
46
  class User
15
47
  class Changed < Startback::Event
16
48
  end
@@ -3,12 +3,8 @@ require 'spec_helper'
3
3
  module Startback
4
4
  describe Context, "dup" do
5
5
 
6
- class Subcontext < Context
7
- attr_accessor :foo
8
- end
9
-
10
6
  let(:context) {
11
- Subcontext.new.tap{|s| s.foo = "bar" }
7
+ SubContext.new.tap{|s| s.foo = "bar" }
12
8
  }
13
9
 
14
10
  class ContextRelatedAbstraction
@@ -27,7 +23,7 @@ module Startback
27
23
  expect(x).not_to be(context)
28
24
  }
29
25
  expect(seen).to be(got)
30
- expect(got).to be_a(Subcontext)
26
+ expect(got).to be_a(SubContext)
31
27
  expect(got).not_to be(context)
32
28
  expect(got.foo).to eql("bar")
33
29
  end
@@ -43,4 +39,4 @@ module Startback
43
39
  end
44
40
 
45
41
  end
46
- end
42
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Context, "fork" do
5
+
6
+ it 'is a simple dup without args' do
7
+ context = SubContext.new
8
+ context.foo = ['hello']
9
+
10
+ forked = context.fork
11
+ expect(forked).not_to be(context)
12
+ expect(forked.foo).to eql(['hello'])
13
+ expect(forked.foo).to be(context.foo)
14
+ end
15
+
16
+ it 'yields the context if a block is provided' do
17
+ context = SubContext.new
18
+
19
+ seen = false
20
+ context.fork({ 'foo' => 'hello' }) do |forked|
21
+ expect(forked).not_to be(context)
22
+ expect(forked.foo).to eql('hello')
23
+ seen = true
24
+ end
25
+ expect(seen).to eql(true)
26
+ end
27
+
28
+ it 'uses the factory on the hash provided' do
29
+ context = SubContext.new
30
+
31
+ forked = context.fork({ 'foo' => 'hello' })
32
+ expect(forked).not_to be(context)
33
+ expect(forked.foo).to eql('hello')
34
+ end
35
+
36
+ end
37
+ end
@@ -7,26 +7,6 @@ module Startback
7
7
  expect(Context.new.to_json).to eql("{}")
8
8
  end
9
9
 
10
- class SubContext < Context
11
- attr_accessor :foo
12
- h_factory do |c,h|
13
- c.foo = h["foo"]
14
- end
15
- h_dump do |h|
16
- h.merge!("foo" => foo)
17
- end
18
- end
19
-
20
- class SubContext
21
- attr_accessor :bar
22
- h_factory do |c,h|
23
- c.bar = h["bar"]
24
- end
25
- h_dump do |h|
26
- h.merge!("bar" => bar)
27
- end
28
- end
29
-
30
10
  it 'allows installing factories' do
31
11
  expect(Context.h_factories).to be_empty
32
12
  expect(SubContext.h_factories.size).to eql(2)
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Context, "with_world" do
5
+
6
+ let(:who) do
7
+ Object.new
8
+ end
9
+
10
+ let(:context) do
11
+ SubContext.new.with_world(hello: who)
12
+ end
13
+
14
+ it 'works as expected' do
15
+ got = context.world.hello
16
+ expect(got).to be(who)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Context, "world" do
5
+
6
+ let(:context) do
7
+ SubContext.new
8
+ end
9
+
10
+ it 'works as expected' do
11
+ got = context.world.partner
12
+ expect(got).not_to be_nil
13
+ expect(context.world.partner).to be(got)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ module Support
5
+ describe DataObject do
6
+
7
+ class FooDataObject
8
+ include DataObject
9
+ end
10
+
11
+ let(:data) do
12
+ {
13
+ :foo => 'bar',
14
+ 'bar' => 'baz'
15
+ }
16
+ end
17
+
18
+ subject do
19
+ FooDataObject.new(data)
20
+ end
21
+
22
+ it 'lets create an instance with providing data' do
23
+ expect(subject).to be_a(FooDataObject)
24
+ end
25
+
26
+ it 'lets get the data back' do
27
+ expect(subject.to_data).to eql(data)
28
+ expect(subject.to_data).not_to be(data)
29
+ end
30
+
31
+ it 'lets to_json it' do
32
+ expect(subject.to_json).to eql(%Q{{"foo":"bar","bar":"baz"}})
33
+ end
34
+
35
+ describe "data helpers" do
36
+ it 'lets access data through methods' do
37
+ expect(subject.foo).to eql('bar')
38
+ end
39
+
40
+ it 'is indifferent to symbol vs. string' do
41
+ expect(subject.bar).to eql('baz')
42
+ end
43
+
44
+ it 'is indifferent to camel casing' do
45
+ expect(subject.bar).to eql('baz')
46
+ end
47
+
48
+ it 'raises a NoMethodError when not known' do
49
+ expect {
50
+ subject.no_such_one
51
+ }.to raise_error(NoMethodError)
52
+ end
53
+
54
+ it 'implements respond_to? correctly' do
55
+ expect(subject.respond_to?(:foo)).to eql(true)
56
+ expect(subject.respond_to?(:bar)).to eql(true)
57
+ expect(subject.respond_to?(:no_such_one)).to eql(false)
58
+ end
59
+ end # data helpers
60
+
61
+ describe "? helpers" do
62
+ let(:data) do
63
+ {
64
+ 'some' => 'thing',
65
+ 'ready' => false,
66
+ 'unready' => true,
67
+ 'nothing' => nil
68
+ }
69
+ end
70
+
71
+ it 'works as expected' do
72
+ expect(subject.some?).to eql(true)
73
+ expect(subject.ready?).to eql(false)
74
+ expect(subject.unready?).to eql(true)
75
+ expect(subject.nothing?).to eql(false)
76
+ end
77
+
78
+ it 'implements respond_to? correctly' do
79
+ expect(subject.respond_to?(:some?)).to eql(true)
80
+ expect(subject.respond_to?(:ready?)).to eql(true)
81
+ expect(subject.respond_to?(:unready?)).to eql(true)
82
+ expect(subject.respond_to?(:nothing?)).to eql(true)
83
+ end
84
+
85
+ it 'stays conservative' do
86
+ expect {
87
+ subject.no_such_one?
88
+ }.to raise_error(NoMethodError)
89
+ expect(subject.respond_to?(:no_such_one?)).to eql(false)
90
+ end
91
+ end
92
+
93
+ describe "case helpers" do
94
+ let(:data) do
95
+ {
96
+ 'camelCase' => 'snake_case'
97
+ }
98
+ end
99
+
100
+ it 'lets use camelCase' do
101
+ expect(subject.camelCase).to eql('snake_case')
102
+ end
103
+
104
+ it 'lets use camel_case' do
105
+ expect(subject.camel_case).to eql('snake_case')
106
+ end
107
+
108
+ it 'implements respond_to? correctly' do
109
+ expect(subject.respond_to?(:camelCase)).to eql(true)
110
+ expect(subject.respond_to?(:camel_case)).to eql(true)
111
+ end
112
+
113
+ it 'is compatible with ? helpers' do
114
+ expect(subject.camelCase?).to eql(true)
115
+ expect(subject.camel_case?).to eql(true)
116
+ end
117
+
118
+ it 'stays conservative' do
119
+ expect {
120
+ subject.no_such_one
121
+ }.to raise_error(NoMethodError)
122
+ expect(subject.respond_to?(:no_such_one)).to eql(false)
123
+ expect(subject.respond_to?(:no_such_one?)).to eql(false)
124
+ end
125
+ end
126
+
127
+ describe '[]' do
128
+ let(:data) do
129
+ {
130
+ :foo => 'bar',
131
+ 'bar' => 'baz',
132
+ 'camelCase' => 'snake_case'
133
+ }
134
+ end
135
+
136
+ it 'lets access data' do
137
+ expect(subject[:foo]).to eql('bar')
138
+ expect(subject['bar']).to eql('baz')
139
+ expect(subject['camelCase']).to eql('snake_case')
140
+ end
141
+
142
+ it 'uses indifferent access' do
143
+ expect(subject['foo']).to eql('bar')
144
+ expect(subject[:bar]).to eql('baz')
145
+ expect(subject[:camelCase]).to eql('snake_case')
146
+ end
147
+
148
+ it 'has no other magic and returns nil in all other cases' do
149
+ expect(subject[:foo?]).to be_nil
150
+ expect(subject[:camel_case]).to be_nil
151
+ expect(subject[:camel_case?]).to be_nil
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ module Support
5
+ describe World do
6
+
7
+ let(:world) do
8
+ World.new
9
+ end
10
+
11
+ describe 'with' do
12
+ subject do
13
+ world.with(foo: :bar, bar: :baz)
14
+ end
15
+
16
+ it 'returns a new world instance' do
17
+ expect(subject).to be_a(World)
18
+ expect(subject).not_to be(world)
19
+ end
20
+
21
+ it 'gives access to those variables' do
22
+ expect(subject.foo).to eql(:bar)
23
+ expect(subject[:bar]).to eql(:baz)
24
+ end
25
+ end
26
+
27
+ describe 'dup' do
28
+ let(:world) do
29
+ World.new(foo: :bar)
30
+ end
31
+
32
+ subject do
33
+ world.dup
34
+ end
35
+
36
+ it 'returns another instance' do
37
+ expect(subject).to be_a(World)
38
+ expect(subject).not_to be(world)
39
+ end
40
+
41
+ it 'keeps variables' do
42
+ expect(subject.foo).to eql(:bar)
43
+ end
44
+ end
45
+
46
+ describe 'class factory' do
47
+ subject do
48
+ world.factory(:foo) do
49
+ hello
50
+ end
51
+ end
52
+
53
+ def hello
54
+ OpenStruct.new(bar: 12)
55
+ end
56
+
57
+ it 'returns a world instance' do
58
+ expect(subject).to be_a(World)
59
+ expect(subject).not_to be(world)
60
+ end
61
+
62
+ it 'installs the factory' do
63
+ bound = subject.with_scope(self)
64
+ got = bound.foo
65
+ expect(got).to be_a(OpenStruct)
66
+ expect(got.bar).to eql(12)
67
+ expect(bound.foo).to be(got)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -50,8 +50,11 @@ module Startback
50
50
  end
51
51
 
52
52
  it 'accepts an explicit context as second argument' do
53
- evt = Event.json(JSON_SRC, 12)
54
- expect(evt.context).to eql(12)
53
+ c = SubContext.new.tap{|x| x.foo = 'hello' }
54
+ evt = Event.json(JSON_SRC, c)
55
+ expect(evt.context).not_to be(c)
56
+ expect(evt.context).to be_a(SubContext)
57
+ expect(evt.context.foo).to eql('hello')
55
58
  end
56
59
  end
57
60
 
data/tasks/test.rake CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'rspec/core/rake_task'
2
+ require 'path'
2
3
 
3
4
  namespace :test do
4
5
 
@@ -16,6 +17,21 @@ namespace :test do
16
17
  end
17
18
  end
18
19
 
19
- task :all => [:unit, :example]
20
+ contribs = (Path.dir.parent/"contrib").glob("*").map do |sub|
21
+ next unless sub.directory?
22
+ name = sub.basename.to_sym
23
+
24
+ desc "Run tests for #{sub}"
25
+ task name do
26
+ Bundler.with_original_env do
27
+ system("cd #{sub} && bundle exec rake")
28
+ abort("#{sub} tests failed") unless $?.exitstatus == 0
29
+ end
30
+ end
31
+
32
+ name
33
+ end
34
+
35
+ task :all => [:unit, :example] + contribs
20
36
  end
21
37
  task :test => :'test:all'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: startback
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-19 00:00:00.000000000 Z
11
+ date: 2022-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -270,20 +270,20 @@ dependencies:
270
270
  requirements:
271
271
  - - ">="
272
272
  - !ruby/object:Gem::Version
273
- version: 0.19.0
273
+ version: 0.20.0
274
274
  - - "<"
275
275
  - !ruby/object:Gem::Version
276
- version: 0.20.0
276
+ version: 0.21.0
277
277
  type: :runtime
278
278
  prerelease: false
279
279
  version_requirements: !ruby/object:Gem::Requirement
280
280
  requirements:
281
281
  - - ">="
282
282
  - !ruby/object:Gem::Version
283
- version: 0.19.0
283
+ version: 0.20.0
284
284
  - - "<"
285
285
  - !ruby/object:Gem::Version
286
- version: 0.20.0
286
+ version: 0.21.0
287
287
  - !ruby/object:Gem::Dependency
288
288
  name: tzinfo
289
289
  requirement: !ruby/object:Gem::Requirement
@@ -389,6 +389,7 @@ files:
389
389
  - lib/startback/caching/no_store.rb
390
390
  - lib/startback/caching/store.rb
391
391
  - lib/startback/context.rb
392
+ - lib/startback/context/h_factory.rb
392
393
  - lib/startback/context/middleware.rb
393
394
  - lib/startback/errors.rb
394
395
  - lib/startback/event.rb
@@ -405,10 +406,13 @@ files:
405
406
  - lib/startback/ext.rb
406
407
  - lib/startback/ext/date_time.rb
407
408
  - lib/startback/ext/time.rb
409
+ - lib/startback/model.rb
408
410
  - lib/startback/operation.rb
409
411
  - lib/startback/operation/error_operation.rb
410
412
  - lib/startback/operation/multi_operation.rb
413
+ - lib/startback/services.rb
411
414
  - lib/startback/support.rb
415
+ - lib/startback/support/data_object.rb
412
416
  - lib/startback/support/env.rb
413
417
  - lib/startback/support/fake_logger.rb
414
418
  - lib/startback/support/hooks.rb
@@ -418,6 +422,7 @@ files:
418
422
  - lib/startback/support/robustness.rb
419
423
  - lib/startback/support/transaction_manager.rb
420
424
  - lib/startback/support/transaction_policy.rb
425
+ - lib/startback/support/world.rb
421
426
  - lib/startback/version.rb
422
427
  - lib/startback/web/api.rb
423
428
  - lib/startback/web/auto_caching.rb
@@ -436,17 +441,22 @@ files:
436
441
  - spec/unit/caching/test_entity_cache.rb
437
442
  - spec/unit/context/test_abstraction_factory.rb
438
443
  - spec/unit/context/test_dup.rb
444
+ - spec/unit/context/test_fork.rb
439
445
  - spec/unit/context/test_h_factory.rb
440
446
  - spec/unit/context/test_middleware.rb
447
+ - spec/unit/context/test_with_world.rb
448
+ - spec/unit/context/test_world.rb
441
449
  - spec/unit/event/bus/memory/test_async.rb
442
450
  - spec/unit/event/bus/memory/test_sync.rb
443
451
  - spec/unit/support/hooks/test_after_hook.rb
444
452
  - spec/unit/support/hooks/test_before_hook.rb
445
453
  - spec/unit/support/operation_runner/test_around_run.rb
446
454
  - spec/unit/support/operation_runner/test_before_after_call.rb
455
+ - spec/unit/support/test_data_object.rb
447
456
  - spec/unit/support/test_env.rb
448
457
  - spec/unit/support/test_robusteness.rb
449
458
  - spec/unit/support/test_transaction_manager.rb
459
+ - spec/unit/support/test_world.rb
450
460
  - spec/unit/test_event.rb
451
461
  - spec/unit/test_operation.rb
452
462
  - spec/unit/test_support.rb