trailblazer 1.1.2 → 2.0.0.beta1
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/.travis.yml +10 -7
- data/CHANGES.md +108 -0
- data/COMM-LICENSE +91 -0
- data/Gemfile +18 -4
- data/LICENSE.txt +7 -20
- data/README.md +55 -15
- data/Rakefile +21 -2
- data/draft-1.2.rb +7 -0
- data/lib/trailblazer.rb +17 -4
- data/lib/trailblazer/dsl.rb +47 -0
- data/lib/trailblazer/operation/auto_inject.rb +47 -0
- data/lib/trailblazer/operation/builder.rb +18 -18
- data/lib/trailblazer/operation/callback.rb +31 -38
- data/lib/trailblazer/operation/contract.rb +46 -0
- data/lib/trailblazer/operation/controller.rb +45 -27
- data/lib/trailblazer/operation/guard.rb +24 -0
- data/lib/trailblazer/operation/model.rb +41 -33
- data/lib/trailblazer/operation/nested.rb +43 -0
- data/lib/trailblazer/operation/params.rb +13 -0
- data/lib/trailblazer/operation/persist.rb +13 -0
- data/lib/trailblazer/operation/policy.rb +26 -72
- data/lib/trailblazer/operation/present.rb +19 -0
- data/lib/trailblazer/operation/procedural/contract.rb +15 -0
- data/lib/trailblazer/operation/procedural/validate.rb +22 -0
- data/lib/trailblazer/operation/pundit.rb +42 -0
- data/lib/trailblazer/operation/representer.rb +25 -92
- data/lib/trailblazer/operation/rescue.rb +23 -0
- data/lib/trailblazer/operation/resolver.rb +18 -24
- data/lib/trailblazer/operation/validate.rb +50 -0
- data/lib/trailblazer/operation/wrap.rb +37 -0
- data/lib/trailblazer/version.rb +1 -1
- data/test/{operation/controller_test.rb → controller_test.rb} +8 -4
- data/test/docs/auto_inject_test.rb +30 -0
- data/test/docs/contract_test.rb +429 -0
- data/test/docs/dry_test.rb +31 -0
- data/test/docs/guard_test.rb +143 -0
- data/test/docs/nested_test.rb +117 -0
- data/test/docs/policy_test.rb +2 -0
- data/test/docs/pundit_test.rb +109 -0
- data/test/docs/representer_test.rb +268 -0
- data/test/docs/rescue_test.rb +153 -0
- data/test/docs/wrap_test.rb +174 -0
- data/test/gemfiles/Gemfile.ruby-1.9 +3 -0
- data/test/gemfiles/Gemfile.ruby-2.0 +12 -0
- data/test/gemfiles/Gemfile.ruby-2.3 +12 -0
- data/test/module_test.rb +22 -15
- data/test/operation/builder_test.rb +66 -18
- data/test/operation/callback_test.rb +70 -0
- data/test/operation/contract_test.rb +385 -15
- data/test/operation/dsl/callback_test.rb +18 -30
- data/test/operation/dsl/contract_test.rb +209 -19
- data/test/operation/dsl/representer_test.rb +42 -15
- data/test/operation/guard_test.rb +1 -147
- data/test/operation/model_test.rb +105 -0
- data/test/operation/params_test.rb +36 -0
- data/test/operation/persist_test.rb +44 -0
- data/test/operation/pipedream_test.rb +59 -0
- data/test/operation/pipetree_test.rb +104 -0
- data/test/operation/present_test.rb +24 -0
- data/test/operation/pundit_test.rb +104 -0
- data/test/{representer_test.rb → operation/representer_test.rb} +58 -42
- data/test/operation/resolver_test.rb +34 -70
- data/test/operation_test.rb +57 -189
- data/test/test_helper.rb +23 -3
- data/trailblazer.gemspec +8 -7
- metadata +91 -59
- data/gemfiles/Gemfile.rails.lock +0 -130
- data/gemfiles/Gemfile.reform-2.0 +0 -6
- data/gemfiles/Gemfile.reform-2.1 +0 -7
- data/lib/trailblazer/autoloading.rb +0 -15
- data/lib/trailblazer/endpoint.rb +0 -31
- data/lib/trailblazer/operation.rb +0 -175
- data/lib/trailblazer/operation/collection.rb +0 -6
- data/lib/trailblazer/operation/dispatch.rb +0 -3
- data/lib/trailblazer/operation/model/dsl.rb +0 -29
- data/lib/trailblazer/operation/model/external.rb +0 -34
- data/lib/trailblazer/operation/policy/guard.rb +0 -35
- data/lib/trailblazer/operation/uploaded_file.rb +0 -77
- data/test/callback_test.rb +0 -104
- data/test/collection_test.rb +0 -57
- data/test/model_test.rb +0 -148
- data/test/operation/external_model_test.rb +0 -71
- data/test/operation/policy_test.rb +0 -97
- data/test/operation/reject_test.rb +0 -34
- data/test/rollback_test.rb +0 -47
data/gemfiles/Gemfile.rails.lock
DELETED
@@ -1,130 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: ../
|
3
|
-
specs:
|
4
|
-
trailblazer (0.2.2)
|
5
|
-
actionpack (>= 3.0.0)
|
6
|
-
reform (>= 1.2.0)
|
7
|
-
uber (>= 0.0.10)
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: http://rubygems.org/
|
11
|
-
specs:
|
12
|
-
actionmailer (4.1.1)
|
13
|
-
actionpack (= 4.1.1)
|
14
|
-
actionview (= 4.1.1)
|
15
|
-
mail (~> 2.5.4)
|
16
|
-
actionpack (4.1.1)
|
17
|
-
actionview (= 4.1.1)
|
18
|
-
activesupport (= 4.1.1)
|
19
|
-
rack (~> 1.5.2)
|
20
|
-
rack-test (~> 0.6.2)
|
21
|
-
actionview (4.1.1)
|
22
|
-
activesupport (= 4.1.1)
|
23
|
-
builder (~> 3.1)
|
24
|
-
erubis (~> 2.7.0)
|
25
|
-
activemodel (4.1.1)
|
26
|
-
activesupport (= 4.1.1)
|
27
|
-
builder (~> 3.1)
|
28
|
-
activerecord (4.1.1)
|
29
|
-
activemodel (= 4.1.1)
|
30
|
-
activesupport (= 4.1.1)
|
31
|
-
arel (~> 5.0.0)
|
32
|
-
activesupport (4.1.1)
|
33
|
-
i18n (~> 0.6, >= 0.6.9)
|
34
|
-
json (~> 1.7, >= 1.7.7)
|
35
|
-
minitest (~> 5.1)
|
36
|
-
thread_safe (~> 0.1)
|
37
|
-
tzinfo (~> 1.1)
|
38
|
-
arel (5.0.1.20140414130214)
|
39
|
-
builder (3.2.2)
|
40
|
-
celluloid (0.16.0)
|
41
|
-
timers (~> 4.0.0)
|
42
|
-
connection_pool (2.0.0)
|
43
|
-
disposable (0.0.9)
|
44
|
-
representable (~> 2.0)
|
45
|
-
uber
|
46
|
-
erubis (2.7.0)
|
47
|
-
hitimes (1.2.2)
|
48
|
-
i18n (0.6.11)
|
49
|
-
json (1.8.1)
|
50
|
-
mail (2.5.4)
|
51
|
-
mime-types (~> 1.16)
|
52
|
-
treetop (~> 1.4.8)
|
53
|
-
mime-types (1.25.1)
|
54
|
-
mini_portile (0.6.2)
|
55
|
-
minitest (5.4.2)
|
56
|
-
multi_json (1.11.0)
|
57
|
-
nokogiri (1.6.6.2)
|
58
|
-
mini_portile (~> 0.6.0)
|
59
|
-
polyglot (0.3.5)
|
60
|
-
rack (1.5.2)
|
61
|
-
rack-test (0.6.2)
|
62
|
-
rack (>= 1.0)
|
63
|
-
rails (4.1.1)
|
64
|
-
actionmailer (= 4.1.1)
|
65
|
-
actionpack (= 4.1.1)
|
66
|
-
actionview (= 4.1.1)
|
67
|
-
activemodel (= 4.1.1)
|
68
|
-
activerecord (= 4.1.1)
|
69
|
-
activesupport (= 4.1.1)
|
70
|
-
bundler (>= 1.3.0, < 2.0)
|
71
|
-
railties (= 4.1.1)
|
72
|
-
sprockets-rails (~> 2.0)
|
73
|
-
railties (4.1.1)
|
74
|
-
actionpack (= 4.1.1)
|
75
|
-
activesupport (= 4.1.1)
|
76
|
-
rake (>= 0.8.7)
|
77
|
-
thor (>= 0.18.1, < 2.0)
|
78
|
-
rake (10.3.2)
|
79
|
-
redis (3.1.0)
|
80
|
-
redis-namespace (1.5.1)
|
81
|
-
redis (~> 3.0, >= 3.0.4)
|
82
|
-
reform (1.2.6)
|
83
|
-
activemodel
|
84
|
-
disposable (~> 0.0.5)
|
85
|
-
representable (~> 2.1.0)
|
86
|
-
uber (~> 0.0.11)
|
87
|
-
representable (2.1.8)
|
88
|
-
multi_json
|
89
|
-
nokogiri
|
90
|
-
uber (~> 0.0.7)
|
91
|
-
responders (1.1.2)
|
92
|
-
railties (>= 3.2, < 4.2)
|
93
|
-
sidekiq (3.1.4)
|
94
|
-
celluloid (>= 0.15.2)
|
95
|
-
connection_pool (>= 2.0.0)
|
96
|
-
json
|
97
|
-
redis (>= 3.0.6)
|
98
|
-
redis-namespace (>= 1.3.1)
|
99
|
-
sprockets (3.1.0)
|
100
|
-
rack (~> 1.0)
|
101
|
-
sprockets-rails (2.3.1)
|
102
|
-
actionpack (>= 3.0)
|
103
|
-
activesupport (>= 3.0)
|
104
|
-
sprockets (>= 2.8, < 4.0)
|
105
|
-
sqlite3 (1.3.9)
|
106
|
-
thor (0.19.1)
|
107
|
-
thread_safe (0.3.4)
|
108
|
-
timers (4.0.1)
|
109
|
-
hitimes
|
110
|
-
treetop (1.4.15)
|
111
|
-
polyglot
|
112
|
-
polyglot (>= 0.3.1)
|
113
|
-
tzinfo (1.2.2)
|
114
|
-
thread_safe (~> 0.1)
|
115
|
-
uber (0.0.13)
|
116
|
-
|
117
|
-
PLATFORMS
|
118
|
-
ruby
|
119
|
-
|
120
|
-
DEPENDENCIES
|
121
|
-
activerecord
|
122
|
-
bundler
|
123
|
-
minitest
|
124
|
-
rails
|
125
|
-
railties
|
126
|
-
rake
|
127
|
-
responders
|
128
|
-
sidekiq (~> 3.1.0)
|
129
|
-
sqlite3
|
130
|
-
trailblazer!
|
data/gemfiles/Gemfile.reform-2.0
DELETED
data/gemfiles/Gemfile.reform-2.1
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
Trailblazer.class_eval do
|
2
|
-
autoload :NotAuthorizedError, "trailblazer/operation/policy"
|
3
|
-
end
|
4
|
-
|
5
|
-
Trailblazer::Operation.class_eval do
|
6
|
-
autoload :Controller, "trailblazer/operation/controller"
|
7
|
-
autoload :Model, "trailblazer/operation/model"
|
8
|
-
autoload :Collection, "trailblazer/operation/collection"
|
9
|
-
autoload :Dispatch, "trailblazer/operation/dispatch" # TODO: remove in 1.2.
|
10
|
-
autoload :Callback, "trailblazer/operation/callback"
|
11
|
-
autoload :Module, "trailblazer/operation/module"
|
12
|
-
autoload :Representer,"trailblazer/operation/representer"
|
13
|
-
autoload :Policy, "trailblazer/operation/policy"
|
14
|
-
autoload :Resolver, "trailblazer/operation/resolver"
|
15
|
-
end
|
data/lib/trailblazer/endpoint.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
module Trailblazer
|
2
|
-
# Encapsulates HTTP-specific logic needed before running an operation.
|
3
|
-
# Right now, all this does is #document_body! which figures out whether or not to pass the request body
|
4
|
-
# into params, so the operation can use a representer to deserialize the original document.
|
5
|
-
# To be used in Hanami, Roda, Rails, etc.
|
6
|
-
class Endpoint
|
7
|
-
def initialize(operation_class, params, request, options)
|
8
|
-
@operation_class = operation_class
|
9
|
-
@params = params
|
10
|
-
@request = request
|
11
|
-
@is_document = options[:is_document]
|
12
|
-
end
|
13
|
-
|
14
|
-
def call
|
15
|
-
document_body! if @is_document
|
16
|
-
yield @params# Create.run(params)
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
attr_reader :params, :operation_class, :request
|
21
|
-
|
22
|
-
def document_body!
|
23
|
-
# this is what happens:
|
24
|
-
# respond_with Comment::Update::JSON.run(params.merge(comment: request.body.string))
|
25
|
-
concept_name = operation_class.model_class.to_s.underscore # this could be renamed to ::concept_class soon.
|
26
|
-
request_body = request.body.respond_to?(:string) ? request.body.string : request.body.read
|
27
|
-
|
28
|
-
params.merge!(concept_name => request_body)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,175 +0,0 @@
|
|
1
|
-
require "reform"
|
2
|
-
|
3
|
-
module Trailblazer
|
4
|
-
class Operation
|
5
|
-
require "trailblazer/operation/builder"
|
6
|
-
extend Builder # imports ::builder_class and ::build_operation.
|
7
|
-
|
8
|
-
extend Uber::InheritableAttr
|
9
|
-
inheritable_attr :contract_class
|
10
|
-
self.contract_class = Reform::Form.clone
|
11
|
-
|
12
|
-
class << self
|
13
|
-
def run(params, &block) # Endpoint behaviour
|
14
|
-
res, op = build_operation(params).run
|
15
|
-
|
16
|
-
if block_given?
|
17
|
-
yield op if res
|
18
|
-
return op
|
19
|
-
end
|
20
|
-
|
21
|
-
[res, op]
|
22
|
-
end
|
23
|
-
|
24
|
-
# Like ::run, but yield block when invalid.
|
25
|
-
def reject(*args)
|
26
|
-
res, op = run(*args)
|
27
|
-
yield op if res == false
|
28
|
-
op
|
29
|
-
end
|
30
|
-
|
31
|
-
# ::call only returns the Operation instance (or whatever was returned from #validate).
|
32
|
-
# This is useful in tests or in irb, e.g. when using Op as a factory and you already know it's valid.
|
33
|
-
def call(params)
|
34
|
-
build_operation(params, raise_on_invalid: true).run.last
|
35
|
-
end
|
36
|
-
|
37
|
-
def [](*args) # TODO: remove in 1.2.
|
38
|
-
warn "[Trailblazer] Operation[] is deprecated. Please use Operation.() and have a nice day."
|
39
|
-
call(*args)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Runs #setup! but doesn't process the operation.
|
43
|
-
def present(params)
|
44
|
-
build_operation(params)
|
45
|
-
end
|
46
|
-
|
47
|
-
# This is a DSL method. Use ::contract_class and ::contract_class= for the explicit version.
|
48
|
-
# Op.contract #=> returns contract class
|
49
|
-
# Op.contract do .. end # defines contract
|
50
|
-
# Op.contract CommentForm # copies (and subclasses) external contract.
|
51
|
-
# Op.contract CommentForm do .. end # copies and extends contract.
|
52
|
-
def contract(constant=nil, &block)
|
53
|
-
return contract_class unless constant or block_given?
|
54
|
-
|
55
|
-
self.contract_class= Class.new(constant) if constant
|
56
|
-
contract_class.class_eval(&block) if block_given?
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
|
-
def initialize(params, options={})
|
62
|
-
@options = options
|
63
|
-
@valid = true
|
64
|
-
|
65
|
-
setup!(params) # assign/find the model
|
66
|
-
end
|
67
|
-
|
68
|
-
# Operation.run(body: "Fabulous!") #=> [true, <Comment body: "Fabulous!">]
|
69
|
-
def run
|
70
|
-
process(@params)
|
71
|
-
|
72
|
-
[valid?, self]
|
73
|
-
end
|
74
|
-
|
75
|
-
attr_reader :model
|
76
|
-
|
77
|
-
def errors
|
78
|
-
contract.errors
|
79
|
-
end
|
80
|
-
|
81
|
-
def valid?
|
82
|
-
@valid
|
83
|
-
end
|
84
|
-
|
85
|
-
def contract(*args)
|
86
|
-
contract!(*args)
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
module Setup
|
91
|
-
attr_writer :model
|
92
|
-
|
93
|
-
def setup!(params)
|
94
|
-
params = assign_params!(params)
|
95
|
-
setup_params!(params)
|
96
|
-
build_model!(params)
|
97
|
-
params # TODO: test me.
|
98
|
-
end
|
99
|
-
|
100
|
-
def assign_params!(params)
|
101
|
-
@params = params!(params)
|
102
|
-
end
|
103
|
-
|
104
|
-
# Overwrite #params! if you need to change its structure, by returning a new params object
|
105
|
-
# from this method.
|
106
|
-
# This is helpful if you don't want to change the original via #setup_params!.
|
107
|
-
def params!(params)
|
108
|
-
params
|
109
|
-
end
|
110
|
-
|
111
|
-
def setup_params!(params)
|
112
|
-
end
|
113
|
-
|
114
|
-
def build_model!(*args)
|
115
|
-
assign_model!(*args) # @model = ..
|
116
|
-
setup_model!(*args)
|
117
|
-
end
|
118
|
-
|
119
|
-
def assign_model!(*args)
|
120
|
-
@model = model!(*args)
|
121
|
-
end
|
122
|
-
|
123
|
-
# Implement #model! to find/create your operation model (if required).
|
124
|
-
def model!(params)
|
125
|
-
end
|
126
|
-
|
127
|
-
# Override to add attributes that can be infered from params.
|
128
|
-
def setup_model!(params)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
include Setup
|
132
|
-
|
133
|
-
def validate(params, model=nil, contract_class=nil)
|
134
|
-
contract!(model, contract_class)
|
135
|
-
|
136
|
-
if @valid = validate_contract(params)
|
137
|
-
yield contract if block_given?
|
138
|
-
else
|
139
|
-
raise!(contract)
|
140
|
-
end
|
141
|
-
|
142
|
-
@valid
|
143
|
-
end
|
144
|
-
|
145
|
-
def validate_contract(params)
|
146
|
-
contract.validate(params)
|
147
|
-
end
|
148
|
-
|
149
|
-
def invalid!(result=self)
|
150
|
-
@valid = false
|
151
|
-
result
|
152
|
-
end
|
153
|
-
|
154
|
-
# When using Op.(), an invalid contract will raise an exception.
|
155
|
-
def raise!(contract)
|
156
|
-
raise InvalidContract.new(contract.errors.to_s) if @options[:raise_on_invalid]
|
157
|
-
end
|
158
|
-
|
159
|
-
# Instantiate the contract, either by using the user's contract passed into #validate
|
160
|
-
# or infer the Operation contract.
|
161
|
-
def contract_for(model=nil, contract_class=nil)
|
162
|
-
model ||= self.model
|
163
|
-
contract_class ||= self.class.contract_class
|
164
|
-
|
165
|
-
contract_class.new(model)
|
166
|
-
end
|
167
|
-
|
168
|
-
def contract!(*args)
|
169
|
-
@contract ||= contract_for(*args)
|
170
|
-
end
|
171
|
-
|
172
|
-
class InvalidContract < RuntimeError
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
class Trailblazer::Operation
|
2
|
-
module Model
|
3
|
-
# Imports ::model and ::action into an operation.
|
4
|
-
module DSL
|
5
|
-
def self.extended(extender)
|
6
|
-
extender.extend Uber::InheritableAttr
|
7
|
-
extender.inheritable_attr :config
|
8
|
-
extender.config = {}
|
9
|
-
end
|
10
|
-
|
11
|
-
def model(name, action=nil)
|
12
|
-
self.config[:model] = name
|
13
|
-
action(action) if action # coolest line ever.
|
14
|
-
end
|
15
|
-
|
16
|
-
def action(name)
|
17
|
-
self.config[:action] = name
|
18
|
-
end
|
19
|
-
|
20
|
-
def action_name # considered private.
|
21
|
-
self.config[:action] or :create
|
22
|
-
end
|
23
|
-
|
24
|
-
def model_class # considered private.
|
25
|
-
self.config[:model] or raise "[Trailblazer] You didn't call Operation::model."
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
require "trailblazer/operation/model"
|
2
|
-
|
3
|
-
class Trailblazer::Operation
|
4
|
-
module Model
|
5
|
-
# Builds (finds or creates) the model _before_ the operation is instantiated.
|
6
|
-
# Passes the model instance into the builder with the following signature.
|
7
|
-
#
|
8
|
-
# builds ->(model, params)
|
9
|
-
#
|
10
|
-
# The initializer will now expect you to pass the model in via options[:model]. This
|
11
|
-
# happens automatically when coming from a builder.
|
12
|
-
module External
|
13
|
-
def self.included(includer)
|
14
|
-
includer.extend Model::DSL
|
15
|
-
includer.extend Model::BuildModel
|
16
|
-
includer.extend ClassMethods
|
17
|
-
end
|
18
|
-
|
19
|
-
def assign_model!(*) # i don't like to "disable" the `@model =` like this but it's the simplest for now.
|
20
|
-
@model = @options[:model]
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
module ClassMethods
|
25
|
-
private
|
26
|
-
def build_operation(params, options={}) # TODO: merge with Resolver::build_operation.
|
27
|
-
model = model!(params)
|
28
|
-
build_operation_class(model, params). # calls builds->(model, params).
|
29
|
-
new(params, options.merge(model: model))
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|