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