waves 0.6.7 → 0.6.9
Sign up to get free protection for your applications and to get access to all the features.
- data/app/Rakefile +1 -1
- data/app/configurations/default.rb.erb +1 -1
- data/app/configurations/mapping.rb.erb +6 -37
- data/app/controllers/default.rb.erb +10 -20
- data/app/lib/tasks/cluster.rb +8 -10
- data/app/lib/tasks/generate.rb +15 -0
- data/app/lib/tasks/schema.rb +6 -5
- data/app/schema/{migration → migrations}/templates/empty.rb.erb +0 -0
- data/app/templates/errors/{not_found.mab → not_found_404.mab} +0 -0
- data/app/templates/errors/{server_error.mab → server_error_500.mab} +0 -0
- data/app/templates/layouts/default.mab +1 -1
- data/bin/waves +1 -1
- data/bin/waves-console +21 -4
- data/lib/controllers/mixin.rb +85 -16
- data/lib/dispatchers/base.rb +26 -15
- data/lib/dispatchers/default.rb +25 -4
- data/lib/helpers/common.rb +50 -10
- data/lib/helpers/form.rb +18 -1
- data/lib/helpers/formatting.rb +17 -9
- data/lib/helpers/model.rb +20 -2
- data/lib/helpers/view.rb +12 -2
- data/lib/mapping/mapping.rb +187 -0
- data/lib/mapping/pretty_urls.rb +95 -0
- data/lib/renderers/erubis.rb +3 -1
- data/lib/renderers/markaby.rb +6 -4
- data/lib/renderers/mixin.rb +12 -0
- data/lib/runtime/application.rb +33 -23
- data/lib/runtime/configuration.rb +131 -9
- data/lib/runtime/console.rb +2 -2
- data/lib/runtime/logger.rb +42 -18
- data/lib/runtime/mime_types.rb +8 -4
- data/lib/runtime/request.rb +14 -5
- data/lib/runtime/response.rb +15 -1
- data/lib/runtime/response_mixin.rb +29 -47
- data/lib/runtime/server.rb +60 -35
- data/lib/runtime/session.rb +14 -1
- data/lib/utilities/integer.rb +7 -1
- data/lib/utilities/kernel.rb +28 -2
- data/lib/utilities/module.rb +3 -0
- data/lib/utilities/object.rb +5 -1
- data/lib/utilities/string.rb +7 -2
- data/lib/utilities/symbol.rb +2 -0
- data/lib/views/mixin.rb +55 -1
- data/lib/waves.rb +9 -2
- metadata +10 -8
- data/lib/runtime/mapping.rb +0 -82
data/lib/renderers/erubis.rb
CHANGED
@@ -2,6 +2,8 @@ require 'erubis'
|
|
2
2
|
|
3
3
|
module Erubis
|
4
4
|
|
5
|
+
# This is added to the Erubis Content class to allow the same helper methods
|
6
|
+
# to be used with both Markaby and Erubis.
|
5
7
|
class Context
|
6
8
|
def <<(s) ; s ; end
|
7
9
|
end
|
@@ -11,7 +13,7 @@ end
|
|
11
13
|
module Waves
|
12
14
|
|
13
15
|
module Renderers
|
14
|
-
|
16
|
+
|
15
17
|
class Erubis
|
16
18
|
|
17
19
|
include Renderers::Mixin
|
data/lib/renderers/markaby.rb
CHANGED
@@ -11,17 +11,19 @@ module Waves
|
|
11
11
|
include Renderers::Mixin
|
12
12
|
|
13
13
|
extension :mab
|
14
|
+
|
14
15
|
# capture needed here for content fragments, otherwise
|
15
16
|
# you'll just get the last tag's output ...
|
16
|
-
def self.capture( template )
|
17
|
-
|
18
|
-
end
|
17
|
+
# def self.capture( template )
|
18
|
+
# "capture { #{template} }"
|
19
|
+
# end
|
19
20
|
|
20
21
|
def self.render( path, assigns )
|
21
22
|
builder = ::Markaby::Builder.new( assigns )
|
22
23
|
helper = helper( path )
|
23
24
|
builder.meta_eval { include( helper ) }
|
24
|
-
builder.instance_eval(
|
25
|
+
builder.instance_eval( template( path ) )
|
26
|
+
builder.to_s
|
25
27
|
end
|
26
28
|
|
27
29
|
end
|
data/lib/renderers/mixin.rb
CHANGED
@@ -5,8 +5,20 @@ module Waves
|
|
5
5
|
extend Autoload
|
6
6
|
autoload :renderers
|
7
7
|
|
8
|
+
# The renderers mixin provides a number of methods to simplify writing new renderers.
|
9
|
+
# Just include this in your Renderer class and write your render method.
|
8
10
|
module Mixin
|
9
11
|
|
12
|
+
# Adds the following methods to the target class:
|
13
|
+
#
|
14
|
+
# - extension: allows you to set or get the extension used by this renderer.
|
15
|
+
#
|
16
|
+
# Renderers::Markaby.extension 'foo' # tell Waves to use .foo as Markaby extension
|
17
|
+
#
|
18
|
+
# - filename: generate a filename for the template based on a logical path.
|
19
|
+
# - template: read the template from the file corresponding to the given logical path.
|
20
|
+
# - helper: return a helper module that corresponds to the given logical path.
|
21
|
+
#
|
10
22
|
def self.included(target)
|
11
23
|
class << target
|
12
24
|
|
data/lib/runtime/application.rb
CHANGED
@@ -1,43 +1,53 @@
|
|
1
|
+
# See the README for an overview.
|
1
2
|
module Waves
|
2
3
|
|
3
4
|
class << self
|
4
5
|
|
6
|
+
# Access the principal Waves application.
|
5
7
|
attr_reader :application
|
6
8
|
|
7
|
-
#
|
9
|
+
# Register a module as a Waves application.
|
10
|
+
# Also, initialize the database connection if necessary.
|
8
11
|
def << ( app )
|
9
|
-
|
12
|
+
@application = app if Module === app
|
13
|
+
app.database if app.respond_to? 'database'
|
10
14
|
end
|
11
15
|
|
12
16
|
end
|
13
17
|
|
18
|
+
# An application in Waves is anything that provides access to the Waves
|
19
|
+
# runtime and the registered Waves applications. This includes both
|
20
|
+
# Waves::Server and Waves::Console. Waves::Application is *not* the actual
|
21
|
+
# application module(s) registered as Waves applications. To access the
|
22
|
+
# main Waves application, you can use +Waves+.+application+.
|
14
23
|
class Application
|
15
|
-
|
16
|
-
def initialize( mode = :development )
|
17
|
-
@mode = mode
|
18
|
-
end
|
19
|
-
|
20
|
-
def debug? ; @mode == :development ; end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
# and / or Waves::Application::* ... because the configuration may be
|
25
|
-
# loaded via autoload ....
|
26
|
-
def config
|
27
|
-
Waves.application.configurations[ @mode ]
|
28
|
-
end
|
25
|
+
# Accessor for options passed to the application. Valid options include
|
26
|
+
attr_reader :options
|
29
27
|
|
30
|
-
#
|
31
|
-
def
|
32
|
-
|
28
|
+
# Create a new Waves application instance.
|
29
|
+
def initialize( options={} )
|
30
|
+
@options = options
|
31
|
+
Dir.chdir options[:directory] if options[:directory]
|
33
32
|
end
|
34
33
|
|
35
|
-
# the
|
36
|
-
|
37
|
-
def reset
|
38
|
-
config.reloadable.each { |mod| mod.reload }
|
39
|
-
end
|
34
|
+
# The 'mode' of the application determines which configuration it will run under.
|
35
|
+
def mode ; @mode ||= @options[:mode]||:development ; end
|
40
36
|
|
37
|
+
# Debug is true if debug is set to true in the current configuration.
|
38
|
+
def debug? ; config.debug ; end
|
39
|
+
|
40
|
+
# Access the current configuration. *Example:* +Waves::Server.config+
|
41
|
+
def config ; Waves.application.configurations[ mode ] ; end
|
42
|
+
|
43
|
+
# Access the mappings for the application.
|
44
|
+
def mapping ; Waves.application.configurations[ :mapping ] ; end
|
45
|
+
|
46
|
+
# Reload the modules specified in the current configuration.
|
47
|
+
def reload ; config.reloadable.each { |mod| mod.reload } ; end
|
48
|
+
|
49
|
+
# Returns the cache set for the current configuration
|
50
|
+
def cache ; config.cache ; end
|
41
51
|
end
|
42
52
|
|
43
53
|
end
|
@@ -1,15 +1,131 @@
|
|
1
1
|
module Waves
|
2
|
+
|
3
|
+
# Waves configurations are simply Ruby code, meaning you can use an Ruby expression as
|
4
|
+
# a value for a configuration parameter, extend and inherit your configurations, and
|
5
|
+
# add your own configuration attributes. You can even use it as a configuration repository
|
6
|
+
# for your applications.
|
7
|
+
#
|
8
|
+
# The form for configuration parameters to use the parameter name as a method name. Passing
|
9
|
+
# in a parameter sets the value.
|
10
|
+
#
|
11
|
+
# == Example
|
12
|
+
#
|
13
|
+
# module Blog
|
14
|
+
# module Configurations
|
15
|
+
# class Development < Default
|
16
|
+
# host '127.0.0.1'
|
17
|
+
# port 2000
|
18
|
+
# reloadable [ Blog ]
|
19
|
+
# log :level => :debug
|
20
|
+
# application do
|
21
|
+
# use Rack::ShowExceptions
|
22
|
+
# run Waves::Dispatchers::Default.new
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# There are three forms for accessing parameters:
|
29
|
+
#
|
30
|
+
# Waves.config.port # generic form - gets current config
|
31
|
+
# Blog.configurations[:development] # gets a value for a specific config
|
32
|
+
# Blog::Configurations::Development.port # Access config constant directly
|
33
|
+
#
|
34
|
+
# You can inherit configurations, as is shown in the example above. Typically, you
|
35
|
+
# can use the application's "default" configuration to set shared configurations,
|
36
|
+
# and then inherit from it for specific variations.
|
37
|
+
#
|
38
|
+
# To define your own attributes, and still make them inheritable, you should use
|
39
|
+
# the +attribute+ class method, like this:
|
40
|
+
#
|
41
|
+
# class Default < Waves::Configurations::Default
|
42
|
+
# attribute 'theme' # define a theme attribute
|
43
|
+
# theme 'ultra' # give it a default
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# There are a number of reserved or built-in attributes. These are:
|
47
|
+
#
|
48
|
+
# - application: configure the application for use with Rack
|
49
|
+
# - database: takes a hash of parameters used to initalize the database; see below
|
50
|
+
# - reloadable: an array of module names to reload; see below for more
|
51
|
+
# - log: takes a hash of parameters; see below for more
|
52
|
+
# - host: the host to bind the server to (string)
|
53
|
+
# - port: the port for the server to listen on (number)
|
54
|
+
# - ports: used by the cluster:start task for clustering servers (array of numbers)
|
55
|
+
# - debug: true if running in "debug" mode, which automatically reloads code
|
56
|
+
#
|
57
|
+
# == Configuring The Rack Application
|
58
|
+
#
|
59
|
+
# One of the really nice features of Rack is the ability to install "middleware"
|
60
|
+
# components to optimize the way you handle requests. Waves exposes this ability
|
61
|
+
# directly to the application developer via the +application+ configuration parameter.
|
62
|
+
#
|
63
|
+
# *Example*
|
64
|
+
#
|
65
|
+
# # Typical debugging configuration
|
66
|
+
# application do
|
67
|
+
# use Rack::ShowExceptions
|
68
|
+
# run Waves::Dispatchers::Default.new
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# == Configuring Database Access
|
72
|
+
#
|
73
|
+
# The database parameter takes a hash with the following elements:
|
74
|
+
#
|
75
|
+
# - host: which host the database is running on
|
76
|
+
# - adapter: which adapter is being used to access the database (mysql, postgres, etc.)
|
77
|
+
# - database: the name of the database the application is connecting to
|
78
|
+
# - user: the user for authentication
|
79
|
+
# - password: password for authentication
|
80
|
+
#
|
81
|
+
# *Example*
|
82
|
+
#
|
83
|
+
# database :host => host, :adapter => 'mysql', :database => 'blog',
|
84
|
+
# :user => 'root', :password => 'guess'
|
85
|
+
#
|
86
|
+
#
|
87
|
+
# == Configuring Code Reloading
|
88
|
+
#
|
89
|
+
# You can specify a list of modules to reload on each request using the +reloadable+
|
90
|
+
# configuration parameter. The Waves server will call +reload+ on each module to trigger
|
91
|
+
# the reloading. Typically, your modules will use the Autocode gem to set parameters for
|
92
|
+
# reloading. This is done for you when you generate an application using the +waves+
|
93
|
+
# command, but you can change the default settings. See the documentation for Autocode
|
94
|
+
# for more information. Typically, you will set this parameter to just include your
|
95
|
+
# main application:
|
96
|
+
#
|
97
|
+
# reloadable [ Blog ]
|
98
|
+
#
|
99
|
+
# although you could do this with several modules just as easily (say, your primary
|
100
|
+
# application and several helper applications).
|
101
|
+
#
|
102
|
+
# == Configuring Logging
|
103
|
+
#
|
104
|
+
# The +log+ configuration parameter takes the following options (as a hash):
|
105
|
+
# - level: The level to filter logging at. Uses Ruby's built in Logger class.
|
106
|
+
# - output: A filename or IO object. Should be a filename if running as a daemon.
|
107
|
+
#
|
108
|
+
# *Examples*
|
109
|
+
#
|
110
|
+
# log :level => :info, :output => $stderr
|
111
|
+
# log :level => :error, :output => 'log/blog.log'
|
112
|
+
#
|
2
113
|
|
3
114
|
module Configurations
|
4
115
|
|
5
116
|
class Base
|
6
117
|
|
118
|
+
# Set the given attribute with the given value. Typically, you wouldn't
|
119
|
+
# use this directly.
|
7
120
|
def self.[]=( name, val )
|
8
121
|
meta_def("_#{name}") { val }
|
9
122
|
end
|
10
123
|
|
124
|
+
# Get the value of the given attribute. Typically, you wouldn't
|
125
|
+
# use this directly.
|
11
126
|
def self.[]( name ) ; send "_#{name}" ; end
|
12
127
|
|
128
|
+
# Define a new attribute. After calling this, you can get and set the value.
|
13
129
|
def self.attribute( name )
|
14
130
|
meta_def(name) do |*args|
|
15
131
|
raise ArgumentError.new('Too many arguments.') if args.length > 1
|
@@ -17,18 +133,23 @@ module Waves
|
|
17
133
|
end
|
18
134
|
self[ name ] = nil
|
19
135
|
end
|
20
|
-
|
21
|
-
def self.mime_types
|
22
|
-
Waves::MimeTypes
|
23
|
-
end
|
24
136
|
|
25
137
|
end
|
26
138
|
|
139
|
+
# The Default configuration provides a good starting point for your applications,
|
140
|
+
# defining a number of attributes that are required by Waves.
|
27
141
|
class Default < Base
|
28
142
|
|
29
|
-
%w( host port ports log reloadable
|
143
|
+
%w( host port ports log reloadable database session debug ).
|
30
144
|
each { |name| attribute(name) }
|
31
145
|
|
146
|
+
# Provide access to the Waves::MimeTypes class via the configuration. You
|
147
|
+
# could potentially point this to your own MIME types repository class.
|
148
|
+
def self.mime_types
|
149
|
+
Waves::MimeTypes
|
150
|
+
end
|
151
|
+
|
152
|
+
# Defines the application for use with Rack.
|
32
153
|
def self.application( &block )
|
33
154
|
if block_given?
|
34
155
|
self['application'] = Rack::Builder.new( &block )
|
@@ -36,10 +157,11 @@ module Waves
|
|
36
157
|
self['application']
|
37
158
|
end
|
38
159
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
160
|
+
|
161
|
+
debug true
|
162
|
+
session :duration => 30.minutes, :path => '/tmp/sessions'
|
163
|
+
log :level => :info, :output => $stderr
|
164
|
+
|
43
165
|
end
|
44
166
|
end
|
45
167
|
end
|
data/lib/runtime/console.rb
CHANGED
data/lib/runtime/logger.rb
CHANGED
@@ -1,26 +1,50 @@
|
|
1
1
|
require 'logger'
|
2
2
|
module Waves
|
3
3
|
|
4
|
+
# Waves::Logger is based on Ruby's built-in Logger. It uses the same filtering approach
|
5
|
+
# (debug, info, warn, error, fatal), although the interface is slightly different.
|
6
|
+
# You won't typically instantiate this class directly; instead, you will specify the
|
7
|
+
# logging configuration you want in your configuration files. See Waves::Configurations
|
8
|
+
# for more information on this.
|
9
|
+
#
|
10
|
+
# To use the logger for output, you can usually just call +log+, since the Waves::ResponseHelper
|
11
|
+
# mixin defines it (meaning it is available in the mapping file, controllers, views, and
|
12
|
+
# templates). Or, you can access Waves::Logger directly. Either way, the logger provides five
|
13
|
+
# methods for output corresponding to the log levels.
|
14
|
+
#
|
15
|
+
# *Examples*
|
16
|
+
# # log the value of foo
|
17
|
+
# log.info "Value of foo: #{foo}"
|
18
|
+
#
|
19
|
+
# # fatal error!
|
20
|
+
# Waves::Logger.fatal "She can't hold up any longer, cap'n!"
|
21
|
+
#
|
4
22
|
module Logger
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
23
|
+
|
24
|
+
class << self
|
25
|
+
|
26
|
+
# Returns the object being used for output by the logger.
|
27
|
+
def output
|
28
|
+
@output ||= ( config[:output] ? File.expand_path( config[:output] ) : $stderr )
|
29
|
+
end
|
30
|
+
# Returns the active configuration for the logger.
|
31
|
+
def config ; @config ||= Waves::Server.config.log ; end
|
32
|
+
# Returns the logging level used to filter logging events.
|
33
|
+
def level ; @level ||= ::Logger.const_get( config[:level].to_s.upcase || 'INFO' ) ; end
|
34
|
+
# Starts the logger, using the active configuration to initialize it.
|
35
|
+
def start
|
36
|
+
@log = config[:rotation] ?
|
37
|
+
::Logger.new( output, config[:rotation].intern ) :
|
38
|
+
::Logger.new( output )
|
39
|
+
@log.level = level
|
40
|
+
self
|
16
41
|
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
42
|
+
# Forwards logging methods to the logger.
|
43
|
+
def method_missing(name,*args,&block)
|
44
|
+
@log.send name,*args, &block
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
24
48
|
|
25
49
|
end
|
26
50
|
|
data/lib/runtime/mime_types.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
module Waves
|
2
|
+
|
3
|
+
# Waves::MimeTypes defines an interface for adding MIME types used in mapping requests
|
4
|
+
# to content types. Mongrel's MIME_TYPES hash is used as the baseline MIME map.
|
5
|
+
|
2
6
|
module MimeTypes
|
3
7
|
|
4
8
|
def self.[]( path )
|
5
9
|
mapping[ File.extname( path ) ]
|
6
10
|
end
|
7
11
|
|
8
|
-
# TODO:
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
+
# TODO: This does not seem to be working.
|
13
|
+
def self.<<( mapping )
|
14
|
+
mapping.merge!( mapping )
|
15
|
+
end
|
12
16
|
|
13
17
|
def self.mapping
|
14
18
|
@mapping ||= Mongrel::DirHandler::MIME_TYPES
|
data/lib/runtime/request.rb
CHANGED
@@ -1,39 +1,48 @@
|
|
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.
|
2
5
|
class Request
|
3
6
|
|
4
7
|
class ParseError < Exception ; end
|
5
8
|
|
6
9
|
attr_reader :response, :session
|
7
10
|
|
8
|
-
|
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 )
|
9
14
|
@request = Rack::Request.new( env )
|
10
15
|
@response = Waves::Response.new( self )
|
11
16
|
@session = Waves::Session.new( self )
|
12
17
|
end
|
13
18
|
|
14
|
-
#
|
19
|
+
# Accessor not explicitly defined by Waves::Request are delegated to Rack::Request.
|
20
|
+
# Check the Rack documentation for more information.
|
15
21
|
def method_missing(name,*args)
|
16
22
|
@request.send(name,*args)
|
17
23
|
end
|
18
24
|
|
19
|
-
#
|
20
|
-
# Is there a Rack API that is more appropos
|
25
|
+
# The request path (PATH_INFO). Ex: +/entry/2008-01-17+
|
21
26
|
def path
|
22
27
|
@request.path_info
|
23
28
|
end
|
24
|
-
|
29
|
+
|
30
|
+
# The request domain. Ex: +www.fubar.com+
|
25
31
|
def domain
|
26
32
|
@request.host
|
27
33
|
end
|
28
34
|
|
35
|
+
# The request method: GET, PUT, POST, or DELETE.
|
29
36
|
def method
|
30
37
|
@request.request_method.downcase.intern
|
31
38
|
end
|
32
39
|
|
40
|
+
# Raise a not found exception.
|
33
41
|
def not_found
|
34
42
|
raise Waves::Dispatchers::NotFoundError.new( @request.url + ' not found.')
|
35
43
|
end
|
36
44
|
|
45
|
+
# Issue a redirect for the given path.
|
37
46
|
def redirect( path )
|
38
47
|
raise Waves::Dispatchers::Redirect.new( path )
|
39
48
|
end
|