waves 0.7.3 → 0.7.5

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