pakyow-core 0.8rc1 → 0.8.rc4

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 (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