tap-server 0.3.0 → 0.4.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.
- data/History +5 -0
- data/cmd/server.rb +36 -8
- data/lib/tap/controller/rest_routes.rb +77 -0
- data/lib/tap/controller/utils.rb +29 -0
- data/lib/tap/controller.rb +244 -145
- data/lib/tap/controllers/app.rb +97 -55
- data/lib/tap/controllers/data.rb +132 -0
- data/lib/tap/controllers/schema.rb +137 -223
- data/lib/tap/controllers/server.rb +70 -27
- data/lib/tap/server/data.rb +178 -0
- data/lib/tap/server/runner.rb +71 -0
- data/lib/tap/server/server_error.rb +35 -0
- data/lib/tap/server.rb +60 -275
- data/lib/tap/tasks/echo.rb +39 -6
- data/lib/tap/tasks/render.rb +65 -0
- data/public/stylesheets/tap.css +15 -2
- data/views/configurable/_config.erb +1 -0
- data/views/configurable/_configs.erb +28 -0
- data/views/configurable/_flag.erb +2 -0
- data/views/configurable/_list_select.erb +8 -0
- data/views/configurable/_select.erb +6 -0
- data/views/configurable/_switch.erb +2 -0
- data/views/layout.erb +1 -1
- data/views/object/obj.erb +1 -0
- data/views/tap/controllers/app/_action.erb +3 -0
- data/views/tap/controllers/app/build.erb +18 -0
- data/views/tap/controllers/app/enque.erb +13 -0
- data/views/tap/controllers/app/info.erb +20 -7
- data/views/tap/controllers/data/_controls.erb +21 -0
- data/views/tap/controllers/data/_index_entry.erb +1 -0
- data/views/tap/controllers/data/_upload.erb +8 -0
- data/views/tap/controllers/data/entry.erb +8 -0
- data/views/tap/controllers/data/index.erb +14 -0
- data/views/tap/controllers/schema/_build.erb +6 -0
- data/views/tap/controllers/schema/_index_entry.erb +6 -0
- data/views/tap/controllers/schema/entry.erb +135 -0
- data/views/tap/controllers/schema/join.erb +6 -4
- data/views/tap/controllers/schema/task.erb +6 -0
- data/views/tap/controllers/server/access.erb +4 -0
- data/views/tap/controllers/server/admin.erb +21 -0
- data/views/tap/controllers/server/help.erb +23 -0
- data/views/tap/controllers/server/index.erb +43 -3
- data/views/tap/task/input.erb +17 -0
- data/views/tap/tasks/load/input.erb +11 -0
- metadata +35 -17
- data/lib/tap/server_error.rb +0 -34
- data/lib/tap/support/persistence.rb +0 -71
- data/lib/tap/tasks/server.rb +0 -30
- data/views/tap/controllers/app/index.erb +0 -44
- data/views/tap/controllers/schema/config/default.erb +0 -4
- data/views/tap/controllers/schema/config/flag.erb +0 -3
- data/views/tap/controllers/schema/config/switch.erb +0 -6
- data/views/tap/controllers/schema/configurations.erb +0 -27
- data/views/tap/controllers/schema/node.erb +0 -47
- data/views/tap/controllers/schema/preview.erb +0 -3
- data/views/tap/controllers/schema/round.erb +0 -30
- data/views/tap/controllers/schema/schema.erb +0 -28
- data/views/tap/tasks/echo/result.html +0 -1
data/History
CHANGED
data/cmd/server.rb
CHANGED
@@ -1,26 +1,54 @@
|
|
1
|
-
# tap server {options}
|
1
|
+
# tap server {options}
|
2
2
|
#
|
3
3
|
# Initializes a tap server.
|
4
|
+
#
|
4
5
|
|
5
6
|
require 'tap'
|
6
7
|
require 'tap/server'
|
7
8
|
|
8
9
|
env = Tap::Env.instance
|
9
10
|
app = Tap::App.instance
|
10
|
-
|
11
|
+
|
12
|
+
begin
|
13
|
+
opts = ConfigParser.new('env' => env, 'app' => app)
|
14
|
+
opts.separator ""
|
15
|
+
opts.separator "configurations:"
|
16
|
+
opts.add(Tap::Server.configurations)
|
11
17
|
|
12
18
|
opts.separator ""
|
13
19
|
opts.separator "options:"
|
14
|
-
|
15
|
-
|
16
|
-
|
20
|
+
|
21
|
+
opts.on('--config FILE', 'Specifies a config file') do |config_file|
|
22
|
+
opts.config.merge! Configurable::Utils.load_file(config_file)
|
23
|
+
end
|
24
|
+
|
17
25
|
opts.on("-h", "--help", "Show this message") do
|
18
26
|
puts Lazydoc.usage(__FILE__)
|
19
27
|
puts opts
|
20
28
|
exit
|
21
29
|
end
|
30
|
+
|
31
|
+
# (note defaults are not added so they will not
|
32
|
+
# conflict with string keys from a config file)
|
33
|
+
args = opts.parse!(ARGV, :clear_config => false, :add_defaults => false)
|
34
|
+
|
35
|
+
if args.empty?
|
36
|
+
args << 'server'
|
37
|
+
end
|
38
|
+
|
39
|
+
controller = env[:controller][args.shift]
|
40
|
+
|
41
|
+
unless args.empty?
|
42
|
+
warn "ignoring args: #{args.inspect}"
|
43
|
+
end
|
44
|
+
|
45
|
+
Tap::Server.new(controller, opts.nested_config).run!
|
46
|
+
rescue
|
47
|
+
raise if $DEBUG
|
48
|
+
puts $!.message
|
49
|
+
exit(1)
|
22
50
|
end
|
23
|
-
argv = parser.parse(ARGV)
|
24
51
|
|
25
|
-
|
26
|
-
|
52
|
+
exit(0)
|
53
|
+
|
54
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Tap
|
2
|
+
class Controller
|
3
|
+
# Adds REST routing to a Tap::Controller.
|
4
|
+
#
|
5
|
+
# class Projects < Tap::Controller
|
6
|
+
# include RestRoutes
|
7
|
+
#
|
8
|
+
# # GET /projects
|
9
|
+
# def index...
|
10
|
+
#
|
11
|
+
# # GET /projects/*args
|
12
|
+
# def show(*args)...
|
13
|
+
#
|
14
|
+
# # POST /projects/*args
|
15
|
+
# def create(*args)...
|
16
|
+
#
|
17
|
+
# # PUT /projects/*args
|
18
|
+
# # POST /projects/*args?_method=put
|
19
|
+
# def update(*args)...
|
20
|
+
#
|
21
|
+
# # DELETE /projects/*args
|
22
|
+
# # POST /projects/*args?_method=delete
|
23
|
+
# def destroy(*args)...
|
24
|
+
#
|
25
|
+
# # extension...
|
26
|
+
#
|
27
|
+
# # POST /projects/*args?_method=another
|
28
|
+
# def another(*args)...
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# === Relation to RESTful Rails
|
32
|
+
#
|
33
|
+
# Unlike the REST syntax in Rails, '/projects/new' is treated like a show
|
34
|
+
# where the id is 'new'. Also missing is the routing for urls like
|
35
|
+
# '/projects/arg;edit/'. See these resources:
|
36
|
+
#
|
37
|
+
# * {RESTful Rails Development}[http://www.b-simple.de/download/restful_rails_en.pdf]
|
38
|
+
# * {REST cheatsheet}[topfunky.com/clients/peepcode/REST-cheatsheet.pdf]
|
39
|
+
#
|
40
|
+
module RestRoutes
|
41
|
+
def route
|
42
|
+
blank, *route = request.path_info.split("/").collect {|arg| unescape(arg) }
|
43
|
+
route.unshift rest_action(route)
|
44
|
+
route
|
45
|
+
end
|
46
|
+
|
47
|
+
def rest_action(args)
|
48
|
+
case request.request_method
|
49
|
+
when /GET/i
|
50
|
+
if args.empty?
|
51
|
+
:index
|
52
|
+
else
|
53
|
+
:show
|
54
|
+
end
|
55
|
+
when /POST/i
|
56
|
+
case _method = request[:_method]
|
57
|
+
when /put/i
|
58
|
+
:update
|
59
|
+
when /delete/i
|
60
|
+
:destroy
|
61
|
+
when nil
|
62
|
+
:create
|
63
|
+
else
|
64
|
+
if action?(_method)
|
65
|
+
_method
|
66
|
+
else
|
67
|
+
raise Server::ServerError.new("unknown post method: #{_method}")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
when /PUT/i then :update
|
71
|
+
when /DELETE/i then :destroy
|
72
|
+
else raise Server::ServerError.new("unknown request method: #{request.request_method}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Tap
|
2
|
+
class Controller
|
3
|
+
module Utils
|
4
|
+
|
5
|
+
def static_file(path)
|
6
|
+
content = File.read(path)
|
7
|
+
headers = {
|
8
|
+
"Last-Modified" => File.mtime(path).httpdate,
|
9
|
+
"Content-Type" => Rack::Mime.mime_type(File.extname(path), 'text/plain'),
|
10
|
+
"Content-Length" => content.size.to_s
|
11
|
+
}
|
12
|
+
|
13
|
+
[200, headers, [content]]
|
14
|
+
end
|
15
|
+
|
16
|
+
def download(path)
|
17
|
+
content = File.read(path)
|
18
|
+
headers = {
|
19
|
+
"Last-Modified" => File.mtime(path).httpdate,
|
20
|
+
"Content-Type" => Rack::Mime.mime_type(File.extname(path), 'text/plain'),
|
21
|
+
"Content-Disposition" => "attachment; filename=#{File.basename(path)};",
|
22
|
+
"Content-Length" => content.size.to_s
|
23
|
+
}
|
24
|
+
|
25
|
+
[200, headers, [content]]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/tap/controller.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
require 'erb'
|
1
2
|
require 'tap/server'
|
2
|
-
require 'tap/
|
3
|
-
|
3
|
+
require 'tap/controller/rest_routes'
|
4
|
+
require 'tap/controller/utils'
|
4
5
|
|
5
6
|
module Tap
|
6
7
|
|
7
8
|
# === Declaring Actions
|
9
|
+
#
|
8
10
|
# By default all public methods in subclasses are declared as actions. You
|
9
11
|
# can declare a private or protected method as an action by:
|
10
12
|
#
|
@@ -17,119 +19,112 @@ module Tap
|
|
17
19
|
# * define it private or protected then call public(:method)
|
18
20
|
#
|
19
21
|
class Controller
|
20
|
-
|
21
|
-
# Adds REST routing (a-la Rails[http://www.b-simple.de/download/restful_rails_en.pdf])
|
22
|
-
# to a Tap::Controller.
|
23
|
-
#
|
24
|
-
# class Projects < Tap::Controller
|
25
|
-
# include RestRoutes
|
26
|
-
#
|
27
|
-
# # GET /projects
|
28
|
-
# def index...
|
29
|
-
#
|
30
|
-
# # GET /projects/*args
|
31
|
-
# def show(*args)...
|
32
|
-
#
|
33
|
-
# # GET /projects/arg;edit/*args
|
34
|
-
# def edit(arg, *args)...
|
35
|
-
#
|
36
|
-
# # POST /projects/*args
|
37
|
-
# def create(*args)...
|
38
|
-
#
|
39
|
-
# # PUT /projects/*args
|
40
|
-
# def update(*args)...
|
41
|
-
#
|
42
|
-
# # DELETE /projects/*args
|
43
|
-
# def destroy(*args)...
|
44
|
-
# end
|
45
|
-
#
|
46
|
-
module RestRoutes
|
47
|
-
def route
|
48
|
-
blank, *args = request.path_info.split("/").collect {|arg| unescape(arg) }
|
49
|
-
action = case request.request_method
|
50
|
-
when /GET/i
|
51
|
-
case
|
52
|
-
when args.empty?
|
53
|
-
:index
|
54
|
-
when args[0] =~ /(.*);edit$/
|
55
|
-
args[0] = $1
|
56
|
-
:edit
|
57
|
-
else
|
58
|
-
:show
|
59
|
-
end
|
60
|
-
when /POST/i then :create
|
61
|
-
when /PUT/i then :update
|
62
|
-
when /DELETE/i then :destroy
|
63
|
-
else raise ServerError.new("unknown request method: #{request.request_method}")
|
64
|
-
end
|
65
|
-
|
66
|
-
[action, args]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
22
|
class << self
|
71
|
-
|
23
|
+
|
72
24
|
# Initialize instance variables on the child and inherit as necessary.
|
73
25
|
def inherited(child) # :nodoc:
|
74
26
|
super
|
27
|
+
|
28
|
+
unless child.instance_variable_defined?(:@source_file)
|
29
|
+
caller[0] =~ Lazydoc::CALLER_REGEXP
|
30
|
+
child.instance_variable_set(:@source_file, File.expand_path($1))
|
31
|
+
end
|
32
|
+
|
33
|
+
set_variables.each do |variable|
|
34
|
+
child.set(variable, get(variable))
|
35
|
+
end
|
36
|
+
|
75
37
|
child.set(:actions, actions.dup)
|
76
|
-
child.set(:default_layout, default_layout)
|
77
38
|
child.set(:define_action, true)
|
78
39
|
end
|
79
|
-
|
40
|
+
|
80
41
|
# An array of methods that can be called as actions. Actions must be
|
81
42
|
# stored as symbols. Actions are inherited.
|
82
43
|
attr_reader :actions
|
83
|
-
|
84
|
-
# The default
|
85
|
-
attr_reader :
|
86
|
-
|
87
|
-
# The base path prepended to render paths (ie render(<path>) renders
|
88
|
-
# <templates_dir/name/path>).
|
89
|
-
def name
|
90
|
-
@name ||= to_s.underscore
|
91
|
-
end
|
44
|
+
|
45
|
+
# The default action called for the request path '/'
|
46
|
+
attr_reader :default_action
|
92
47
|
|
93
48
|
# Instantiates self and performs call.
|
94
49
|
def call(env)
|
95
50
|
new.call(env)
|
96
51
|
end
|
97
|
-
|
98
|
-
# Sets an instance variable for self, short for:
|
52
|
+
|
53
|
+
# Sets an instance variable for self (ie the class), short for:
|
99
54
|
#
|
100
55
|
# instance_variable_set(:@attribute, input)
|
101
56
|
#
|
102
|
-
#
|
57
|
+
# These variables are meaningful to a default Tap::Controller and will
|
58
|
+
# be inherited by subclasses:
|
103
59
|
#
|
104
60
|
# actions:: sets actions
|
105
|
-
#
|
106
|
-
# default_layout:: the default layout (used by render)
|
61
|
+
# default_action:: the default action (:index)
|
107
62
|
#
|
108
63
|
def set(variable, input)
|
64
|
+
set_variables << variable
|
109
65
|
instance_variable_set("@#{variable}", input)
|
110
66
|
end
|
111
67
|
|
112
|
-
|
68
|
+
# Gets the value of an instance variable set via set. Returns nil for
|
69
|
+
# variables that have not been set through set.
|
70
|
+
def get(variable)
|
71
|
+
return nil unless set_variables.include?(variable)
|
72
|
+
instance_variable_get("@#{variable}")
|
73
|
+
end
|
113
74
|
|
75
|
+
# An array of variables set via set. set_variables are inherited.
|
76
|
+
def set_variables
|
77
|
+
@set_variables ||= []
|
78
|
+
end
|
79
|
+
|
80
|
+
def nest(key, controller, &block)
|
81
|
+
|
82
|
+
# generate a subclass if anything gets overridden
|
83
|
+
if block_given?
|
84
|
+
controller = Class.new(controller)
|
85
|
+
controller.class_eval(&block)
|
86
|
+
end
|
87
|
+
|
88
|
+
# this check prevents a warning in cases where the nesting
|
89
|
+
# class defines the nested class
|
90
|
+
const_name = key.to_s.camelize
|
91
|
+
unless const_defined?(const_name) && const_get(const_name) == subclass
|
92
|
+
const_set(const_name, controller)
|
93
|
+
end
|
94
|
+
|
95
|
+
define_method(key) do |*args|
|
96
|
+
instance = controller.new
|
97
|
+
|
98
|
+
instance.server = server
|
99
|
+
instance.controller_path = controller_path ? "#{controller_path}/#{key}" : key
|
100
|
+
instance.request = request
|
101
|
+
instance.response = response
|
102
|
+
|
103
|
+
instance.dispatch(args)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
protected
|
108
|
+
|
114
109
|
# Overridden so that if declare_action is set, new methods
|
115
110
|
# are added to actions.
|
116
111
|
def method_added(sym) # :nodoc:
|
117
112
|
actions << sym if @define_action
|
118
113
|
super
|
119
114
|
end
|
120
|
-
|
115
|
+
|
121
116
|
# Turns on declare_action when changing method context.
|
122
117
|
def public(*symbols) # :nodoc:
|
123
118
|
@define_action = true if symbols.empty?
|
124
119
|
super
|
125
120
|
end
|
126
|
-
|
121
|
+
|
127
122
|
# Turns off declare_action when changing method context.
|
128
123
|
def protected(*symbols) # :nodoc:
|
129
124
|
@define_action = false if symbols.empty?
|
130
125
|
super
|
131
126
|
end
|
132
|
-
|
127
|
+
|
133
128
|
# Turns off declare_action when changing method context.
|
134
129
|
def private(*symbols) # :nodoc:
|
135
130
|
@define_action = false if symbols.empty?
|
@@ -137,107 +132,234 @@ module Tap
|
|
137
132
|
end
|
138
133
|
end
|
139
134
|
|
135
|
+
extend Lazydoc::Attributes
|
136
|
+
include Rack::Utils
|
137
|
+
ServerError = Tap::Server::ServerError
|
138
|
+
|
139
|
+
lazy_attr :desc, 'controller'
|
140
|
+
|
140
141
|
set :actions, []
|
141
|
-
set :
|
142
|
+
set :default_action, :index
|
143
|
+
set :default_layout, 'layout.erb'
|
142
144
|
|
145
|
+
#--
|
143
146
|
# Ensures methods (even public methods) on Controller will
|
144
147
|
# not be actions in subclasses.
|
145
148
|
set :define_action, false
|
146
149
|
|
147
|
-
include Rack::Utils
|
148
|
-
|
149
|
-
# Accesses the 'tap.server' specified in env, set during call.
|
150
150
|
attr_accessor :server
|
151
151
|
|
152
|
+
attr_accessor :controller_path
|
153
|
+
|
152
154
|
# A Rack::Request wrapping env, set during call.
|
153
155
|
attr_accessor :request
|
154
|
-
|
156
|
+
|
155
157
|
# A Rack::Response. If the action returns a string, it will be written to
|
156
158
|
# response and response will be returned by call. Otherwise, call returns
|
157
159
|
# the action result and response is ignored.
|
158
160
|
attr_accessor :response
|
159
161
|
|
160
|
-
#
|
161
|
-
|
162
|
+
# Initializes a new instance of self.
|
163
|
+
def initialize
|
164
|
+
@request = @response = @server = @controller_path = nil
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns true if action is registered as an action for self.
|
168
|
+
def action?(action)
|
169
|
+
self.class.actions.include?(action.to_sym)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns a uri to the specified action on self.
|
173
|
+
def uri(action=nil, params={})
|
174
|
+
uri = []
|
175
|
+
|
176
|
+
if controller_path
|
177
|
+
uri << '/'
|
178
|
+
uri << controller_path
|
179
|
+
end
|
180
|
+
|
181
|
+
if action
|
182
|
+
uri << '/'
|
183
|
+
uri << action
|
184
|
+
end
|
185
|
+
|
186
|
+
unless params.empty?
|
187
|
+
uri << '?'
|
188
|
+
uri << build_query(params)
|
189
|
+
end
|
190
|
+
|
191
|
+
uri.join
|
192
|
+
end
|
193
|
+
|
194
|
+
def template_path(path)
|
195
|
+
server.env.path(:views, path) {|file| File.file?(file) }
|
196
|
+
end
|
162
197
|
|
163
|
-
|
164
|
-
|
165
|
-
def initialize(server=nil, request=nil, response=nil)
|
166
|
-
@server = server
|
167
|
-
@request = request
|
168
|
-
@response = response
|
169
|
-
@action = nil
|
198
|
+
def module_path(path, klass=self.class)
|
199
|
+
server.env.module_path(:views, klass.ancestors, path) {|file| File.file?(file) }
|
170
200
|
end
|
171
201
|
|
202
|
+
# Routes the request to an action and returns the response. Routing is
|
203
|
+
# simple and fixed (see route):
|
204
|
+
#
|
205
|
+
# route calls
|
206
|
+
# / default_action (ie 'index')
|
207
|
+
# /action/*args action(*args)
|
208
|
+
#
|
209
|
+
# If the action returns a string, it will be written to response.
|
210
|
+
# Otherwise, call returns the result of action. This allows actions like:
|
211
|
+
#
|
212
|
+
# class ActionsController < Tap::Controller
|
213
|
+
# def simple
|
214
|
+
# "html body"
|
215
|
+
# end
|
216
|
+
#
|
217
|
+
# def standard
|
218
|
+
# response["Content-Type"] = "text/plain"
|
219
|
+
# response << "text"
|
220
|
+
# response.finish
|
221
|
+
# end
|
222
|
+
#
|
223
|
+
# def custom
|
224
|
+
# [200, {"Content-Type" => "text/plain"}, ["text"]]
|
225
|
+
# end
|
226
|
+
# end
|
227
|
+
#
|
172
228
|
def call(env)
|
173
|
-
@server = env['tap.server']
|
229
|
+
@server = env['tap.server']
|
230
|
+
@controller_path = env['tap.controller_path']
|
231
|
+
|
174
232
|
@request = Rack::Request.new(env)
|
175
233
|
@response = Rack::Response.new
|
176
234
|
|
177
|
-
|
178
|
-
|
179
|
-
unless self.class.actions.include?(@action)
|
180
|
-
raise ServerError.new("404 Error: page not found", 404)
|
181
|
-
end
|
182
|
-
|
183
|
-
result = send(@action, *args)
|
184
|
-
if result.kind_of?(String)
|
235
|
+
case result = dispatch(route)
|
236
|
+
when String
|
185
237
|
response.write result
|
186
238
|
response.finish
|
239
|
+
when nil
|
240
|
+
response.finish
|
187
241
|
else
|
188
242
|
result
|
189
243
|
end
|
190
244
|
end
|
191
|
-
|
245
|
+
|
246
|
+
# Returns the action, args, and extname for the request.path_info. Routing
|
247
|
+
# is simple and fixed:
|
248
|
+
#
|
249
|
+
# route returns
|
250
|
+
# / [:index, []]
|
251
|
+
# /action/*args [:action, args]
|
252
|
+
#
|
253
|
+
# The action and args are unescaped by route. An alternate default action
|
254
|
+
# may be specified using set. Override this method in subclasses for
|
255
|
+
# fancier routes.
|
192
256
|
def route
|
193
|
-
blank,
|
194
|
-
|
195
|
-
|
257
|
+
blank, *route = request.path_info.split("/").collect {|arg| unescape(arg) }
|
258
|
+
route
|
259
|
+
end
|
260
|
+
|
261
|
+
def dispatch(route)
|
262
|
+
action, *args = route
|
263
|
+
|
264
|
+
if action == nil || action == ""
|
265
|
+
action = self.class.default_action
|
266
|
+
end
|
196
267
|
|
197
|
-
|
268
|
+
unless action?(action)
|
269
|
+
raise ServerError.new("404 Error: page not found", 404)
|
270
|
+
end
|
271
|
+
|
272
|
+
send(action, *args)
|
198
273
|
end
|
199
274
|
|
275
|
+
# Renders the class_file at path with the specified options. Path can be
|
276
|
+
# omitted if options specifies an alternate path to render. Options:
|
277
|
+
#
|
278
|
+
# template:: renders the template relative to the template directory
|
279
|
+
# file:: renders the specified file
|
280
|
+
# layout:: renders with the specified layout, or default_layout if true
|
281
|
+
# locals:: a hash of local variables used in the template
|
282
|
+
#
|
200
283
|
def render(path, options={})
|
201
284
|
options, path = path, nil if path.kind_of?(Hash)
|
202
|
-
|
285
|
+
|
203
286
|
# lookup template
|
204
287
|
template_path = case
|
205
|
-
when options
|
206
|
-
|
288
|
+
when options[:file]
|
289
|
+
options[:file]
|
290
|
+
when options[:template]
|
291
|
+
self.template_path(options[:template])
|
207
292
|
else
|
208
|
-
|
293
|
+
self.module_path(path)
|
209
294
|
end
|
210
|
-
|
295
|
+
|
211
296
|
unless template_path
|
212
|
-
raise "could not find template
|
297
|
+
raise "could not find template: (path: #{path.inspect}, file: #{options[:file].inspect}, template: #{options[:template].inspect})"
|
213
298
|
end
|
214
299
|
|
215
300
|
# render template
|
216
301
|
template = File.read(template_path)
|
217
|
-
content = render_erb(template, options)
|
302
|
+
content = render_erb(template, options, template_path)
|
218
303
|
|
219
304
|
# render layout
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
305
|
+
render_layout(options[:layout], content)
|
306
|
+
end
|
307
|
+
|
308
|
+
# Renders the specified layout with content as a local variable. If layout
|
309
|
+
# is true, the class default_layout will be rendered. Returns content if no
|
310
|
+
# layout is specified.
|
311
|
+
def render_layout(layout, content)
|
312
|
+
return content unless layout
|
313
|
+
|
314
|
+
if layout == true
|
315
|
+
layout = self.class.get(:default_layout)
|
316
|
+
end
|
317
|
+
|
318
|
+
if layout.kind_of?(Hash)
|
319
|
+
locals = layout[:locals] ||= {}
|
320
|
+
|
321
|
+
if locals.has_key?(:content)
|
322
|
+
raise "layout already has local content assigned: #{layout.inspect}"
|
323
|
+
end
|
324
|
+
|
325
|
+
locals[:content] = content
|
224
326
|
else
|
225
|
-
content
|
327
|
+
layout = {:template => layout, :locals => {:content => content}}
|
226
328
|
end
|
329
|
+
|
330
|
+
render(layout)
|
227
331
|
end
|
228
|
-
|
229
|
-
|
332
|
+
|
333
|
+
# Renders the specified template as ERB using the options. Options:
|
334
|
+
#
|
335
|
+
# locals:: a hash of local variables used in the template
|
336
|
+
#
|
337
|
+
# The filename used to identify errors in an erb template to a specific
|
338
|
+
# file and is completely options (but handy).
|
339
|
+
def render_erb(template, options={}, filename=nil)
|
230
340
|
# assign locals to the render binding
|
231
341
|
# this almost surely may be optimized...
|
232
342
|
locals = options[:locals]
|
233
|
-
binding =
|
234
|
-
|
343
|
+
binding = render_erb_binding
|
344
|
+
|
235
345
|
locals.each_pair do |key, value|
|
236
346
|
@assignment_value = value
|
237
347
|
eval("#{key} = remove_instance_variable(:@assignment_value)", binding)
|
238
348
|
end if locals
|
349
|
+
|
350
|
+
erb = ERB.new(template, nil, "<>")
|
351
|
+
erb.filename = filename
|
352
|
+
erb.result(binding)
|
353
|
+
end
|
354
|
+
|
355
|
+
def module_render(path, obj, options={})
|
356
|
+
obj = obj.class unless obj.kind_of?(Module)
|
357
|
+
options[:file] = module_path(path, obj) || module_path(path)
|
358
|
+
|
359
|
+
locals = options[:locals] ||= {}
|
360
|
+
locals[:obj] ||= obj
|
239
361
|
|
240
|
-
|
362
|
+
render options
|
241
363
|
end
|
242
364
|
|
243
365
|
# Redirects to the specified uri.
|
@@ -245,38 +367,15 @@ module Tap
|
|
245
367
|
response.status = status
|
246
368
|
response.headers.merge!(headers)
|
247
369
|
response.body = body
|
248
|
-
|
249
|
-
response['Location'] = uri
|
370
|
+
|
371
|
+
response['Location'] = [uri]
|
250
372
|
response.finish
|
251
373
|
end
|
252
374
|
|
253
|
-
|
254
|
-
def session
|
255
|
-
request.env['rack.session'] ||= {}
|
256
|
-
end
|
257
|
-
|
258
|
-
# Returns the app for the current session.
|
259
|
-
def app
|
260
|
-
server.app(session[:id] ||= server.initialize_session)
|
261
|
-
end
|
262
|
-
|
263
|
-
# Returns the root for the current session.
|
264
|
-
def root
|
265
|
-
server.root(session[:id] ||= server.initialize_session)
|
266
|
-
end
|
267
|
-
|
268
|
-
# Returns the file-based controller persistence.
|
269
|
-
def persistence
|
270
|
-
@persistence ||= Support::Persistence.new(root)
|
271
|
-
end
|
272
|
-
|
273
|
-
# Returns a controller uri.
|
274
|
-
def uri(action=nil, params={})
|
275
|
-
server.uri(self.class.name, action, params)
|
276
|
-
end
|
375
|
+
private
|
277
376
|
|
278
377
|
# Generates an empty binding to self without any locals assigned.
|
279
|
-
def
|
378
|
+
def render_erb_binding # :nodoc:
|
280
379
|
binding
|
281
380
|
end
|
282
381
|
end
|