tzu 0.0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|