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