pakyow-core 0.8rc1 → 0.8.rc4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/pakyow-core/lib/core/app.rb +448 -0
  3. data/pakyow-core/lib/core/base.rb +35 -12
  4. data/pakyow-core/lib/core/{configuration → config}/app.rb +38 -35
  5. data/pakyow-core/lib/core/config/base.rb +30 -0
  6. data/pakyow-core/lib/core/config/cookies.rb +21 -0
  7. data/pakyow-core/lib/core/config/logger.rb +37 -0
  8. data/pakyow-core/lib/core/{configuration → config}/server.rb +3 -1
  9. data/pakyow-core/lib/core/exceptions.rb +3 -0
  10. data/pakyow-core/lib/core/helpers.rb +20 -16
  11. data/pakyow-core/lib/core/loader.rb +1 -1
  12. data/pakyow-core/lib/core/middleware/logger.rb +170 -16
  13. data/pakyow-core/lib/core/middleware/static.rb +20 -8
  14. data/pakyow-core/lib/core/multilog.rb +19 -0
  15. data/pakyow-core/lib/core/request.rb +52 -30
  16. data/pakyow-core/lib/core/route_eval.rb +390 -0
  17. data/pakyow-core/lib/core/route_lookup.rb +17 -5
  18. data/pakyow-core/lib/core/route_set.rb +17 -210
  19. data/pakyow-core/lib/core/route_template_defaults.rb +18 -12
  20. data/pakyow-core/lib/core/router.rb +41 -31
  21. data/pakyow-core/lib/utils/dir.rb +19 -0
  22. data/pakyow-core/lib/utils/hash.rb +14 -4
  23. data/pakyow-core/lib/views/errors/404.html +77 -0
  24. data/pakyow-core/lib/views/errors/500.html +56 -0
  25. metadata +30 -53
  26. data/pakyow-core/bin/pakyow +0 -18
  27. data/pakyow-core/lib/commands/USAGE +0 -9
  28. data/pakyow-core/lib/commands/USAGE-CONSOLE +0 -12
  29. data/pakyow-core/lib/commands/USAGE-NEW +0 -11
  30. data/pakyow-core/lib/commands/USAGE-SERVER +0 -12
  31. data/pakyow-core/lib/commands/console.rb +0 -18
  32. data/pakyow-core/lib/commands/server.rb +0 -8
  33. data/pakyow-core/lib/core/application.rb +0 -330
  34. data/pakyow-core/lib/core/cache.rb +0 -25
  35. data/pakyow-core/lib/core/configuration/base.rb +0 -31
  36. data/pakyow-core/lib/core/fn_context.rb +0 -5
  37. data/pakyow-core/lib/core/log.rb +0 -39
  38. data/pakyow-core/lib/core/middleware/not_found.rb +0 -40
  39. data/pakyow-core/lib/core/middleware/presenter.rb +0 -25
  40. data/pakyow-core/lib/core/middleware/router.rb +0 -33
  41. data/pakyow-core/lib/core/middleware/setup.rb +0 -15
  42. data/pakyow-core/lib/core/presenter_base.rb +0 -11
  43. data/pakyow-core/lib/core/route_template.rb +0 -77
  44. data/pakyow-core/lib/generators/pakyow/app/app_generator.rb +0 -36
  45. data/pakyow-core/lib/generators/pakyow/app/templates/README +0 -54
  46. data/pakyow-core/lib/generators/pakyow/app/templates/app.rb +0 -12
  47. data/pakyow-core/lib/generators/pakyow/app/templates/config.ru +0 -3
  48. data/pakyow-core/lib/generators/pakyow/app/templates/public/favicon.ico +0 -0
  49. data/pakyow-core/lib/generators/pakyow/app/templates/rakefile +0 -2
  50. data/pakyow-core/lib/generators/pakyow/app/templates/views/main.html +0 -1
  51. data/pakyow-core/lib/generators/pakyow/app/templates/views/pakyow.html +0 -12
@@ -1,330 +0,0 @@
1
- module Pakyow
2
- class Application
3
- class << self
4
- attr_accessor :core_proc, :middleware_proc, :middlewares, :configurations
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 = StringUtils.parse_path_from_caller(caller[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
- return if running?
18
-
19
- @running = true
20
- self.builder.run(self.prepare(args))
21
- detect_handler.run(builder, :Host => Pakyow::Configuration::Base.server.host, :Port => Pakyow::Configuration::Base.server.port) do |server|
22
- trap(:INT) { stop(server) }
23
- trap(:TERM) { stop(server) }
24
- end
25
- end
26
-
27
- # Stages the application. Everything is loaded but the application is
28
- # not started. Accepts the same arguments as #run.
29
- #
30
- def stage(*args)
31
- return if staged?
32
- @staged = true
33
- prepare(args)
34
- end
35
-
36
- def builder
37
- @builder ||= Rack::Builder.new
38
- end
39
-
40
- def prepared?
41
- @prepared
42
- end
43
-
44
- # Returns true if the application is running.
45
- #
46
- def running?
47
- @running
48
- end
49
-
50
- # Returns true if the application is staged.
51
- #
52
- def staged?
53
- @staged
54
- end
55
-
56
- # Convenience method for base configuration class.
57
- #
58
- def config
59
- Pakyow::Configuration::Base
60
- end
61
-
62
- # Creates configuration for a particular environment. Example:
63
- # configure(:development) { app.auto_reload = true }
64
- #
65
- def configure(environment, &block)
66
- self.configurations ||= {}
67
- self.configurations[environment] = block
68
- end
69
-
70
- # The block that stores routes, handlers, and hooks.
71
- #
72
- def core(&block)
73
- self.core_proc = block
74
- end
75
-
76
- # The block that stores presenter related things.
77
- #
78
- def presenter(&block)
79
- Configuration::Base.app.presenter.proc = block
80
- end
81
-
82
- def middleware(&block)
83
- self.middleware_proc = block
84
- end
85
-
86
- def before(step, middlewares)
87
- middlewares = [middlewares] unless middlewares.is_a?(Array)
88
- step = step.to_sym
89
-
90
- self.middlewares ||= {}
91
- self.middlewares[step] ||= {}
92
- (self.middlewares[step][:before] ||= []).concat(middlewares)
93
- end
94
-
95
- def after(step, middlewares)
96
- middlewares = [middlewares] unless middlewares.is_a?(Array)
97
- step = step.to_sym
98
-
99
- self.middlewares ||= {}
100
- self.middlewares[step] ||= {}
101
- (self.middlewares[step][:after] ||= []).concat(middlewares)
102
- end
103
-
104
- def use(step, type, builder)
105
- return unless self.middlewares
106
- return unless self.middlewares[step]
107
- return unless self.middlewares[step][type]
108
-
109
- self.middlewares[step][type].each { |m|
110
- builder.use(m)
111
- }
112
- end
113
-
114
-
115
- protected
116
-
117
- # Prepares the application for running or staging and returns an instance
118
- # of the application.
119
- def prepare(args)
120
- self.load_config args.empty? || args.first.nil? ? [Configuration::Base.app.default_environment] : args
121
- return if prepared?
122
-
123
- self.builder.use(Rack::MethodOverride)
124
-
125
- self.builder.use(Pakyow::Middleware::Setup)
126
-
127
- #TODO possibly deprecate
128
- self.builder.instance_eval(&self.middleware_proc) if self.middleware_proc
129
-
130
- self.builder.use(Pakyow::Middleware::Static) if Configuration::Base.app.static
131
- self.builder.use(Pakyow::Middleware::Logger) if Configuration::Base.app.log
132
- self.builder.use(Pakyow::Middleware::Reloader) if Configuration::Base.app.auto_reload
133
-
134
- if Configuration::Base.app.presenter
135
- self.use(:presentation, :before, self.builder)
136
- self.builder.use(Pakyow::Middleware::Presenter)
137
- self.use(:presentation, :after, self.builder)
138
- end
139
-
140
- unless Configuration::Base.app.ignore_routes
141
- self.use(:routing, :before, self.builder)
142
- self.builder.use(Pakyow::Middleware::Router)
143
- self.use(:routing, :after, self.builder)
144
- end
145
-
146
- self.builder.use(Pakyow::Middleware::NotFound) # always
147
-
148
- @prepared = true
149
-
150
- $:.unshift(Dir.pwd) unless $:.include? Dir.pwd
151
- return self.new
152
- end
153
-
154
- def load_config(args)
155
- if self.configurations
156
- args << Configuration::Base.app.default_environment if args.empty?
157
- args.each do |env|
158
- next unless config = self.configurations[env.to_sym]
159
- Configuration::Base.instance_eval(&config)
160
- end
161
- end
162
- end
163
-
164
- def detect_handler
165
- handlers = ['thin', 'mongrel', 'webrick']
166
- handlers.unshift(Configuration::Base.server.handler) if Configuration::Base.server.handler
167
-
168
- handlers.each do |handler|
169
- begin
170
- return Rack::Handler.get(handler)
171
- rescue LoadError
172
- rescue NameError
173
- end
174
- end
175
- end
176
-
177
- def stop(server)
178
- if server.respond_to?('stop!')
179
- server.stop!
180
- elsif server.respond_to?('stop')
181
- server.stop
182
- else
183
- # exit ungracefully if necessary...
184
- Process.exit!
185
- end
186
- end
187
- end
188
-
189
- include Helpers
190
-
191
- attr_accessor :request, :response, :presenter, :router
192
-
193
- def initialize
194
- Pakyow.app = self
195
-
196
- Pakyow.app.presenter = Configuration::Base.app.presenter.instance if Configuration::Base.app.presenter
197
-
198
- # Load application files
199
- load_app(false)
200
-
201
- # Prepare for logging
202
- Log.reopen
203
- end
204
-
205
- def setup_rr(env)
206
- self.request = Request.new(env)
207
- self.response = Response.new
208
- end
209
-
210
- # Called on every request.
211
- #
212
- def call(env)
213
- finish
214
- end
215
-
216
- # This is NOT a useless method, it's a part of the external api
217
- def reload
218
- load_app
219
- end
220
-
221
-
222
- # APP ACTIONS
223
-
224
- # Interrupts the application and returns response immediately.
225
- #
226
- def halt
227
- throw :halt, response
228
- end
229
-
230
- # Routes the request to different logic.
231
- #
232
- def reroute(path, method = nil)
233
- self.request.setup(path, method)
234
-
235
- begin
236
- # caught by other middleware (e.g. presenter) that does something with the
237
- # new request then hands it back down to the router
238
- throw :rerouted, request
239
- rescue ArgumentError
240
- # nobody caught it, so tell the router to reroute
241
- app.router.reroute!(request)
242
- end
243
- end
244
-
245
- # Sends data in the response (immediately). Accepts a string of data or a File,
246
- # mime-type (auto-detected; defaults to octet-stream), and optional file name.
247
- #
248
- # If a File, mime type will be guessed. Otherwise mime type and file name will
249
- # default to whatever is set in the response.
250
- #
251
- def send(file_or_data, type = nil, send_as = nil)
252
- case file_or_data.class
253
- when File
254
- data = File.open(path, "r").each_line { |line| data << line }
255
-
256
- # auto set type based on file type
257
- type = Rack::Mime.mime_type("." + StringUtils.split_at_last_dot(File.path))[1]
258
- else
259
- data = file_or_data
260
- end
261
-
262
- headers = {}
263
- headers["Content-Type"] = type if type
264
- headers["Content-disposition"] = "attachment; filename=#{send_as}" if send_as
265
-
266
- app.response = Rack::Response.new(data, response.status, response.header.merge(headers))
267
- halt
268
- end
269
-
270
- # Redirects to location (immediately).
271
- #
272
- def redirect(location, status_code = 302)
273
- headers = response ? response.header : {}
274
- headers = headers.merge({'Location' => location})
275
-
276
- app.response = Rack::Response.new('', status_code, headers)
277
- halt
278
- end
279
-
280
- def handle(name_or_code)
281
- app.router.handle!(name_or_code, true)
282
- end
283
-
284
- protected
285
-
286
- #TODO need configuration options for cookies (plus ability to override for each?)
287
- def set_cookies
288
- if self.request.cookies && self.request.cookies != {}
289
- self.request.cookies.each do |key, value|
290
- if value.nil?
291
- self.response.set_cookie(key, {:path => '/', :expires => Time.now + 604800 * -1 }.merge({:value => value}))
292
- elsif value.is_a?(Hash)
293
- self.response.set_cookie(key, {:path => '/', :expires => Time.now + 604800}.merge(value))
294
- else
295
- self.response.set_cookie(key, {:path => '/', :expires => Time.now + 604800}.merge({:value => value}))
296
- end
297
- end
298
- end
299
- end
300
-
301
- # Reloads all application files in application_path and presenter (if specified).
302
- #
303
- def load_app(reload_app = true)
304
- load(Configuration::App.application_path) if reload_app
305
-
306
- @loader = Loader.new unless @loader
307
- @loader.load_from_path(Configuration::Base.app.src_dir)
308
-
309
- self.load_core
310
- self.presenter.load if self.presenter
311
- end
312
-
313
- # Evaluates core_proc
314
- #
315
- def load_core
316
- @router = Router.instance.reset
317
-
318
- @router.set(:default, &self.class.core_proc) if self.class.core_proc
319
- end
320
-
321
- # Send the response and cleanup.
322
- #
323
- #TODO remove exclamation
324
- def finish
325
- set_cookies
326
- self.response.finish
327
- end
328
-
329
- end
330
- end
@@ -1,25 +0,0 @@
1
- module Pakyow
2
- class Cache
3
- def initialize
4
- @store = {}
5
- end
6
-
7
- def put(key, v)
8
- @store[key] = v
9
- end
10
-
11
- def get(key, &block)
12
- v = @store[key]
13
- if v == nil && block_given?
14
- v = block.call(key)
15
- @store[key] = v
16
- end
17
- v
18
- end
19
-
20
- def invalidate(key)
21
- put(key, nil)
22
- end
23
-
24
- end
25
- end
@@ -1,31 +0,0 @@
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.to_sym == :'@application_path'
25
- klass.send("#{var.to_s.gsub('@', '')}=", nil)
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,5 +0,0 @@
1
- module Pakyow
2
- class FnContext
3
- include Helpers
4
- end
5
- end
@@ -1,39 +0,0 @@
1
- module Pakyow
2
-
3
- # Provides an easy way to log text, warnings, etc.
4
- class Log
5
- # Opens stdout and the log file for writing.
6
- def self.reopen
7
- @@console = $stdout
8
-
9
- d = Configuration::Base.app.log_dir
10
- @@file = File.exists?(d) ? File.open("#{d}/#{Configuration::Base.app.log_name}", 'a') : nil
11
- end
12
-
13
- def self.close
14
- @@file.close if @@file
15
- end
16
-
17
- # Adds text to the log.
18
- def self.puts(text = "")
19
- return if !Configuration::Base.app.log
20
-
21
- @@console << "#{text}\r\n"
22
- @@file.write "#{text}\r\n" if @@file
23
- end
24
-
25
- class << self
26
- alias :enter :puts
27
- end
28
-
29
- # Adds warning text to the log.
30
- def self.warn(text)
31
- Log.enter("WARNING: #{text}")
32
- end
33
-
34
- # Adds error text to the log.
35
- def self.error(text)
36
- Log.enter("ERROR: #{text}")
37
- end
38
- end
39
- end
@@ -1,40 +0,0 @@
1
- module Pakyow
2
- module Middleware
3
- class NotFound
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- @app.call(env)
10
-
11
- # 404 if no route matched and no views were found
12
- unless found?
13
- Log.enter "[404] Not Found"
14
-
15
- Pakyow.app.response.body = []
16
- Pakyow.app.presenter.reset if Pakyow.app.presenter
17
-
18
- Pakyow.app.response.status = 404
19
- Pakyow.app.router.handle!(404)
20
-
21
- if Pakyow.app.presenter
22
- # consider moving to presenter middleware
23
- # Pakyow.app.presenter.prepare_for_request(Pakyow.app.request)
24
- Pakyow.app.response.body = [Pakyow.app.presenter.content] if Pakyow.app.presenter.presented?
25
- end
26
- end
27
- end
28
-
29
- private
30
-
31
- def found?
32
- return true if Pakyow.app.router.routed?
33
- return true if Pakyow.app.presenter && Pakyow.app.presenter.presented? && Configuration::App.all_views_visible
34
-
35
- false
36
- end
37
- end
38
- end
39
- end
40
-
@@ -1,25 +0,0 @@
1
- module Pakyow
2
- module Middleware
3
- class Presenter
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- r = Pakyow.app.request
10
-
11
- while(r) do
12
- Pakyow.app.presenter.prepare_for_request(Pakyow.app.request)
13
-
14
- r = catch(:rerouted) {
15
- @app.call(@env)
16
- nil
17
- }
18
- end
19
- #TODO the right thing to do?
20
- Pakyow.app.response.body = [Pakyow.app.presenter.content] if Pakyow.app.presenter.presented?
21
- Pakyow.app.response.finish
22
- end
23
- end
24
- end
25
- end
@@ -1,33 +0,0 @@
1
- module Pakyow
2
- module Middleware
3
- class Router
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- catch(:halt) {
10
- Pakyow.app.router.route!(Pakyow.app.request)
11
- @app.call(env)
12
- }
13
- rescue StandardError => error
14
- Pakyow.app.request.error = error
15
-
16
- Pakyow.app.response.status = 500
17
- Pakyow.app.router.handle!(500)
18
-
19
- if Configuration::Base.app.errors_in_browser
20
- Pakyow.app.response.body = []
21
- Pakyow.app.response.body << "<h4>#{CGI.escapeHTML(error.to_s)}</h4>"
22
- Pakyow.app.response.body << error.backtrace.join("<br />")
23
- end
24
-
25
- begin
26
- # caught by other middleware (e.g. logger)
27
- throw :error, error
28
- rescue ArgumentError
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,15 +0,0 @@
1
- module Pakyow
2
- module Middleware
3
- class Setup
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- #TODO don't track r/r on app; pass through middleware instead (or call in a context that has access to current r/r)
10
- Pakyow.app.setup_rr(env)
11
- @app.call(env)
12
- end
13
- end
14
- end
15
- end
@@ -1,11 +0,0 @@
1
- module Pakyow
2
- class PresenterBase
3
- def self.inherited(subclass)
4
- Configuration::Base.app.presenter = subclass
5
- end
6
-
7
- def self.instance
8
- @@instance ||= self.new
9
- end
10
- end
11
- end
@@ -1,77 +0,0 @@
1
- #TODO rename router to set and .func to .fn
2
-
3
- module Pakyow
4
- class RouteTemplate
5
- attr_accessor :path
6
-
7
- def initialize(block, g_name, path, router)
8
- @fns = {}
9
- @g_name = g_name
10
- @path = path
11
- @router = router
12
-
13
- self.instance_exec(&block)
14
- end
15
-
16
- def action(method, *args, &block)
17
- fns = block_given? ? [block] : args[0]
18
- @fns[method] = fns
19
- end
20
-
21
- def expand(template, data)
22
- @expanding = true
23
-
24
- t = self
25
- if @path
26
- @router.namespace(@path, @g_name) {
27
- t.instance_exec(data, &template)
28
- }
29
- else
30
- @router.group(@g_name) {
31
- t.instance_exec(data, &template)
32
- }
33
- end
34
- end
35
-
36
- def fn(name)
37
- @expanding ? @fns[name] : @router.func(name)
38
- end
39
-
40
- def call(controller, action)
41
- @router.call(controller, action)
42
- end
43
-
44
- def get(*args, &block)
45
- @router.get(*args, &block)
46
- end
47
-
48
- def put(*args, &block)
49
- @router.put(*args, &block)
50
- end
51
-
52
- def post(*args, &block)
53
- @router.post(*args, &block)
54
- end
55
-
56
- def delete(*args, &block)
57
- @router.delete(*args, &block)
58
- end
59
-
60
- #TODO best name?
61
- def map_actions(controller, actions)
62
- actions.each { |a|
63
- self.action(a, self.call(controller, a))
64
- }
65
- end
66
-
67
- #TODO best name?
68
- def map_restful_actions(controller)
69
- self.map_actions(controller, self.restful_actions)
70
- end
71
-
72
- def restful_actions
73
- [:index, :show, :new, :create, :edit, :update, :delete]
74
- end
75
- end
76
- end
77
-
@@ -1,36 +0,0 @@
1
- require 'fileutils'
2
-
3
- module Pakyow
4
- module Generators
5
- class AppGenerator
6
- class << self
7
- def start
8
- case ARGV.first
9
- when '--help', '-h', nil
10
- puts File.open(File.join(CORE_PATH, 'commands/USAGE-NEW')).read
11
- else
12
- generator = self.new
13
- generator.build(ARGV.first)
14
- end
15
- end
16
- end
17
-
18
- def initialize
19
- @src = "#{File.expand_path('../', __FILE__)}/templates/."
20
- end
21
-
22
- def build(dest)
23
- if !File.directory?(dest) || (Dir.entries(dest) - ['.', '..']).empty?
24
- FileUtils.cp_r(@src, dest)
25
- else
26
- ARGV.clear
27
- print "The folder '#{dest}' is in use. Would you like to populate it anyway? [Yn] "
28
-
29
- if gets.chomp! == 'Y'
30
- FileUtils.cp_r(@src, dest)
31
- end
32
- end
33
- end
34
- end
35
- end
36
- end