waves 0.6.7 → 0.6.9
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 +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/helpers/common.rb
CHANGED
@@ -1,21 +1,61 @@
|
|
1
1
|
module Waves
|
2
2
|
module Helpers
|
3
|
+
|
4
|
+
# Common helpers are helpers that are needed for just about any Web page. For example,
|
5
|
+
# each page will likely have a layout and a doctype.
|
6
|
+
|
3
7
|
module Common
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
|
9
|
+
DOCTYPES = {
|
10
|
+
:html3 => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">',
|
11
|
+
:html4_transitional =>
|
12
|
+
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"' <<
|
13
|
+
'"http://www.w3.org/TR/html4/loose.dtd">',
|
14
|
+
:html4_strict =>
|
15
|
+
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" ' <<
|
16
|
+
'"http://www.w3.org/TR/html4/strict.dtd">',
|
17
|
+
:html4_frameset =>
|
18
|
+
'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"' <<
|
19
|
+
'"http://www.w3.org/TR/html4/frameset.dtd">',
|
20
|
+
:xhtml1_transitional =>
|
21
|
+
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' <<
|
22
|
+
'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
|
23
|
+
:xhtml1_strict =>
|
24
|
+
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' <<
|
25
|
+
'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
|
26
|
+
:xhtml1_frameset =>
|
27
|
+
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"' <<
|
28
|
+
'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
|
29
|
+
:xhtml2 => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">'
|
30
|
+
}
|
31
|
+
|
32
|
+
# Invokes a layout view (i.e., a view from the layouts template directory), using
|
33
|
+
# the assigns parameter to define instance variables for the view. The block is
|
34
|
+
# evaluated and also passed into the view as the +layout_content+ instance variable.
|
35
|
+
#
|
36
|
+
# You can define a layout just by creating a template and then calling the
|
37
|
+
# +layout_content+ accessor when you want to embed the caller's content.
|
38
|
+
#
|
39
|
+
# == Example
|
40
|
+
#
|
41
|
+
# doctype :html4_transitional
|
42
|
+
# html do
|
43
|
+
# title @title # passed as an assigns parameter
|
44
|
+
# end
|
45
|
+
# body do
|
46
|
+
# layout_content
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
def layout( name, assigns = {}, &block )
|
50
|
+
assigns[ :layout_content ] = capture(&block)
|
51
|
+
self << Waves.application.views[:layouts].process( request ) do
|
8
52
|
send( name, assigns )
|
9
53
|
end
|
10
54
|
end
|
11
55
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" ' <<
|
16
|
-
'"http://www.w3.org/TR/html4/strict.dtd">'
|
17
|
-
end
|
18
|
-
end
|
56
|
+
# The doctype method simply generates a valid DOCTYPE declaration for your page.
|
57
|
+
# Valid options are defined in the +DOCTYPES+ constant.
|
58
|
+
def doctype(type) ; self << DOCTYPES[type||:html4_strict] ; end
|
19
59
|
|
20
60
|
end
|
21
61
|
end
|
data/lib/helpers/form.rb
CHANGED
@@ -2,14 +2,31 @@ module Waves
|
|
2
2
|
|
3
3
|
module Helpers
|
4
4
|
|
5
|
+
# Form helpers are used in generating forms. Since Markaby already provides Ruby
|
6
|
+
# methods for basic form generation, the focus of this helper is on provide templates
|
7
|
+
# to handle things that go beyond the basics. You must define a form template
|
8
|
+
# directory with templates for each type of form element you wish to use. The names
|
9
|
+
# of the template should match the +type+ option provided in the property method.
|
10
|
+
#
|
11
|
+
# For example, this code:
|
12
|
+
#
|
13
|
+
# property :name => 'blog.title', :type => :text, :value => @blog.title
|
14
|
+
#
|
15
|
+
# will invoke the +text+ form view (the template in +templates/form/text.mab+),
|
16
|
+
# passing in the name ('blog.title') and the value (@blog.title) as instance variables.
|
17
|
+
#
|
5
18
|
module Form
|
6
|
-
|
19
|
+
|
20
|
+
# This method really is a place-holder for common wrappers around groups of
|
21
|
+
# properties. You will usually want to override this. As is, it simply places
|
22
|
+
# a DIV element with class 'properties' around the block.
|
7
23
|
def properties(&block)
|
8
24
|
div.properties do
|
9
25
|
yield
|
10
26
|
end
|
11
27
|
end
|
12
28
|
|
29
|
+
# Invokes the form view for the +type+ given in the option.
|
13
30
|
def property( options )
|
14
31
|
self << view( :form, options[:type], options )
|
15
32
|
end
|
data/lib/helpers/formatting.rb
CHANGED
@@ -1,20 +1,28 @@
|
|
1
1
|
require 'redcloth'
|
2
2
|
module Waves
|
3
3
|
module Helpers
|
4
|
+
|
5
|
+
# Formatting helpers are used to convert specialized content, like Markaby or
|
6
|
+
# Textile, into valid HTML. It also provides common escaping functions.
|
4
7
|
module Formatting
|
8
|
+
|
9
|
+
# Escape a string as HTML content.
|
10
|
+
def escape_html(s); Rack::Utils.escape_html(s); end
|
11
|
+
|
12
|
+
# Escape a URI, converting quotes and spaces and so on.
|
13
|
+
def escape_uri(s); Rack::Utils.escape(s); end
|
14
|
+
|
15
|
+
# Treat content as Markaby and evaluate (only works within a Markaby template).
|
16
|
+
# Used to pull Markaby content from a file or database into a Markaby template.
|
17
|
+
def markaby( content ); self << eval( content ); end
|
5
18
|
|
6
|
-
#
|
7
|
-
# but i hate to do a whole new Builder when I'm
|
8
|
-
# already inside one! test self === Builder?
|
9
|
-
def mab( content )
|
10
|
-
eval content
|
11
|
-
end
|
12
|
-
|
19
|
+
# Treat content as Textile.
|
13
20
|
def textile( content )
|
14
|
-
|
21
|
+
return if content.nil? or content.empty?
|
22
|
+
( ::RedCloth::TEXTILE_TAGS << [ 96.chr, '&8216;'] ).each do |pat,ent|
|
15
23
|
content.gsub!( pat, ent.gsub('&','&#') )
|
16
24
|
end
|
17
|
-
::RedCloth.new( content ).to_html
|
25
|
+
self << ::RedCloth.new( content ).to_html
|
18
26
|
end
|
19
27
|
|
20
28
|
end
|
data/lib/helpers/model.rb
CHANGED
@@ -1,13 +1,31 @@
|
|
1
1
|
module Waves
|
2
2
|
module Helpers
|
3
|
+
|
4
|
+
# Model helpers allow you to directly access a model from within a view.
|
5
|
+
# This is useful when creating things like select boxes that need data
|
6
|
+
# from anther model. For example, a Markaby select box for authors might look like:
|
7
|
+
#
|
8
|
+
# select do
|
9
|
+
# all(:user).each do |user|
|
10
|
+
# option user.full_name, :value => user.id
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# You could also use these within a view class to keep model-based logic out
|
15
|
+
# of the templates themselves. For example, in the view class you might define
|
16
|
+
# a method called +authors+ that returns an array of name / id pairs. This could
|
17
|
+
# then be called from the template instead of the model helper.
|
18
|
+
#
|
3
19
|
module Model
|
4
20
|
|
21
|
+
# Just like model.all. Returns all the instances of that model.
|
5
22
|
def all( model )
|
6
|
-
|
23
|
+
Waves.application.models[ model ].all( domain )
|
7
24
|
end
|
8
25
|
|
26
|
+
# Finds a specific instance using the name field
|
9
27
|
def find( model, name )
|
10
|
-
|
28
|
+
Waves.application.models[ model ][ :name => name ] rescue nil
|
11
29
|
end
|
12
30
|
|
13
31
|
end
|
data/lib/helpers/view.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
module Waves
|
2
2
|
module Helpers
|
3
|
+
|
4
|
+
# View helpers are intended to help reuse views from within other views.
|
5
|
+
# Both the +layout+ method in the common helpers and the +property+ method
|
6
|
+
# of the form helpers are specialized instance of this.
|
7
|
+
#
|
8
|
+
# The star of our show here is the +view+ method. This takes a model, view,
|
9
|
+
# and assigns hash (which are converted into instance variables in the target
|
10
|
+
# view) and returns the result of evaluating the view as content in the current
|
11
|
+
# template.
|
3
12
|
module View
|
4
13
|
|
14
|
+
# Invokes the view for the given model, passing the assigns as instance variables.
|
5
15
|
def view( model, view, assigns = {} )
|
6
|
-
self <<
|
7
|
-
send view, assigns
|
16
|
+
self << Waves.application.views[ model ].process( request ) do
|
17
|
+
send( view, assigns )
|
8
18
|
end
|
9
19
|
end
|
10
20
|
|
@@ -0,0 +1,187 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
# Waves::Mapping is a mixin for defining Waves URI mappings (mapping a request to Ruby code).
|
4
|
+
# Mappings can work against the request url, path, and elements of the request (such as the
|
5
|
+
# request method or accept header). Mappings may also include before, after, or wrap filters
|
6
|
+
# to be run if they match the request. Mappings are created using an appropriate mapping method
|
7
|
+
# along with a URL pattern (a string or regular expression), a hash of constraint options, and
|
8
|
+
# a block, which is the code to run if the pattern matches.
|
9
|
+
#
|
10
|
+
# == Examples
|
11
|
+
#
|
12
|
+
# path %r{^/#{resource}/#{name}/?$} do |resource, name|
|
13
|
+
# "Hello from a #{resource} named #{name.capitalize}."
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# In this example, we are using binding regular expressions defined by +resource+
|
17
|
+
# and +name+. The matches are passed into the block as parameters. Thus, this
|
18
|
+
# rule, given the URL '/person/john' will return:
|
19
|
+
#
|
20
|
+
# Hello from a person named John.
|
21
|
+
#
|
22
|
+
# The given block may simple return a string. The content type is inferred from the request
|
23
|
+
# if possible, otherwise it defaults to +text+/+html+.
|
24
|
+
#
|
25
|
+
# path '/critters', :method => :post do
|
26
|
+
# request.content_type
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# /critters # => 'text/html'
|
30
|
+
#
|
31
|
+
# In this example, we match against a string and check to make sure that the request is a
|
32
|
+
# POST. If so, we return the request content_type. The request (and response) objects are
|
33
|
+
# available from within the block implicitly.
|
34
|
+
#
|
35
|
+
# = Invoking Controllers and Views
|
36
|
+
#
|
37
|
+
# You may invoking a controller or view method for the primary application by using the
|
38
|
+
# corresponding methods, preceded by the +use+ directive.
|
39
|
+
#
|
40
|
+
# == Examples
|
41
|
+
#
|
42
|
+
# path %r{^/#{resource}/#{name}/?$} do |resource, name|
|
43
|
+
# use( resource ) | controller { find( name ) } |
|
44
|
+
# view { | instance | show( resource => instance ) }
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# In this example, we take the same rule from above but invoke a controller and view method.
|
48
|
+
# We use the +use+ directive and the resource parameter to set the MVC instances we're going
|
49
|
+
# to use. This is necessary to use the +controller+ or +view+ methods. Each of these take
|
50
|
+
# a block as arguments which are evaluated in the context of the instance. The +view+ method
|
51
|
+
# can further take an argument which is "piped" from the result of the controller block. This
|
52
|
+
# isn't required, but helps to clarify the request processing. Within a view block, a hash
|
53
|
+
# may also be passed in, which is converted into instance variables for the view instance. In
|
54
|
+
# this example, the +show+ method is assigned to an instance variable with the same name as
|
55
|
+
# the resource type.
|
56
|
+
#
|
57
|
+
# So given the same URL as above - /person/john - what will happen is the +find+ method for
|
58
|
+
# the +Person+ controller will be invoked and the result passed to the +Person+ view's +show+
|
59
|
+
# method, with +@person+ holding the value returned.
|
60
|
+
#
|
61
|
+
# Crucially, the controller does not need to know what variables the view depends on. This is
|
62
|
+
# the job of the mapping block, to act as the "glue" between the controller and view. The
|
63
|
+
# controller and view can thus be completely decoupled and become easier to reuse separately.
|
64
|
+
#
|
65
|
+
# url 'http://admin.foobar.com:/' do
|
66
|
+
# use( admin ) | view { console }
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# In this example, we are using the +url+ method to map a subdomain of +foobar.com+ to the
|
70
|
+
# console method of the Admin view. In this case, we did not need a controller method, so
|
71
|
+
# we simply didn't call one.
|
72
|
+
#
|
73
|
+
# = Mapping Modules
|
74
|
+
#
|
75
|
+
# You may encapsulate sets of related rules into modules and simply include them into your
|
76
|
+
# mapping module. Some rule sets come packaged with Waves, such as PrettyUrls (rules for
|
77
|
+
# matching resources using names instead of ids). The simplest way to define such modules for
|
78
|
+
# reuse is by defining the +included+ class method for the rules module, and then define
|
79
|
+
# the rules using +module_eval+. This will likely be made simpler in a future release, but
|
80
|
+
# see the PrettyUrls module for an example of how to do this.
|
81
|
+
#
|
82
|
+
# *Important:* Using pre-packaged mapping rules does not prevent you from adding to or
|
83
|
+
# overriding these rules. However, order does matter, so you should put your own rules
|
84
|
+
# ahead of those your may be importing. Also, place rules with constraints (for example,
|
85
|
+
# rules that require a POST) ahead of those with no constraints, otherwise the constrainted
|
86
|
+
# rules may never be called.
|
87
|
+
|
88
|
+
module Mapping
|
89
|
+
|
90
|
+
# If the pattern matches and constraints given by the options hash are satisfied, run the
|
91
|
+
# block before running any +path+ or +url+ actions. You can have as many +before+ matches
|
92
|
+
# as you want - they will all run, unless one of them calls redirect, generates an
|
93
|
+
# unhandled exception, etc.
|
94
|
+
def before( pattern, options=nil, &block )
|
95
|
+
filters[:before] << [ pattern, options, block ]
|
96
|
+
end
|
97
|
+
|
98
|
+
# Similar to before, except it runs its actions after any matching +url+ or +path+ actions.
|
99
|
+
def after( pattern, options=nil, &block )
|
100
|
+
filters[:after] << [ pattern, options, block ]
|
101
|
+
end
|
102
|
+
|
103
|
+
# Run the action before and after the matching +url+ or +path+ action.
|
104
|
+
def wrap( pattern, options=nil, &block )
|
105
|
+
filters[:before] << [ pattern, options, block ]
|
106
|
+
filters[:after] << [ pattern, options, block ]
|
107
|
+
end
|
108
|
+
|
109
|
+
# Maps a request to a block. Don't use this method directly unless you know what
|
110
|
+
# you're doing. Use +path+ or +url+ instead.
|
111
|
+
def map( options, &block )
|
112
|
+
pattern = options[:path] || options[:url]
|
113
|
+
mapping << [ pattern, options, block ]
|
114
|
+
end
|
115
|
+
|
116
|
+
# Match pattern against the +request.path+, along with satisfying any constraints
|
117
|
+
# specified by the options hash. If the pattern matches and the constraints are satisfied,
|
118
|
+
# run the block. Only one +path+ or +url+ match will be run (the first one).
|
119
|
+
def path( pat, options = {}, &block )
|
120
|
+
options[:path] = pat; map( options, &block )
|
121
|
+
end
|
122
|
+
|
123
|
+
# Match pattern against the +request.url+, along with satisfying any constraints
|
124
|
+
# specified by the options hash. If the pattern matches and the constraints are satisfied,
|
125
|
+
# run the block. Only one +path+ or +url+ match will be run (the first one).
|
126
|
+
def url( pat, options = {}, &block )
|
127
|
+
options[:url] = pat; map( options, block )
|
128
|
+
end
|
129
|
+
|
130
|
+
# Match the given request against the defined rules. This is typically only called
|
131
|
+
# by a dispatcher object, so you shouldn't typically use it directly.
|
132
|
+
def []( request )
|
133
|
+
|
134
|
+
rx = { :before => [], :after => [], :action => nil }
|
135
|
+
|
136
|
+
( filters[:before] + filters[:wrap] ).each do | pattern, options, function |
|
137
|
+
matches = pattern.match(request.path)
|
138
|
+
rx[:before] << [ function, matches[1..-1] ] if matches &&
|
139
|
+
( ! options || satisfy( request, options ))
|
140
|
+
end
|
141
|
+
|
142
|
+
mapping.find do |pattern, options, function|
|
143
|
+
matches = pattern.match(request.path)
|
144
|
+
rx[:action] = [ function, matches[1..-1] ] if matches &&
|
145
|
+
( ! options || satisfy( request, options ) )
|
146
|
+
end
|
147
|
+
|
148
|
+
( filters[:after] + filters[:wrap] ).each do | pattern, options, function |
|
149
|
+
matches = pattern.match(request.path)
|
150
|
+
rx[:after] << [ function, matches[1..-1] ] if matches &&
|
151
|
+
( ! options || satisfy( request, options ))
|
152
|
+
end
|
153
|
+
|
154
|
+
not_found(request) unless rx[:action]
|
155
|
+
|
156
|
+
return rx
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def mapping; @mapping ||= []; end
|
163
|
+
|
164
|
+
def filters; @filters ||= { :before => [], :after => [], :wrap => [] }; end
|
165
|
+
|
166
|
+
def not_found(request)
|
167
|
+
raise Waves::Dispatchers::NotFoundError.new( request.url + ' not found.')
|
168
|
+
end
|
169
|
+
|
170
|
+
def satisfy( request, options )
|
171
|
+
options.each do |method, param|
|
172
|
+
return false unless self.send( method, param, request )
|
173
|
+
end
|
174
|
+
return true
|
175
|
+
end
|
176
|
+
|
177
|
+
def method( method, request )
|
178
|
+
request.method == method
|
179
|
+
end
|
180
|
+
|
181
|
+
# TODO: Add constraint for request accept header
|
182
|
+
def accept( format, request )
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
@@ -0,0 +1,95 @@
|
|
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}/?$} do | model |
|
30
|
+
use( 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}/?$} do | model, name |
|
35
|
+
use(model) | controller { find( name ) } |
|
36
|
+
view { |data| show( model => data ) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# display an editor for the given resource / model
|
40
|
+
path %r{^/#{model}/#{name}/editor/?$} do | model, name |
|
41
|
+
use(model) | controller { find( name ) } |
|
42
|
+
view { |data| editor( model => data ) }
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# RestRules defines the following URL conventions:
|
53
|
+
#
|
54
|
+
# POST /resources # => add a new resource using the POST variables
|
55
|
+
# POST /resource/name # => update the given resource using the POST variables
|
56
|
+
# DELETE /resource/name # => delete the given resource
|
57
|
+
#
|
58
|
+
module RestRules
|
59
|
+
|
60
|
+
def self.included(target)
|
61
|
+
|
62
|
+
target.module_eval do
|
63
|
+
|
64
|
+
extend Waves::Mapping
|
65
|
+
|
66
|
+
name = '([\w\-\_\.\+\@]+)'; model = '([\w\-]+)'
|
67
|
+
|
68
|
+
# create a new resource for the given model
|
69
|
+
path %r{^/#{model}/?$}, :method => :post do | model |
|
70
|
+
use( model.singular )
|
71
|
+
instance = controller { create }
|
72
|
+
redirect( "/#{model.singular}/#{instance.name}/editor" )
|
73
|
+
end
|
74
|
+
|
75
|
+
# add / update the given resource for the given model
|
76
|
+
path %r{^/#{model}/#{name}/?$}, :method => :post do | model, name |
|
77
|
+
use(model) | controller { update( name ) }; redirect( url )
|
78
|
+
end
|
79
|
+
|
80
|
+
# delete the given resource for the given model
|
81
|
+
path %r{^/#{model}/#{name}/?$}, :method => :delete do | model, name |
|
82
|
+
use( model ) | controller { delete( name ) }
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|