waves 0.6.7
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.
- 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
|
+
|