waves 0.7.3 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/app/Rakefile +11 -19
  2. data/app/bin/waves-console +3 -5
  3. data/app/bin/waves-server +3 -5
  4. data/app/configurations/development.rb.erb +19 -11
  5. data/app/configurations/mapping.rb.erb +4 -5
  6. data/app/configurations/production.rb.erb +18 -13
  7. data/app/{doc/EMTPY → controllers/.gitignore} +0 -0
  8. data/app/{public/css/EMPTY → doc/.gitignore} +0 -0
  9. data/app/{public/flash/EMPTY → helpers/.gitignore} +0 -0
  10. data/app/lib/application.rb.erb +4 -51
  11. data/app/{public/images/EMPTY → lib/tasks/.gitignore} +0 -0
  12. data/app/{public/javascript/EMPTY → log/.gitignore} +0 -0
  13. data/app/{tmp/sessions/EMPTY → models/.gitignore} +0 -0
  14. data/app/public/css/.gitignore +0 -0
  15. data/app/public/flash/.gitignore +0 -0
  16. data/app/public/images/.gitignore +0 -0
  17. data/app/public/javascript/.gitignore +0 -0
  18. data/app/schema/migrations/.gitignore +0 -0
  19. data/app/startup.rb +5 -0
  20. data/app/templates/layouts/default.mab +2 -2
  21. data/app/tmp/sessions/.gitignore +0 -0
  22. data/app/views/.gitignore +0 -0
  23. data/bin/waves +38 -27
  24. data/bin/waves-console +3 -25
  25. data/bin/waves-server +4 -45
  26. data/lib/commands/waves-console.rb +21 -0
  27. data/lib/commands/waves-server.rb +55 -0
  28. data/lib/controllers/base.rb +11 -0
  29. data/lib/controllers/mixin.rb +130 -102
  30. data/lib/dispatchers/base.rb +65 -50
  31. data/lib/dispatchers/default.rb +79 -52
  32. data/lib/foundations/default.rb +26 -0
  33. data/lib/foundations/simple.rb +30 -0
  34. data/lib/helpers/common.rb +60 -56
  35. data/lib/helpers/default.rb +13 -0
  36. data/lib/helpers/form.rb +39 -38
  37. data/lib/helpers/formatting.rb +11 -11
  38. data/lib/helpers/model.rb +12 -12
  39. data/lib/helpers/view.rb +13 -13
  40. data/lib/layers/default_errors.rb +29 -0
  41. data/lib/layers/mvc.rb +58 -0
  42. data/lib/layers/orm/active_record.rb +41 -0
  43. data/lib/layers/orm/active_record/migrations/empty.rb.erb +9 -0
  44. data/lib/layers/orm/active_record/tasks/schema.rb +30 -0
  45. data/lib/layers/orm/data_mapper.rb +42 -0
  46. data/lib/layers/orm/filebase.rb +22 -0
  47. data/lib/layers/orm/migration.rb +70 -0
  48. data/lib/layers/orm/sequel.rb +82 -0
  49. data/lib/layers/orm/sequel/migrations/empty.rb.erb +9 -0
  50. data/lib/layers/orm/sequel/tasks/schema.rb +24 -0
  51. data/lib/layers/simple.rb +39 -0
  52. data/lib/layers/simple_errors.rb +26 -0
  53. data/lib/mapping/mapping.rb +222 -120
  54. data/lib/mapping/pretty_urls.rb +42 -41
  55. data/lib/renderers/erubis.rb +54 -31
  56. data/lib/renderers/markaby.rb +28 -28
  57. data/lib/renderers/mixin.rb +49 -52
  58. data/lib/runtime/application.rb +66 -48
  59. data/lib/runtime/blackboard.rb +57 -0
  60. data/lib/runtime/configuration.rb +117 -101
  61. data/lib/runtime/console.rb +19 -20
  62. data/lib/runtime/debugger.rb +9 -0
  63. data/lib/runtime/logger.rb +43 -37
  64. data/lib/runtime/mime_types.rb +19 -19
  65. data/lib/runtime/request.rb +72 -46
  66. data/lib/runtime/response.rb +37 -37
  67. data/lib/runtime/response_mixin.rb +26 -23
  68. data/lib/runtime/response_proxy.rb +25 -24
  69. data/lib/runtime/server.rb +99 -80
  70. data/lib/runtime/session.rb +63 -53
  71. data/lib/tasks/cluster.rb +26 -0
  72. data/lib/tasks/gem.rb +31 -0
  73. data/lib/tasks/generate.rb +80 -0
  74. data/lib/utilities/hash.rb +22 -0
  75. data/lib/utilities/inflect.rb +194 -0
  76. data/lib/utilities/integer.rb +15 -12
  77. data/lib/utilities/kernel.rb +32 -32
  78. data/lib/utilities/module.rb +11 -4
  79. data/lib/utilities/object.rb +5 -5
  80. data/lib/utilities/proc.rb +10 -0
  81. data/lib/utilities/string.rb +44 -38
  82. data/lib/utilities/symbol.rb +4 -4
  83. data/lib/views/base.rb +9 -0
  84. data/lib/views/mixin.rb +91 -89
  85. data/lib/waves.rb +29 -9
  86. metadata +52 -26
  87. data/app/configurations/default.rb.erb +0 -8
  88. data/app/controllers/default.rb.erb +0 -29
  89. data/app/helpers/default.rb.erb +0 -13
  90. data/app/lib/startup.rb.erb +0 -3
  91. data/app/lib/tasks/cluster.rb +0 -24
  92. data/app/lib/tasks/generate.rb +0 -15
  93. data/app/lib/tasks/schema.rb +0 -29
  94. data/app/models/default.rb.erb +0 -13
  95. data/app/schema/migrations/templates/empty.rb.erb +0 -9
  96. data/app/views/default.rb.erb +0 -13
@@ -1,22 +1,22 @@
1
1
  module Waves
2
-
2
+
3
3
  # Waves::MimeTypes defines an interface for adding MIME types used in mapping requests
4
4
  # to content types. Mongrel's MIME_TYPES hash is used as the baseline MIME map.
5
-
6
- module MimeTypes
7
-
8
- def self.[]( path )
9
- mapping[ File.extname( path ) ]
10
- end
11
-
12
- # TODO: This does not seem to be working.
13
- def self.<<( mapping )
14
- mapping.merge!( mapping )
15
- end
16
-
17
- def self.mapping
18
- @mapping ||= Mongrel::DirHandler::MIME_TYPES
19
- end
20
-
21
- end
22
- end
5
+
6
+ module MimeTypes
7
+
8
+ def self.[]( path )
9
+ mapping[ File.extname( path ) ]
10
+ end
11
+
12
+ # TODO: This does not seem to be working.
13
+ def self.<<( mapping )
14
+ mapping.merge!( mapping )
15
+ end
16
+
17
+ def self.mapping
18
+ @mapping ||= Mongrel::DirHandler::MIME_TYPES
19
+ end
20
+
21
+ end
22
+ end
@@ -1,52 +1,78 @@
1
1
  module Waves
2
- # Waves::Request represents an HTTP request and has methods for accessing anything
3
- # relating to the request. See Rack::Request for more information, since many methods
4
- # are actually delegated to Rack::Request.
5
- class Request
6
-
7
- class ParseError < Exception ; end
8
-
9
- attr_reader :response, :session
10
-
11
- # Create a new request. Takes a env parameter representing the request passed in from Rack.
12
- # You shouldn't need to call this directly.
13
- def initialize( env )
14
- @request = Rack::Request.new( env )
15
- @response = Waves::Response.new( self )
16
- @session = Waves::Session.new( self )
17
- end
18
-
19
- # Accessor not explicitly defined by Waves::Request are delegated to Rack::Request.
20
- # Check the Rack documentation for more information.
21
- def method_missing(name,*args)
22
- @request.send(name,*args)
23
- end
24
-
25
- # The request path (PATH_INFO). Ex: +/entry/2008-01-17+
26
- def path
27
- @request.path_info
28
- end
29
-
30
- # The request domain. Ex: +www.fubar.com+
2
+ # Waves::Request represents an HTTP request and provides convenient methods for accessing request attributes. See Rack::Request for documentation of any method not defined here.
3
+ class Request
4
+
5
+ class ParseError < Exception ; end
6
+
7
+ attr_reader :response, :session, :blackboard
8
+
9
+ # Create a new request. Takes a env parameter representing the request passed in from Rack.
10
+ # You shouldn't need to call this directly.
11
+ def initialize( env )
12
+ @request = Rack::Request.new( env )
13
+ @response = Waves::Response.new( self )
14
+ @session = Waves::Session.new( self )
15
+ @blackboard = Waves::Blackboard.new( self )
16
+ end
17
+
18
+ def rack_request; @request; end
19
+
20
+ # Accessor not explicitly defined by Waves::Request are delegated to Rack::Request.
21
+ # Check the Rack documentation for more information.
22
+ def method_missing(name,*args)
23
+ @request.send(name,*args)
24
+ end
25
+
26
+ # The request path (PATH_INFO). Ex: +/entry/2008-01-17+
27
+ def path
28
+ @request.path_info
29
+ end
30
+
31
+ # The request domain. Ex: +www.fubar.com+
31
32
  def domain
32
33
  @request.host
33
34
  end
34
-
35
- # The request method: GET, PUT, POST, or DELETE.
36
- def method
37
- @request.request_method.downcase.intern
38
- end
39
-
40
- # Raise a not found exception.
41
- def not_found
42
- raise Waves::Dispatchers::NotFoundError.new( @request.url + ' not found.')
43
- end
35
+
36
+ # The request content type.
37
+ def content_type
38
+ @request.env['CONTENT_TYPE']
39
+ end
40
+
41
+ # Supported request methods
42
+ METHODS = %w{get post put delete head options trace}
43
+
44
+ # Override the Rack methods for querying the request method.
45
+ METHODS.each do |method|
46
+ class_eval "def #{method}?; method == :#{method} end"
47
+ end
48
+
49
+ # The request method. Because browsers can't send PUT or DELETE
50
+ # requests this can be simulated by sending a POST with a hidden
51
+ # field named '_method' and a value with 'PUT' or 'DELETE'. Also
52
+ # accepted is when a query parameter named '_method' is provided.
53
+ def method
54
+ @method ||= begin
55
+ request_method = @request.request_method.downcase
56
+ if request_method == 'post'
57
+ _method = @request['_method']
58
+ _method.downcase! if _method
59
+ METHODS.include?(_method) ? _method.intern : :post
60
+ else
61
+ request_method.intern
62
+ end
63
+ end
64
+ end
65
+
66
+ # Raise a not found exception.
67
+ def not_found
68
+ raise Waves::Dispatchers::NotFoundError.new( @request.url + ' not found.' )
69
+ end
44
70
 
45
71
  # Issue a redirect for the given path.
46
- def redirect( path )
47
- raise Waves::Dispatchers::Redirect.new( path )
48
- end
49
-
50
- end
51
-
52
- end
72
+ def redirect( path, status = '302' )
73
+ raise Waves::Dispatchers::Redirect.new( path, status )
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -1,40 +1,40 @@
1
1
  module Waves
2
2
  # Waves::Response represents an HTTP response and has methods for constructing a response.
3
- # These include setters for +content_type+, +content_length+, +location+, and +expires+
4
- # headers. You may also set the headers directly using the [] operator. If you don't find
5
- # what you are looking for here, check the documentation for Rack::Response since many
6
- # methods for this class are delegated to Rack::Response.
7
- class Response
8
-
9
- attr_reader :request
10
-
11
- # Create a new response. Takes the request object. You shouldn't need to call this directly.
12
- def initialize( request )
13
- @request = request
14
- @response = Rack::Response.new
15
- end
16
-
17
- %w( Content-Type Content-Length Location Expires ).each do |header|
18
- define_method( header.downcase.gsub('-','_')+ '=' ) do | val |
19
- @response[header] = val
20
- end
21
- end
22
-
23
- # Returns the sessions associated with the request, allowing you to set values within it.
24
- # The session will be created if necessary and saved when the response is complete.
25
- def session ; request.session ; end
26
-
27
- # Finish the response. This will send the response back to the client, so you shouldn't
28
- # attempt to further modify the response once this method is called. You don't usually
29
- # need to call it yourself, since it is called by the dispatcher once request processing
30
- # is finished.
31
- def finish ; request.session.save ; @response.finish ; end
32
-
33
- # Methods not explicitly defined by Waves::Response are delegated to Rack::Response.
34
- # Check the Rack documentation for more informations
35
- def method_missing(name,*args)
36
- @response.send(name,*args)
37
- end
38
-
39
- end
3
+ # These include setters for +content_type+, +content_length+, +location+, and +expires+
4
+ # headers. You may also set the headers directly using the [] operator. See Rack::Response for documentation of any method not defined here.
5
+ class Response
6
+
7
+ attr_reader :request
8
+
9
+ # Create a new response. Takes the request object. You shouldn't need to call this directly.
10
+ def initialize( request )
11
+ @request = request
12
+ @response = Rack::Response.new
13
+ end
14
+
15
+ def rack_response; @response; end
16
+
17
+ %w( Content-Type Content-Length Location Expires ).each do |header|
18
+ define_method( header.downcase.gsub('-','_')+ '=' ) do | val |
19
+ @response[header] = val
20
+ end
21
+ end
22
+
23
+ # Returns the sessions associated with the request, allowing you to set values within it.
24
+ # The session will be created if necessary and saved when the response is complete.
25
+ def session ; request.session ; end
26
+
27
+ # Finish the response. This will send the response back to the client, so you shouldn't
28
+ # attempt to further modify the response once this method is called. You don't usually
29
+ # need to call it yourself, since it is called by the dispatcher once request processing
30
+ # is finished.
31
+ def finish ; request.session.save ; @response.finish ; end
32
+
33
+ # Methods not explicitly defined by Waves::Response are delegated to Rack::Response.
34
+ # Check the Rack documentation for more informations
35
+ def method_missing(name,*args)
36
+ @response.send(name,*args)
37
+ end
38
+
39
+ end
40
40
  end
@@ -1,5 +1,5 @@
1
1
  module Waves
2
-
2
+
3
3
  # Defines a set of methods that simplify accessing common request and response methods.
4
4
  # These include methods not necessarily associated with the Waves::Request and Waves::Response
5
5
  # objects, but which may still be useful for constructing a response.
@@ -11,25 +11,28 @@ module Waves
11
11
  # Access the request parameters.
12
12
  def params; request.params; end
13
13
  # Access the request session.
14
- def session; request.session; end
15
- # Access the request path.
16
- def path; request.path; end
17
- # Access the request url.
18
- def url; request.url; end
19
- # Access the request domain.
20
- def domain; request.domain; end
21
- # Issue a redirect for the given location.
22
- def redirect(location); request.redirect(location); end
23
- # Access the primary application's models
24
- def models; Waves.application.models; end
25
- # Access the primary application's views
26
- def views; Waves.application.views; end
27
- # Access the primary application's controllers
28
- def controllers; Waves.application.controllers; end
29
- # Raise a "not found" exception.
30
- def not_found; request.not_found; end
31
- # Access the Waves::Logger.
32
- def log; Waves::Logger; end
33
- end
34
-
35
- end
14
+ def session; request.session; end
15
+ # Access the request path.
16
+ def path; request.path; end
17
+ # Access the request url.
18
+ def url; request.url; end
19
+ # Access the request domain.
20
+ def domain; request.domain; end
21
+ # Issue a redirect for the given location.
22
+ def redirect(location, status = '302'); request.redirect(location, status); end
23
+ # Access the primary application's models
24
+ def models; Waves.application.models; end
25
+ # Access the primary application's views
26
+ def views; Waves.application.views; end
27
+ # Access the primary application's controllers
28
+ def controllers; Waves.application.controllers; end
29
+ # Raise a "not found" exception.
30
+ def not_found; request.not_found; end
31
+ # Access the Waves::Logger.
32
+ def log; Waves::Logger; end
33
+ # Access the Blackboard
34
+ def blackboard; request.blackboard; end
35
+
36
+ end
37
+
38
+ end
@@ -1,29 +1,30 @@
1
1
  module Waves
2
-
3
- class ResponseProxy
2
+
3
+ # Mapping actions are evaluated in the context of a ResponseProxy.
4
+ class ResponseProxy
4
5
 
5
6
  attr_reader :request
6
7
 
7
8
  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
9
+
10
+ def initialize(request)
11
+ @request = request
12
+ end
13
+
14
+ def resource( resource, &block )
15
+ @resource = resource; yield.call
16
+ end
17
+
18
+ def controller( &block )
19
+ lambda { Waves.application.controllers[ @resource ].process( @request, &block ) }
20
+ end
21
+
22
+ def view( &block )
23
+ lambda { |val| Waves.application.views[ @resource ].process( @request, val, &block ) }
24
+ end
25
+
26
+ def redirect(path, status = '302'); @request.redirect(path, status); end
27
+
28
+ end
29
+
30
+ end
@@ -1,83 +1,102 @@
1
1
  module Waves
2
- # You can run the Waves::Server via the +waves-server+ command or via <tt>rake cluster:start</tt>. Run <tt>waves-server --help</tt> for options on the <tt>waves-server</tt> command. The <tt>cluster.start</tt> task use the +mode+ environment parameter to determine which configuration to use. You can define +port+ to run on a single port, or +ports+ (taking an array) to run on multiple ports.
3
- #
4
- # *Example*
5
- #
6
- # Assume that +ports+ is set in the development configuration like this:
7
- #
8
- # ports [ 2020, 2021, 2022 ]
9
- #
10
- # Then you could start up instances on all three ports using:
11
- #
12
- # rake cluster:start mode=development
13
- #
14
- # This is the equivalent of running:
15
- #
16
- # waves-server -c development -p 2020 -d
17
- # waves-server -c development -p 2021 -d
18
- # waves-server -c development -p 2022 -d
19
- #
20
- class Server < Application
21
-
22
- # Access the server thread.
23
- attr_reader :thread
24
-
25
- # Access the host we're binding to (set via the configuration).
26
- def host ; options[:host] || config.host ; end
27
- # Access the port we're listening on (set via the configuration).
28
- def port ; options[:port] || config.port ; end
29
- # Run the server as a daemon. Corresponds to the -d switch on +waves-server+.
30
- def daemonize
31
- pwd = Dir.pwd
32
- Daemonize.daemonize( Waves::Logger.output )
33
- Dir.chdir(pwd)
34
- File.write( :log / $$+'.pid', '' )
35
- end
36
- # Start and / or access the Waves::Logger instance.
37
- def log ; @log ||= Waves::Logger.start ; end
38
- # Start the server.
39
- def start
40
- load( :lib / 'startup.rb' )
41
- daemonize if options[:daemon]
42
- log.info "** Waves Server Starting ..."
43
- t = real_start
44
- log.info "** Waves Server Running on #{host}:#{port}"
45
- log.info "Server started in #{(t*1000).round} ms."
46
- @thread.join
47
- end
48
- # Stop the server.
49
- def stop
50
- log.info "** Waves Server Stopping ..."
51
- pid_file = :log / $$ + '.pid'
52
- FileUtils.rm( pid_file ) if options[:daemon] and File.exist?( pid_file )
53
- @server.stop
54
- log.info "** Waves Server Stopped"
55
- end
56
- # Provides access to the server mutex for thread-safe operation.
57
- def synchronize( &block ) ; ( @mutex ||= Mutex.new ).synchronize( &block ) ; end
2
+ # You can run the Waves::Server via the +waves-server+ command or via <tt>rake cluster:start</tt>. Run <tt>waves-server --help</tt> for options on the <tt>waves-server</tt> command. The <tt>cluster:start</tt> task uses the +mode+ environment variable to determine the active configuration. You can define +port+ to run on a single port, or +ports+ (taking an array) to run on multiple ports.
3
+ #
4
+ # *Example*
5
+ #
6
+ # Assume that +ports+ is set in the development configuration like this:
7
+ #
8
+ # ports [ 2020, 2021, 2022 ]
9
+ #
10
+ # Then you could start up instances on all three ports using:
11
+ #
12
+ # rake cluster:start mode=development
13
+ #
14
+ # This is the equivalent of running:
15
+ #
16
+ # waves-server -c development -p 2020 -d
17
+ # waves-server -c development -p 2021 -d
18
+ # waves-server -c development -p 2022 -d
19
+ #
20
+ # The +cluster:stop+ task stops all of the instances.
21
+ #
22
+ class Server < Application
58
23
 
59
- class << self
60
- private :new, :dup, :clone
61
- # Start or restart the server.
62
- def run( options={} )
63
- @server.stop if @server; @server = new( options ); @server.start
64
- end
65
- # Allows us to access the Waves::Server instance.
66
- def method_missing(*args); @server.send(*args); end
67
- # Probably wouldn't need this if I added a block parameter to method_missing.
68
- def synchronize(&block) ; @server.synchronize(&block) ; end
69
- end
70
-
71
- private
72
-
73
- def real_start
74
- Benchmark.realtime do
75
- @server = ::Mongrel::HttpServer.new( host, port )
76
- @server.register('/', Rack::Handler::Mongrel.new( config.application.to_app ) )
77
- trap('INT') { puts; stop }; @thread = @server.run
78
- end
79
- end
24
+ # Access the server thread.
25
+ attr_reader :thread
80
26
 
81
- end
82
-
83
- end
27
+ # Access the host we're binding to (set via the configuration).
28
+ def host ; options[:host] || config.host ; end
29
+
30
+ # Access the port we're listening on (set via the configuration).
31
+ def port ; options[:port] || config.port ; end
32
+
33
+ # Run the server as a daemon. Corresponds to the -d switch on +waves-server+.
34
+ def daemonize
35
+ pwd = Dir.pwd
36
+ Daemonize.daemonize( Waves::Logger.output )
37
+ Dir.chdir(pwd)
38
+ File.write( :log / "#{port}.pid", $$ )
39
+ end
40
+
41
+ # Start and / or access the Waves::Logger instance.
42
+ def log
43
+ @log ||= Waves::Logger.start
44
+ end
45
+
46
+ # Start the server.
47
+ def start
48
+ daemonize if options[:daemon]
49
+ start_debugger if options[:debugger]
50
+ log.info "** Waves Server starting on #{host}:#{port}"
51
+ handler, options = config.handler
52
+ handler.run( config.application.to_app, options ) do |server|
53
+ @server = server
54
+ trap('INT') { puts; stop } if @server.respond_to? :stop
55
+ end
56
+ end
57
+
58
+ # Stop the server.
59
+ def stop
60
+ log.info "** Waves Server Stopping ..."
61
+ if options[:daemon]
62
+ pid_file = :log / $$ + '.pid'; FileUtils.rm( pid_file ) if File.exist?( pid_file )
63
+ end
64
+ @server.stop
65
+ log.info "** Waves Server Stopped"
66
+ end
67
+
68
+ # Provides access to the server mutex for thread-safe operation.
69
+ def synchronize( &block ) ; ( @mutex ||= Mutex.new ).synchronize( &block ) ; end
70
+
71
+ class << self
72
+ private :new, :dup, :clone
73
+ # Start or restart the server.
74
+ def run( options={} )
75
+ @server.stop if @server; @server = new( options ); @server.start
76
+ end
77
+
78
+ # Allows us to access the Waves::Server instance.
79
+ def method_missing(*args)
80
+ @server.send(*args)
81
+ end
82
+
83
+ #-- Probably wouldn't need this if I added a block parameter to method_missing.
84
+ def synchronize(&block) ; @server.synchronize(&block) ; end
85
+ end
86
+
87
+ private
88
+
89
+ def start_debugger
90
+ begin
91
+ require 'ruby-debug'
92
+ Debugger.start
93
+ Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
94
+ log.info "Debugger enabled"
95
+ rescue Exception
96
+ log.info "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
97
+ exit
98
+ end
99
+ end
100
+ end
101
+
102
+ end