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 +4 -4
- data/lib/startback/context/h_factory.rb +43 -0
- data/lib/startback/context.rb +32 -34
- data/lib/startback/event/agent.rb +13 -2
- data/lib/startback/event/engine.rb +1 -1
- data/lib/startback/event.rb +3 -0
- data/lib/startback/model.rb +6 -0
- data/lib/startback/operation.rb +5 -0
- data/lib/startback/services.rb +11 -0
- data/lib/startback/support/data_object.rb +71 -0
- data/lib/startback/support/world.rb +54 -0
- data/lib/startback/support.rb +2 -0
- data/lib/startback/version.rb +2 -2
- data/lib/startback.rb +2 -0
- data/spec/spec_helper.rb +33 -1
- data/spec/unit/context/test_dup.rb +3 -7
- data/spec/unit/context/test_fork.rb +37 -0
- data/spec/unit/context/test_h_factory.rb +0 -20
- data/spec/unit/context/test_with_world.rb +20 -0
- data/spec/unit/context/test_world.rb +17 -0
- data/spec/unit/support/test_data_object.rb +156 -0
- data/spec/unit/support/test_world.rb +72 -0
- data/spec/unit/test_event.rb +5 -2
- data/tasks/test.rake +17 -1
- metadata +16 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b7ccc8dd2081ba0dffda6092a2dbb2a345b01e6b7231aee41aa506e85949a4a
|
4
|
+
data.tar.gz: c53f396f235226bbbfd336c872a5e1334708e1dcc6ca62d456d7b969bf7baad2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/startback/context.rb
CHANGED
@@ -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
|
-
|
52
|
-
|
52
|
+
require_relative 'context/h_factory'
|
53
|
+
extend(Context::HFactory)
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
70
|
-
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
83
|
-
|
84
|
-
|
73
|
+
def world
|
74
|
+
@_world ||= self.class.factor_world(self)
|
75
|
+
end
|
85
76
|
|
86
|
-
|
87
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/startback/event.rb
CHANGED
@@ -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
|
|
data/lib/startback/operation.rb
CHANGED
@@ -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
|
data/lib/startback/support.rb
CHANGED
data/lib/startback/version.rb
CHANGED
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
|
-
|
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(
|
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
|
data/spec/unit/test_event.rb
CHANGED
@@ -50,8 +50,11 @@ module Startback
|
|
50
50
|
end
|
51
51
|
|
52
52
|
it 'accepts an explicit context as second argument' do
|
53
|
-
|
54
|
-
|
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
|
-
|
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.
|
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-
|
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.
|
273
|
+
version: 0.20.0
|
274
274
|
- - "<"
|
275
275
|
- !ruby/object:Gem::Version
|
276
|
-
version: 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.
|
283
|
+
version: 0.20.0
|
284
284
|
- - "<"
|
285
285
|
- !ruby/object:Gem::Version
|
286
|
-
version: 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
|