described_routes 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.7.0 2009-07-26
2
+
3
+ * Discovery protocol via link headers
4
+
1
5
  == 0.6.1 2009-06-28
2
6
 
3
7
  * Add all_preorder and all_postorder to ResourceTemplate and ResourceTemplates
data/README.rdoc CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  == DESCRIPTION
4
4
 
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!
6
-
7
- See roadmap for described_routes and path-to[http://github.com/asplake/path-to/tree] at http://positiveincline.com/?p=213.
5
+ Features:
6
+ * Dynamic, framework-neutral, client-friendly <code>ResourceTemplate</code> metadata describing the path/URI structures of your whole site or of specific resources
7
+ * JSON, YAML and XML formats, also a bonus plain text report
8
+ * A link header-based discovery protocol, enabling clients to find <code>ResourceTemplate</code> metadata from the resources of any enabled controller
9
+ * Easy integration with Rails
8
10
 
9
11
  == SYNOPSIS:
10
12
 
@@ -58,29 +60,35 @@ include full URI templates.
58
60
 
59
61
  === Run time
60
62
 
61
- Include the controller, perhaps in an initializer:
63
+ There are two integration steps for run time support:
64
+
65
+ 1) Include the controller, perhaps in an initializer:
62
66
 
63
67
  require 'described_routes/rails_controller'
64
68
 
65
- Add the following route in config/routes.rb:
69
+ 2) Add the following route in config/routes.rb:
66
70
 
67
71
  map.resources :described_routes, :controller => "described_routes/rails"
68
72
 
69
73
  You (or your client application) can now browse to any of the following top level addresses:
70
74
 
75
+ * .../described_routes
76
+ * .../described_routes.txt
71
77
  * .../described_routes.json
72
78
  * .../described_routes.xml
73
79
  * .../described_routes.yaml
74
- * .../described_routes.ytxt
75
80
 
76
81
  and for the named route "users" (say):
77
82
 
83
+ * .../described_routes/users
84
+ * .../described_routes/users.txt
78
85
  * .../described_routes/users.json
79
86
  * .../described_routes/users.xml
80
87
  * .../described_routes/users.yaml
81
- * .../described_routes/users.txt
82
88
 
83
- If the application has a route named "root", run-time-generated data will include uri_template attributes based on root_url in addition to the path_template attributes supported at build time.
89
+ In the absence of content negotiation, requests to addresses without format extensions redirect to the respective .txt address.
90
+
91
+ If the application has a route named "root", run-time-generated data will include full URIs in <code>uri_template</code> attributes based on <code>root_url</code> in addition to the <code>path_template</code> attributes supported at build time.
84
92
 
85
93
  Example:
86
94
 
@@ -165,21 +173,14 @@ JSON example (after pretty printing):
165
173
 
166
174
  === Link Generation
167
175
 
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
176
+ Generate link headers (see the draft spec http://tools.ietf.org/id/draft-nottingham-http-link-header-06.txt) by including
177
177
 
178
- before_filter :set_link_header
178
+ include DescribedRoutes::DescribedRoutesHelper
179
+ after_filter :set_link_header
179
180
 
180
- in your controllers. You can do this once in ApplicationController to get this behaviour across all controllers.
181
+ in your controllers. You can do this once in ApplicationController to get this behaviour across all controllers, or in specific controllers (for example the one for the root resource).
181
182
 
182
- See DescribedRoutes::DescribedRoutesHelper#link_data for configuration options.
183
+ See DescribedRoutes::DescribedRoutesHelper#link_data for configuration options; note however that you will need to define a new filter method if you wish to override the defaults. These are set to provide the minimum information necessary to support site discovery via resource-specific metadata links.
183
184
 
184
185
  == DATA STRUCTURES and FORMATS
185
186
 
data/Rakefile CHANGED
@@ -1,26 +1,27 @@
1
1
  %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
2
  $:.push File.dirname(__FILE__) + '/lib'
3
3
  require 'described_routes'
4
+ require 'hoe'
4
5
 
5
6
  # Generate all the Rake tasks
6
7
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
7
- $hoe = Hoe.new('described_routes', DescribedRoutes::VERSION) do |p|
8
- p.developer('Mike Burrows', 'mjb@asplake.co.uk')
9
- p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
10
- p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
11
- p.rubyforge_name = 'describedroutes'
12
- p.url = 'http://positiveincline.com/?p=213'
13
- p.extra_deps = [
8
+ $hoe = Hoe.spec 'described_routes' do
9
+ developer('Mike Burrows', 'mjb@asplake.co.uk')
10
+ self.readme_file = "README.rdoc"
11
+ self.changes = paragraphs_of("History.txt", 0..1).join("\n\n")
12
+ self.rubyforge_name = 'describedroutes'
13
+ self.url = 'http://positiveincline.com/?p=213'
14
+ self.extra_deps = [
14
15
  ['addressable','>= 2.1.0'],
15
16
  ]
16
- p.extra_dev_deps = [
17
+ self.extra_dev_deps = [
17
18
  ['newgem', ">= #{::Newgem::VERSION}"]
18
19
  ]
19
20
 
20
- p.clean_globs |= %w[**/.DS_Store tmp *.log]
21
- path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
22
- p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
23
- p.rsync_args = '-av --delete --ignore-errors'
21
+ self.clean_globs |= %w[**/.DS_Store tmp *.log]
22
+ path = (rubyforge_name == name) ? rubyforge_name : "\#{rubyforge_name}/\#{name}"
23
+ self.remote_rdoc_dir = File.join(path.gsub(/^#{rubyforge_name}\/?/,''), 'rdoc')
24
+ self.rsync_args = '-av --delete --ignore-errors'
24
25
  end
25
26
 
26
27
  task :info do
@@ -2,5 +2,5 @@ require 'resource_template'
2
2
 
3
3
  module DescribedRoutes
4
4
  # rubygem version
5
- VERSION = "0.6.1"
5
+ VERSION = "0.7.0"
6
6
  end
@@ -7,12 +7,12 @@ module DescribedRoutes
7
7
 
8
8
  # The default options parameter to #link_elements; controls which links appear in html link elements
9
9
  LINK_ELEMENT_OPTIONS = {
10
- :self => true, :describedby => true, :describedby => true, :describedbywithparams => true, :up => true, :related => true
10
+ :self => false, :describedby => true, :up => false, :related => false
11
11
  }
12
12
 
13
13
  # The default options parameter to #link_headers; controls which links appear in html link elements
14
14
  LINK_HEADER_OPTIONS = {
15
- :self => true, :describedby => true, :describedby => true, :describedbywithparams => true, :up => true, :related => true
15
+ :self => false, :describedby => true, :up => false, :related => false
16
16
  }
17
17
 
18
18
  # get the resource template structure, initialised (once) from Rails routes
@@ -44,8 +44,12 @@ module DescribedRoutes
44
44
  # Render link_data as <link <url> rel=<rel> ... type=<type>> elements. Add to the <head> part of your layout with:
45
45
  # <%= link_elements %>
46
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}">)
47
+ link_data(options).map{|url, rels, attrs|
48
+ [
49
+ %Q(<link href="#{url}"),
50
+ rels.map{|r| %Q(rel="#{r}")},
51
+ attrs.map{|k, v| %Q(#{k}="#{v}")}
52
+ ].join(' ')
49
53
  }.join("\n")
50
54
  end
51
55
 
@@ -53,74 +57,81 @@ module DescribedRoutes
53
57
  # response.headers["Link"] = link_header(options)
54
58
  # or use #set_link_header
55
59
  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}")
60
+ link_data(options).map{|url, rels, attrs|
61
+ [
62
+ "<#{url}>",
63
+ rels.map{|r| %Q(rel="#{r}")},
64
+ attrs.map{|k, v| %Q(#{k}="#{v}")}
65
+ ].join('; ')
58
66
  }.join(', ')
59
67
  end
60
68
 
61
69
  # Sets a link header in the response
62
- # before_filter :set_link_header
70
+ # after_filter :set_link_header
63
71
  def set_link_header(options=LINK_HEADER_OPTIONS)
64
72
  response.headers["Link"] = link_header(options)
65
73
  end
66
74
 
67
75
  # Returns an array of link information, each element containing
68
76
  # 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"
77
+ # 1) a list of link relation types (there can be more than one)
78
+ # 2) a hash of attributes, typically just one, either "role" (for regular resources) or "meta" (for metadata resources)
71
79
  # The list of link relations types will contain a standard type ('self', 'up', 'describedby') &/or an extention type
72
80
  # in the form "described_route_url(name)#rel", using the name and rel of the resource template.
73
81
  #
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.
82
+ # The output is filtered by the options hash, with members :self, :describedby, :up, :related.
85
83
  # Rel values will include a short value (e.g. 'edit') if the template's rel has a mapping in REGISTERED_RELS.
86
84
  #
87
85
  def link_data(options)
88
86
  result = []
89
87
  rt = resource_template
90
88
  if rt
89
+ type_prefix = described_routes_url + '#'
90
+ #
91
+ # For the application's root, the link with rel="describedby" has meta="ResourceTemplates" and it refers to a list of all
92
+ # top level resource templates. Otherwise, rel="describedby" has meta="ResourceTemplate" and it refers to a single resource
93
+ # template (together with any descendants).
94
+ #
91
95
  if rt.name == 'root'
92
96
  described_by = described_routes_url
93
97
  related = resource_templates
98
+ meta = "ResourceTemplates"
94
99
  else
95
100
  described_by = described_route_url(rt.name)
96
101
  related = rt.resource_templates
102
+ meta = "ResourceTemplate"
97
103
  end
98
104
 
105
+ #
106
+ # Add any query parameters to the rel="describedby" link
107
+ #
99
108
  if resource_parameters.empty?
100
109
  described_by_with_params = described_by
101
110
  else
102
111
  described_by_with_params = described_by + '?' + resource_parameters.to_query
103
112
  end
104
113
 
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
114
+ # data for rel="self"
115
+ result << [request.url, ['self'], {'role' => type_prefix + rt.name}] if options[:self]
116
+
117
+ # data for rel="described_by"
118
+ result << [described_by_with_params, ['describedby'], {'meta' => meta}] if options[:describedby]
119
+
120
+ # data for rel="up"
112
121
  if options[:up]
113
122
  if rt.parent
114
- result << [rt.parent.uri_for(resource_parameters), ['up'], type_prefix + rt.parent.name]
123
+ result << [rt.parent.uri_for(resource_parameters), ['up'], {'role' => type_prefix + rt.parent.name}]
115
124
  elsif rt.name != 'root'
116
- result << [root_url, ['up'], type_prefix + "root"]
125
+ result << [root_url, ['up'], {'role' => type_prefix + 'root'}]
117
126
  end
118
127
  end
128
+
129
+ # data for rel="related"
119
130
  if options[:related]
120
131
  related.expand_links(resource_parameters).map do |l|
121
132
  if l.name != rt.name
122
133
  rel = l.rel || l.name
123
- result << [l.uri, REGISTERED_RELS[rel].to_a + [described_by + '#' + rel], type_prefix + l.name]
134
+ result << [l.uri, REGISTERED_RELS[rel].to_a + [described_by + '#' + rel], {'role' => type_prefix + l.name}]
124
135
  end
125
136
  end
126
137
  end
@@ -6,6 +6,8 @@ module DescribedRoutes
6
6
  class RailsController < ActionController::Base
7
7
  include DescribedRoutes::DescribedRoutesHelper
8
8
 
9
+ after_filter :set_link_header
10
+
9
11
  def index
10
12
  expanded_templates = resource_templates.partial_expand(request.query_parameters)
11
13
 
@@ -32,5 +34,10 @@ module DescribedRoutes
32
34
  format.xml { render :xml => resource_template.to_xml(Builder::XmlMarkup.new(:indent => 2)).target! }
33
35
  end
34
36
  end
37
+
38
+ def set_link_header
39
+ rel = request.path == described_routes_path ? "self" : "index"
40
+ response.headers["Link"] = %Q(<#{described_routes_url}>; rel="#{rel}"; meta="ResourceTemplates")
41
+ end
35
42
  end
36
43
  end
@@ -7,11 +7,18 @@ class ApplicationController < ActionController::Base
7
7
  include DescribedRoutes::DescribedRoutesHelper
8
8
  helper DescribedRoutes::DescribedRoutesHelper
9
9
 
10
- before_filter :set_link_header
10
+ after_filter :set_link_headers
11
+
11
12
  layout "default"
12
13
 
13
14
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
14
15
 
15
16
  # Scrub sensitive parameters from your log
16
17
  # filter_parameter_logging :password
18
+
19
+ protected
20
+
21
+ def set_link_headers
22
+ set_link_header :self => true, :up => true, :describedby => true, :related => true
23
+ end
17
24
  end
@@ -3,7 +3,15 @@ class UsersController < ApplicationController
3
3
  render :text => "<h1>index</h1>", :layout => true
4
4
  end
5
5
 
6
+ def new
7
+ render :text => "<h1>new</h1>", :layout => true
8
+ end
9
+
6
10
  def show
7
11
  render :text => "<h1>show #{params[:id]}</h1>", :layout => true
8
12
  end
13
+
14
+ def edit
15
+ render :text => "<h1>edit #{params[:id]}</h1>", :layout => true
16
+ end
9
17
  end
@@ -4,35 +4,53 @@ class DescribedRoutesRunTimeTest < ActionController::IntegrationTest
4
4
  def test_root_headers
5
5
  get "/"
6
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"',
7
+ '<http://www.example.com/>; rel="self"; role="http://www.example.com/described_routes#root", ' +
8
+ '<http://www.example.com/described_routes>; rel="describedby"; meta="ResourceTemplates", ' +
9
+ '<http://www.example.com/admin/products>; rel="http://www.example.com/described_routes#admin_products"; role="http://www.example.com/described_routes#admin_products", ' +
10
+ '<http://www.example.com/described_routes>; rel="http://www.example.com/described_routes#described_routes"; role="http://www.example.com/described_routes#described_routes", ' +
11
+ '<http://www.example.com/pages>; rel="http://www.example.com/described_routes#pages"; role="http://www.example.com/described_routes#pages", ' +
12
+ '<http://www.example.com/users>; rel="http://www.example.com/described_routes#users"; role="http://www.example.com/described_routes#users"',
13
13
  headers["Link"])
14
14
  end
15
15
 
16
16
  def test_users_headers
17
17
  get "/users"
18
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"',
19
+ '<http://www.example.com/users>; rel="self"; role="http://www.example.com/described_routes#users", ' +
20
+ '<http://www.example.com/described_routes/users>; rel="describedby"; meta="ResourceTemplate", ' +
21
+ '<http://www.example.com/>; rel="up"; role="http://www.example.com/described_routes#root", ' +
22
+ '<http://www.example.com/users/new>; rel="http://www.example.com/described_routes/users#new_user"; role="http://www.example.com/described_routes#new_user"',
23
+ headers["Link"])
24
+ end
25
+
26
+ def test_new_user_headers
27
+ get "/users/new"
28
+ assert_equal(
29
+ '<http://www.example.com/users/new>; rel="self"; role="http://www.example.com/described_routes#new_user", ' +
30
+ '<http://www.example.com/described_routes/new_user>; rel="describedby"; meta="ResourceTemplate", ' +
31
+ '<http://www.example.com/users>; rel="up"; role="http://www.example.com/described_routes#users"',
23
32
  headers["Link"])
24
33
  end
25
34
 
26
35
  def test_user_headers
27
36
  get "/users/dojo"
28
37
  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"',
38
+ '<http://www.example.com/users/dojo>; rel="self"; role="http://www.example.com/described_routes#user", ' +
39
+ '<http://www.example.com/described_routes/user?user_id=dojo>; rel="describedby"; meta="ResourceTemplate", ' +
40
+ '<http://www.example.com/users>; rel="up"; role="http://www.example.com/described_routes#users", ' +
41
+ '<http://www.example.com/users/dojo/edit>; rel="edit"; rel="http://www.example.com/described_routes/user#edit"; role="http://www.example.com/described_routes#edit_user", ' +
42
+ '<http://www.example.com/users/dojo/articles>; rel="http://www.example.com/described_routes/user#articles"; role="http://www.example.com/described_routes#user_articles", ' +
43
+ '<http://www.example.com/users/dojo/profile>; rel="http://www.example.com/described_routes/user#profile"; role="http://www.example.com/described_routes#user_profile"',
36
44
  headers["Link"])
37
45
  end
46
+
47
+ def test_edit_user_headers
48
+ get "/users/dojo/edit"
49
+ assert_equal(
50
+ '<http://www.example.com/users/dojo/edit>; rel="self"; role="http://www.example.com/described_routes#edit_user", ' +
51
+ '<http://www.example.com/described_routes/edit_user?user_id=dojo>; rel="describedby"; meta="ResourceTemplate", ' +
52
+ '<http://www.example.com/users/dojo>; rel="up"; role="http://www.example.com/described_routes#user"',
53
+ headers["Link"])
54
+ end
55
+
38
56
  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.6.1
4
+ version: 0.7.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-06-28 00:00:00 +01:00
12
+ date: 2009-07-26 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.4.1
33
+ version: 1.5.1
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: hoe
@@ -40,12 +40,14 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 1.8.0
43
+ version: 2.3.2
44
44
  version:
45
45
  description: |-
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!
47
-
48
- See roadmap for described_routes and path-to[http://github.com/asplake/path-to/tree] at http://positiveincline.com/?p=213.
46
+ Features:
47
+ * Dynamic, framework-neutral, client-friendly <code>ResourceTemplate</code> metadata describing the path/URI structures of your whole site or of specific resources
48
+ * JSON, YAML and XML formats, also a bonus plain text report
49
+ * A link header-based discovery protocol, enabling clients to find <code>ResourceTemplate</code> metadata from the resources of any enabled controller
50
+ * Easy integration with Rails
49
51
  email:
50
52
  - mjb@asplake.co.uk
51
53
  executables: []
@@ -56,7 +58,6 @@ extra_rdoc_files:
56
58
  - History.txt
57
59
  - Manifest.txt
58
60
  - PostInstall.txt
59
- - README.rdoc
60
61
  files:
61
62
  - History.txt
62
63
  - LICENSE
@@ -114,7 +115,7 @@ has_rdoc: true
114
115
  homepage: http://positiveincline.com/?p=213
115
116
  licenses: []
116
117
 
117
- post_install_message: PostInstall.txt
118
+ post_install_message:
118
119
  rdoc_options:
119
120
  - --main
120
121
  - README.rdoc
@@ -135,10 +136,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
136
  requirements: []
136
137
 
137
138
  rubyforge_project: describedroutes
138
- rubygems_version: 1.3.4
139
+ rubygems_version: 1.3.5
139
140
  signing_key:
140
141
  specification_version: 3
141
- summary: Dynamic, framework-neutral metadata describing path/URI structures, with natural translations to/from JSON, YAML and XML
142
+ summary: "Features: * Dynamic, framework-neutral, client-friendly <code>ResourceTemplate</code> metadata describing the path/URI structures of your whole site or of specific resources * JSON, YAML and XML formats, also a bonus plain text report * A link header-based discovery protocol, enabling clients to find <code>ResourceTemplate</code> metadata from the resources of any enabled controller * Easy integration with Rails"
142
143
  test_files:
143
144
  - test/test_described_routes.rb
144
145
  - test/test_helper.rb