trailblazer 0.0.1 → 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/.gitignore +1 -1
- data/.travis.yml +5 -0
- data/CHANGES.md +3 -0
- data/Gemfile +4 -0
- data/README.md +417 -16
- data/Rakefile +14 -0
- data/THOUGHTS +12 -0
- data/TODO.md +6 -0
- data/doc/Trb-The-Stack.png +0 -0
- data/doc/trb.jpg +0 -0
- data/gemfiles/Gemfile.rails +7 -0
- data/gemfiles/Gemfile.rails.lock +99 -0
- data/lib/trailblazer.rb +2 -0
- data/lib/trailblazer/autoloading.rb +5 -0
- data/lib/trailblazer/operation.rb +124 -0
- data/lib/trailblazer/operation/controller.rb +76 -0
- data/lib/trailblazer/operation/crud.rb +61 -0
- data/lib/trailblazer/operation/representer.rb +18 -0
- data/lib/trailblazer/operation/responder.rb +24 -0
- data/lib/trailblazer/operation/uploaded_file.rb +77 -0
- data/lib/trailblazer/operation/worker.rb +96 -0
- data/lib/trailblazer/version.rb +1 -1
- data/test/crud_test.rb +115 -0
- data/test/fixtures/apotomo.png +0 -0
- data/test/fixtures/cells.png +0 -0
- data/test/operation_test.rb +334 -0
- data/test/rails/controller_test.rb +175 -0
- data/test/rails/fake_app/app-cells/.gitkeep +0 -0
- data/test/rails/fake_app/cells.rb +21 -0
- data/test/rails/fake_app/config.rb +3 -0
- data/test/rails/fake_app/controllers.rb +101 -0
- data/test/rails/fake_app/models.rb +13 -0
- data/test/rails/fake_app/rails_app.rb +57 -0
- data/test/rails/fake_app/song/operations.rb +63 -0
- data/test/rails/fake_app/views/bands/show.html.erb +1 -0
- data/test/rails/fake_app/views/songs/new.html.erb +1 -0
- data/test/rails/test_helper.rb +4 -0
- data/test/responder_test.rb +77 -0
- data/test/test_helper.rb +15 -0
- data/test/uploaded_file_test.rb +85 -0
- data/test/worker_test.rb +116 -0
- data/trailblazer.gemspec +10 -2
- metadata +160 -23
@@ -0,0 +1,175 @@
|
|
1
|
+
# BUNDLE_GEMFILE=gemfiles/Gemfile.rails bundle exec rake rails
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
ActionController::TestCase.class_eval do
|
5
|
+
setup do
|
6
|
+
@routes = Rails.application.routes
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class GenericResponderTest < ActionController::TestCase
|
11
|
+
tests SongsController
|
12
|
+
|
13
|
+
setup do
|
14
|
+
@routes = Rails.application.routes
|
15
|
+
end
|
16
|
+
|
17
|
+
test "Create with params" do
|
18
|
+
post :create_with_params, {song: {title: "You're Going Down", length: 120}}
|
19
|
+
assert_response 302
|
20
|
+
|
21
|
+
song = Song.last
|
22
|
+
assert_equal "A Beautiful Indifference", song.title
|
23
|
+
assert_equal nil, song.length # params overwritten from controller.
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# overriding Controller#process_params.
|
28
|
+
class ProcessParamsTest < ActionController::TestCase
|
29
|
+
tests BandsController
|
30
|
+
|
31
|
+
setup do
|
32
|
+
@routes = Rails.application.routes
|
33
|
+
end
|
34
|
+
|
35
|
+
test "Create with overridden #process_params" do
|
36
|
+
post :create, band: {name: "Kreator"}
|
37
|
+
|
38
|
+
band = Band.last
|
39
|
+
assert_equal "Kreator", band.name
|
40
|
+
assert_equal "Essen", band.locality
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class ResponderRespondTest < ActionController::TestCase
|
45
|
+
tests SongsController
|
46
|
+
|
47
|
+
setup do
|
48
|
+
@routes = Rails.application.routes
|
49
|
+
end
|
50
|
+
|
51
|
+
# HTML
|
52
|
+
# #respond Create [valid]
|
53
|
+
test "Create [html/valid]" do
|
54
|
+
post :create, {song: {title: "You're Going Down"}}
|
55
|
+
assert_redirected_to song_path(Song.last)
|
56
|
+
end
|
57
|
+
|
58
|
+
test "Create [html/invalid]" do
|
59
|
+
post :create, {song: {title: ""}}
|
60
|
+
assert_equal @response.body, "{:title=>["can't be blank"]}"
|
61
|
+
end
|
62
|
+
|
63
|
+
test "Delete [html/valid]" do
|
64
|
+
song = Song::Create[song: {title: "You're Going Down"}].model
|
65
|
+
delete :destroy, id: song.id
|
66
|
+
assert_redirected_to songs_path
|
67
|
+
# assert that model is deleted.
|
68
|
+
end
|
69
|
+
|
70
|
+
test "respond with block [html/valid]" do
|
71
|
+
post :create_with_block, {song: {title: "You're Going Down"}}
|
72
|
+
assert_equal "block run, valid: true", response.body
|
73
|
+
end
|
74
|
+
|
75
|
+
test "respond with block [html/invalid]" do
|
76
|
+
post :create_with_block, {song: {title: ""}}
|
77
|
+
assert_equal "block run, valid: false", response.body
|
78
|
+
end
|
79
|
+
|
80
|
+
# JSON
|
81
|
+
test "Delete [json/valid]" do
|
82
|
+
song = Song::Create[song: {title: "You're Going Down"}].model
|
83
|
+
delete :destroy, id: song.id, format: :json
|
84
|
+
assert_response 204 # no content.
|
85
|
+
end
|
86
|
+
|
87
|
+
# JS
|
88
|
+
test "Delete [js/valid]" do
|
89
|
+
song = Song::Create[song: {title: "You're Going Down"}].model
|
90
|
+
assert_raises ActionView::MissingTemplate do
|
91
|
+
# js wants to render destroy.js.erb
|
92
|
+
delete :destroy, id: song.id, format: :js
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
test "Delete with formats [js/valid]" do
|
97
|
+
song = Song::Create[song: {title: "You're Going Down"}].model
|
98
|
+
|
99
|
+
delete :destroy_with_formats, id: song.id, format: :js
|
100
|
+
assert_response 200
|
101
|
+
assert_equal "Song slayer!", response.body
|
102
|
+
end
|
103
|
+
|
104
|
+
# TODO: #present
|
105
|
+
# TODO: #run
|
106
|
+
|
107
|
+
# describe "#run" do
|
108
|
+
# test "#run" do
|
109
|
+
|
110
|
+
# end
|
111
|
+
# end
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
class ResponderRunTest < ActionController::TestCase
|
119
|
+
tests BandsController
|
120
|
+
|
121
|
+
test "[html/valid]" do
|
122
|
+
put :update, {id: 1, band: {name: "Nofx"}}
|
123
|
+
assert_equal "no block: Nofx, Essen", response.body
|
124
|
+
end
|
125
|
+
|
126
|
+
test "with block [html/valid]" do
|
127
|
+
put :update_with_block, {id: 1, band: {name: "Nofx"}}
|
128
|
+
assert_equal "[valid] with block: Nofx, Essen", response.body
|
129
|
+
end
|
130
|
+
|
131
|
+
test "with block [html/invalid]" do
|
132
|
+
put :update_with_block, {id: 1, band: {name: ""}}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
#present.
|
137
|
+
class ControllerPresentTest < ActionController::TestCase
|
138
|
+
tests BandsController
|
139
|
+
|
140
|
+
# let (:band) { }
|
141
|
+
|
142
|
+
test "#present" do
|
143
|
+
band = Band::Create[band: {name: "Nofx"}].model
|
144
|
+
|
145
|
+
get :show, id: band.id
|
146
|
+
|
147
|
+
assert_equal "bands/show.html: Band,Band,true,Band::Create,Essen\n", response.body
|
148
|
+
end
|
149
|
+
|
150
|
+
test "#present [JSON]" do
|
151
|
+
band = Band::Create[band: {name: "Nofx"}].model
|
152
|
+
|
153
|
+
get :show, id: band.id, format: :json
|
154
|
+
assert_equal "{\"name\":\"Nofx\"}", response.body
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
# #form.
|
160
|
+
class ControllerFormTest < ActionController::TestCase
|
161
|
+
tests BandsController
|
162
|
+
|
163
|
+
test "#form" do
|
164
|
+
get :new
|
165
|
+
|
166
|
+
assert_select "form input#band_name"
|
167
|
+
assert_select "b", ",Band,true,Band::Create"
|
168
|
+
end
|
169
|
+
|
170
|
+
test "#form with block" do
|
171
|
+
get :new_with_block
|
172
|
+
|
173
|
+
assert_select "b", "Band,Band,true,Band::Create,Essen"
|
174
|
+
end
|
175
|
+
end
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class UserCell < Cell::Rails
|
2
|
+
include Kaminari::Cells
|
3
|
+
|
4
|
+
def show(users)
|
5
|
+
@users = users
|
6
|
+
|
7
|
+
render :inline => <<-ERB
|
8
|
+
<%= paginate @users %>
|
9
|
+
ERB
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ViewModelCell < Cell::ViewModel
|
14
|
+
include Kaminari::Cells
|
15
|
+
|
16
|
+
def show
|
17
|
+
render :inline => <<-ERB
|
18
|
+
<%= paginate model %>
|
19
|
+
ERB
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# controllers
|
2
|
+
class ApplicationController < ActionController::Base
|
3
|
+
append_view_path "test/rails/fake_app/views"
|
4
|
+
end
|
5
|
+
|
6
|
+
class SongsController < ApplicationController
|
7
|
+
respond_to :json, :js
|
8
|
+
|
9
|
+
def index
|
10
|
+
@users = Song.all.page params[:page]
|
11
|
+
render inline: <<-ERB
|
12
|
+
<%= render_cell(:user, :show, @users) %>
|
13
|
+
ERB
|
14
|
+
end
|
15
|
+
|
16
|
+
include Trailblazer::Operation::Controller
|
17
|
+
respond_to :html
|
18
|
+
|
19
|
+
def create
|
20
|
+
respond Song::Create
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_with_params
|
24
|
+
respond Song::Create, song: {title: "A Beautiful Indifference"}
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_with_block
|
28
|
+
respond Song::Create do |op, formats|
|
29
|
+
return render text: "block run, valid: #{op.valid?}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy
|
34
|
+
respond Song::Delete
|
35
|
+
end
|
36
|
+
|
37
|
+
def destroy_with_formats
|
38
|
+
respond Song::Delete do |op, formats|
|
39
|
+
formats.js { render text: "#{op.model.class} slayer!" }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class BandsController < ApplicationController
|
45
|
+
include Trailblazer::Operation::Controller
|
46
|
+
respond_to :html, :json
|
47
|
+
|
48
|
+
def show
|
49
|
+
present Band::Create do |op|
|
50
|
+
@klass = op.model.class
|
51
|
+
@locality = params[:band][:locality]
|
52
|
+
end # respond_to
|
53
|
+
end
|
54
|
+
|
55
|
+
def new
|
56
|
+
form Band::Create
|
57
|
+
|
58
|
+
render inline: <<-ERB
|
59
|
+
<%= form_for @form do |f| %>
|
60
|
+
<%= f.text_field :name %>
|
61
|
+
<% end %>
|
62
|
+
|
63
|
+
<b><%= [@klass, @model.class, @form.is_a?(Reform::Form), @operation.class].join(",") %></b>
|
64
|
+
ERB
|
65
|
+
end
|
66
|
+
|
67
|
+
def new_with_block
|
68
|
+
form Band::Create do |op|
|
69
|
+
@klass = op.model.class
|
70
|
+
@locality = params[:band][:locality]
|
71
|
+
end
|
72
|
+
|
73
|
+
render inline: <<-ERB
|
74
|
+
<b><%= [@klass, @model.class, @form.is_a?(Reform::Form), @operation.class, @locality].join(",") %></b>
|
75
|
+
ERB
|
76
|
+
end
|
77
|
+
|
78
|
+
def create
|
79
|
+
respond Band::Create
|
80
|
+
end
|
81
|
+
|
82
|
+
def update
|
83
|
+
run Band::Create
|
84
|
+
|
85
|
+
render text: "no block: #{@operation.model.name}, #{params[:band][:locality]}"
|
86
|
+
end
|
87
|
+
|
88
|
+
def update_with_block
|
89
|
+
run Band::Create do |op|
|
90
|
+
return render text: "[valid] with block: #{op.model.name}, #{params[:band][:locality]}"
|
91
|
+
end
|
92
|
+
|
93
|
+
render text: "[invalid] with block: #{@operation.model.name}, #{params[:band][:locality]}"
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
def process_params!(params) # this is where you set :current_user, etc.
|
98
|
+
params[:band] ||= {}
|
99
|
+
params[:band][:locality] = "Essen"
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# models
|
2
|
+
class Song < ActiveRecord::Base
|
3
|
+
end
|
4
|
+
|
5
|
+
# migrations
|
6
|
+
class CreateAllTables < ActiveRecord::Migration
|
7
|
+
def self.up
|
8
|
+
create_table(:songs) { |t| t.string :title; t.integer :length }
|
9
|
+
create_table(:bands) { |t| t.string :name; t.string :locality }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
ActiveRecord::Migration.verbose = false
|
13
|
+
CreateAllTables.up
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# BUNDLE_GEMFILE=gemfiles/Gemfile.rails bundle exec rake rails
|
2
|
+
# TODO: how does rails handle all the different rake test tasks?
|
3
|
+
|
4
|
+
# require 'rails/all'
|
5
|
+
require 'action_controller/railtie'
|
6
|
+
require 'action_view/railtie'
|
7
|
+
require 'active_record'
|
8
|
+
|
9
|
+
require 'fake_app/config'
|
10
|
+
|
11
|
+
|
12
|
+
# config
|
13
|
+
app = Class.new(Rails::Application)
|
14
|
+
app.config.secret_token = '3b7cd727ee24e8444053437c36cc66c4'
|
15
|
+
app.config.session_store :cookie_store, :key => '_myapp_session'
|
16
|
+
app.config.active_support.deprecation = :log
|
17
|
+
app.config.eager_load = false
|
18
|
+
# Rais.root
|
19
|
+
app.config.root = File.dirname(__FILE__)
|
20
|
+
Rails.backtrace_cleaner.remove_silencers!
|
21
|
+
app.initialize!
|
22
|
+
|
23
|
+
# routes
|
24
|
+
app.routes.draw do
|
25
|
+
resources :songs do
|
26
|
+
member do # argh.
|
27
|
+
delete :destroy_with_formats
|
28
|
+
end
|
29
|
+
|
30
|
+
collection do
|
31
|
+
post :create_with_params
|
32
|
+
post :create_with_block
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
resources :bands do
|
37
|
+
collection do
|
38
|
+
post :create
|
39
|
+
get :new_with_block
|
40
|
+
end
|
41
|
+
|
42
|
+
member do
|
43
|
+
post :update_with_block
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'trailblazer/operation/responder'
|
49
|
+
require 'trailblazer/operation/controller'
|
50
|
+
require 'trailblazer/operation/representer'
|
51
|
+
|
52
|
+
require 'fake_app/controllers'
|
53
|
+
require 'fake_app/models'
|
54
|
+
require 'fake_app/song/operations.rb'
|
55
|
+
|
56
|
+
# helpers
|
57
|
+
Object.const_set(:ApplicationHelper, Module.new)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class Song < ActiveRecord::Base
|
2
|
+
class Create < Trailblazer::Operation
|
3
|
+
include CRUD
|
4
|
+
include Responder
|
5
|
+
model Song, :create
|
6
|
+
|
7
|
+
|
8
|
+
contract do
|
9
|
+
property :title, validates: {presence: true}
|
10
|
+
property :length
|
11
|
+
end
|
12
|
+
|
13
|
+
def process(params)
|
14
|
+
validate(params[:song]) do
|
15
|
+
contract.save
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
class Delete < Create
|
22
|
+
action :find
|
23
|
+
|
24
|
+
def process(params)
|
25
|
+
model.destroy
|
26
|
+
self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Band < ActiveRecord::Base
|
32
|
+
class Create < Trailblazer::Operation
|
33
|
+
include CRUD, Responder
|
34
|
+
model Band, :create
|
35
|
+
|
36
|
+
contract do
|
37
|
+
include Reform::Form::ActiveModel
|
38
|
+
model Band
|
39
|
+
|
40
|
+
property :name, validates: {presence: true}
|
41
|
+
property :locality
|
42
|
+
end
|
43
|
+
|
44
|
+
def process(params)
|
45
|
+
validate(params[:band]) do
|
46
|
+
contract.save
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class JSON < self
|
51
|
+
action :find
|
52
|
+
include Representer
|
53
|
+
# self.representer_class = Class.new(contract_class)
|
54
|
+
# representer_class do
|
55
|
+
# include Reform::Form::JSON
|
56
|
+
# end
|
57
|
+
end
|
58
|
+
|
59
|
+
builds do |params|
|
60
|
+
JSON if params[:format] == "json"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
bands/show.html: <%= [@klass, @model.class, @form.is_a?(Reform::Form), @operation.class, @locality].join(",") %>
|