waves 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- data/app/Rakefile +4 -0
- data/app/configurations/default.rb.erb +8 -0
- data/app/configurations/development.rb.erb +22 -0
- data/app/configurations/mapping.rb.erb +49 -0
- data/app/configurations/production.rb.erb +25 -0
- data/app/controllers/default.rb.erb +39 -0
- data/app/doc/EMTPY +0 -0
- data/app/helpers/default.rb.erb +13 -0
- data/app/lib/application.rb.erb +52 -0
- data/app/lib/startup.rb.erb +2 -0
- data/app/lib/tasks/cluster.rb +26 -0
- data/app/lib/tasks/schema.rb +28 -0
- data/app/models/default.rb.erb +13 -0
- data/app/schema/migration/templates/empty.rb.erb +9 -0
- data/app/templates/errors/not_found.mab +2 -0
- data/app/templates/errors/server_error.mab +2 -0
- data/app/templates/layouts/default.mab +14 -0
- data/app/views/default.rb.erb +13 -0
- data/bin/waves +32 -0
- data/bin/waves-console +8 -0
- data/bin/waves-server +45 -0
- data/lib/controllers/mixin.rb +62 -0
- data/lib/dispatchers/base.rb +41 -0
- data/lib/dispatchers/default.rb +33 -0
- data/lib/helpers/common.rb +22 -0
- data/lib/helpers/form.rb +22 -0
- data/lib/helpers/formatting.rb +22 -0
- data/lib/helpers/model.rb +15 -0
- data/lib/helpers/view.rb +14 -0
- data/lib/renderers/erubis.rb +38 -0
- data/lib/renderers/markaby.rb +31 -0
- data/lib/renderers/mixin.rb +41 -0
- data/lib/runtime/application.rb +43 -0
- data/lib/runtime/configuration.rb +47 -0
- data/lib/runtime/console.rb +21 -0
- data/lib/runtime/logger.rb +28 -0
- data/lib/runtime/mapping.rb +82 -0
- data/lib/runtime/mime_types.rb +18 -0
- data/lib/runtime/request.rb +43 -0
- data/lib/runtime/response.rb +26 -0
- data/lib/runtime/response_mixin.rb +53 -0
- data/lib/runtime/response_proxy.rb +29 -0
- data/lib/runtime/server.rb +58 -0
- data/lib/runtime/session.rb +43 -0
- data/lib/utilities/integer.rb +8 -0
- data/lib/utilities/kernel.rb +8 -0
- data/lib/utilities/module.rb +7 -0
- data/lib/utilities/object.rb +13 -0
- data/lib/utilities/string.rb +36 -0
- data/lib/utilities/symbol.rb +5 -0
- data/lib/views/mixin.rb +54 -0
- data/lib/waves.rb +50 -0
- metadata +189 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
class Console < Application
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
attr_reader :console
|
8
|
+
|
9
|
+
def load(mode=:development)
|
10
|
+
@console ||= Waves::Console.new(mode)
|
11
|
+
Kernel.load( :lib / 'startup.rb' )
|
12
|
+
end
|
13
|
+
|
14
|
+
# allow Waves::Console to act as The Console Instance
|
15
|
+
def method_missing(*args); @console.send(*args); end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'logger'
|
2
|
+
module Waves
|
3
|
+
|
4
|
+
module Logger
|
5
|
+
|
6
|
+
# Initializes the logger based on the config, and then adds Waves#log.
|
7
|
+
|
8
|
+
def self.start
|
9
|
+
config = Waves::Server.config
|
10
|
+
output = ( config.log[:output] || $stderr )
|
11
|
+
level = ::Logger.const_get( config.log[:level].to_s.upcase || 'INFO' )
|
12
|
+
@log = if config.log(:rotation)
|
13
|
+
::Logger.new( output, config.log[:rotation].intern );
|
14
|
+
else
|
15
|
+
::Logger.new( output );
|
16
|
+
end
|
17
|
+
@log.level = level
|
18
|
+
end
|
19
|
+
|
20
|
+
# delegate everything to the logger
|
21
|
+
def self.method_missing(name,*args,&block)
|
22
|
+
@log.send name,*args, &block
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
module Mapping
|
4
|
+
|
5
|
+
def before( pattern, options=nil, &block )
|
6
|
+
filters[:before] << [ pattern, options, block ]
|
7
|
+
end
|
8
|
+
|
9
|
+
def after( pattern, options=nil, &block )
|
10
|
+
filters[:after] << [ pattern, options, block ]
|
11
|
+
end
|
12
|
+
|
13
|
+
def wrap( pattern, options=nil, &block )
|
14
|
+
filters[:before] << [ pattern, options, block ]
|
15
|
+
filters[:after] << [ pattern, options, block ]
|
16
|
+
end
|
17
|
+
|
18
|
+
def map( options, &block )
|
19
|
+
pattern = options[:path] || options[:url]
|
20
|
+
mapping << [ pattern, options, block ]
|
21
|
+
end
|
22
|
+
|
23
|
+
def path( pat, options = {}, &block )
|
24
|
+
options[:path] = pat; map( options, &block )
|
25
|
+
end
|
26
|
+
|
27
|
+
def url( pat, options = {}, &block )
|
28
|
+
options[:url] = pat; map( options, block )
|
29
|
+
end
|
30
|
+
|
31
|
+
def []( request )
|
32
|
+
|
33
|
+
rx = { :before => [], :after => [], :action => nil }
|
34
|
+
|
35
|
+
( filters[:before] + filters[:wrap] ).each do | pattern, options, function |
|
36
|
+
matches = pattern.match(request.path)
|
37
|
+
rx[:before] << [ function, matches[1..-1] ] if matches &&
|
38
|
+
( ! options || satisfy( request, options ))
|
39
|
+
end
|
40
|
+
|
41
|
+
mapping.find do |pattern, options, function|
|
42
|
+
matches = pattern.match(request.path)
|
43
|
+
rx[:action] = [ function, matches[1..-1] ] if matches &&
|
44
|
+
( ! options || satisfy( request, options ) )
|
45
|
+
end
|
46
|
+
|
47
|
+
( filters[:after] + filters[:wrap] ).each do | pattern, options, function |
|
48
|
+
matches = pattern.match(request.path)
|
49
|
+
rx[:after] << [ function, matches[1..-1] ] if matches &&
|
50
|
+
( ! options || satisfy( request, options ))
|
51
|
+
end
|
52
|
+
|
53
|
+
not_found(request) unless rx[:action]
|
54
|
+
|
55
|
+
return rx
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def mapping; @mapping ||= []; end
|
62
|
+
|
63
|
+
def filters; @filters ||= { :before => [], :after => [], :wrap => [] }; end
|
64
|
+
|
65
|
+
def not_found(request)
|
66
|
+
raise Waves::Dispatchers::NotFoundError.new( request.url + ' not found.')
|
67
|
+
end
|
68
|
+
|
69
|
+
def satisfy( request, options )
|
70
|
+
options.each do |method, param|
|
71
|
+
return false unless self.send( method, param, request )
|
72
|
+
end
|
73
|
+
return true
|
74
|
+
end
|
75
|
+
|
76
|
+
def method( method, request )
|
77
|
+
request.method == method
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Waves
|
2
|
+
module MimeTypes
|
3
|
+
|
4
|
+
def self.[]( path )
|
5
|
+
mapping[ File.extname( path ) ]
|
6
|
+
end
|
7
|
+
|
8
|
+
# TODO: why isn't this working?
|
9
|
+
# def self.<<( mapping )
|
10
|
+
# mapping.merge!( mapping )
|
11
|
+
# end
|
12
|
+
|
13
|
+
def self.mapping
|
14
|
+
@mapping ||= Mongrel::DirHandler::MIME_TYPES
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Waves
|
2
|
+
class Request
|
3
|
+
|
4
|
+
class ParseError < Exception ; end
|
5
|
+
|
6
|
+
attr_reader :response, :session
|
7
|
+
|
8
|
+
def initialize( env ) # Rack::Request
|
9
|
+
@request = Rack::Request.new( env )
|
10
|
+
@response = Waves::Response.new( self )
|
11
|
+
@session = Waves::Session.new( self )
|
12
|
+
end
|
13
|
+
|
14
|
+
# if we haven't overridden it, give it to Rack
|
15
|
+
def method_missing(name,*args)
|
16
|
+
@request.send(name,*args)
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO: should / does this exclude the query_string?
|
20
|
+
# Is there a Rack API that is more appropos
|
21
|
+
def path
|
22
|
+
@request.path_info
|
23
|
+
end
|
24
|
+
|
25
|
+
def domain
|
26
|
+
@request.host
|
27
|
+
end
|
28
|
+
|
29
|
+
def method
|
30
|
+
@request.request_method.downcase.intern
|
31
|
+
end
|
32
|
+
|
33
|
+
def not_found
|
34
|
+
raise Waves::Dispatchers::NotFoundError.new( @request.url + ' not found.')
|
35
|
+
end
|
36
|
+
|
37
|
+
def redirect( path )
|
38
|
+
raise Waves::Dispatchers::Redirect.new( path )
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Waves
|
2
|
+
class Response
|
3
|
+
|
4
|
+
attr_reader :request
|
5
|
+
|
6
|
+
def initialize( request )
|
7
|
+
@request = request
|
8
|
+
@response = Rack::Response.new
|
9
|
+
end
|
10
|
+
|
11
|
+
%w( Content-Type Content-Length Location Expires ).each do |header|
|
12
|
+
define_method( header.downcase.gsub('-','_')+ '=' ) do | val |
|
13
|
+
@response.headers[header] = val
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def session ; request.session ; end
|
18
|
+
|
19
|
+
def finish ; request.session.save ; @response.finish ; end
|
20
|
+
|
21
|
+
def method_missing(name,*args)
|
22
|
+
@response.send(name,*args)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
module ResponseMixin
|
4
|
+
|
5
|
+
# assumes request method
|
6
|
+
|
7
|
+
def response
|
8
|
+
request.response
|
9
|
+
end
|
10
|
+
|
11
|
+
def params
|
12
|
+
request.params
|
13
|
+
end
|
14
|
+
|
15
|
+
def session
|
16
|
+
request.session
|
17
|
+
end
|
18
|
+
|
19
|
+
def path
|
20
|
+
request.path
|
21
|
+
end
|
22
|
+
|
23
|
+
def url
|
24
|
+
request.url
|
25
|
+
end
|
26
|
+
|
27
|
+
def domain
|
28
|
+
request.domain
|
29
|
+
end
|
30
|
+
|
31
|
+
def redirect(location)
|
32
|
+
request.redirect(location)
|
33
|
+
end
|
34
|
+
|
35
|
+
def models
|
36
|
+
Waves.application.models
|
37
|
+
end
|
38
|
+
|
39
|
+
def views
|
40
|
+
Waves.application.views
|
41
|
+
end
|
42
|
+
|
43
|
+
def controllers
|
44
|
+
Waves.application.controllers
|
45
|
+
end
|
46
|
+
|
47
|
+
def not_found
|
48
|
+
request.not_found
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
class ResponseProxy
|
4
|
+
|
5
|
+
attr_reader :request
|
6
|
+
|
7
|
+
include ResponseMixin
|
8
|
+
|
9
|
+
def initialize(request); @request = request; end
|
10
|
+
|
11
|
+
def use( model ) ; @model = model ; self ; end
|
12
|
+
|
13
|
+
def controller( &block )
|
14
|
+
Waves.application.controllers[ @model ].process( @request, &block )
|
15
|
+
end
|
16
|
+
|
17
|
+
def view( &block )
|
18
|
+
Waves.application.views[ @model ].process( @request, @value, &block )
|
19
|
+
end
|
20
|
+
|
21
|
+
def |( val ); @value = val; self; end
|
22
|
+
|
23
|
+
def to_s; @value ; end
|
24
|
+
|
25
|
+
def redirect(path); @request.redirect(path); end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
class Server < Application
|
4
|
+
|
5
|
+
attr_reader :thread
|
6
|
+
|
7
|
+
def start
|
8
|
+
load( :lib / 'startup.rb' )
|
9
|
+
Waves::Logger.start
|
10
|
+
log.info "** Waves Server Starting ..."
|
11
|
+
|
12
|
+
t = Benchmark.realtime do
|
13
|
+
app = config.application.to_app
|
14
|
+
@server = ::Mongrel::HttpServer.new( config.host, config.port )
|
15
|
+
@server.register('/', Rack::Handler::Mongrel.new( app ) )
|
16
|
+
trap('INT') { puts; stop }
|
17
|
+
@thread = @server.run
|
18
|
+
end
|
19
|
+
log.info "** Waves Server Running on #{config.host}:#{config.port}"
|
20
|
+
log.info "Server started in #{(t*1000).round} milliseconds."
|
21
|
+
@thread.join
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
log.info "** Waves Server Stopping ..."
|
26
|
+
@server.stop
|
27
|
+
log.info "** Waves Server Stopped"
|
28
|
+
end
|
29
|
+
|
30
|
+
def synchronize( &block )
|
31
|
+
( @mutex ||= Mutex.new ).synchronize( &block )
|
32
|
+
end
|
33
|
+
|
34
|
+
def cache
|
35
|
+
#@cache ||= MemCache::new '127.0.0.1'
|
36
|
+
end
|
37
|
+
|
38
|
+
# make this a singleton ... we don't use Ruby's std lib
|
39
|
+
# singleton module because it doesn't do quite what we
|
40
|
+
# want - need a run method and implicit instance method
|
41
|
+
class << self
|
42
|
+
|
43
|
+
private :new, :dup, :clone
|
44
|
+
|
45
|
+
def run( mode = :development )
|
46
|
+
@server.stop if @server; @server = new( mode ); @server.start
|
47
|
+
end
|
48
|
+
|
49
|
+
# allow Waves::Server to act as The Server Instance
|
50
|
+
def method_missing(*args); @server.send(*args); end
|
51
|
+
|
52
|
+
def synchronize(&block) ; @server.synchronize(&block) ; end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Waves
|
2
|
+
class Session
|
3
|
+
|
4
|
+
def initialize( request )
|
5
|
+
@request = request
|
6
|
+
@data ||= ( File.exist?( session_path ) ? load_session : {} )
|
7
|
+
end
|
8
|
+
|
9
|
+
def save
|
10
|
+
if @data && @data.length > 0
|
11
|
+
File.write( session_path, @data.to_yaml )
|
12
|
+
@request.response.set_cookie( 'session_id',
|
13
|
+
:value => session_id, :path => '/',
|
14
|
+
:expires => Time.now + Waves::Server.config.session[:duration] )
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](key) ; @data[key] ; end
|
19
|
+
def []=(key,val) ; @data[key] = val ; end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def session_id
|
24
|
+
@request.cookies['session_id'] || generate_session_id
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_session_id # from Camping ...
|
28
|
+
chars = [*'A'..'Z'] + [*'0'..'9'] + [*'a'..'z']
|
29
|
+
(0..48).inject(''){|s,x| s+=chars[ rand(chars.length) ] }
|
30
|
+
end
|
31
|
+
|
32
|
+
def session_path
|
33
|
+
Waves::Server.config.session[:path] / session_id
|
34
|
+
end
|
35
|
+
|
36
|
+
def load_session
|
37
|
+
YAML.load( File.read( session_path ) )
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|