dyoder-waves 0.7.3
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 +14 -0
- data/app/bin/waves-console +3 -0
- data/app/bin/waves-server +3 -0
- data/app/configurations/development.rb.erb +31 -0
- data/app/configurations/mapping.rb.erb +14 -0
- data/app/configurations/production.rb.erb +30 -0
- data/app/lib/application.rb.erb +3 -0
- data/app/startup.rb +5 -0
- data/app/templates/errors/not_found_404.mab +2 -0
- data/app/templates/errors/server_error_500.mab +2 -0
- data/app/templates/layouts/default.mab +14 -0
- data/bin/waves +66 -0
- data/bin/waves-console +4 -0
- data/bin/waves-server +4 -0
- data/lib/commands/waves-console.rb +24 -0
- data/lib/commands/waves-server.rb +55 -0
- data/lib/controllers/mixin.rb +158 -0
- data/lib/dispatchers/base.rb +52 -0
- data/lib/dispatchers/default.rb +67 -0
- data/lib/foundations/default.rb +28 -0
- data/lib/foundations/simple.rb +17 -0
- data/lib/helpers/common.rb +62 -0
- data/lib/helpers/form.rb +39 -0
- data/lib/helpers/formatting.rb +30 -0
- data/lib/helpers/model.rb +33 -0
- data/lib/helpers/view.rb +24 -0
- data/lib/layers/default_errors.rb +24 -0
- data/lib/layers/simple_errors.rb +17 -0
- data/lib/mapping/mapping.rb +252 -0
- data/lib/mapping/pretty_urls.rb +94 -0
- data/lib/renderers/erubis.rb +61 -0
- data/lib/renderers/markaby.rb +33 -0
- data/lib/renderers/mixin.rb +53 -0
- data/lib/runtime/application.rb +65 -0
- data/lib/runtime/configuration.rb +180 -0
- data/lib/runtime/console.rb +20 -0
- data/lib/runtime/debugger.rb +9 -0
- data/lib/runtime/logger.rb +52 -0
- data/lib/runtime/mime_types.rb +22 -0
- data/lib/runtime/request.rb +77 -0
- data/lib/runtime/response.rb +40 -0
- data/lib/runtime/response_mixin.rb +35 -0
- data/lib/runtime/response_proxy.rb +27 -0
- data/lib/runtime/server.rb +94 -0
- data/lib/runtime/session.rb +56 -0
- data/lib/tasks/cluster.rb +25 -0
- data/lib/tasks/gem.rb +31 -0
- data/lib/tasks/generate.rb +15 -0
- data/lib/utilities/inflect.rb +194 -0
- data/lib/utilities/integer.rb +17 -0
- data/lib/utilities/kernel.rb +34 -0
- data/lib/utilities/module.rb +17 -0
- data/lib/utilities/object.rb +17 -0
- data/lib/utilities/proc.rb +9 -0
- data/lib/utilities/string.rb +47 -0
- data/lib/utilities/symbol.rb +7 -0
- data/lib/verify/mapping.rb +29 -0
- data/lib/verify/request.rb +40 -0
- data/lib/views/mixin.rb +108 -0
- data/lib/waves.rb +80 -0
- metadata +260 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
module Waves
|
2
|
+
module Mapping
|
3
|
+
|
4
|
+
# A set of pre-packed mapping rules for dealing with pretty URLs (that use names instead
|
5
|
+
# of numbers to identify resources). There are two modules.
|
6
|
+
# - GetRules, which defines all the GET methods for dealing with named resources
|
7
|
+
# - RestRules, which defines add, update, and delete rules using a REST style interface
|
8
|
+
#
|
9
|
+
module PrettyUrls
|
10
|
+
|
11
|
+
#
|
12
|
+
# GetRules defines the following URL conventions:
|
13
|
+
#
|
14
|
+
# /resources # => get a list of all instances of resource
|
15
|
+
# /resource/name # => get a specific instance of resource with the given name
|
16
|
+
# /resource/name/editor # => display an edit page for the given resource
|
17
|
+
#
|
18
|
+
module GetRules
|
19
|
+
|
20
|
+
def self.included(target)
|
21
|
+
|
22
|
+
target.module_eval do
|
23
|
+
|
24
|
+
extend Waves::Mapping
|
25
|
+
|
26
|
+
name = '([\w\-\_\.\+\@]+)'; model = '([\w\-]+)'
|
27
|
+
|
28
|
+
# get all resources for the given model
|
29
|
+
path %r{^/#{model}/?$}, :method => :get do | model |
|
30
|
+
resource( model.singular ) { controller { all } | view { |data| list( model => data ) } }
|
31
|
+
end
|
32
|
+
|
33
|
+
# get the given resource for the given model
|
34
|
+
path %r{^/#{model}/#{name}/?$}, :method => :get do | model, name |
|
35
|
+
resource( model ) { controller { find( name ) } | view { |data| show( model => data ) } }
|
36
|
+
end
|
37
|
+
|
38
|
+
# display an editor for the given resource / model
|
39
|
+
path %r{^/#{model}/#{name}/editor/?$}, :method => :get do | model, name |
|
40
|
+
resource( model ) { controller { find( name ) } | view { |data| editor( model => data ) } }
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# RestRules defines the following URL conventions:
|
51
|
+
#
|
52
|
+
# POST /resources # => add a new resource
|
53
|
+
# PUT /resource/name # => update the given resource
|
54
|
+
# DELETE /resource/name # => delete the given resource
|
55
|
+
#
|
56
|
+
module RestRules
|
57
|
+
|
58
|
+
def self.included(target)
|
59
|
+
|
60
|
+
target.module_eval do
|
61
|
+
|
62
|
+
extend Waves::Mapping
|
63
|
+
|
64
|
+
name = '([\w\-\_\.\+\@]+)'; model = '([\w\-]+)'
|
65
|
+
|
66
|
+
# create a new resource for the given model
|
67
|
+
path %r{^/#{model}/?$}, :method => :post do | model |
|
68
|
+
resource( model.singular ) do
|
69
|
+
instance = controller { create }
|
70
|
+
redirect( "/#{model.singular}/#{instance.name}/editor" )
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# update the given resource for the given model
|
75
|
+
path %r{^/#{model}/#{name}/?$}, :method => :put do | model, name |
|
76
|
+
resource( model ) { controller { update( name ) }; redirect( url ) }
|
77
|
+
end
|
78
|
+
|
79
|
+
# delete the given resource for the given model
|
80
|
+
path %r{^/#{model}/#{name}/?$}, :method => :delete do | model, name |
|
81
|
+
resource( model ) { controller { delete( name ) } }
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
3
|
+
module Erubis
|
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.
|
7
|
+
class Context
|
8
|
+
include Waves::Helpers::UrlHelper
|
9
|
+
include Waves::Helpers::TagHelper
|
10
|
+
|
11
|
+
def <<(s)
|
12
|
+
eval("_buf", @binding).concat s # add to rendered output
|
13
|
+
end
|
14
|
+
|
15
|
+
def capture
|
16
|
+
eval("_context.push(_buf); _buf = ''", @binding) #ignore output from that eval, will be added via "<<"
|
17
|
+
result = Erubis::Eruby.new(yield).result @binding
|
18
|
+
eval("_buf = _context.pop", @binding)
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
def render(eruby)
|
23
|
+
unless @binding
|
24
|
+
@binding = binding
|
25
|
+
eval("_buf = ''; _context = []", @binding)
|
26
|
+
end
|
27
|
+
eruby.result @binding
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
module Waves
|
35
|
+
|
36
|
+
module Renderers
|
37
|
+
|
38
|
+
class Erubis
|
39
|
+
|
40
|
+
include Renderers::Mixin
|
41
|
+
|
42
|
+
extension :erb
|
43
|
+
|
44
|
+
def self.render( path, assigns )
|
45
|
+
eruby = ::Erubis::Eruby.new( template( path ) )
|
46
|
+
helper = helper( path )
|
47
|
+
context = ::Erubis::Context.new
|
48
|
+
context.meta_eval { include( helper ) ; }
|
49
|
+
context.instance_eval do
|
50
|
+
assigns.each do |key,val|
|
51
|
+
instance_variable_set("@#{key}",val)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
context.render(eruby)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'markaby'
|
2
|
+
|
3
|
+
::Markaby::Builder.set( :indent, 2 )
|
4
|
+
|
5
|
+
module Waves
|
6
|
+
|
7
|
+
module Renderers
|
8
|
+
|
9
|
+
class Markaby
|
10
|
+
|
11
|
+
include Renderers::Mixin
|
12
|
+
|
13
|
+
extension :mab
|
14
|
+
|
15
|
+
# capture needed here for content fragments, otherwise
|
16
|
+
# you'll just get the last tag's output ...
|
17
|
+
# def self.capture( template )
|
18
|
+
# "capture { #{template} }"
|
19
|
+
# end
|
20
|
+
|
21
|
+
def self.render( path, assigns )
|
22
|
+
builder = ::Markaby::Builder.new( assigns )
|
23
|
+
helper = helper( path )
|
24
|
+
builder.meta_eval { include( helper ) }
|
25
|
+
builder.instance_eval( template( path ) )
|
26
|
+
builder.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
module Renderers
|
4
|
+
|
5
|
+
extend Autocode
|
6
|
+
# autoload :renderers, Class
|
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.
|
10
|
+
module Mixin
|
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
|
+
#
|
22
|
+
def self.included(target)
|
23
|
+
class << target
|
24
|
+
|
25
|
+
def extension(*args)
|
26
|
+
return @extension if args.length == 0
|
27
|
+
@extension = args.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def filename(path)
|
31
|
+
:templates / "#{path}.#{self.extension}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def render(path,args=nil)
|
35
|
+
end
|
36
|
+
|
37
|
+
def template( path )
|
38
|
+
File.read( filename( path ) )
|
39
|
+
end
|
40
|
+
|
41
|
+
def helper( path )
|
42
|
+
Waves.application.helpers[
|
43
|
+
File.basename( File.dirname( path ) ).camel_case ]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# See the README for an overview.
|
2
|
+
module Waves
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Access the principal Waves application.
|
7
|
+
attr_reader :application
|
8
|
+
|
9
|
+
# Register a module as a Waves application.
|
10
|
+
# Also, initialize the database connection if necessary.
|
11
|
+
def << ( app )
|
12
|
+
@application = app if Module === app
|
13
|
+
app.database if app.respond_to? 'database'
|
14
|
+
end
|
15
|
+
|
16
|
+
def instance ; Waves::Application.instance ; end
|
17
|
+
|
18
|
+
def method_missing(name,*args,&block)
|
19
|
+
instance.send(name,*args,&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
# An application in Waves is anything that provides access to the Waves
|
25
|
+
# runtime and the registered Waves applications. This includes both
|
26
|
+
# Waves::Server and Waves::Console. Waves::Application is *not* the actual
|
27
|
+
# application module(s) registered as Waves applications. To access the
|
28
|
+
# main Waves application, you can use +Waves+.+application+.
|
29
|
+
class Application
|
30
|
+
|
31
|
+
class << self; attr_accessor :instance; end
|
32
|
+
|
33
|
+
# Accessor for options passed to the application. Valid options include
|
34
|
+
attr_reader :options
|
35
|
+
|
36
|
+
# Create a new Waves application instance.
|
37
|
+
def initialize( options={} )
|
38
|
+
@options = options
|
39
|
+
Dir.chdir options[:directory] if options[:directory]
|
40
|
+
Application.instance = self
|
41
|
+
Kernel.load( :lib / 'application.rb' ) if Waves.application.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
def synchronize( &block ) ; ( @mutex ||= Mutex.new ).synchronize( &block ) ; end
|
45
|
+
|
46
|
+
# The 'mode' of the application determines which configuration it will run under.
|
47
|
+
def mode ; @mode ||= @options[:mode]||:development ; end
|
48
|
+
|
49
|
+
# Debug is true if debug is set to true in the current configuration.
|
50
|
+
def debug? ; config.debug ; end
|
51
|
+
|
52
|
+
# Access the current configuration. *Example:* +Waves::Server.config+
|
53
|
+
def config ; Waves.application.configurations[ mode ] ; end
|
54
|
+
|
55
|
+
# Access the mappings for the application.
|
56
|
+
def mapping ; Waves.application.configurations[ :mapping ] ; end
|
57
|
+
|
58
|
+
# Reload the modules specified in the current configuration.
|
59
|
+
def reload ; config.reloadable.each { |mod| mod.reload } ; end
|
60
|
+
|
61
|
+
# Returns the cache set for the current configuration
|
62
|
+
def cache ; config.cache ; end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,180 @@
|
|
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 => 'localhost', :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
|
+
#
|
113
|
+
|
114
|
+
module Configurations
|
115
|
+
|
116
|
+
class Base
|
117
|
+
|
118
|
+
# Set the given attribute with the given value. Typically, you wouldn't
|
119
|
+
# use this directly.
|
120
|
+
def self.[]=( name, val )
|
121
|
+
meta_def("_#{name}") { val }
|
122
|
+
end
|
123
|
+
|
124
|
+
# Get the value of the given attribute. Typically, you wouldn't
|
125
|
+
# use this directly.
|
126
|
+
def self.[]( name ) ; send "_#{name}" ; end
|
127
|
+
|
128
|
+
# Define a new attribute. After calling this, you can get and set the value.
|
129
|
+
def self.attribute( name )
|
130
|
+
meta_def(name) do |*args|
|
131
|
+
raise ArgumentError.new('Too many arguments.') if args.length > 1
|
132
|
+
args.length == 1 ? self[ name ] = args.first : self[ name ]
|
133
|
+
end
|
134
|
+
self[ name ] = nil
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
# The Default configuration provides a good starting point for your applications,
|
140
|
+
# defining a number of attributes that are required by Waves.
|
141
|
+
class Default < Base
|
142
|
+
|
143
|
+
%w( host port ports log reloadable database session debug root ).
|
144
|
+
each { |name| attribute(name) }
|
145
|
+
|
146
|
+
# Set the handler for use with Rack, along with any handler-specific options
|
147
|
+
# that will be passed to the handler's #run method. When accessing the value
|
148
|
+
# (calling with no arguments) returns an array of the handler and options.
|
149
|
+
def self.handler(*args)
|
150
|
+
if args.length > 0
|
151
|
+
@rack_handler, @rack_handler_options = args
|
152
|
+
else
|
153
|
+
[ @rack_handler, @rack_handler_options ]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Provide access to the Waves::MimeTypes class via the configuration. You
|
158
|
+
# could potentially point this to your own MIME types repository class.
|
159
|
+
def self.mime_types
|
160
|
+
Waves::MimeTypes
|
161
|
+
end
|
162
|
+
|
163
|
+
# Defines the application for use with Rack.
|
164
|
+
def self.application( &block )
|
165
|
+
if block_given?
|
166
|
+
self['application'] = Rack::Builder.new( &block )
|
167
|
+
else
|
168
|
+
self['application']
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
debug true
|
173
|
+
session :duration => 30.minutes, :path => '/tmp/sessions'
|
174
|
+
log :level => :info, :output => $stderr
|
175
|
+
reloadable []
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
|