tzu 0.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/LICENSE.txt +20 -0
- data/README.md +1 -0
- data/lib/tzu.rb +88 -0
- data/lib/tzu/failure.rb +10 -0
- data/lib/tzu/hooks.rb +57 -0
- data/lib/tzu/invalid.rb +9 -0
- data/lib/tzu/match.rb +55 -0
- data/lib/tzu/organizer.rb +35 -0
- data/lib/tzu/outcome.rb +28 -0
- data/lib/tzu/validation.rb +43 -0
- data/lib/tzu/validation_result.rb +13 -0
- data/spec/command_spec.rb +39 -0
- data/spec/hooks_spec.rb +169 -0
- data/spec/organizer_spec.rb +48 -0
- data/spec/outcome_spec.rb +48 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/tzu_spec.rb +354 -0
- data/spec/validation_spec.rb +44 -0
- metadata +154 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b809317c8b5ff13fcb4784360d28703691ea3d9d
|
4
|
+
data.tar.gz: 141562074c39e1d23fc945f2d6d7bf825eb37c6c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1b231785af2e5ca4fab9e1a8590676875f87796592050391f9e32a2358e70878e31cc85c42b5c383c2fb484ab00afc7abb549c15a56a5f0b29fa0dccd3f96878
|
7
|
+
data.tar.gz: bff733337e18acb528bd37978f3034f67e788225b23b487c878f60d00bca8c0ef95b07c362ec5166024b633b102f968d1c0418451b7ab13a4accee6911d4ff93
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2015 Blake Turner
|
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 @@
|
|
1
|
+
# Tzu
|
data/lib/tzu.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'tzu/failure'
|
2
|
+
require 'tzu/hooks'
|
3
|
+
require 'tzu/invalid'
|
4
|
+
require 'tzu/match'
|
5
|
+
require 'tzu/organizer'
|
6
|
+
require 'tzu/outcome'
|
7
|
+
require 'tzu/validation'
|
8
|
+
require 'tzu/validation_result'
|
9
|
+
|
10
|
+
module Tzu
|
11
|
+
def self.included(base)
|
12
|
+
base.class_eval do
|
13
|
+
extend ClassMethods
|
14
|
+
include Hooks
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def run(params, *context, &block)
|
20
|
+
result = get_instance(*context).run(params)
|
21
|
+
if block
|
22
|
+
result.handle(&block)
|
23
|
+
else
|
24
|
+
result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def run!(params, *context)
|
29
|
+
get_instance(*context).run!(params)
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_instance(*context)
|
33
|
+
method = respond_to?(:build) ? :build : :new
|
34
|
+
send(method, *context)
|
35
|
+
end
|
36
|
+
|
37
|
+
def command_name(value = nil)
|
38
|
+
if value.nil?
|
39
|
+
@name ||= name.underscore.to_sym
|
40
|
+
else
|
41
|
+
@name = (value.presence && value.to_sym)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def command_name
|
47
|
+
self.class.command_name
|
48
|
+
end
|
49
|
+
|
50
|
+
def run(params)
|
51
|
+
run!(request_object(params))
|
52
|
+
rescue Failure => f
|
53
|
+
Outcome.new(false, f.errors, f.type)
|
54
|
+
end
|
55
|
+
|
56
|
+
def run!(params)
|
57
|
+
with_hooks(params) do |p|
|
58
|
+
outcome = call(p)
|
59
|
+
outcome.is_a?(Tzu::Outcome) ? outcome : Outcome.new(true, outcome)
|
60
|
+
end
|
61
|
+
rescue
|
62
|
+
rollback! if self.respond_to?(:rollback!)
|
63
|
+
raise
|
64
|
+
end
|
65
|
+
|
66
|
+
def fail!(type, data={})
|
67
|
+
raise Failure.new(type, data)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def request_object(params)
|
73
|
+
klass = request_class
|
74
|
+
return klass.new(params) if klass && !params.is_a?(klass)
|
75
|
+
params
|
76
|
+
end
|
77
|
+
|
78
|
+
# Get the name of a request class related to calling class
|
79
|
+
# ie. Tzus::MyNameSpace::MyTzu
|
80
|
+
# has Tzus::MyNameSpace::Requests::MyTzu
|
81
|
+
def request_class
|
82
|
+
namespace = self.class.name.deconstantize.constantize
|
83
|
+
request_object_name = "Requests::#{ self.class.name.demodulize}"
|
84
|
+
namespace.qualified_const_get(request_object_name)
|
85
|
+
rescue NameError
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
data/lib/tzu/failure.rb
ADDED
data/lib/tzu/hooks.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Tzu
|
2
|
+
|
3
|
+
# Provides hooks for arbitrary pre- and post- processing within a command
|
4
|
+
module Hooks
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
extend ClassMethods
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def before(*hooks, &block)
|
13
|
+
hooks << block if block
|
14
|
+
hooks.each { |hook| before_hooks.push(hook) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def after(*hooks, &block)
|
18
|
+
hooks << block if block
|
19
|
+
hooks.each { |hook| after_hooks.push(hook) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def before_hooks
|
23
|
+
@before_hooks ||= []
|
24
|
+
end
|
25
|
+
|
26
|
+
def after_hooks
|
27
|
+
@after_hooks ||= []
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def with_hooks(params, &block)
|
32
|
+
run_before_hooks(params)
|
33
|
+
result = block.call(params)
|
34
|
+
run_after_hooks(params)
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def run_before_hooks(params)
|
41
|
+
run_hooks(self.class.before_hooks, params)
|
42
|
+
end
|
43
|
+
|
44
|
+
def run_after_hooks(params)
|
45
|
+
run_hooks(self.class.after_hooks, params)
|
46
|
+
end
|
47
|
+
|
48
|
+
def run_hooks(hooks, params)
|
49
|
+
hooks.each { |hook| run_hook(hook, params) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def run_hook(hook, args)
|
53
|
+
hook.is_a?(Symbol) ? send(hook, args) : instance_exec(args, &hook)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
data/lib/tzu/invalid.rb
ADDED
data/lib/tzu/match.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Tzu
|
2
|
+
|
3
|
+
# with thanks to https://github.com/pzol/deterministic
|
4
|
+
class Match
|
5
|
+
def initialize(outcome, context)
|
6
|
+
@outcome, @context, @collection = outcome, context, []
|
7
|
+
end
|
8
|
+
|
9
|
+
def result
|
10
|
+
matcher = @collection.detect { |m| m.matches?(@outcome.type) }
|
11
|
+
raise "No match could be made for #{@outcome}" if matcher.nil?
|
12
|
+
@context.instance_exec(@outcome.result, &matcher.block)
|
13
|
+
end
|
14
|
+
|
15
|
+
%w(success failure).each do |type|
|
16
|
+
define_method type.to_sym do |condition=nil, &result_block|
|
17
|
+
push(type, condition, result_block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# todo: hash and define_method if more overrides identified
|
22
|
+
def invalid(&result_block)
|
23
|
+
push('failure', :validation, result_block)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
Matcher = Struct.new(:condition, :block) do
|
29
|
+
def matches?(value)
|
30
|
+
condition.call(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def push(type, condition, result_block)
|
35
|
+
condition_pred = case
|
36
|
+
when condition.nil?; ->(v) { true }
|
37
|
+
when condition.is_a?(Proc); condition
|
38
|
+
when condition.is_a?(Class); ->(v) { condition === @outcome.type }
|
39
|
+
else ->(v) { @outcome.type == condition }
|
40
|
+
end
|
41
|
+
|
42
|
+
matcher_pred = compose_predicates(type_pred[type], condition_pred)
|
43
|
+
@collection << Matcher.new(matcher_pred, result_block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def compose_predicates(f, g)
|
47
|
+
->(*args) { f[*args] && g[*args] }
|
48
|
+
end
|
49
|
+
|
50
|
+
# return a partial function for matching a matcher's type
|
51
|
+
def type_pred
|
52
|
+
(->(type, x) { @outcome.send("#{type.to_s}?") }).curry
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Tzu
|
4
|
+
module Organizer
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
include Tzu
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Step = Struct.new(:command, :transform)
|
12
|
+
|
13
|
+
def steps
|
14
|
+
@steps ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_step(command, &transform)
|
18
|
+
steps << Step.new(command, transform)
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(params)
|
22
|
+
result = call_steps(params)
|
23
|
+
self.respond_to?(:parse) ? parse(result) : result
|
24
|
+
end
|
25
|
+
|
26
|
+
def call_steps(params)
|
27
|
+
result = ::OpenStruct.new
|
28
|
+
steps.each do |step|
|
29
|
+
call_with = step.transform ? step.transform(params, result) : params
|
30
|
+
result[step.command.command_name] = step.command.run!(call_with)
|
31
|
+
end
|
32
|
+
result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/tzu/outcome.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Tzu
|
2
|
+
|
3
|
+
# The result of executing a command
|
4
|
+
class Outcome
|
5
|
+
attr_reader :success, :result, :type
|
6
|
+
|
7
|
+
def initialize(success, result, type = nil)
|
8
|
+
@success = success
|
9
|
+
@result = result
|
10
|
+
@type = type
|
11
|
+
end
|
12
|
+
|
13
|
+
def success?
|
14
|
+
@success
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure?
|
18
|
+
!@success
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle(context=nil, &block)
|
22
|
+
context ||= block.binding.eval('self')
|
23
|
+
match = Match.new(self, context)
|
24
|
+
match.instance_eval &block
|
25
|
+
match.result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Tzu
|
2
|
+
module Validation
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
# registers validation as a before hook
|
7
|
+
before :when_valid
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def when_valid(params)
|
12
|
+
validation_result = validate(params)
|
13
|
+
invalid!(validation_result.errors) unless validation_result.valid?
|
14
|
+
validation_result
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate(params)
|
18
|
+
# see if the command defines a valid? method
|
19
|
+
if self.respond_to?(:valid?)
|
20
|
+
result = valid?(params)
|
21
|
+
errors = self.respond_to?(:errors) ? self.errors : nil
|
22
|
+
return !!result == result ? ValidationResult.new(result, errors) : result
|
23
|
+
end
|
24
|
+
|
25
|
+
# do the params define their own validation method (cf. ActiveRecord)
|
26
|
+
if params.respond_to?(:valid?)
|
27
|
+
return ValidationResult.new(params.valid?, params.errors)
|
28
|
+
end
|
29
|
+
|
30
|
+
# otherwise valid
|
31
|
+
return ValidationResult.new(true)
|
32
|
+
end
|
33
|
+
|
34
|
+
def invalid!(obj)
|
35
|
+
output = [:errors, :messages].reduce(obj) do |result, m|
|
36
|
+
result = result.respond_to?(m) ? result.send(m) : result
|
37
|
+
end
|
38
|
+
|
39
|
+
raise Invalid.new(output)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tzu do
|
4
|
+
|
5
|
+
context 'command fails' do
|
6
|
+
subject do
|
7
|
+
Class.new do
|
8
|
+
include Tzu
|
9
|
+
|
10
|
+
def call(params)
|
11
|
+
fail! :something
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns failure' do
|
17
|
+
result = subject.run(nil)
|
18
|
+
expect(result).to have_attributes(success: false, type: :something)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'command succeeds' do
|
23
|
+
subject do
|
24
|
+
Class.new do
|
25
|
+
include Tzu
|
26
|
+
|
27
|
+
def call(params)
|
28
|
+
1234
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns result' do
|
34
|
+
result = subject.run(nil)
|
35
|
+
expect(result).to have_attributes(success: true, result: 1234)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/spec/hooks_spec.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tzu::Hooks do
|
4
|
+
describe '#with_hooks' do
|
5
|
+
def build_hooked(&block)
|
6
|
+
hooked = Class.new.send(:include, Tzu::Hooks)
|
7
|
+
|
8
|
+
hooked.class_eval do
|
9
|
+
attr_reader :steps
|
10
|
+
|
11
|
+
def self.process
|
12
|
+
new.tap(&:process).steps
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@steps = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def process
|
20
|
+
with_hooks({}) { steps << :process }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
hooked.class_eval(&block) if block
|
25
|
+
hooked
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when before hook is a method' do
|
29
|
+
let(:hooked) do
|
30
|
+
build_hooked do
|
31
|
+
before :add_before
|
32
|
+
|
33
|
+
def add_before(p)
|
34
|
+
steps << :before
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'runs the before hook method' do
|
40
|
+
expect(hooked.process).to eq([:before, :process])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when before hook is a block' do
|
45
|
+
let(:hooked) do
|
46
|
+
build_hooked do
|
47
|
+
before do
|
48
|
+
steps << :before
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'runs the before hook block' do
|
54
|
+
expect(hooked.process).to eq([:before, :process])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when after hook is a method' do
|
59
|
+
let(:hooked) do
|
60
|
+
build_hooked do
|
61
|
+
after :add_after
|
62
|
+
|
63
|
+
def add_after(p)
|
64
|
+
steps << :after
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'runs the after hook method' do
|
70
|
+
expect(hooked.process).to eq([:process, :after])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when after hook is a block' do
|
75
|
+
let(:hooked) do
|
76
|
+
build_hooked do
|
77
|
+
after do
|
78
|
+
steps << :after
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'runs the after hook block' do
|
84
|
+
expect(hooked.process).to eq([:process, :after])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'when both before and after blocks are defined' do
|
89
|
+
let(:hooked) do
|
90
|
+
build_hooked do
|
91
|
+
before do
|
92
|
+
steps << :before
|
93
|
+
end
|
94
|
+
|
95
|
+
after do
|
96
|
+
steps << :after
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'runs hooks in the expected order' do
|
102
|
+
expect(hooked.process).to eq([:before, :process, :after])
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
context 'when both before and after methods are defined' do
|
108
|
+
let(:hooked) do
|
109
|
+
build_hooked do
|
110
|
+
before :add_before
|
111
|
+
after :add_after
|
112
|
+
|
113
|
+
def add_before(p)
|
114
|
+
steps << :before
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_after(p)
|
118
|
+
steps << :after
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'runs hooks in the expected order' do
|
124
|
+
expect(hooked.process).to eq([:before, :process, :after])
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when multiple before methods are defined' do
|
129
|
+
let(:hooked) do
|
130
|
+
build_hooked do
|
131
|
+
before :add_before1, :add_before2
|
132
|
+
|
133
|
+
def add_before1(p)
|
134
|
+
steps << :before1
|
135
|
+
end
|
136
|
+
|
137
|
+
def add_before2(p)
|
138
|
+
steps << :before2
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'runs hooks in the expected order' do
|
144
|
+
expect(hooked.process).to eq([:before1, :before2, :process])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'when multiple after methods are defined' do
|
149
|
+
let(:hooked) do
|
150
|
+
build_hooked do
|
151
|
+
after :add_after1, :add_after2
|
152
|
+
|
153
|
+
def add_after1(p)
|
154
|
+
steps << :after1
|
155
|
+
end
|
156
|
+
|
157
|
+
def add_after2(p)
|
158
|
+
steps << :after2
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'runs hooks in the expected order' do
|
164
|
+
expect(hooked.process).to eq([:process, :after1, :after2])
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tzu::Organizer do
|
4
|
+
let(:params) { [1, 2, 3] }
|
5
|
+
let(:commands) { [spy(run!: :step1, command_name: :step1), spy(run!: :step2, command_name: :step2)] }
|
6
|
+
|
7
|
+
let(:organized) do
|
8
|
+
organized = Class.new do
|
9
|
+
include Tzu::Organizer
|
10
|
+
|
11
|
+
def initialize(commands)
|
12
|
+
commands.each { |s| add_step(s) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
organized
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when organizer is called' do
|
20
|
+
|
21
|
+
it 'calls each step' do
|
22
|
+
organized.run(params, commands)
|
23
|
+
commands.each { |s| expect(s).to have_received(:run!).with(params) }
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'collates result of steps' do
|
27
|
+
result = organized.run(params, commands)
|
28
|
+
expect(result.result.step1).to eq(:step1)
|
29
|
+
expect(result.result.step2).to eq(:step2)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when organizer defines parse' do
|
34
|
+
before do
|
35
|
+
organized.class_eval do
|
36
|
+
def parse(result)
|
37
|
+
12345
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'it parses results from commands' do
|
43
|
+
result = organized.run(params, commands)
|
44
|
+
expect(result).to have_attributes(success: true, result: 12345)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tzu::Outcome do
|
4
|
+
|
5
|
+
context 'outcome is failed with specified type' do
|
6
|
+
subject { Tzu::Outcome.new(false, 'abc', :validation) }
|
7
|
+
|
8
|
+
it 'calls appropriate handler' do
|
9
|
+
matched = false
|
10
|
+
subject.handle do
|
11
|
+
success { raise }
|
12
|
+
failure(:something) { raise }
|
13
|
+
failure(:validation) { matched = true }
|
14
|
+
end
|
15
|
+
expect(matched).to eq true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'outcome is failed with unspecified type' do
|
20
|
+
subject { Tzu::Outcome.new(false, 'abc', :validation) }
|
21
|
+
|
22
|
+
it 'calls appropriate handler' do
|
23
|
+
matched = false
|
24
|
+
subject.handle do
|
25
|
+
success { raise }
|
26
|
+
failure { matched = true }
|
27
|
+
failure(:validation) { raise }
|
28
|
+
end
|
29
|
+
expect(matched).to eq true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'outcome is successful' do
|
34
|
+
subject { Tzu::Outcome.new(true, 'abc') }
|
35
|
+
|
36
|
+
it 'calls success handler' do
|
37
|
+
matched = false
|
38
|
+
subject.handle do
|
39
|
+
success { matched = true }
|
40
|
+
failure(:something) { raise }
|
41
|
+
end
|
42
|
+
expect(matched).to eq true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
data/spec/spec_helper.rb
ADDED
data/spec/tzu_spec.rb
ADDED
@@ -0,0 +1,354 @@
|
|
1
|
+
# require 'spec_helper'
|
2
|
+
#
|
3
|
+
# if !defined?(ActiveRecord::Base)
|
4
|
+
# puts "** require 'active_record' to run the specs in #{__FILE__}"
|
5
|
+
# else
|
6
|
+
# ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
7
|
+
#
|
8
|
+
# ActiveRecord::Migration.suppress_messages do
|
9
|
+
# ActiveRecord::Schema.define(:version => 0) do
|
10
|
+
# create_table(:employers, force: true) {|t| t.string :name }
|
11
|
+
# create_table(:users, force: true) {|t| t.string :first_name; t.string :last_name; t.references :employer; }
|
12
|
+
# create_table(:sports_cars, force: true) {|t| t.string :make; t.references :employer; }
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# module GetSpec
|
17
|
+
# class Employer < ActiveRecord::Base
|
18
|
+
# has_many :users
|
19
|
+
# has_many :sports_cars
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# class User < ActiveRecord::Base
|
23
|
+
# belongs_to :employer
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# class SportsCar < ActiveRecord::Base
|
27
|
+
# belongs_to :employer
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# describe Get do
|
33
|
+
# let(:last_name) { 'Turner' }
|
34
|
+
# let(:adapter) { :active_record }
|
35
|
+
#
|
36
|
+
# # Preserve system config for other tests
|
37
|
+
# before(:all) { @system_config = Get.configuration }
|
38
|
+
# after(:all) { Get.configuration = @system_config }
|
39
|
+
#
|
40
|
+
# # Reset base config with each iteration
|
41
|
+
# before { Get.configure { |config| config.set_adapter(adapter) } }
|
42
|
+
# after do
|
43
|
+
# GetSpec::User.delete_all
|
44
|
+
# GetSpec::Employer.delete_all
|
45
|
+
# Get.reset
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# class MyCustomEntity < Horza::Entities::Collection
|
49
|
+
# def east_london_length
|
50
|
+
# "#{length}, bruv"
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# describe '#configure' do
|
55
|
+
# context '#register_entity' do
|
56
|
+
# let(:user_count) { 3 }
|
57
|
+
#
|
58
|
+
# before do
|
59
|
+
# Get.configure { |config| config.register_entity(:users_by_last_name, MyCustomEntity) }
|
60
|
+
# user_count.times { GetSpec::User.create(last_name: last_name) }
|
61
|
+
# end
|
62
|
+
# after { Get.reset }
|
63
|
+
#
|
64
|
+
# it 'gets registers entity' do
|
65
|
+
# expect(Get.configuration.entity_for(:users_by_last_name)).to eq MyCustomEntity
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# it 'returns specified entity type after querying db' do
|
69
|
+
# result = Get::UsersByLastName.run(last_name)
|
70
|
+
# expect(result.is_a? MyCustomEntity).to be true
|
71
|
+
# expect(result.east_london_length).to eq "#{user_count}, bruv"
|
72
|
+
# end
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# context '#entity_for' do
|
77
|
+
# context 'when entity has been registered' do
|
78
|
+
# before do
|
79
|
+
# Get.configure do |config|
|
80
|
+
# config.set_adapter(adapter)
|
81
|
+
# config.register_entity(:users_by_last_name, MyCustomEntity)
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# after { Get.reset }
|
85
|
+
#
|
86
|
+
# it 'registers entity' do
|
87
|
+
# expect(Get.entity_for(:users_by_last_name)).to eq MyCustomEntity
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# context 'when entity has not been registered' do
|
92
|
+
# it 'returns nil' do
|
93
|
+
# expect(Get.entity_for(:users_by_last_name)).to be nil
|
94
|
+
# end
|
95
|
+
# end
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# context '#adapter' do
|
99
|
+
# context 'when the adapter is set' do
|
100
|
+
# it 'returns the correct adapter class' do
|
101
|
+
# expect(Get.adapter).to eq Horza::Adapters::ActiveRecord
|
102
|
+
# end
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# context 'when the adapter is not set' do
|
106
|
+
# before { Get.reset }
|
107
|
+
# after { Get.reset }
|
108
|
+
#
|
109
|
+
# it 'throws error' do
|
110
|
+
# expect { Get.adapter }.to raise_error(Get::Errors::Base)
|
111
|
+
# end
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# context '#reset' do
|
116
|
+
# before do
|
117
|
+
# Get.configure do |config|
|
118
|
+
# config.set_adapter('my_adapter')
|
119
|
+
# config.register_entity(:users_by_last_name, MyCustomEntity)
|
120
|
+
# end
|
121
|
+
# Get.reset
|
122
|
+
# end
|
123
|
+
# it 'resets the config' do
|
124
|
+
# expect(Get.configuration.adapter).to be nil
|
125
|
+
# expect(Get.entity_for(:users_by_last_name)).to be nil
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
# context '#run!' do
|
130
|
+
# context 'singular form' do
|
131
|
+
# context 'when the record exists' do
|
132
|
+
# let!(:user) { GetSpec::User.create(last_name: last_name) }
|
133
|
+
#
|
134
|
+
# context 'field in class name' do
|
135
|
+
# it 'gets the records based on By[KEY]' do
|
136
|
+
# result = Get::UserById.run!(user.id)
|
137
|
+
# expect(result.to_h).to eq user.attributes
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# it 'returns a dynamically generated response entity' do
|
141
|
+
# expect(Get::UserById.run!(user.id).is_a?(Horza::Entities::Single)).to be true
|
142
|
+
# end
|
143
|
+
# end
|
144
|
+
#
|
145
|
+
# context 'field in parameters' do
|
146
|
+
# it 'gets the records based on parameters' do
|
147
|
+
# result = Get::UserBy.run!(last_name: last_name)
|
148
|
+
# expect(result.to_h).to eq user.attributes
|
149
|
+
# end
|
150
|
+
#
|
151
|
+
# it 'returns a dynamically generated response entity' do
|
152
|
+
# expect(Get::UserBy.run!(last_name: last_name).is_a?(Horza::Entities::Single)).to be true
|
153
|
+
# end
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# context 'when the record does not exist' do
|
158
|
+
# it 'returns nil' do
|
159
|
+
# expect { Get::UserById.run!(999) }.to raise_error Get::Errors::Base
|
160
|
+
# end
|
161
|
+
# end
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# context 'ancestry' do
|
165
|
+
# context 'valid ancestry with no saved parent' do
|
166
|
+
# let(:user2) { GetSpec::User.create }
|
167
|
+
# it 'returns nil' do
|
168
|
+
# expect { Get::EmployerFromUser.run!(user2) }.to raise_error Get::Errors::RecordNotFound
|
169
|
+
# end
|
170
|
+
# end
|
171
|
+
# end
|
172
|
+
# end
|
173
|
+
#
|
174
|
+
# context '#run' do
|
175
|
+
# context 'singular form' do
|
176
|
+
# context 'when the record exists' do
|
177
|
+
# let!(:user) { GetSpec::User.create(last_name: last_name) }
|
178
|
+
#
|
179
|
+
# context 'field in class name' do
|
180
|
+
# it 'gets the records based on By[KEY]' do
|
181
|
+
# result = Get::UserById.run(user.id)
|
182
|
+
# expect(result.to_h).to eq user.attributes
|
183
|
+
# end
|
184
|
+
#
|
185
|
+
# it 'returns a dynamically generated response entity' do
|
186
|
+
# expect(Get::UserById.run(user.id).is_a?(Horza::Entities::Single)).to be true
|
187
|
+
# end
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# context 'field in parameters' do
|
191
|
+
# it 'gets the records based on parameters' do
|
192
|
+
# result = Get::UserBy.run(last_name: last_name)
|
193
|
+
# expect(result.to_h).to eq user.attributes
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
# it 'returns a dynamically generated response entity' do
|
197
|
+
# expect(Get::UserBy.run(last_name: last_name).is_a?(Horza::Entities::Single)).to be true
|
198
|
+
# end
|
199
|
+
# end
|
200
|
+
# end
|
201
|
+
#
|
202
|
+
# context 'when the record does not exist' do
|
203
|
+
# it 'returns nil' do
|
204
|
+
# expect(Get::UserById.run(999)).to eq nil
|
205
|
+
# end
|
206
|
+
# end
|
207
|
+
# end
|
208
|
+
#
|
209
|
+
# context 'plural form' do
|
210
|
+
# let(:last_name) { 'Turner' }
|
211
|
+
# let(:match_count) { 3 }
|
212
|
+
# let(:miss_count) { 2 }
|
213
|
+
#
|
214
|
+
# context 'when records exist' do
|
215
|
+
# before do
|
216
|
+
# match_count.times { GetSpec::User.create(last_name: last_name) }
|
217
|
+
# miss_count.times { GetSpec::User.create }
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# context 'field in class name' do
|
221
|
+
# it 'gets the records based on By[KEY]' do
|
222
|
+
# result = Get::UsersByLastName.run(last_name)
|
223
|
+
# expect(result.length).to eq match_count
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# it 'returns a dynamically generated response entity' do
|
227
|
+
# expect(Get::UsersByLastName.run(last_name).is_a?(Horza::Entities::Collection)).to be true
|
228
|
+
# end
|
229
|
+
# end
|
230
|
+
#
|
231
|
+
# context 'field in parameters' do
|
232
|
+
# it 'gets the records based on parameters' do
|
233
|
+
# result = Get::UsersBy.run(last_name: last_name)
|
234
|
+
# expect(result.length).to eq match_count
|
235
|
+
# end
|
236
|
+
#
|
237
|
+
# it 'returns a dynamically generated response entity' do
|
238
|
+
# expect(Get::UsersBy.run(last_name: last_name).is_a?(Horza::Entities::Collection)).to be true
|
239
|
+
# end
|
240
|
+
# end
|
241
|
+
# end
|
242
|
+
#
|
243
|
+
# context 'when no records exist' do
|
244
|
+
# it 'returns empty collection' do
|
245
|
+
# expect(Get::UsersBy.run(last_name: last_name).empty?).to be true
|
246
|
+
# end
|
247
|
+
# end
|
248
|
+
# end
|
249
|
+
#
|
250
|
+
# context 'ancestry' do
|
251
|
+
# context 'direct relation' do
|
252
|
+
# let(:employer) { GetSpec::Employer.create }
|
253
|
+
# let!(:user1) { GetSpec::User.create(employer: employer) }
|
254
|
+
# let!(:user2) { GetSpec::User.create(employer: employer) }
|
255
|
+
#
|
256
|
+
# context 'ParentFromChild' do
|
257
|
+
# it 'returns parent' do
|
258
|
+
# expect(Get::EmployerFromUser.run(user1).to_h).to eq employer.attributes
|
259
|
+
# end
|
260
|
+
# end
|
261
|
+
#
|
262
|
+
# context 'ChildrenFromParent' do
|
263
|
+
# it 'returns children' do
|
264
|
+
# result = Get::UsersFromEmployer.run(employer)
|
265
|
+
# expect(result.first.to_h).to eq user1.attributes
|
266
|
+
# expect(result.last.to_h).to eq user2.attributes
|
267
|
+
# end
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# context 'invalid ancestry' do
|
271
|
+
# it 'throws error' do
|
272
|
+
# expect { Get::UserFromEmployer.run(employer) }.to raise_error Get::Errors::InvalidAncestry
|
273
|
+
# end
|
274
|
+
# end
|
275
|
+
#
|
276
|
+
# context 'valid ancestry with no saved childred' do
|
277
|
+
# let(:employer2) { GetSpec::Employer.create }
|
278
|
+
# it 'returns empty collection error' do
|
279
|
+
# expect(Get::UsersFromEmployer.run(employer2).empty?).to be true
|
280
|
+
# end
|
281
|
+
# end
|
282
|
+
#
|
283
|
+
# context 'valid ancestry with no saved parent' do
|
284
|
+
# let(:user2) { GetSpec::User.create }
|
285
|
+
# it 'returns nil' do
|
286
|
+
# expect(Get::EmployerFromUser.run(user2)).to be nil
|
287
|
+
# end
|
288
|
+
# end
|
289
|
+
# end
|
290
|
+
#
|
291
|
+
# context 'using via' do
|
292
|
+
# let(:employer) { GetSpec::Employer.create }
|
293
|
+
# let(:user) { GetSpec::User.create(employer: employer) }
|
294
|
+
# let(:sportscar) { GetSpec::SportsCar.create(employer: employer) }
|
295
|
+
#
|
296
|
+
# before do
|
297
|
+
# employer.sports_cars << sportscar
|
298
|
+
# end
|
299
|
+
#
|
300
|
+
# it 'returns the correct ancestor (single via symbol)' do
|
301
|
+
# result = Get::SportsCarsFromUser.run(user, via: :employer)
|
302
|
+
# expect(result.first.to_h).to eq sportscar.attributes
|
303
|
+
# end
|
304
|
+
#
|
305
|
+
# it 'returns the correct ancestor (array of via symbols)' do
|
306
|
+
# result = Get::SportsCarsFromUser.run(user, via: [:employer])
|
307
|
+
# expect(result.first.to_h).to eq sportscar.attributes
|
308
|
+
# end
|
309
|
+
# end
|
310
|
+
# end
|
311
|
+
# end
|
312
|
+
# end
|
313
|
+
#
|
314
|
+
# describe Get::Builders::AncestryBuilder do
|
315
|
+
# let(:name) { 'UserFromEmployer' }
|
316
|
+
#
|
317
|
+
# before { Get.configure { |config| config.set_adapter(:active_record) } }
|
318
|
+
# after { Get.reset }
|
319
|
+
#
|
320
|
+
# subject { Get::Builders::AncestryBuilder.new(name) }
|
321
|
+
#
|
322
|
+
# describe '#class' do
|
323
|
+
# it 'builds a class that inherits from Get::Db' do
|
324
|
+
# expect(subject.class.superclass).to eq Get::Db
|
325
|
+
# end
|
326
|
+
#
|
327
|
+
# it 'correctly assigns class-level variables' do
|
328
|
+
# [:entity, :query_key, :collection, :store, :result_key].each do |class_var|
|
329
|
+
# expect(subject.class.respond_to? class_var).to be true
|
330
|
+
# end
|
331
|
+
# end
|
332
|
+
# end
|
333
|
+
# end
|
334
|
+
#
|
335
|
+
# describe Get::Builders::QueryBuilder do
|
336
|
+
# let(:name) { 'UserFromEmployer' }
|
337
|
+
#
|
338
|
+
# before { Get.configure { |config| config.set_adapter(:active_record) } }
|
339
|
+
# after { Get.reset }
|
340
|
+
#
|
341
|
+
# subject { Get::Builders::QueryBuilder.new(name) }
|
342
|
+
#
|
343
|
+
# describe '#class' do
|
344
|
+
# it 'builds a class that inherits from Get::Db' do
|
345
|
+
# expect(subject.class.superclass).to eq Get::Db
|
346
|
+
# end
|
347
|
+
#
|
348
|
+
# it 'correctly assigns class-level variables' do
|
349
|
+
# [:entity, :query_key, :collection, :store, :field].each do |class_var|
|
350
|
+
# expect(subject.class.respond_to? class_var).to be true
|
351
|
+
# end
|
352
|
+
# end
|
353
|
+
# end
|
354
|
+
# end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tzu::Validation do
|
4
|
+
|
5
|
+
context 'params define valid? method' do
|
6
|
+
subject do
|
7
|
+
Class.new do
|
8
|
+
include Tzu
|
9
|
+
include Tzu::Validation
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:errors) { [1, 2, 3] }
|
14
|
+
let(:params) { spy(errors: errors, valid?: false) }
|
15
|
+
|
16
|
+
it 'valid? method is called' do
|
17
|
+
subject.run(params)
|
18
|
+
expect(params).to have_received(:valid?)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'returns validation result' do
|
22
|
+
result = subject.run(params)
|
23
|
+
expect(result).to have_attributes(success: false, type: :validation, result: errors)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'command defines valid? method' do
|
28
|
+
subject do
|
29
|
+
Class.new do
|
30
|
+
include Tzu
|
31
|
+
include Tzu::Validation
|
32
|
+
|
33
|
+
def valid?(params)
|
34
|
+
Tzu::ValidationResult.new(false, [])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'returns validation result' do
|
40
|
+
result = subject.run(nil)
|
41
|
+
expect(result).to have_attributes(success: false, type: :validation)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tzu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Morgan Bruce
|
8
|
+
- Blake Turner
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-05-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 1.0.0
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 1.0.0
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: activerecord
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 3.2.15
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 3.2.15
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: activesupport
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 3.2.15
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 3.2.15
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.4.0
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.4.0
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: sqlite3
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: byebug
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
description: Tzu is a library for issuing commands in Ruby
|
99
|
+
email: morgan@onfido.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- lib/tzu.rb
|
107
|
+
- lib/tzu/failure.rb
|
108
|
+
- lib/tzu/hooks.rb
|
109
|
+
- lib/tzu/invalid.rb
|
110
|
+
- lib/tzu/match.rb
|
111
|
+
- lib/tzu/organizer.rb
|
112
|
+
- lib/tzu/outcome.rb
|
113
|
+
- lib/tzu/validation.rb
|
114
|
+
- lib/tzu/validation_result.rb
|
115
|
+
- spec/command_spec.rb
|
116
|
+
- spec/hooks_spec.rb
|
117
|
+
- spec/organizer_spec.rb
|
118
|
+
- spec/outcome_spec.rb
|
119
|
+
- spec/spec_helper.rb
|
120
|
+
- spec/tzu_spec.rb
|
121
|
+
- spec/validation_spec.rb
|
122
|
+
homepage: https://github.com/onfido/tzu
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata: {}
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 2.2.2
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: Standardise and encapsulate your application's actions
|
146
|
+
test_files:
|
147
|
+
- spec/command_spec.rb
|
148
|
+
- spec/hooks_spec.rb
|
149
|
+
- spec/organizer_spec.rb
|
150
|
+
- spec/outcome_spec.rb
|
151
|
+
- spec/spec_helper.rb
|
152
|
+
- spec/tzu_spec.rb
|
153
|
+
- spec/validation_spec.rb
|
154
|
+
has_rdoc:
|