described_routes 0.5.1 → 0.6.0
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/History.txt +5 -0
- data/LICENSE +1 -1
- data/Manifest.txt +5 -0
- data/README.rdoc +19 -3
- data/lib/described_routes/helpers/described_routes_helper.rb +131 -0
- data/lib/described_routes/rails_controller.rb +12 -11
- data/lib/described_routes/rails_routes.rb +37 -9
- data/lib/described_routes.rb +1 -1
- data/lib/resource_template.rb +41 -10
- data/test/test_resource_template.rb +29 -0
- data/test_rails_app/app/controllers/application_controller.rb +8 -1
- data/test_rails_app/app/controllers/users_controller.rb +9 -0
- data/test_rails_app/app/controllers/welcome_controller.rb +9 -0
- data/test_rails_app/app/views/layouts/default.html.erb +9 -0
- data/test_rails_app/test/integration/headers_test.rb +38 -0
- metadata +10 -7
data/History.txt
CHANGED
data/LICENSE
CHANGED
data/Manifest.txt
CHANGED
@@ -5,6 +5,7 @@ PostInstall.txt
|
|
5
5
|
README.rdoc
|
6
6
|
Rakefile
|
7
7
|
lib/described_routes.rb
|
8
|
+
lib/described_routes/helpers/described_routes_helper.rb
|
8
9
|
lib/described_routes/rails_controller.rb
|
9
10
|
lib/described_routes/rails_routes.rb
|
10
11
|
lib/described_routes/rake_task_methods.rb
|
@@ -19,7 +20,10 @@ test/test_helper.rb
|
|
19
20
|
test/test_resource_template.rb
|
20
21
|
test_rails_app/Rakefile
|
21
22
|
test_rails_app/app/controllers/application_controller.rb
|
23
|
+
test_rails_app/app/controllers/users_controller.rb
|
24
|
+
test_rails_app/app/controllers/welcome_controller.rb
|
22
25
|
test_rails_app/app/helpers/application_helper.rb
|
26
|
+
test_rails_app/app/views/layouts/default.html.erb
|
23
27
|
test_rails_app/config/boot.rb
|
24
28
|
test_rails_app/config/environment.rb
|
25
29
|
test_rails_app/config/environments/development.rb
|
@@ -43,5 +47,6 @@ test_rails_app/test/fixtures/run_time/described_routes.text
|
|
43
47
|
test_rails_app/test/fixtures/run_time/described_routes.xml
|
44
48
|
test_rails_app/test/fixtures/run_time/described_routes.yaml
|
45
49
|
test_rails_app/test/integration/described_routes_run_time_test.rb
|
50
|
+
test_rails_app/test/integration/headers_test.rb
|
46
51
|
test_rails_app/test/integration/rake_tasks_test.rb
|
47
52
|
test_rails_app/test/test_helper.rb
|
data/README.rdoc
CHANGED
@@ -2,9 +2,7 @@
|
|
2
2
|
|
3
3
|
== DESCRIPTION
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
Also the home (for now at least) of the ResourceTemplate class.
|
5
|
+
Dynamic, framework-neutral metadata describing path/URI structures, with natural translations to/from JSON, YAML and XML. Bonus features: easy Rails integration, link element / link header generation and a plain text report format!
|
8
6
|
|
9
7
|
See roadmap for described_routes and path-to[http://github.com/asplake/path-to/tree] at http://positiveincline.com/?p=213.
|
10
8
|
|
@@ -164,6 +162,24 @@ JSON example (after pretty printing):
|
|
164
162
|
}
|
165
163
|
]
|
166
164
|
}
|
165
|
+
|
166
|
+
=== Link Generation
|
167
|
+
|
168
|
+
TODO: document how to integrate described_routes_helper; meanwhile see the test_rails_app for guidance.
|
169
|
+
|
170
|
+
Generate HTML link elements by generated by adding
|
171
|
+
|
172
|
+
<%= link_elements %>
|
173
|
+
|
174
|
+
to the <head> part of you layout.
|
175
|
+
|
176
|
+
Generate link headers (see the draft spec http://tools.ietf.org/id/draft-nottingham-http-link-header-05.txt) by including
|
177
|
+
|
178
|
+
before_filter :set_link_header
|
179
|
+
|
180
|
+
in your controllers. You can do this once in ApplicationController to get this behaviour across all controllers.
|
181
|
+
|
182
|
+
See DescribedRoutes::DescribedRoutesHelper#link_data for configuration options.
|
167
183
|
|
168
184
|
== DATA STRUCTURES and FORMATS
|
169
185
|
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module DescribedRoutes
|
2
|
+
module DescribedRoutesHelper
|
3
|
+
# Map rels to standard relation types, used by #link_data
|
4
|
+
REGISTERED_RELS = {
|
5
|
+
'edit' => 'edit'
|
6
|
+
}
|
7
|
+
|
8
|
+
# The default options parameter to #link_elements; controls which links appear in html link elements
|
9
|
+
LINK_ELEMENT_OPTIONS = {
|
10
|
+
:self => true, :describedby => true, :describedby => true, :describedbywithparams => true, :up => true, :related => true
|
11
|
+
}
|
12
|
+
|
13
|
+
# The default options parameter to #link_headers; controls which links appear in html link elements
|
14
|
+
LINK_HEADER_OPTIONS = {
|
15
|
+
:self => true, :describedby => true, :describedby => true, :describedbywithparams => true, :up => true, :related => true
|
16
|
+
}
|
17
|
+
|
18
|
+
# get the resource template structure, initialised (once) from Rails routes
|
19
|
+
def resource_templates
|
20
|
+
@@resource_templates ||= begin
|
21
|
+
base_url = root_url rescue nil
|
22
|
+
RailsRoutes.get_resource_templates(base_url)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# get the resource template for the current request
|
27
|
+
def resource_template
|
28
|
+
r = resource_templates.routing[[controller_name, action_name]]
|
29
|
+
r[0] if r
|
30
|
+
end
|
31
|
+
|
32
|
+
# combined path and query parameters (not POST parameters), with the id param renamed to foo_id (say)
|
33
|
+
def resource_parameters
|
34
|
+
@resource_parameters ||= begin
|
35
|
+
p = request.path_parameters.merge(request.query_parameters)
|
36
|
+
r = resource_templates.routing[[controller_name, action_name]]
|
37
|
+
if r && r[1] && p[:id]
|
38
|
+
p[r[1]] = p.delete(:id)
|
39
|
+
end
|
40
|
+
p.except("action", "controller")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Render link_data as <link <url> rel=<rel> ... type=<type>> elements. Add to the <head> part of your layout with:
|
45
|
+
# <%= link_elements %>
|
46
|
+
def link_elements(options=LINK_ELEMENT_OPTIONS)
|
47
|
+
link_data(options).map{|url, rels, type|
|
48
|
+
%Q(<link href="#{url}" #{rels.map{|r| %Q(rel="#{r}")}.join(" ")} type="#{type}">)
|
49
|
+
}.join("\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
# Render link_data as a link header. Usage:
|
53
|
+
# response.headers["Link"] = link_header(options)
|
54
|
+
# or use #set_link_header
|
55
|
+
def link_header(options=LINK_HEADER_OPTIONS)
|
56
|
+
link_data(options).map{|url, rels, type|
|
57
|
+
%Q(<#{url}>; #{rels.map{|r| %Q(rel="#{r}")}.join("; ")}; type="#{type}")
|
58
|
+
}.join(', ')
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sets a link header in the response
|
62
|
+
# before_filter :set_link_header
|
63
|
+
def set_link_header(options=LINK_HEADER_OPTIONS)
|
64
|
+
response.headers["Link"] = link_header(options)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns an array of link information, each element containing
|
68
|
+
# 0) a URL
|
69
|
+
# 1) a *list* of link relation types (there can be more than one) - see explanation below
|
70
|
+
# 2) a "type" - actually a route name or (literally) "ResourceTemplate"
|
71
|
+
# The list of link relations types will contain a standard type ('self', 'up', 'describedby') &/or an extention type
|
72
|
+
# in the form "described_route_url(name)#rel", using the name and rel of the resource template.
|
73
|
+
#
|
74
|
+
# Example output for a request to a "user" route:
|
75
|
+
#
|
76
|
+
# [
|
77
|
+
# ['http://example.com/users/dojo', ['self'], 'user'],
|
78
|
+
# ['http://example.com/users', ['up'], 'users'],
|
79
|
+
# ['http://example.com/users/described_routes/user?user_id=dojo', ['describedby'], 'ResourceTemplate'],
|
80
|
+
# ['http://example.com/users/dojo/edit', ['edit', 'http://example.com/user/described_routes/user#edit'], 'edit_user'],
|
81
|
+
# ['http://example.com/users/dojo/edit', ['http://example.com/user/described_routes/user#profile'], 'user_profile']
|
82
|
+
# ]
|
83
|
+
#
|
84
|
+
# The output is filtered by the options hash, with members :self, :describedby, :describedby, :describedbywithparams, :up, :related.
|
85
|
+
# Rel values will include a short value (e.g. 'edit') if the template's rel has a mapping in REGISTERED_RELS.
|
86
|
+
#
|
87
|
+
def link_data(options)
|
88
|
+
result = []
|
89
|
+
rt = resource_template
|
90
|
+
if rt
|
91
|
+
if rt.name == 'root'
|
92
|
+
described_by = described_routes_url
|
93
|
+
related = resource_templates
|
94
|
+
else
|
95
|
+
described_by = described_route_url(rt.name)
|
96
|
+
related = rt.resource_templates
|
97
|
+
end
|
98
|
+
|
99
|
+
if resource_parameters.empty?
|
100
|
+
described_by_with_params = described_by
|
101
|
+
else
|
102
|
+
described_by_with_params = described_by + '?' + resource_parameters.to_query
|
103
|
+
end
|
104
|
+
|
105
|
+
type_prefix = described_routes_url + '#'
|
106
|
+
|
107
|
+
result << [request.url, ['self'], type_prefix + rt.name] if options[:self]
|
108
|
+
result << [described_by, ['describedby'], type_prefix + 'ResourceTemplate'] if options[:describedby]
|
109
|
+
if options[:describedbywithparams]
|
110
|
+
result << [described_by_with_params, ['describedby'], type_prefix + 'ResourceTemplate'] if described_by_with_params != described_by || !options[:describedby]
|
111
|
+
end
|
112
|
+
if options[:up]
|
113
|
+
if rt.parent
|
114
|
+
result << [rt.parent.uri_for(resource_parameters), ['up'], type_prefix + rt.parent.name]
|
115
|
+
elsif rt.name != 'root'
|
116
|
+
result << [root_url, ['up'], type_prefix + "root"]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
if options[:related]
|
120
|
+
related.expand_links(resource_parameters).map do |l|
|
121
|
+
if l.name != rt.name
|
122
|
+
rel = l.rel || l.name
|
123
|
+
result << [l.uri, REGISTERED_RELS[rel].to_a + [described_by + '#' + rel], type_prefix + l.name]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
result
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -1,30 +1,31 @@
|
|
1
1
|
require 'described_routes/rails_routes'
|
2
|
+
require 'described_routes/helpers/described_routes_helper'
|
2
3
|
require 'active_support'
|
3
4
|
|
4
5
|
module DescribedRoutes
|
5
6
|
class RailsController < ActionController::Base
|
7
|
+
include DescribedRoutes::DescribedRoutesHelper
|
8
|
+
|
6
9
|
def index
|
7
|
-
|
8
|
-
resource_templates = RailsRoutes.get_resource_templates(base_url).partial_expand(request.query_parameters)
|
10
|
+
expanded_templates = resource_templates.partial_expand(request.query_parameters)
|
9
11
|
|
10
12
|
respond_to do |format|
|
11
|
-
format.html # index.html.erb
|
12
|
-
format.json { render :json =>
|
13
|
-
format.text { render :text =>
|
14
|
-
format.yaml { render :text =>
|
15
|
-
format.xml { render :xml =>
|
13
|
+
format.html { render rescue redirect_to :format => :text } # render index.html.erb or fall back to text
|
14
|
+
format.json { render :json => expanded_templates.to_json }
|
15
|
+
format.text { render :text => expanded_templates.to_text }
|
16
|
+
format.yaml { render :text => expanded_templates.to_yaml }
|
17
|
+
format.xml { render :xml => expanded_templates.to_xml(Builder::XmlMarkup.new(:indent => 2)).target! }
|
16
18
|
end
|
17
19
|
end
|
18
|
-
|
20
|
+
|
19
21
|
def show
|
20
|
-
|
21
|
-
resource_templates = RailsRoutes.get_resource_templates(base_url).partial_expand(request.query_parameters)
|
22
|
+
expanded_templates = resource_templates.partial_expand(request.query_parameters)
|
22
23
|
resource_template = resource_templates.all_by_name[params[:id]]
|
23
24
|
# TODO 404 if nil
|
24
25
|
resource_template = resource_template.partial_expand(request.query_parameters)
|
25
26
|
|
26
27
|
respond_to do |format|
|
27
|
-
format.html # show.html.erb
|
28
|
+
format.html { render rescue redirect_to :format => :text } # render show.html.erb or fall back to text
|
28
29
|
format.json { render :json => resource_template.to_json }
|
29
30
|
format.text { render :text => resource_template.to_text }
|
30
31
|
format.yaml { render :text => resource_template.to_yaml }
|
@@ -2,6 +2,33 @@ require 'resource_template'
|
|
2
2
|
|
3
3
|
module DescribedRoutes
|
4
4
|
module RailsRoutes
|
5
|
+
# This is just glue really. It captures some extra data in the top level ResourceTemplates container to help address a
|
6
|
+
# couple of issues:
|
7
|
+
# 1) Inconsistent id parameter naming - id become {foo}_id when foo becomes the parent of another type of resources
|
8
|
+
# 2) Rails doesn't pass in the route object (not even its name) when routing a request to a controller so we have
|
9
|
+
# to keep enough information here for us to be able to guess it. Controller and action will be enough 99% of the time.
|
10
|
+
class RailsResourceTemplates < ResourceTemplate::ResourceTemplates
|
11
|
+
# Maps [controller, action] to [resource_template, id_name]
|
12
|
+
attr_reader :routing
|
13
|
+
|
14
|
+
def initialize(parsed)
|
15
|
+
super
|
16
|
+
|
17
|
+
@routing = {}
|
18
|
+
save_routing(parsed)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def save_routing(parsed)
|
24
|
+
if parsed
|
25
|
+
parsed.each do |p|
|
26
|
+
@routing[[p["controller"], p["action"]]] = [all_by_name[p["name"]], p["id_name"]]
|
27
|
+
save_routing(p["resource_templates"])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
5
32
|
|
6
33
|
#
|
7
34
|
# Hook to customise the "parsed" (Array/Hash) data. For example, to remove certain sensitive routes:
|
@@ -11,12 +38,12 @@ module DescribedRoutes
|
|
11
38
|
mattr_accessor :parsed_hook
|
12
39
|
|
13
40
|
#
|
14
|
-
# Process Rails routes and return an array of ResourceTemplate objects
|
41
|
+
# Process Rails routes and return an array of ResourceTemplate objects.
|
15
42
|
#
|
16
|
-
def self.get_resource_templates(base_url =
|
43
|
+
def self.get_resource_templates(base_url=nil, routing=nil)
|
17
44
|
parsed = get_parsed_rails_resources(base_url)
|
18
45
|
parsed = parsed_hook.call(parsed) if parsed_hook
|
19
|
-
|
46
|
+
RailsResourceTemplates.new(parsed)
|
20
47
|
end
|
21
48
|
|
22
49
|
#
|
@@ -34,13 +61,11 @@ module DescribedRoutes
|
|
34
61
|
|
35
62
|
# prefix :id parameters consistently
|
36
63
|
# TODO - probably a better way to do this, just need a pattern that matches :id and not :id[a-zA-Z0-9_]+
|
64
|
+
id_name = nil
|
37
65
|
segs.gsub!(/:[a-zA-Z0-9_]+/) do |match|
|
38
66
|
if match == ":id" && controller
|
39
|
-
|
40
|
-
|
41
|
-
else
|
42
|
-
":#{controller.singularize.sub(/.*\//, "")}_id"
|
43
|
-
end
|
67
|
+
id_name = (controller == "described_routes/rails") ? "route_name" : "#{controller.singularize.sub(/.*\//, "")}_id"
|
68
|
+
':' + id_name
|
44
69
|
else
|
45
70
|
match
|
46
71
|
end
|
@@ -81,12 +106,15 @@ module DescribedRoutes
|
|
81
106
|
# options #=> ["GET"]
|
82
107
|
# name #=> "edit_user"
|
83
108
|
# controller #=> "rails"
|
109
|
+
# id_name #=> "user_id"
|
84
110
|
|
85
111
|
# create a new route hash
|
86
112
|
resource = {
|
87
113
|
"path_template" => template,
|
88
114
|
"options" => options,
|
89
|
-
"controller" => controller
|
115
|
+
"controller" => controller,
|
116
|
+
"action" => action,
|
117
|
+
"id_name" => id_name
|
90
118
|
}
|
91
119
|
resource["params"] = params unless params.empty?
|
92
120
|
resource["optional_params"] = optional_params unless optional_params.empty?
|
data/lib/described_routes.rb
CHANGED
data/lib/resource_template.rb
CHANGED
@@ -27,6 +27,9 @@ class ResourceTemplate
|
|
27
27
|
# Nested resource templates, a Resources object
|
28
28
|
attr_reader :resource_templates
|
29
29
|
|
30
|
+
# Inverse of resource_templates
|
31
|
+
attr_reader :parent
|
32
|
+
|
30
33
|
#
|
31
34
|
# Initialize a ResourceTemplate from a hash. For example:
|
32
35
|
#
|
@@ -46,10 +49,11 @@ class ResourceTemplate
|
|
46
49
|
# user_articles = ResourceTemplate.new(JSON.parse(json))
|
47
50
|
# user_articles = ResourceTemplate.new(YAML.load(yaml))
|
48
51
|
#
|
49
|
-
def initialize(hash={})
|
52
|
+
def initialize(hash={}, parent=nil)
|
50
53
|
@name, @rel, @uri_template, @path_template = %w(name rel uri_template path_template).map{|attr| hash[attr]}
|
51
54
|
@params, @optional_params, @options = %w(params optional_params options).map{|attr| hash[attr] || []}
|
52
|
-
@resource_templates = ResourceTemplates.new(hash["resource_templates"])
|
55
|
+
@resource_templates = ResourceTemplates.new(hash["resource_templates"], self)
|
56
|
+
@parent = parent
|
53
57
|
end
|
54
58
|
|
55
59
|
# Convert to a hash (equivalent to its JSON or YAML representation)
|
@@ -156,6 +160,11 @@ class ResourceTemplate
|
|
156
160
|
Addressable::Template.new(t).expand(params_hash).to_s
|
157
161
|
end
|
158
162
|
|
163
|
+
# Returns a URI (assuming the template needs to parameters!)
|
164
|
+
def uri
|
165
|
+
uri_for({}, nil)
|
166
|
+
end
|
167
|
+
|
159
168
|
# Returns an expanded path template with template variables filled from the given params hash.
|
160
169
|
# Raises ArgumentError if params doesn't contain all mandatory params, and a RuntimeError if there is no path_template.
|
161
170
|
def path_for(params_hash)
|
@@ -165,7 +174,13 @@ class ResourceTemplate
|
|
165
174
|
Addressable::Template.new(path_template).expand(params_hash).to_s
|
166
175
|
end
|
167
176
|
|
168
|
-
#
|
177
|
+
# Returns a path (assuming the template needs to parameters!)
|
178
|
+
def path
|
179
|
+
path_for({})
|
180
|
+
end
|
181
|
+
|
182
|
+
# Return a new resource template with the path_template or uri_template partially expanded with the given params; does the same
|
183
|
+
# recursively descending through child resource templates.
|
169
184
|
def partial_expand(actual_params)
|
170
185
|
self.class.new(
|
171
186
|
"name" => name,
|
@@ -183,14 +198,14 @@ class ResourceTemplate
|
|
183
198
|
template && Addressable::Template.new(template).partial_expand(params).pattern
|
184
199
|
end
|
185
200
|
|
186
|
-
# Find member ResourceTemplate objects
|
187
|
-
def find_by_rel(
|
188
|
-
resource_templates.select{|resource_template| resource_template.rel
|
201
|
+
# Find member ResourceTemplate objects matching the given rel
|
202
|
+
def find_by_rel(matching_rel)
|
203
|
+
resource_templates.select{|resource_template| matching_rel === resource_template.rel}
|
189
204
|
end
|
190
205
|
|
191
206
|
class ResourceTemplates < Array
|
192
207
|
# Initialize Resources (i.e. a new collection of ResourceTemplate objects) from given collection of ResourceTemplates or hashes
|
193
|
-
def initialize(collection=[])
|
208
|
+
def initialize(collection=[], parent=nil)
|
194
209
|
if collection
|
195
210
|
raise ArgumentError.new("#{collection.inspect} is not a collection") unless collection.kind_of?(Enumerable)
|
196
211
|
|
@@ -198,7 +213,7 @@ class ResourceTemplate
|
|
198
213
|
if r.kind_of?(ResourceTemplate)
|
199
214
|
push(r)
|
200
215
|
elsif r.kind_of?(Hash)
|
201
|
-
push(ResourceTemplate.new(r))
|
216
|
+
push(ResourceTemplate.new(r, parent))
|
202
217
|
else
|
203
218
|
raise ArgumentError.new("#{r.inspect} is neither a ResourceTemplate nor a Hash")
|
204
219
|
end
|
@@ -267,7 +282,6 @@ class ResourceTemplate
|
|
267
282
|
]
|
268
283
|
resource_template.resource_templates.to_table(resource_template, t, indent + ' ')
|
269
284
|
end
|
270
|
-
t
|
271
285
|
end
|
272
286
|
|
273
287
|
# text report
|
@@ -287,7 +301,24 @@ class ResourceTemplate
|
|
287
301
|
# Partially expand the path_template or uri_template of the given resource templates with the given params,
|
288
302
|
# returning new resource templates
|
289
303
|
def partial_expand(actual_params)
|
290
|
-
|
304
|
+
ResourceTemplates.new(map{|resource_template| resource_template.partial_expand(actual_params)})
|
305
|
+
end
|
306
|
+
|
307
|
+
# Return a new resource template with the path_template or uri_template expanded; expands also any child resource templates
|
308
|
+
# that don't require additional parameters.
|
309
|
+
def expand_links(actual_params)
|
310
|
+
ResourceTemplates.new(
|
311
|
+
select{|rt| (rt.positional_params(rt.parent) - rt.optional_params).empty?}.map {|rt|
|
312
|
+
{
|
313
|
+
"name" => rt.name,
|
314
|
+
"rel" => rt.rel,
|
315
|
+
"uri_template" => rt.partial_expand_uri_template(rt.uri_template, actual_params),
|
316
|
+
"path_template" => rt.partial_expand_uri_template(rt.path_template, actual_params),
|
317
|
+
"params" => rt.params - actual_params.keys,
|
318
|
+
"optional_params" => rt.optional_params - actual_params.keys,
|
319
|
+
"options" => rt.options
|
320
|
+
}
|
321
|
+
})
|
291
322
|
end
|
292
323
|
end
|
293
324
|
end
|
@@ -99,4 +99,33 @@ class TestResourceTemplate < Test::Unit::TestCase
|
|
99
99
|
ResourceTemplate.new.path_for({}) # no path_template
|
100
100
|
end
|
101
101
|
end
|
102
|
+
|
103
|
+
def test_parent
|
104
|
+
assert_equal("user", user_articles.parent.name)
|
105
|
+
assert_equal("users", user_articles.parent.parent.name)
|
106
|
+
assert_nil(user_articles.parent.parent.parent)
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_expand_links
|
110
|
+
assert_equal(
|
111
|
+
[
|
112
|
+
{
|
113
|
+
"name" => "new_user_article",
|
114
|
+
"options" => ["GET"],
|
115
|
+
"path_template" => "/users/dojo/articles/new{-prefix|.|format}",
|
116
|
+
"uri_template" => "http://localhost:3000/users/dojo/articles/new{-prefix|.|format}",
|
117
|
+
"rel" => "new_user_article",
|
118
|
+
"optional_params" => ["format"]
|
119
|
+
},
|
120
|
+
{
|
121
|
+
"name" => "recent_user_articles",
|
122
|
+
"options" => ["GET"],
|
123
|
+
"path_template" => "/users/dojo/articles/recent{-prefix|.|format}",
|
124
|
+
"uri_template" => "http://localhost:3000/users/dojo/articles/recent{-prefix|.|format}",
|
125
|
+
"rel" => "recent",
|
126
|
+
"optional_params" => ["format"]
|
127
|
+
}
|
128
|
+
],
|
129
|
+
user_articles.resource_templates.expand_links({'user_id' => 'dojo'}).to_parsed)
|
130
|
+
end
|
102
131
|
end
|
@@ -1,8 +1,15 @@
|
|
1
|
+
require 'described_routes/helpers/described_routes_helper'
|
2
|
+
|
1
3
|
# Filters added to this controller apply to all controllers in the application.
|
2
4
|
# Likewise, all the methods added will be available for all controllers.
|
3
|
-
|
4
5
|
class ApplicationController < ActionController::Base
|
5
6
|
helper :all # include all helpers, all the time
|
7
|
+
include DescribedRoutes::DescribedRoutesHelper
|
8
|
+
helper DescribedRoutes::DescribedRoutesHelper
|
9
|
+
|
10
|
+
before_filter :set_link_header
|
11
|
+
layout "default"
|
12
|
+
|
6
13
|
protect_from_forgery # See ActionController::RequestForgeryProtection for details
|
7
14
|
|
8
15
|
# Scrub sensitive parameters from your log
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class DescribedRoutesRunTimeTest < ActionController::IntegrationTest
|
4
|
+
def test_root_headers
|
5
|
+
get "/"
|
6
|
+
assert_equal(
|
7
|
+
'<http://www.example.com/>; rel="self"; type="http://www.example.com/described_routes#root", ' +
|
8
|
+
'<http://www.example.com/described_routes>; rel="describedby"; type="http://www.example.com/described_routes#ResourceTemplate", ' +
|
9
|
+
'<http://www.example.com/admin/products>; rel="http://www.example.com/described_routes#admin_products"; type="http://www.example.com/described_routes#admin_products", ' +
|
10
|
+
'<http://www.example.com/described_routes>; rel="http://www.example.com/described_routes#described_routes"; type="http://www.example.com/described_routes#described_routes", ' +
|
11
|
+
'<http://www.example.com/pages>; rel="http://www.example.com/described_routes#pages"; type="http://www.example.com/described_routes#pages", ' +
|
12
|
+
'<http://www.example.com/users>; rel="http://www.example.com/described_routes#users"; type="http://www.example.com/described_routes#users"',
|
13
|
+
headers["Link"])
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_users_headers
|
17
|
+
get "/users"
|
18
|
+
assert_equal(
|
19
|
+
'<http://www.example.com/users>; rel="self"; type="http://www.example.com/described_routes#users", ' +
|
20
|
+
'<http://www.example.com/described_routes/users>; rel="describedby"; type="http://www.example.com/described_routes#ResourceTemplate", ' +
|
21
|
+
'<http://www.example.com/>; rel="up"; type="http://www.example.com/described_routes#root", ' +
|
22
|
+
'<http://www.example.com/users/new>; rel="http://www.example.com/described_routes/users#new_user"; type="http://www.example.com/described_routes#new_user"',
|
23
|
+
headers["Link"])
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_user_headers
|
27
|
+
get "/users/dojo"
|
28
|
+
assert_equal(
|
29
|
+
'<http://www.example.com/users/dojo>; rel="self"; type="http://www.example.com/described_routes#user", ' +
|
30
|
+
'<http://www.example.com/described_routes/user>; rel="describedby"; type="http://www.example.com/described_routes#ResourceTemplate", ' +
|
31
|
+
'<http://www.example.com/described_routes/user?user_id=dojo>; rel="describedby"; type="http://www.example.com/described_routes#ResourceTemplate", ' +
|
32
|
+
'<http://www.example.com/users>; rel="up"; type="http://www.example.com/described_routes#users", ' +
|
33
|
+
'<http://www.example.com/users/dojo/edit>; rel="edit"; rel="http://www.example.com/described_routes/user#edit"; type="http://www.example.com/described_routes#edit_user", ' +
|
34
|
+
'<http://www.example.com/users/dojo/articles>; rel="http://www.example.com/described_routes/user#articles"; type="http://www.example.com/described_routes#user_articles", ' +
|
35
|
+
'<http://www.example.com/users/dojo/profile>; rel="http://www.example.com/described_routes/user#profile"; type="http://www.example.com/described_routes#user_profile"',
|
36
|
+
headers["Link"])
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: described_routes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Burrows
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-28 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -43,9 +43,7 @@ dependencies:
|
|
43
43
|
version: 1.8.0
|
44
44
|
version:
|
45
45
|
description: |-
|
46
|
-
|
47
|
-
|
48
|
-
Also the home (for now at least) of the ResourceTemplate class.
|
46
|
+
Dynamic, framework-neutral metadata describing path/URI structures, with natural translations to/from JSON, YAML and XML. Bonus features: easy Rails integration, link element / link header generation and a plain text report format!
|
49
47
|
|
50
48
|
See roadmap for described_routes and path-to[http://github.com/asplake/path-to/tree] at http://positiveincline.com/?p=213.
|
51
49
|
email:
|
@@ -67,6 +65,7 @@ files:
|
|
67
65
|
- README.rdoc
|
68
66
|
- Rakefile
|
69
67
|
- lib/described_routes.rb
|
68
|
+
- lib/described_routes/helpers/described_routes_helper.rb
|
70
69
|
- lib/described_routes/rails_controller.rb
|
71
70
|
- lib/described_routes/rails_routes.rb
|
72
71
|
- lib/described_routes/rake_task_methods.rb
|
@@ -81,7 +80,10 @@ files:
|
|
81
80
|
- test/test_resource_template.rb
|
82
81
|
- test_rails_app/Rakefile
|
83
82
|
- test_rails_app/app/controllers/application_controller.rb
|
83
|
+
- test_rails_app/app/controllers/users_controller.rb
|
84
|
+
- test_rails_app/app/controllers/welcome_controller.rb
|
84
85
|
- test_rails_app/app/helpers/application_helper.rb
|
86
|
+
- test_rails_app/app/views/layouts/default.html.erb
|
85
87
|
- test_rails_app/config/boot.rb
|
86
88
|
- test_rails_app/config/environment.rb
|
87
89
|
- test_rails_app/config/environments/development.rb
|
@@ -105,6 +107,7 @@ files:
|
|
105
107
|
- test_rails_app/test/fixtures/run_time/described_routes.xml
|
106
108
|
- test_rails_app/test/fixtures/run_time/described_routes.yaml
|
107
109
|
- test_rails_app/test/integration/described_routes_run_time_test.rb
|
110
|
+
- test_rails_app/test/integration/headers_test.rb
|
108
111
|
- test_rails_app/test/integration/rake_tasks_test.rb
|
109
112
|
- test_rails_app/test/test_helper.rb
|
110
113
|
has_rdoc: true
|
@@ -132,10 +135,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
135
|
requirements: []
|
133
136
|
|
134
137
|
rubyforge_project: describedroutes
|
135
|
-
rubygems_version: 1.3.
|
138
|
+
rubygems_version: 1.3.4
|
136
139
|
signing_key:
|
137
140
|
specification_version: 3
|
138
|
-
summary:
|
141
|
+
summary: Dynamic, framework-neutral metadata describing path/URI structures, with natural translations to/from JSON, YAML and XML
|
139
142
|
test_files:
|
140
143
|
- test/test_described_routes.rb
|
141
144
|
- test/test_helper.rb
|