pakyow-core 0.6.1
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/pakyow-core/CHANGES +3 -0
- data/pakyow-core/MIT-LICENSE +20 -0
- data/pakyow-core/README +1 -0
- data/pakyow-core/bin/pakyow +14 -0
- data/pakyow-core/lib/commands/USAGE +8 -0
- data/pakyow-core/lib/commands/USAGE-NEW +11 -0
- data/pakyow-core/lib/commands/USAGE-SERVER +12 -0
- data/pakyow-core/lib/commands/server.rb +8 -0
- data/pakyow-core/lib/core/application.rb +463 -0
- data/pakyow-core/lib/core/base.rb +17 -0
- data/pakyow-core/lib/core/configuration/app.rb +73 -0
- data/pakyow-core/lib/core/configuration/base.rb +32 -0
- data/pakyow-core/lib/core/configuration/server.rb +19 -0
- data/pakyow-core/lib/core/helpers.rb +22 -0
- data/pakyow-core/lib/core/loader.rb +35 -0
- data/pakyow-core/lib/core/log.rb +35 -0
- data/pakyow-core/lib/core/presenter_base.rb +7 -0
- data/pakyow-core/lib/core/request.rb +66 -0
- data/pakyow-core/lib/core/route_store.rb +117 -0
- data/pakyow-core/lib/generators/pakyow/app/app_generator.rb +26 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/README +54 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/app/lib/application_controller.rb +6 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/app/views/main.html +1 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/app/views/pakyow.html +12 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/config/application.rb +18 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/config.ru +10 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/logs/requests.log +0 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/public/favicon.ico +0 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/rakefile +5 -0
- data/pakyow-core/lib/pakyow-core.rb +14 -0
- data/pakyow-core/lib/utils/dir.rb +18 -0
- data/pakyow-core/lib/utils/hash.rb +31 -0
- data/pakyow-core/lib/utils/string.rb +37 -0
- metadata +113 -0
data/pakyow-core/CHANGES
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Bryan Powell
|
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/pakyow-core/README
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
TODO
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
CORE_PATH = File.expand_path('../../lib', __FILE__)
|
4
|
+
|
5
|
+
if ARGV.first == 'new'
|
6
|
+
ARGV.shift
|
7
|
+
require 'generators/pakyow/app/app_generator'
|
8
|
+
Pakyow::Generators::AppGenerator.start
|
9
|
+
elsif ARGV.first == 'server'
|
10
|
+
ARGV.shift
|
11
|
+
require 'commands/server'
|
12
|
+
elsif ARGV.first == '--help' || ARGV.first == '-h' || ARGV.empty?
|
13
|
+
puts File.open(File.join(CORE_PATH, 'commands/USAGE')).read
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Usage:
|
2
|
+
pakyow server [environment]
|
3
|
+
|
4
|
+
Description:
|
5
|
+
The 'pakyow server' command starts the application server. If environment
|
6
|
+
is not specified, the default_environment defined by your application
|
7
|
+
will be used.
|
8
|
+
|
9
|
+
Example:
|
10
|
+
pakyow server development
|
11
|
+
|
12
|
+
This starts the application server with the 'development' configuration.
|
@@ -0,0 +1,463 @@
|
|
1
|
+
module Pakyow
|
2
|
+
class Application
|
3
|
+
class << self
|
4
|
+
attr_accessor :routes_proc, :middleware_proc, :configurations, :error_handlers
|
5
|
+
|
6
|
+
# Sets the path to the application file so it can be reloaded later.
|
7
|
+
#
|
8
|
+
def inherited(subclass)
|
9
|
+
Pakyow::Configuration::App.application_path = caller[0].split(':')[0]
|
10
|
+
end
|
11
|
+
|
12
|
+
# Runs the application. Accepts the environment(s) to run, for example:
|
13
|
+
# run(:development)
|
14
|
+
# run([:development, :staging])
|
15
|
+
#
|
16
|
+
def run(*args)
|
17
|
+
self.load_config args.empty? || args.first.nil? ? [Configuration::Base.app.default_environment] : args
|
18
|
+
return if running?
|
19
|
+
|
20
|
+
@running = true
|
21
|
+
|
22
|
+
builder = Rack::Builder.new
|
23
|
+
builder.use(Rack::MethodOverride)
|
24
|
+
builder.instance_eval(&self.middleware_proc) if self.middleware_proc
|
25
|
+
builder.run(self.new)
|
26
|
+
detect_handler.run(builder, :Host => Pakyow::Configuration::Base.server.host, :Port => Pakyow::Configuration::Base.server.port)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Stages the application. Everything is loaded but the application is
|
30
|
+
# not started. Accepts the same arguments as #run.
|
31
|
+
#
|
32
|
+
def stage(*args)
|
33
|
+
load_config args.empty? || args.first.nil? ? [Configuration::Base.app.default_environment] : args
|
34
|
+
return if staged?
|
35
|
+
|
36
|
+
app = self.new
|
37
|
+
|
38
|
+
@staged = true
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns true if the application is running.
|
42
|
+
#
|
43
|
+
def running?
|
44
|
+
@running
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns true if the application is staged.
|
48
|
+
#
|
49
|
+
def staged?
|
50
|
+
@staged
|
51
|
+
end
|
52
|
+
|
53
|
+
# Convenience method for base configuration class.
|
54
|
+
#
|
55
|
+
def config
|
56
|
+
Pakyow::Configuration::Base
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates configuration for a particular environment. Example:
|
60
|
+
# configure(:development) { app.auto_reload = true }
|
61
|
+
#
|
62
|
+
def configure(environment, &block)
|
63
|
+
self.configurations ||= {}
|
64
|
+
self.configurations[environment] = block
|
65
|
+
end
|
66
|
+
|
67
|
+
# Creates routes. Example:
|
68
|
+
# routes { get '/' { # do something } }
|
69
|
+
#
|
70
|
+
def routes(&block)
|
71
|
+
self.routes_proc = block
|
72
|
+
end
|
73
|
+
|
74
|
+
# Creates an error handler (currently 404 and 500 errors are handled).
|
75
|
+
# The handler can be created one of two ways:
|
76
|
+
#
|
77
|
+
# Define a controller/action for a particular error:
|
78
|
+
# error(404, :ApplicationController, :handle_404)
|
79
|
+
#
|
80
|
+
# Specify a block for a particular error:
|
81
|
+
# error(404) { # handle error }
|
82
|
+
#
|
83
|
+
def error(*args, &block)
|
84
|
+
self.error_handlers ||= {}
|
85
|
+
code, controller, action = args
|
86
|
+
|
87
|
+
if block
|
88
|
+
self.error_handlers[code] = block
|
89
|
+
else
|
90
|
+
self.error_handlers[code] = {
|
91
|
+
:controller => controller,
|
92
|
+
:action => action
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def middleware(&block)
|
98
|
+
self.middleware_proc = block
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
def load_config(args)
|
104
|
+
if self.configurations
|
105
|
+
args << Configuration::Base.app.default_environment if args.empty?
|
106
|
+
args.each do |env|
|
107
|
+
next unless config = self.configurations[env]
|
108
|
+
Configuration::Base.instance_eval(&config)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def detect_handler
|
114
|
+
['thin', 'mongrel', 'webrick'].each do |server|
|
115
|
+
begin
|
116
|
+
return Rack::Handler.get(server)
|
117
|
+
rescue LoadError
|
118
|
+
rescue NameError
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
include Helpers
|
125
|
+
|
126
|
+
attr_accessor :request, :response, :presenter, :route_store, :restful_routes
|
127
|
+
|
128
|
+
def initialize
|
129
|
+
Pakyow.app = self
|
130
|
+
|
131
|
+
# Create static handler
|
132
|
+
@static_handler = Rack::File.new(Configuration::Base.app.public_dir)
|
133
|
+
|
134
|
+
# This configuration option will be set if a presenter is to be used
|
135
|
+
if Configuration::Base.app.presenter
|
136
|
+
# Create a new instance of the presenter
|
137
|
+
self.presenter = Configuration::Base.app.presenter.new
|
138
|
+
end
|
139
|
+
|
140
|
+
# Load application files
|
141
|
+
load_app
|
142
|
+
end
|
143
|
+
|
144
|
+
# Interrupts the application and returns response immediately.
|
145
|
+
#
|
146
|
+
def interrupt!
|
147
|
+
@interrupted = true
|
148
|
+
throw :halt, self.response
|
149
|
+
end
|
150
|
+
|
151
|
+
# Called on every request.
|
152
|
+
#
|
153
|
+
def call(env)
|
154
|
+
start_time = Time.now.to_f
|
155
|
+
|
156
|
+
# Handle static files
|
157
|
+
if env['PATH_INFO'] =~ /\.(.*)$/ && File.exists?(File.join(Configuration::Base.app.public_dir, env['PATH_INFO']))
|
158
|
+
@static = true
|
159
|
+
@static_handler.call(env)
|
160
|
+
else
|
161
|
+
# The request object
|
162
|
+
self.request = Request.new(env)
|
163
|
+
|
164
|
+
# Reload application files
|
165
|
+
load_app
|
166
|
+
|
167
|
+
if Configuration::Base.app.presenter
|
168
|
+
# Handle presentation for this request
|
169
|
+
self.presenter.present_for_request(request)
|
170
|
+
end
|
171
|
+
|
172
|
+
Log.enter "Processing #{env['PATH_INFO']} (#{env['REMOTE_ADDR']} at #{Time.now}) [#{env['REQUEST_METHOD']}]"
|
173
|
+
|
174
|
+
# The response object
|
175
|
+
self.response = Rack::Response.new
|
176
|
+
rhs = nil
|
177
|
+
just_the_path, format = StringUtils.split_at_last_dot(self.request.path)
|
178
|
+
self.request.format = ((format && (format[format.length - 1, 1] == '/')) ? format[0, format.length - 1] : format)
|
179
|
+
catch(:halt) do
|
180
|
+
rhs, packet = @route_store.get_block(just_the_path, self.request.method)
|
181
|
+
packet[:vars].each_pair { |var, val|
|
182
|
+
request.params[var] = val
|
183
|
+
}
|
184
|
+
self.request.route_spec = packet[:data][:route_spec] if packet[:data]
|
185
|
+
restful_info = packet[:data][:restful] if packet[:data]
|
186
|
+
self.request.restful = restful_info
|
187
|
+
rhs.call() if rhs && !Pakyow::Configuration::App.ignore_routes
|
188
|
+
end
|
189
|
+
|
190
|
+
if !self.interrupted?
|
191
|
+
if Configuration::Base.app.presenter
|
192
|
+
self.response.body = [self.presenter.content]
|
193
|
+
end
|
194
|
+
|
195
|
+
# 404 if no facts matched and no views were found
|
196
|
+
if !rhs && (!self.presenter || !self.presenter.presented?)
|
197
|
+
self.handle_error(404)
|
198
|
+
|
199
|
+
Log.enter "[404] Not Found"
|
200
|
+
self.response.status = 404
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
return finish!
|
205
|
+
end
|
206
|
+
rescue StandardError => error
|
207
|
+
self.request.error = error
|
208
|
+
self.handle_error(500)
|
209
|
+
|
210
|
+
Log.enter "[500] #{error}\n"
|
211
|
+
Log.enter error.backtrace.join("\n") + "\n\n"
|
212
|
+
|
213
|
+
self.response = Rack::Response.new
|
214
|
+
|
215
|
+
if Configuration::Base.app.errors_in_browser
|
216
|
+
# Show errors in browser
|
217
|
+
self.response.body << "<h4>#{CGI.escapeHTML(error.to_s)}</h4>"
|
218
|
+
self.response.body << error.backtrace.join("<br />")
|
219
|
+
end
|
220
|
+
|
221
|
+
self.response.status = 500
|
222
|
+
return finish!
|
223
|
+
ensure
|
224
|
+
unless @static
|
225
|
+
end_time = Time.now.to_f
|
226
|
+
difference = ((end_time - start_time) * 1000).to_f
|
227
|
+
|
228
|
+
Log.enter "Completed in #{difference}ms | #{self.response.status} | [#{self.request.url}]"
|
229
|
+
Log.enter
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Sends a file in the response (immediately). Accepts a File object. Mime
|
234
|
+
# type is automatically detected.
|
235
|
+
#
|
236
|
+
def send_file(source_file, send_as = nil, type = nil)
|
237
|
+
path = source_file.is_a?(File) ? source_file.path : source_file
|
238
|
+
send_as ||= path
|
239
|
+
type ||= Rack::Mime.mime_type(".#{send_as.split('.')[-1]}")
|
240
|
+
|
241
|
+
data = ""
|
242
|
+
File.open(path, "r").each_line { |line| data << line }
|
243
|
+
|
244
|
+
self.response = Rack::Response.new(data, self.response.status, self.response.header.merge({ "Content-Type" => type }))
|
245
|
+
interrupt!
|
246
|
+
end
|
247
|
+
|
248
|
+
# Sends data in the response (immediately). Accepts the data, mime type,
|
249
|
+
# and optional file name.
|
250
|
+
#
|
251
|
+
def send_data(data, type, file_name = nil)
|
252
|
+
status = self.response ? self.response.status : 200
|
253
|
+
|
254
|
+
headers = self.response ? self.response.header : {}
|
255
|
+
headers = headers.merge({ "Content-Type" => type })
|
256
|
+
headers = headers.merge({ "Content-disposition" => "attachment; filename=#{file_name}"}) if file_name
|
257
|
+
|
258
|
+
self.response = Rack::Response.new(data, status, headers)
|
259
|
+
interrupt!
|
260
|
+
end
|
261
|
+
|
262
|
+
# Redirects to location (immediately).
|
263
|
+
#
|
264
|
+
def redirect_to(location, status_code = 302)
|
265
|
+
headers = self.response ? self.response.header : {}
|
266
|
+
headers = headers.merge({'Location' => location})
|
267
|
+
|
268
|
+
self.response = Rack::Response.new('', status_code, headers)
|
269
|
+
interrupt!
|
270
|
+
end
|
271
|
+
|
272
|
+
# Registers a route for GET requests. Route can be defined one of two ways:
|
273
|
+
# get('/', :ControllerClass, :action_method)
|
274
|
+
# get('/') { # do something }
|
275
|
+
#
|
276
|
+
# Routes for namespaced controllers (e.g. Admin::ControllerClass) can be defined like this:
|
277
|
+
# get('/', :Admin_ControllerClass, :action_method)
|
278
|
+
#
|
279
|
+
def get(route, controller = nil, action = nil, &block)
|
280
|
+
register_route(route, block, :get, controller, action)
|
281
|
+
end
|
282
|
+
|
283
|
+
# Registers a route for POST requests (see #get).
|
284
|
+
#
|
285
|
+
def post(route, controller = nil, action = nil, &block)
|
286
|
+
register_route(route, block, :post, controller, action)
|
287
|
+
end
|
288
|
+
|
289
|
+
# Registers a route for PUT requests (see #get).
|
290
|
+
#
|
291
|
+
def put(route, controller = nil, action = nil, &block)
|
292
|
+
register_route(route, block, :put, controller, action)
|
293
|
+
end
|
294
|
+
|
295
|
+
# Registers a route for DELETE requests (see #get).
|
296
|
+
#
|
297
|
+
def delete(route, controller = nil, action = nil, &block)
|
298
|
+
register_route(route, block, :delete, controller, action)
|
299
|
+
end
|
300
|
+
|
301
|
+
# Registers the default route (see #get).
|
302
|
+
#
|
303
|
+
def default(controller = nil, action = nil, &block)
|
304
|
+
register_route('/', block, :get, controller, action)
|
305
|
+
end
|
306
|
+
|
307
|
+
# Creates REST routes for a resource. Arguments: url, controller, model
|
308
|
+
#
|
309
|
+
def restful(*args, &block)
|
310
|
+
url, controller, model = args
|
311
|
+
|
312
|
+
with_scope(:url => url.gsub(/^[\/]+|[\/]+$/,""), :model => model) do
|
313
|
+
nest_scope(&block) if block_given?
|
314
|
+
|
315
|
+
@restful_routes ||= {}
|
316
|
+
@restful_routes[model] ||= {} if model
|
317
|
+
|
318
|
+
@@restful_actions.each do |opts|
|
319
|
+
action_url = current_path
|
320
|
+
if suffix = opts[:url_suffix]
|
321
|
+
action_url = File.join(action_url, suffix)
|
322
|
+
end
|
323
|
+
|
324
|
+
# Create the route
|
325
|
+
register_route(action_url, nil, opts[:method], controller, opts[:action], true)
|
326
|
+
|
327
|
+
# Store url for later use (currently used by Binder#action)
|
328
|
+
@restful_routes[model][opts[:action]] = action_url if model
|
329
|
+
end
|
330
|
+
|
331
|
+
remove_scope
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
@@restful_actions = [
|
336
|
+
{ :action => :index, :method => :get },
|
337
|
+
{ :action => :show, :method => :get, :url_suffix => ':id' },
|
338
|
+
{ :action => :new, :method => :get, :url_suffix => 'new' },
|
339
|
+
{ :action => :create, :method => :post },
|
340
|
+
{ :action => :edit, :method => :get, :url_suffix => 'edit/:id' },
|
341
|
+
{ :action => :update, :method => :put, :url_suffix => ':id' },
|
342
|
+
{ :action => :delete, :method => :delete, :url_suffix => ':id' }
|
343
|
+
]
|
344
|
+
|
345
|
+
protected
|
346
|
+
|
347
|
+
def interrupted?
|
348
|
+
@interrupted
|
349
|
+
end
|
350
|
+
|
351
|
+
# Handles route registration.
|
352
|
+
#
|
353
|
+
def register_route(route, block, method, controller = nil, action = nil, restful = false)
|
354
|
+
if controller
|
355
|
+
controller = eval(controller.to_s)
|
356
|
+
action ||= Configuration::Base.app.default_action
|
357
|
+
|
358
|
+
block = lambda {
|
359
|
+
instance = controller.new
|
360
|
+
request.controller = instance
|
361
|
+
request.action = action
|
362
|
+
|
363
|
+
instance.send(action)
|
364
|
+
}
|
365
|
+
end
|
366
|
+
|
367
|
+
data = {:route_spec=>route}
|
368
|
+
if restful
|
369
|
+
data[:restful] = {:restful_action=>action}
|
370
|
+
end
|
371
|
+
@route_store.add_route(route, block, method, data)
|
372
|
+
end
|
373
|
+
|
374
|
+
def with_scope(opts)
|
375
|
+
@scope ||= {}
|
376
|
+
@scope[:path] ||= []
|
377
|
+
@scope[:model] = opts[:model]
|
378
|
+
|
379
|
+
@scope[:path] << opts[:url]
|
380
|
+
|
381
|
+
yield
|
382
|
+
end
|
383
|
+
|
384
|
+
def remove_scope
|
385
|
+
@scope[:path].pop
|
386
|
+
end
|
387
|
+
|
388
|
+
def nest_scope(&block)
|
389
|
+
@scope[:path].insert(-1, ":#{StringUtils.underscore(@scope[:model].to_s)}_id")
|
390
|
+
yield
|
391
|
+
@scope[:path].pop
|
392
|
+
end
|
393
|
+
|
394
|
+
def current_path
|
395
|
+
@scope[:path].join('/')
|
396
|
+
end
|
397
|
+
|
398
|
+
def handle_error(code)
|
399
|
+
return unless self.class.error_handlers
|
400
|
+
return unless handler = self.class.error_handlers[code]
|
401
|
+
|
402
|
+
if handler.is_a? Proc
|
403
|
+
handler.call
|
404
|
+
else
|
405
|
+
c = eval(handler[:controller].to_s).new
|
406
|
+
c.send(handler[:action])
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
def set_cookies
|
411
|
+
if self.request.cookies && self.request.cookies != {}
|
412
|
+
self.request.cookies.each do |key, value|
|
413
|
+
if value.is_a?(Hash)
|
414
|
+
self.response.set_cookie(key, {:path => '/', :expires => Time.now + 604800}.merge(value))
|
415
|
+
elsif value.is_a?(String)
|
416
|
+
self.response.set_cookie(key, {:path => '/', :expires => Time.now + 604800}.merge({:value => value}))
|
417
|
+
else
|
418
|
+
self.response.set_cookie(key, {:path => '/', :expires => Time.now + 604800 * -1 }.merge({:value => value}))
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
# Reloads all application files in application_path and presenter (if specified).
|
425
|
+
#
|
426
|
+
def load_app
|
427
|
+
return if @loaded && !Configuration::Base.app.auto_reload
|
428
|
+
@loaded = true
|
429
|
+
|
430
|
+
# Reload Application
|
431
|
+
load(Configuration::App.application_path)
|
432
|
+
|
433
|
+
@loader = Loader.new unless @loader
|
434
|
+
@loader.load!(Configuration::Base.app.src_dir)
|
435
|
+
|
436
|
+
load_routes
|
437
|
+
|
438
|
+
# Reload views
|
439
|
+
if Configuration::Base.app.presenter
|
440
|
+
self.presenter.reload!
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
def load_routes
|
445
|
+
@route_store = RouteStore.new
|
446
|
+
self.instance_eval(&self.class.routes_proc) if self.class.routes_proc
|
447
|
+
end
|
448
|
+
|
449
|
+
# Send the response and cleanup.
|
450
|
+
#
|
451
|
+
def finish!
|
452
|
+
@interrupted = false
|
453
|
+
@static = false
|
454
|
+
|
455
|
+
# Set cookies
|
456
|
+
set_cookies
|
457
|
+
|
458
|
+
# Finished
|
459
|
+
self.response.finish
|
460
|
+
end
|
461
|
+
|
462
|
+
end
|
463
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Pakyow
|
2
|
+
autoload :Configuration, 'core/configuration/base'
|
3
|
+
autoload :Helpers, 'core/helpers'
|
4
|
+
autoload :GeneralHelpers, 'core/helpers'
|
5
|
+
autoload :Log, 'core/log'
|
6
|
+
autoload :Request, 'core/request'
|
7
|
+
autoload :Loader, 'core/loader'
|
8
|
+
autoload :Application, 'core/application'
|
9
|
+
autoload :RouteStore, 'core/route_store'
|
10
|
+
|
11
|
+
# utils
|
12
|
+
autoload :StringUtils, 'utils/string'
|
13
|
+
autoload :HashUtils, 'utils/hash'
|
14
|
+
autoload :DirUtils, 'utils/dir'
|
15
|
+
|
16
|
+
attr_accessor :app
|
17
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Pakyow
|
2
|
+
module Configuration
|
3
|
+
class App
|
4
|
+
class << self
|
5
|
+
attr_accessor :dev_mode, :log, :public_dir, :root, :log_dir,
|
6
|
+
:presenter, :default_action, :ignore_routes, :error_level,
|
7
|
+
:default_environment, :application_path, :log_name, :src_dir,
|
8
|
+
:auto_reload, :errors_in_browser
|
9
|
+
|
10
|
+
# Displays development-specific warnings.
|
11
|
+
#
|
12
|
+
def dev_mode
|
13
|
+
@dev_mode.nil? ? true : @dev_mode
|
14
|
+
end
|
15
|
+
|
16
|
+
def auto_reload
|
17
|
+
@auto_reload.nil? ? true : @auto_reload
|
18
|
+
end
|
19
|
+
|
20
|
+
def errors_in_browser
|
21
|
+
@errors_in_browser.nil? ? true : @errors_in_browser
|
22
|
+
end
|
23
|
+
|
24
|
+
# Log requests?
|
25
|
+
def log
|
26
|
+
@log.nil? ? true : @log
|
27
|
+
end
|
28
|
+
|
29
|
+
# Root directory
|
30
|
+
def root
|
31
|
+
@root || File.dirname('')
|
32
|
+
end
|
33
|
+
|
34
|
+
# Public directory
|
35
|
+
def public_dir
|
36
|
+
@public_dir || "#{root}/public"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Log directory
|
40
|
+
def log_dir
|
41
|
+
@log_dir || "#{root}/logs"
|
42
|
+
end
|
43
|
+
|
44
|
+
def log_name
|
45
|
+
@log_name || "requests.log"
|
46
|
+
end
|
47
|
+
|
48
|
+
def src_dir
|
49
|
+
@src_dir || "#{root}/app/lib"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Default action
|
53
|
+
def default_action
|
54
|
+
@default_action || :index
|
55
|
+
end
|
56
|
+
|
57
|
+
# Mockup mode
|
58
|
+
def ignore_routes
|
59
|
+
@ignore_routes.nil? ? false : @ignore_routes
|
60
|
+
end
|
61
|
+
|
62
|
+
def default_environment
|
63
|
+
@default_environment || :development
|
64
|
+
end
|
65
|
+
|
66
|
+
# The path to the application class
|
67
|
+
def application_path
|
68
|
+
@application_path
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Pakyow
|
2
|
+
module Configuration
|
3
|
+
autoload :App, 'core/configuration/app'
|
4
|
+
autoload :Server, 'core/configuration/server'
|
5
|
+
|
6
|
+
class Base
|
7
|
+
# Fetches the server configuration
|
8
|
+
def self.server
|
9
|
+
Configuration::Server
|
10
|
+
end
|
11
|
+
|
12
|
+
# Fetches to application configuration
|
13
|
+
def self.app
|
14
|
+
Configuration::App
|
15
|
+
end
|
16
|
+
|
17
|
+
# Resets all configuration
|
18
|
+
def self.reset!
|
19
|
+
%w[app server].each do |type|
|
20
|
+
klass = self.send(type.to_sym)
|
21
|
+
klass.instance_variables.each do |var|
|
22
|
+
# Assumes application_path shouldn't be reset, since it's only set
|
23
|
+
# once when Pakyow::Application is inherited.
|
24
|
+
next if var == '@application_path'
|
25
|
+
|
26
|
+
klass.send("#{var.gsub('@', '')}=", nil)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Pakyow
|
2
|
+
module Configuration
|
3
|
+
class Server
|
4
|
+
class << self
|
5
|
+
attr_accessor :port, :host
|
6
|
+
|
7
|
+
# On what port does the application run?
|
8
|
+
def port
|
9
|
+
@port || 3000
|
10
|
+
end
|
11
|
+
|
12
|
+
# On what host does the application run?
|
13
|
+
def host
|
14
|
+
@host || '0.0.0.0'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|