waves 0.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/app/Rakefile +4 -0
  2. data/app/configurations/default.rb.erb +8 -0
  3. data/app/configurations/development.rb.erb +22 -0
  4. data/app/configurations/mapping.rb.erb +49 -0
  5. data/app/configurations/production.rb.erb +25 -0
  6. data/app/controllers/default.rb.erb +39 -0
  7. data/app/doc/EMTPY +0 -0
  8. data/app/helpers/default.rb.erb +13 -0
  9. data/app/lib/application.rb.erb +52 -0
  10. data/app/lib/startup.rb.erb +2 -0
  11. data/app/lib/tasks/cluster.rb +26 -0
  12. data/app/lib/tasks/schema.rb +28 -0
  13. data/app/models/default.rb.erb +13 -0
  14. data/app/schema/migration/templates/empty.rb.erb +9 -0
  15. data/app/templates/errors/not_found.mab +2 -0
  16. data/app/templates/errors/server_error.mab +2 -0
  17. data/app/templates/layouts/default.mab +14 -0
  18. data/app/views/default.rb.erb +13 -0
  19. data/bin/waves +32 -0
  20. data/bin/waves-console +8 -0
  21. data/bin/waves-server +45 -0
  22. data/lib/controllers/mixin.rb +62 -0
  23. data/lib/dispatchers/base.rb +41 -0
  24. data/lib/dispatchers/default.rb +33 -0
  25. data/lib/helpers/common.rb +22 -0
  26. data/lib/helpers/form.rb +22 -0
  27. data/lib/helpers/formatting.rb +22 -0
  28. data/lib/helpers/model.rb +15 -0
  29. data/lib/helpers/view.rb +14 -0
  30. data/lib/renderers/erubis.rb +38 -0
  31. data/lib/renderers/markaby.rb +31 -0
  32. data/lib/renderers/mixin.rb +41 -0
  33. data/lib/runtime/application.rb +43 -0
  34. data/lib/runtime/configuration.rb +47 -0
  35. data/lib/runtime/console.rb +21 -0
  36. data/lib/runtime/logger.rb +28 -0
  37. data/lib/runtime/mapping.rb +82 -0
  38. data/lib/runtime/mime_types.rb +18 -0
  39. data/lib/runtime/request.rb +43 -0
  40. data/lib/runtime/response.rb +26 -0
  41. data/lib/runtime/response_mixin.rb +53 -0
  42. data/lib/runtime/response_proxy.rb +29 -0
  43. data/lib/runtime/server.rb +58 -0
  44. data/lib/runtime/session.rb +43 -0
  45. data/lib/utilities/integer.rb +8 -0
  46. data/lib/utilities/kernel.rb +8 -0
  47. data/lib/utilities/module.rb +7 -0
  48. data/lib/utilities/object.rb +13 -0
  49. data/lib/utilities/string.rb +36 -0
  50. data/lib/utilities/symbol.rb +5 -0
  51. data/lib/views/mixin.rb +54 -0
  52. data/lib/waves.rb +50 -0
  53. 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
+
@@ -0,0 +1,8 @@
1
+ class Integer
2
+ def seconds ; self ; end
3
+ def minutes ; self * 60 ; end
4
+ def hours ; self * 60.minutes ; end
5
+ def days ; self * 24.hours ; end
6
+ def weeks ; self * 7.days ; end
7
+ # months and years are not precise
8
+ end
@@ -0,0 +1,8 @@
1
+ module Kernel
2
+
3
+ # inspired by similar function in rails ...
4
+ def returning( object, &block )
5
+ yield object; object
6
+ end
7
+
8
+ end
@@ -0,0 +1,7 @@
1
+ class Module
2
+
3
+ def basename
4
+ self.name.split('::').last || ''
5
+ end
6
+
7
+ end