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 CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.6.0 2009-06-28
2
+
3
+ * Add automatic link header/element generation
4
+ * LICENSE, README tweaks
5
+
1
6
  == 0.5.1 2009-05-22
2
7
 
3
8
  * Add ResourceTemplate::ResourceTemplate.find_by_rel
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- path-to, Copyright (c) 2009 Mike Burrows
1
+ described_routes, Copyright (c) 2009 Mike Burrows
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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
- Framework-neutral metadata, describing (among other things) your Rails routes in JSON, YAML, XML and plain text formats.
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 &lt;head&gt; 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
- base_url = root_url rescue nil
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 => resource_templates.to_json }
13
- format.text { render :text => resource_templates.to_text }
14
- format.yaml { render :text => resource_templates.to_yaml }
15
- format.xml { render :xml => resource_templates.to_xml(Builder::XmlMarkup.new(:indent => 2)).target! }
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
- base_url = root_url rescue nil
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 = nil)
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
- ResourceTemplate::ResourceTemplates.new(parsed)
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
- if controller == "described_routes/rails"
40
- ":route_name"
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?
@@ -2,5 +2,5 @@ require 'resource_template'
2
2
 
3
3
  module DescribedRoutes
4
4
  # rubygem version
5
- VERSION = "0.5.1"
5
+ VERSION = "0.6.0"
6
6
  end
@@ -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
- # Return a new resource template with the path_template or uri_template partially expanded with the given params
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 with the given rel
187
- def find_by_rel(rel)
188
- resource_templates.select{|resource_template| resource_template.rel == 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
- self.class.new(map{|resource_template| resource_template.partial_expand(actual_params)})
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,9 @@
1
+ class UsersController < ApplicationController
2
+ def index
3
+ render :text => "<h1>index</h1>", :layout => true
4
+ end
5
+
6
+ def show
7
+ render :text => "<h1>show #{params[:id]}</h1>", :layout => true
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class WelcomeController < ApplicationController
2
+ def index
3
+ render :text => "<h1>index</h1>", :layout => true
4
+ end
5
+
6
+ def show
7
+ render :text => "<h1>show #{params[:id]}</h1>", :layout => true
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head>
3
+ <title>A test page with links</title>
4
+ <%= link_elements %>
5
+ </head>
6
+ <body>
7
+ <%= yield %>
8
+ </body>
9
+ </html>
@@ -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.5.1
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-05-25 00:00:00 +01:00
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
- Framework-neutral metadata, describing (among other things) your Rails routes in JSON, YAML, XML and plain text formats.
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.3
138
+ rubygems_version: 1.3.4
136
139
  signing_key:
137
140
  specification_version: 3
138
- summary: Framework-neutral metadata, describing (among other things) your Rails routes in JSON, YAML, XML and plain text formats
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