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.
Files changed (34) hide show
  1. data/pakyow-core/CHANGES +3 -0
  2. data/pakyow-core/MIT-LICENSE +20 -0
  3. data/pakyow-core/README +1 -0
  4. data/pakyow-core/bin/pakyow +14 -0
  5. data/pakyow-core/lib/commands/USAGE +8 -0
  6. data/pakyow-core/lib/commands/USAGE-NEW +11 -0
  7. data/pakyow-core/lib/commands/USAGE-SERVER +12 -0
  8. data/pakyow-core/lib/commands/server.rb +8 -0
  9. data/pakyow-core/lib/core/application.rb +463 -0
  10. data/pakyow-core/lib/core/base.rb +17 -0
  11. data/pakyow-core/lib/core/configuration/app.rb +73 -0
  12. data/pakyow-core/lib/core/configuration/base.rb +32 -0
  13. data/pakyow-core/lib/core/configuration/server.rb +19 -0
  14. data/pakyow-core/lib/core/helpers.rb +22 -0
  15. data/pakyow-core/lib/core/loader.rb +35 -0
  16. data/pakyow-core/lib/core/log.rb +35 -0
  17. data/pakyow-core/lib/core/presenter_base.rb +7 -0
  18. data/pakyow-core/lib/core/request.rb +66 -0
  19. data/pakyow-core/lib/core/route_store.rb +117 -0
  20. data/pakyow-core/lib/generators/pakyow/app/app_generator.rb +26 -0
  21. data/pakyow-core/lib/generators/pakyow/app/templates/README +54 -0
  22. data/pakyow-core/lib/generators/pakyow/app/templates/app/lib/application_controller.rb +6 -0
  23. data/pakyow-core/lib/generators/pakyow/app/templates/app/views/main.html +1 -0
  24. data/pakyow-core/lib/generators/pakyow/app/templates/app/views/pakyow.html +12 -0
  25. data/pakyow-core/lib/generators/pakyow/app/templates/config/application.rb +18 -0
  26. data/pakyow-core/lib/generators/pakyow/app/templates/config.ru +10 -0
  27. data/pakyow-core/lib/generators/pakyow/app/templates/logs/requests.log +0 -0
  28. data/pakyow-core/lib/generators/pakyow/app/templates/public/favicon.ico +0 -0
  29. data/pakyow-core/lib/generators/pakyow/app/templates/rakefile +5 -0
  30. data/pakyow-core/lib/pakyow-core.rb +14 -0
  31. data/pakyow-core/lib/utils/dir.rb +18 -0
  32. data/pakyow-core/lib/utils/hash.rb +31 -0
  33. data/pakyow-core/lib/utils/string.rb +37 -0
  34. metadata +113 -0
@@ -0,0 +1,3 @@
1
+ = 0.6.0 / 2011-08-20
2
+
3
+ * Initial gem release of 0.6.0 codebase
@@ -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.
@@ -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,8 @@
1
+ Usage:
2
+ pakyow command
3
+
4
+ There are two commands:
5
+ new Create a new Pakyow application
6
+ server Start the application server
7
+
8
+ Run a command with -h for more information.
@@ -0,0 +1,11 @@
1
+ Usage:
2
+ pakyow new application
3
+
4
+ Description:
5
+ The 'pakyow new' command creates a new Pakyow application at the path
6
+ specified.
7
+
8
+ Example:
9
+ pakyow new path/to/application
10
+
11
+ This generates a new Pakyow application in path/to/application.
@@ -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,8 @@
1
+ if ARGV.first == '--help' || ARGV.first == '-h'
2
+ puts File.open(File.join(CORE_PATH, 'commands/USAGE-SERVER')).read
3
+ else
4
+ $:.unshift(Dir.pwd)
5
+
6
+ require File.join('config', 'application')
7
+ PakyowApplication::Application.run(ARGV.first)
8
+ end
@@ -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