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
@@ -0,0 +1,37 @@
1
+ module Pakyow
2
+ module Config
3
+ class Logger
4
+ Config::Base.register_config(:logger, self)
5
+
6
+ class << self
7
+ attr_accessor :path, :name, :sync, :colorize, :auto_flush, :level
8
+
9
+ # Path to logs
10
+ def path
11
+ @path || "#{Config::Base.app.root}/logs"
12
+ end
13
+
14
+ def name
15
+ @name || "requests.log"
16
+ end
17
+
18
+ def sync
19
+ instance_variable_defined?(:@sync) ? @sync : true
20
+ end
21
+
22
+ def auto_flush
23
+ instance_variable_defined?(:@auto_flush) ? @auto_flush : true
24
+ end
25
+
26
+ def colorize
27
+ instance_variable_defined?(:@colorize) ? @colorize : true
28
+ end
29
+
30
+ def level
31
+ @level || Pakyow::Logger::LEVELS[:debug]
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,6 +1,8 @@
1
1
  module Pakyow
2
- module Configuration
2
+ module Config
3
3
  class Server
4
+ Config::Base.register_config(:server, self)
5
+
4
6
  class << self
5
7
  attr_accessor :port, :host, :handler
6
8
 
@@ -0,0 +1,3 @@
1
+ module Pakyow
2
+ class Error < StandardError; end
3
+ end
@@ -1,19 +1,25 @@
1
1
  module Pakyow
2
2
 
3
- # Helper methods that simply provide information (for use in binders)
4
- module GeneralHelpers
5
- def request
6
- Pakyow.app.request
7
- end
8
-
9
- def response
10
- Pakyow.app.response
3
+ # For methods that should be accessible anywhere
4
+ module Helpers
5
+ def logger
6
+ request.logger
11
7
  end
12
-
8
+
13
9
  def router
14
10
  RouteLookup.new
15
11
  end
16
12
 
13
+ def request
14
+ @request
15
+ end
16
+ alias_method :req, :request
17
+
18
+ def response
19
+ @response
20
+ end
21
+ alias_method :res, :response
22
+
17
23
  def params
18
24
  request.params
19
25
  end
@@ -25,14 +31,12 @@ module Pakyow
25
31
  def cookies
26
32
  request.cookies
27
33
  end
28
- end
29
34
 
30
- # Helper methods specific to delegates and controllers.
31
- module Helpers
32
- include GeneralHelpers
33
-
34
- def app
35
- Pakyow.app
35
+ def config
36
+ Pakyow::Config::Base
36
37
  end
37
38
  end
39
+
40
+ # For methods that should only be accessible through App
41
+ module AppHelpers; end
38
42
  end
@@ -17,7 +17,7 @@ module Pakyow
17
17
  next if FileTest.directory?(path)
18
18
  next if path.split('.')[-1] != 'rb'
19
19
 
20
- if Configuration::Base.app.auto_reload
20
+ if Config::Base.app.auto_reload
21
21
  if !@times[path] || (@times[path] && File.mtime(path) - @times[path] > 0)
22
22
  load(path)
23
23
  @times[path] = File.mtime(path)
@@ -1,28 +1,124 @@
1
+ module Pakyow
2
+ class Logger
3
+ LEVELS = {
4
+ :debug => 0,
5
+ :info => 1,
6
+ :warn => 2,
7
+ :error => 3,
8
+ :fatal => 4,
9
+ :unknown => 5,
10
+ }
11
+
12
+ LEVEL_COLORS = {
13
+ :debug => :cyan,
14
+ :info => :green,
15
+ :warn => :yellow,
16
+ :error => :red,
17
+ :fatal => :red,
18
+ # :unknown => nil,
19
+ }
20
+
21
+ COLOR_TABLE = [
22
+ :black,
23
+ :red,
24
+ :green,
25
+ :yellow,
26
+ :blue,
27
+ :magenta,
28
+ :cyan,
29
+ :white,
30
+ ]
31
+
32
+ RESET_SEQ = "\033[0m"
33
+ COLOR_SEQ = "\033[%dm"
34
+ BOLD_SEQ = "\033[1m"
35
+
36
+ def initialize(log = $stdout, level = 0, format = false, auto_flush = false)
37
+ @log, @level, @format, @auto_flush = log, level, format, auto_flush
38
+ @mutex = Mutex.new
39
+ end
40
+
41
+ def <<(msg = nil, severity = :unknown)
42
+ msg << "\n"
43
+
44
+ msg = format(msg, severity) if @format
45
+ @mutex.synchronize do
46
+ @log.write msg
47
+ @log.flush if @auto_flush
48
+ end
49
+ end
50
+
51
+ alias :write :<<
52
+
53
+ def add(severity, msg = nil)
54
+ severity ||= LEVELS[:unknown]
55
+ return if severity < @level
56
+
57
+ write(msg, severity)
58
+ end
59
+
60
+ alias :log :add
61
+
62
+ def debug(msg = nil)
63
+ add(LEVELS[:debug], msg)
64
+ end
65
+
66
+ def info(msg = nil)
67
+ add(LEVELS[:info], msg)
68
+ end
69
+
70
+ def warn(msg = nil)
71
+ add(LEVELS[:warn], msg)
72
+ end
73
+
74
+ def error(msg = nil)
75
+ add(LEVELS[:error], msg)
76
+ end
77
+
78
+ def fatal(msg = nil)
79
+ add(LEVELS[:fatal], msg)
80
+ end
81
+
82
+ def format(msg, level)
83
+ return msg unless color = level_color(level)
84
+ return COLOR_SEQ % (30 + COLOR_TABLE.index(color)) + msg + RESET_SEQ
85
+ end
86
+
87
+ def level_color(level)
88
+ LEVEL_COLORS[LEVELS.key(level)]
89
+ end
90
+
91
+ def close
92
+ @log.close
93
+ end
94
+
95
+ end
96
+ end
97
+
1
98
  module Pakyow
2
99
  module Middleware
3
100
  class Logger
101
+ # handles logging after an error occurs
102
+ Pakyow::App.after(:error) {
103
+ error = request.error
104
+ Pakyow.logger.error "[500] #{error}\n" + error.backtrace.join("\n") + "\n\n"
105
+ }
106
+
4
107
  def initialize(app)
5
108
  @app = app
6
109
  end
7
-
110
+
8
111
  def call(env)
112
+ env['rack.logger'] = Pakyow.logger
113
+
9
114
  result = nil
10
115
  difference = time { |began_at|
11
- Log.enter "Processing #{env['PATH_INFO']} (#{env['REMOTE_ADDR']} at #{began_at}) [#{env['REQUEST_METHOD']}]"
12
-
13
- if error = catch(:error) {
14
- result = @app.call(env)
15
- nil
16
- }
17
- Log.enter "[500] #{error}\n"
18
- Log.enter error.backtrace.join("\n") + "\n\n"
19
-
20
- result = Pakyow.app.response.finish
21
- end
116
+ Pakyow.logger << "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']} for #{env['REMOTE_ADDR']} at #{began_at}"
117
+ result = @app.call(env)
22
118
  }
23
-
24
- Log.enter "Completed in #{difference}ms | #{Pakyow.app.response.status} | [#{Pakyow.app.request.url}]"
25
- Log.enter
119
+
120
+ status = result[0]
121
+ Pakyow.logger << "#{status} (#{nice_status(status)}) in #{difference}ms\n"
26
122
 
27
123
  result
28
124
  end
@@ -30,7 +126,65 @@ module Pakyow
30
126
  def time
31
127
  s = Time.now
32
128
  yield(s)
33
- (Time.now.to_f - s.to_f) * 1000.0
129
+ time = ((Time.now.to_f - s.to_f) * 1000.0)
130
+ (time * 10**2).round / (10**2).to_f
131
+ end
132
+
133
+ def nice_status(status)
134
+ {
135
+ 100 => 'Continue',
136
+ 101 => 'Switching Protocols',
137
+
138
+ 200 => 'OK',
139
+ 201 => 'Created',
140
+ 202 => 'Accepted',
141
+ 203 => 'Non-Authoritative Information',
142
+ 204 => 'No Content',
143
+ 205 => 'Reset Content',
144
+ 206 => 'Partial Content',
145
+
146
+ 300 => 'Multiple Choices',
147
+ 301 => 'Moved Permanently',
148
+ 302 => 'Found',
149
+ 303 => 'See Other',
150
+ 304 => 'Not Modified',
151
+ 305 => 'Use Proxy',
152
+ 306 => 'Switch Proxy',
153
+ 307 => 'Temporary Redirect',
154
+
155
+ 400 => 'Bad Request',
156
+ 401 => 'Unauthorized',
157
+ 402 => 'Payment Required',
158
+ 403 => 'Forbidden',
159
+ 404 => 'Not Found',
160
+ 405 => 'Method Not Allowed',
161
+ 406 => 'Not Acceptable',
162
+ 407 => 'Proxy Authentication Required',
163
+ 408 => 'Request Timeout',
164
+ 409 => 'Conflict',
165
+ 410 => 'Gone',
166
+ 411 => 'Length Required',
167
+ 412 => 'Precondition Failed',
168
+ 413 => 'Request Entity Too Large',
169
+ 414 => 'Request-URI Too Long',
170
+ 415 => 'Unsupported Media Type',
171
+ 416 => 'Requested Range Not Satisfiable',
172
+ 417 => 'Expectation Failed',
173
+ 418 => 'I\'m a teapot',
174
+
175
+ 500 => 'Internal Server Error',
176
+ 501 => 'Not Implemented',
177
+ 502 => 'Bad Gateway',
178
+ 503 => 'Service Unavailable',
179
+ 504 => 'Gateway Timeout',
180
+ 505 => 'HTTP Version Not Supported',
181
+ 506 => 'Variant Also Negotiates',
182
+ 507 => 'Insufficient Storage',
183
+ 508 => 'Loop Detected',
184
+ 509 => 'Bandwidth Limit Exceeded',
185
+ 510 => 'Not Extended',
186
+ 511 => 'Network Authentication Required'
187
+ }[status] || '?'
34
188
  end
35
189
  end
36
190
  end
@@ -4,24 +4,36 @@ module Pakyow
4
4
  def initialize(app)
5
5
  @app = app
6
6
  end
7
-
7
+
8
8
  def call(env)
9
- if is_static?(env)
10
- response = Rack::Response.new
11
-
9
+ static, resource_path = is_static?(env)
10
+
11
+ if static
12
12
  catch(:halt) do
13
- Pakyow.app.send(File.open(File.join(Configuration::Base.app.public_dir, env['PATH_INFO'])))
13
+ app = Pakyow.app.dup
14
+ app.response = Response.new
15
+ app.request = Request.new(env)
16
+ app.send(File.open(resource_path))
14
17
  end
15
18
  else
16
19
  @app.call(env)
17
20
  end
18
21
  end
19
-
22
+
20
23
  private
21
-
24
+
22
25
  def is_static?(env)
23
- env['PATH_INFO'] =~ /\.(.*)$/ && File.exists?(File.join(Configuration::Base.app.public_dir, env['PATH_INFO']))
26
+ return false unless env['PATH_INFO'] =~ /\.(.*)$/
27
+
28
+ Config::App.resources.each_pair do |name, path|
29
+ resource_path = File.join(path, env['PATH_INFO'])
30
+ next unless File.exists?(resource_path)
31
+ return true, resource_path
32
+ end
33
+
34
+ return false
24
35
  end
25
36
  end
26
37
  end
27
38
  end
39
+
@@ -0,0 +1,19 @@
1
+ module Pakyow
2
+ class MultiLog
3
+ def initialize(*targets)
4
+ @targets = targets
5
+ end
6
+
7
+ def write(*args)
8
+ @targets.each { |t| t.write(*args) }
9
+ end
10
+
11
+ def close
12
+ @targets.each(&:close)
13
+ end
14
+
15
+ def flush
16
+ @targets.each(&:flush)
17
+ end
18
+ end
19
+ end
@@ -2,61 +2,81 @@ module Pakyow
2
2
 
3
3
  # The Request object.
4
4
  class Request < Rack::Request
5
- attr_accessor :restful, :route_path, :controller, :action, :format, :error, :working_path, :working_method
5
+ attr_accessor :restful, :route_path, :controller, :action, :format,
6
+ :error, :app, :path, :method, :paths, :methods, :formats
6
7
 
7
8
  def initialize(*args)
8
9
  super
9
10
 
10
- self.setup(self.path)
11
+ @paths = []
12
+ @methods = []
13
+ @formats = []
14
+
15
+ @path = path_info
16
+ @method = request_method.downcase.to_sym
11
17
  end
12
18
 
13
- # Easy access to path_info.
14
- def path
15
- self.path_info
19
+ def path=(path)
20
+ @paths << path
21
+ @path = path
16
22
  end
17
-
18
- # Determines the request method.
19
- def method
20
- request_method.downcase.to_sym
23
+
24
+ def method=(method)
25
+ @methods << method
26
+ @method = method
21
27
  end
22
28
 
23
29
  def format=(format)
24
- @format = format ? format.to_sym : :html
25
-
30
+ format = format ? format.to_sym : :html
31
+ @formats << format
32
+ @format = format
33
+
26
34
  # Set response type
27
- Pakyow.app.response["Content-Type"] = Rack::Mime.mime_type(".#{@format}")
35
+ @app.response["Content-Type"] = Rack::Mime.mime_type(".#{@format}")
36
+ end
37
+
38
+ def first_path
39
+ @paths[0]
40
+ end
41
+
42
+ def first_method
43
+ @methods[0]
44
+ end
45
+
46
+ def first_format
47
+ @formats[0]
28
48
  end
29
49
 
30
50
  def session
31
51
  self.env['rack.session'] || {}
32
52
  end
33
-
53
+
34
54
  def cookies
35
55
  @cookies ||= HashUtils.strhash(super)
36
56
  end
37
-
57
+
38
58
  # Returns indifferent params (see {HashUtils.strhash} for more info on indifferent hashes).
39
59
  def params
40
60
  @params ||= HashUtils.strhash(super)
41
61
  end
42
-
62
+
43
63
  # Returns array of url components.
44
64
  def path_parts
45
- @url ||= self.path ? self.class.split_url(self.path) : []
65
+ @url ||= path ? self.class.split_url(path) : []
46
66
  end
47
67
 
48
68
  def referer
49
- @referer ||= self.env['HTTP_REFERER']
69
+ @referer ||= env['HTTP_REFERER']
50
70
  end
51
-
71
+
52
72
  # Returns array of referer components.
53
73
  def referer_parts
54
- @referer_parts ||= self.referer ? self.class.split_url(self.referer) : []
74
+ @referer_parts ||= referer ? self.class.split_url(referer) : []
55
75
  end
56
76
 
57
- def setup(path, method = nil)
58
- self.set_request_format_from_path(path)
59
- self.set_working_path_from_path(path, method)
77
+ def setup(path = self.path, method = nil)
78
+ set_request_format_from_path(path)
79
+ set_working_path_from_path(path, method)
60
80
  end
61
81
 
62
82
  #TODO move to util class
@@ -65,25 +85,27 @@ module Pakyow
65
85
  url.split('/').each { |r|
66
86
  arr << r unless r.empty?
67
87
  }
68
-
88
+
69
89
  return arr
70
90
  end
71
-
91
+
92
+ def has_route_vars?
93
+ return false if @route_path.nil?
94
+ return false if @route_path.is_a?(Regexp)
95
+ return true if @route_path.index(':')
96
+ end
97
+
72
98
  protected
73
99
 
74
100
  def set_working_path_from_path(path, method)
75
101
  base_route, ignore_format = StringUtils.split_at_last_dot(path)
76
102
 
77
- self.working_path = base_route
78
- self.working_method = method || self.method
103
+ self.path = base_route
104
+ self.method = method || self.method
79
105
  end
80
106
 
81
107
  def set_request_format_from_path(path)
82
108
  path, format = StringUtils.split_at_last_dot(path)
83
-
84
- #TODO why it no work without this? was working fine in application
85
- return unless format
86
-
87
109
  self.format = ((format && (format[format.length - 1, 1] == '/')) ? format[0, format.length - 1] : format)
88
110
  end
89
111
  end