described_routes 0.4.1 → 0.5.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,10 @@
1
+ == 0.5.0 2009-05-22
2
+
3
+ * API refactor, a possible prelude to new resource_template gem:
4
+ * Top level class ResourceTemplate (was DescribedRoutes::ResourceTemplate)
5
+ * New class ResourceTemplate::ResourceTemplates to which most of ResourceTemplate's class methods have been moved
6
+ * Removed the yaml_short format (superseded by the plain text format)
7
+
1
8
  == 0.4.1 2009-05-20
2
9
 
3
10
  * Configure gem dependency on addressable 2.1.0 (now available on RubyForge)
data/Manifest.txt CHANGED
@@ -8,7 +8,7 @@ lib/described_routes.rb
8
8
  lib/described_routes/rails_controller.rb
9
9
  lib/described_routes/rails_routes.rb
10
10
  lib/described_routes/rake_task_methods.rb
11
- lib/described_routes/resource_template.rb
11
+ lib/resource_template.rb
12
12
  lib/tasks/described_routes.rb
13
13
  script/console
14
14
  script/destroy
@@ -38,13 +38,10 @@ test_rails_app/test/fixtures/build_time/described_routes.json
38
38
  test_rails_app/test/fixtures/build_time/described_routes.text
39
39
  test_rails_app/test/fixtures/build_time/described_routes.xml
40
40
  test_rails_app/test/fixtures/build_time/described_routes.yaml
41
- test_rails_app/test/fixtures/build_time/described_routes.yaml_short
42
- test_rails_app/test/fixtures/build_time/described_routes.yaml_short_no_admin
43
41
  test_rails_app/test/fixtures/run_time/described_routes.json
44
42
  test_rails_app/test/fixtures/run_time/described_routes.text
45
43
  test_rails_app/test/fixtures/run_time/described_routes.xml
46
44
  test_rails_app/test/fixtures/run_time/described_routes.yaml
47
- test_rails_app/test/fixtures/run_time/described_routes.yaml_short
48
45
  test_rails_app/test/integration/described_routes_run_time_test.rb
49
46
  test_rails_app/test/integration/rake_tasks_test.rb
50
47
  test_rails_app/test/test_helper.rb
data/README.rdoc CHANGED
@@ -22,7 +22,6 @@ Then:
22
22
  rake described_routes:json # Describe resource structure in JSON format
23
23
  rake described_routes:xml # Describe resource structure in XML format
24
24
  rake described_routes:yaml # Describe resource structure in YAML format
25
- rake described_routes:yaml_short # Describe resource structure in YAML format (basic structure only)
26
25
  rake described_routes:text # Describe resource structure in text (comparable to "rake routes")
27
26
 
28
27
  The text output looks like this:
@@ -76,7 +75,6 @@ You (or your client application) can now browse to any of the following top leve
76
75
  * .../described_routes.json
77
76
  * .../described_routes.xml
78
77
  * .../described_routes.yaml
79
- * .../described_routes.yaml?short=true
80
78
  * .../described_routes.ytxt
81
79
 
82
80
  and for the named route "users" (say):
@@ -84,7 +82,6 @@ and for the named route "users" (say):
84
82
  * .../described_routes/users.json
85
83
  * .../described_routes/users.xml
86
84
  * .../described_routes/users.yaml
87
- * .../described_routes/users.yaml?short=true
88
85
  * .../described_routes/users.txt
89
86
 
90
87
  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.
@@ -5,44 +5,30 @@ module DescribedRoutes
5
5
  class RailsController < ActionController::Base
6
6
  def index
7
7
  base_url = root_url rescue nil
8
- resource_templates = ResourceTemplate.partial_expand(RailsRoutes.get_resource_templates(base_url), request.query_parameters)
8
+ resource_templates = RailsRoutes.get_resource_templates(base_url).partial_expand(request.query_parameters)
9
9
 
10
10
  respond_to do |format|
11
11
  format.html # index.html.erb
12
- format.json { render :json => ResourceTemplate.to_json(resource_templates) }
13
- format.text { render :text => ResourceTemplate.to_text(resource_templates) }
14
- format.yaml do
15
- yaml = ResourceTemplate::to_yaml(resource_templates)
16
- yaml = yaml.grep(/(name|rel|path_template|uri_template|resources):|^---/).to_s if ['true', '1'].member?(params["short"])
17
- render :text => yaml
18
- end
19
- format.xml do
20
- render :xml => ResourceTemplate::to_xml(
21
- Builder::XmlMarkup.new(:indent => 2),
22
- resource_templates).target!
23
- end
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! }
24
16
  end
25
17
  end
26
18
 
27
19
  def show
28
20
  base_url = root_url rescue nil
29
- resources = RailsRoutes.get_resource_templates(base_url)
30
- resource_template = ResourceTemplate.all_by_name(resources)[params[:id]]
21
+ resource_templates = RailsRoutes.get_resource_templates(base_url).partial_expand(request.query_parameters)
22
+ resource_template = resource_templates.all_by_name[params[:id]]
31
23
  # TODO 404 if nil
32
24
  resource_template = resource_template.partial_expand(request.query_parameters)
33
25
 
34
26
  respond_to do |format|
35
27
  format.html # show.html.erb
36
28
  format.json { render :json => resource_template.to_json }
37
- format.text { render :text => ResourceTemplate.to_text([resource_template]) }
38
- format.xml do
39
- render :xml => resource_template.to_xml(Builder::XmlMarkup.new(:indent => 2)).target!
40
- end
41
- format.yaml do
42
- yaml = resource_template.to_yaml
43
- yaml = yaml.grep(/(name|rel|path_template|uri_template|resources):|^---/).to_s if ['true', '1'].member?(params["short"])
44
- render :text => yaml
45
- end
29
+ format.text { render :text => resource_template.to_text }
30
+ format.yaml { render :text => resource_template.to_yaml }
31
+ format.xml { render :xml => resource_template.to_xml(Builder::XmlMarkup.new(:indent => 2)).target! }
46
32
  end
47
33
  end
48
34
  end
@@ -1,4 +1,4 @@
1
- require 'described_routes/resource_template'
1
+ require 'resource_template'
2
2
 
3
3
  module DescribedRoutes
4
4
  module RailsRoutes
@@ -11,12 +11,12 @@ module DescribedRoutes
11
11
  mattr_accessor :parsed_hook
12
12
 
13
13
  #
14
- # Process Rails routes and return an array of DescribedRoutes::ResourceTemplate objects
14
+ # Process Rails routes and return an array of ResourceTemplate objects
15
15
  #
16
16
  def self.get_resource_templates(base_url = nil)
17
17
  parsed = get_parsed_rails_resources(base_url)
18
18
  parsed = parsed_hook.call(parsed) if parsed_hook
19
- DescribedRoutes::ResourceTemplate.from_parsed(parsed)
19
+ ResourceTemplate::ResourceTemplates.new(parsed)
20
20
  end
21
21
 
22
22
  #
@@ -4,35 +4,27 @@ module DescribedRoutes
4
4
  module RakeTaskMethods
5
5
  # Describe resource structure in JSON format
6
6
  def self.json
7
- DescribedRoutes::ResourceTemplate.to_json(
8
- DescribedRoutes::RailsRoutes.get_resource_templates(ENV['BASE']))
7
+ get_routes.to_json
9
8
  end
10
9
 
11
10
  # "Describe resource structure in YAML format
12
11
  def self.yaml
13
- DescribedRoutes::ResourceTemplate.to_yaml(
14
- DescribedRoutes::RailsRoutes.get_resource_templates(ENV['BASE']))
15
- end
16
-
17
- # Describe resource structure in YAML format (basic structure only)
18
- def self.yaml_short
19
- DescribedRoutes::ResourceTemplate.to_yaml(
20
- DescribedRoutes::RailsRoutes.get_resource_templates(ENV['BASE'])).grep(
21
- /(name|rel|path_template|uri_template|resources):|^---/).join
12
+ get_routes.to_yaml
22
13
  end
23
14
 
24
15
  # Describe resource structure in XML format
25
16
  def self.xml
26
- DescribedRoutes::ResourceTemplate.to_xml(
27
- Builder::XmlMarkup.new(:indent => 2),
28
- DescribedRoutes::RailsRoutes.get_resource_templates(ENV['BASE'])
29
- ).target!
17
+ get_routes.to_xml(Builder::XmlMarkup.new(:indent => 2)).target!
30
18
  end
31
19
 
32
20
  # Describe resource structure in text format
33
21
  def self.text
34
- DescribedRoutes::ResourceTemplate.to_text(
35
- DescribedRoutes::RailsRoutes.get_resource_templates(ENV['BASE']))
22
+ get_routes.to_text
23
+ end
24
+
25
+ # Gets the application's routes
26
+ def self.get_routes
27
+ DescribedRoutes::RailsRoutes.get_resource_templates(ENV['BASE'])
36
28
  end
37
29
  end
38
30
  end
@@ -1,6 +1,6 @@
1
- require 'described_routes/resource_template'
1
+ require 'resource_template'
2
2
 
3
3
  module DescribedRoutes
4
4
  # rubygem version
5
- VERSION = "0.4.1"
5
+ VERSION = "0.5.0"
6
6
  end
@@ -0,0 +1,258 @@
1
+ require "json"
2
+ require "addressable/template"
3
+
4
+ class ResourceTemplate
5
+ # The template's name. Optional. Making these unique across the application is helpful for clients
6
+ # that may wish to pick out nested templates by name.
7
+ attr_reader :name
8
+
9
+ # Optional attribute that describes a resource's relationship to its parent. For example:
10
+ # * a nested route to a resource's edit page would have rel of "edit"
11
+ # * a nested collection of articles under a "user" resource would have have a rel of "articles"
12
+ # Collection members generally don't need a rel as they are identified by their params
13
+ attr_reader :rel
14
+
15
+ # A template for generating URIs.
16
+ attr_reader :uri_template
17
+
18
+ # A template for generating paths relative to the application's base.
19
+ attr_reader :path_template
20
+
21
+ # The parameters required by the path template
22
+ attr_reader :params
23
+
24
+ # Optional paramaters that may be used by the path template
25
+ attr_reader :optional_params
26
+
27
+ # "options" in the sense of the HTTP option request - i.e. a list of HTTP methods. Optional.
28
+ attr_reader :options
29
+
30
+ # Nested resource templates, a Resources object
31
+ attr_reader :resource_templates
32
+
33
+ # Initialize a ResourceTemplate. See the attribute descriptions above for explanations of the parameters.
34
+ def initialize(name, rel, uri_template, path_template, params, optional_params, options, resource_templates)
35
+ @name, @rel, @uri_template, @path_template = name, rel, uri_template, path_template
36
+ @params = params || []
37
+ @optional_params = optional_params || []
38
+ @options = options || []
39
+ @resource_templates = resource_templates || Resources.new
40
+ end
41
+
42
+ # Create a ResourceTemplate from its Hash representation
43
+ def self.from_hash(hash)
44
+ attributes = %w(name rel uri_template path_template params optional_params options).map{|k| hash[k]}
45
+ attributes << ResourceTemplates.new(hash["resource_templates"])
46
+ self.new(*attributes)
47
+ end
48
+
49
+ # Convert to a hash (equivalent to its JSON or YAML representation)
50
+ def to_hash
51
+ hash = {}
52
+ hash["name"] = name if name && !name.empty?
53
+ hash["rel"] = rel if rel && !rel.empty?
54
+ hash["uri_template"] = uri_template if uri_template && !uri_template.empty?
55
+ hash["path_template"] = path_template if path_template && !path_template.empty?
56
+
57
+ hash["params"] = params if params && !params.empty?
58
+ hash["optional_params"] = optional_params if optional_params && !optional_params.empty?
59
+
60
+ hash["options"] = options if options && !options.empty?
61
+
62
+ hash["resource_templates"] = resource_templates.to_parsed if !resource_templates.empty?
63
+
64
+ hash
65
+ end
66
+
67
+ # Convert to JSON
68
+ def to_json
69
+ to_hash.to_json
70
+ end
71
+
72
+ # Convert to YAML
73
+ def to_yaml
74
+ to_hash.to_yaml
75
+ end
76
+
77
+ # Text report
78
+ def to_text
79
+ ResourceTemplates.new([self]).to_text
80
+ end
81
+
82
+ #
83
+ # Produces the XML format, given an XML builder object and an array of ResourceTemplate objects
84
+ #
85
+ def to_xml(xm)
86
+ xm.ResourceTemplate do |xm|
87
+ value_tag(xm, "rel")
88
+ value_tag(xm, "name")
89
+ value_tag(xm, "path_template")
90
+ value_tag(xm, "uri_template")
91
+
92
+ list_tag(xm, params, "Params", "param")
93
+ list_tag(xm, optional_params, "OptionalParams", "param")
94
+
95
+ # could use a list of elements here, but let's follow HTTP's lead and reduce the verbosity
96
+ xm.options(options.join(", ")) unless options.empty?
97
+
98
+ resource_templates.to_xml(xm) unless resource_templates.empty?
99
+ end
100
+ xm
101
+ end
102
+
103
+ def value_tag(xm, tag) #:nodoc:
104
+ value = self.send(tag.to_sym)
105
+ xm.tag!(tag, value) unless value.blank?
106
+ end
107
+
108
+ def list_tag(xm, collection, collection_tag, member_tag) #:nodoc:
109
+ unless collection.nil? or collection.empty?
110
+ xm.tag!(collection_tag) do |xm|
111
+ collection.each do |value|
112
+ xm.tag!(member_tag, value)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ # returns params and any optional_params in order, removing the parent's params
119
+ def positional_params(parent)
120
+ all_params = params + optional_params
121
+ if parent
122
+ all_params - parent.params
123
+ else
124
+ all_params
125
+ end
126
+ end
127
+
128
+ # Return a new resource template with the path_template or uri_template partially expanded with the given params
129
+ def partial_expand(actual_params)
130
+ self.class.new(
131
+ name,
132
+ rel,
133
+ partial_expand_uri_template(uri_template, actual_params),
134
+ partial_expand_uri_template(path_template, actual_params),
135
+ params - actual_params.keys,
136
+ optional_params - actual_params.keys,
137
+ options,
138
+ resource_templates.partial_expand(actual_params))
139
+ end
140
+
141
+ # Partially expand a URI template
142
+ def partial_expand_uri_template(template, params)#:nodoc:
143
+ template && Addressable::Template.new(template).partial_expand(params).pattern
144
+ end
145
+
146
+ class ResourceTemplates < Array
147
+ # Initialize Resources (i.e. a new collection of ResourceTemplate objects) from given collection of ResourceTemplates or hashes
148
+ def initialize(collection=[])
149
+ if collection
150
+ raise ArgumentError.new("#{collection.inspect} is not a collection") unless collection.kind_of?(Enumerable)
151
+
152
+ collection.each do |r|
153
+ if r.kind_of?(ResourceTemplate)
154
+ push(r)
155
+ elsif r.kind_of?(Hash)
156
+ push(ResourceTemplate.from_hash(r))
157
+ else
158
+ raise ArgumentError.new("#{r.inspect} is neither a ResourceTemplate nor a Hash")
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ # Create Resources from a YAML string
165
+ def self.parse_yaml(yaml)
166
+ new(YAML::load(yaml))
167
+ end
168
+
169
+ # Create Resources from a JSON string
170
+ def self.parse_json(json)
171
+ new(JSON.parse(json))
172
+ end
173
+
174
+ # Create Resources from an XML string
175
+ def self.parse_xml
176
+ raise NotImplementedError.new
177
+ end
178
+
179
+ # Convert member ResourceTemplate objects to array of hashes equivalent to their JSON or YAML representations
180
+ def to_parsed
181
+ map {|resource_template| resource_template.to_hash}
182
+ end
183
+
184
+ # Convert an array of ResourceTemplate objects to JSON
185
+ def to_json
186
+ to_parsed.to_json
187
+ end
188
+
189
+ # Convert an array of ResourceTemplate objects to YAML
190
+ def to_yaml
191
+ to_parsed.to_yaml
192
+ end
193
+
194
+ #
195
+ # Produces the XML format, given an XML builder object and an array of ResourceTemplate objects
196
+ #
197
+ def to_xml(xm)
198
+ xm.ResourceTemplates do |xm|
199
+ each do |resource_template|
200
+ resource_template.to_xml(xm)
201
+ end
202
+ end
203
+ xm
204
+ end
205
+
206
+ # Get a hash of all named ResourceTemplate objects contained in the supplied collection, keyed by name
207
+ def all_by_name(h = {})
208
+ inject(h) do |hash, resource_template|
209
+ hash[resource_template.name] = resource_template if resource_template.name
210
+ resource_template.resource_templates.all_by_name(hash)
211
+ hash
212
+ end
213
+ h
214
+ end
215
+
216
+ # for #to_text
217
+ def to_table(parent_template = nil, t = [], indent = '')
218
+ inject(t) do |table, resource_template|
219
+ if parent_template
220
+ link = (resource_template.rel || '')
221
+ new_params = resource_template.params - parent_template.params
222
+ else
223
+ link = resource_template.name
224
+ new_params = resource_template.params
225
+ end
226
+ link += new_params.map{|p| "{#{p}}"}.join(', ')
227
+ table << [
228
+ indent + link,
229
+ resource_template.name || '',
230
+ resource_template.options.join(', '),
231
+ resource_template.uri_template || resource_template.path_template
232
+ ]
233
+ resource_template.resource_templates.to_table(resource_template, t, indent + ' ')
234
+ end
235
+ t
236
+ end
237
+
238
+ # text report
239
+ def to_text
240
+ table = self.to_table
241
+
242
+ 0.upto(2) do |i|
243
+ width = table.map{|row| row[i].length}.max
244
+ table.each do |row|
245
+ row[i] = row[i].ljust(width)
246
+ end
247
+ end
248
+
249
+ table.map{|row| row.join(' ')}.join("\n") + "\n"
250
+ end
251
+
252
+ # Partially expand the path_template or uri_template of the given resource templates with the given params,
253
+ # returning new resource templates
254
+ def partial_expand(actual_params)
255
+ self.class.new(map{|resource_template| resource_template.partial_expand(actual_params)})
256
+ end
257
+ end
258
+ end
@@ -12,11 +12,6 @@ namespace :described_routes do
12
12
  puts DescribedRoutes::RakeTaskMethods.yaml
13
13
  end
14
14
 
15
- desc 'Describe resource structure in YAML format (basic structure only) (optional: add "BASE=http://...")'
16
- task :yaml_short => :environment do
17
- puts DescribedRoutes::RakeTaskMethods.yaml_short
18
- end
19
-
20
15
  desc 'Describe resource structure in XML format (optional: add "BASE=http://...")'
21
16
  task :xml => :environment do
22
17
  puts DescribedRoutes::RakeTaskMethods.xml
@@ -29,7 +24,7 @@ namespace :described_routes do
29
24
 
30
25
  # unsupported
31
26
  task :ruby => :environment do
32
- puts DescribedRoutes::ResourceTemplate.to_parsed(
27
+ puts ResourceTemplate.to_parsed(
33
28
  DescribedRoutes::RailsRoutes.get_resource_templates).inspect
34
29
  end
35
30
 
@@ -1,33 +1,33 @@
1
1
  require 'test/unit'
2
- require 'described_routes/resource_template'
2
+ require 'resource_template'
3
3
 
4
4
  class TestResourceTemplate < Test::Unit::TestCase
5
5
  attr_reader :json, :resource_templates, :resource_templates_by_name, :user_articles, :user_article, :edit_user_article
6
6
 
7
7
  def setup
8
- @json ||= File.read(File.dirname(__FILE__) + "/fixtures/described_routes_test.json")
9
- @resource_templates = DescribedRoutes::ResourceTemplate.parse_json(json)
10
- @resource_templates_by_name = DescribedRoutes::ResourceTemplate.all_by_name(@resource_templates)
11
- @user_articles = @resource_templates_by_name["user_articles"]
12
- @user_article = @resource_templates_by_name["user_article"]
13
- @edit_user_article = @resource_templates_by_name["edit_user_article"]
8
+ @json ||= File.read(File.dirname(__FILE__) + '/fixtures/described_routes_test.json')
9
+ @resource_templates = ResourceTemplate::ResourceTemplates.parse_json(json)
10
+ @resource_templates_by_name = @resource_templates.all_by_name
11
+ @user_articles = @resource_templates_by_name['user_articles']
12
+ @user_article = @resource_templates_by_name['user_article']
13
+ @edit_user_article = @resource_templates_by_name['edit_user_article']
14
14
  end
15
15
 
16
16
  def test_fixture
17
- assert_kind_of(DescribedRoutes::ResourceTemplate, user_articles)
18
- assert_kind_of(DescribedRoutes::ResourceTemplate, user_article)
19
- assert_kind_of(DescribedRoutes::ResourceTemplate, edit_user_article)
17
+ assert_kind_of(ResourceTemplate, user_articles)
18
+ assert_kind_of(ResourceTemplate, user_article)
19
+ assert_kind_of(ResourceTemplate, edit_user_article)
20
20
 
21
- assert_equal("user_article", user_article.name)
22
- assert_equal(["user_id", "article_id"], user_article.params)
23
- assert_equal(["format"], user_article.optional_params)
21
+ assert_equal('user_article', user_article.name)
22
+ assert_equal(['user_id', 'article_id'], user_article.params)
23
+ assert_equal(['format'], user_article.optional_params)
24
24
 
25
- assert_equal("articles", user_articles.rel)
25
+ assert_equal('articles', user_articles.rel)
26
26
  assert_nil(user_article.rel)
27
- assert_equal("edit", edit_user_article.rel)
27
+ assert_equal('edit', edit_user_article.rel)
28
28
 
29
- assert_equal("/users/{user_id}/articles{-prefix|.|format}", user_articles.path_template)
30
- assert_equal("http://localhost:3000/users/{user_id}/articles{-prefix|.|format}", user_articles.uri_template)
29
+ assert_equal('/users/{user_id}/articles{-prefix|.|format}', user_articles.path_template)
30
+ assert_equal('http://localhost:3000/users/{user_id}/articles{-prefix|.|format}', user_articles.uri_template)
31
31
 
32
32
  assert(user_articles.resource_templates.member?(user_article))
33
33
  assert(user_article.resource_templates.member?(edit_user_article))
@@ -36,26 +36,26 @@ class TestResourceTemplate < Test::Unit::TestCase
36
36
  def test_json
37
37
  assert_equal(
38
38
  JSON.parse(json),
39
- JSON.parse(DescribedRoutes::ResourceTemplate.to_json(resource_templates)))
39
+ JSON.parse(resource_templates.to_json))
40
40
  end
41
41
 
42
42
  def test_yaml
43
43
  assert_equal(
44
44
  JSON.parse(json),
45
- YAML.load(DescribedRoutes::ResourceTemplate.to_yaml(resource_templates)))
45
+ YAML.load(resource_templates.to_yaml))
46
46
  end
47
47
 
48
48
  def test_positional_params
49
- assert_equal(["user_id", "article_id", "format"], user_article.positional_params(nil))
50
- assert_equal(["article_id", "format"], user_article.positional_params(user_articles))
49
+ assert_equal(['user_id', 'article_id', 'format'], user_article.positional_params(nil))
50
+ assert_equal(['article_id', 'format'], user_article.positional_params(user_articles))
51
51
  end
52
52
 
53
53
  def test_partial_expand
54
- expanded = DescribedRoutes::ResourceTemplate.all_by_name([user_articles.partial_expand("user_id" => "dojo", "format" => "json")])
55
- expanded_edit_user_article = expanded["edit_user_article"]
54
+ expanded_user_articles = user_articles.partial_expand('user_id' => 'dojo', 'format' => 'json')
55
+ expanded_edit_user_article = expanded_user_articles.resource_templates.all_by_name['edit_user_article']
56
56
 
57
- assert_equal(["article_id"], expanded_edit_user_article.params)
57
+ assert_equal(['article_id'], expanded_edit_user_article.params)
58
58
  assert(expanded_edit_user_article.optional_params.empty?)
59
- assert_equal("/users/dojo/articles/{article_id}/edit.json", expanded_edit_user_article.path_template)
59
+ assert_equal('/users/dojo/articles/{article_id}/edit.json', expanded_edit_user_article.path_template)
60
60
  end
61
61
  end
@@ -29,12 +29,6 @@ class DescribedRoutesRunTimeTest < ActionController::IntegrationTest
29
29
  assert_equal(read_fixture("yaml"), body)
30
30
  end
31
31
 
32
- def test_yaml_short
33
- get "/described_routes.yaml?short=1"
34
- assert_response :success
35
- assert_equal(read_fixture("yaml_short"), body)
36
- end
37
-
38
32
  def test_partial_expand
39
33
  get "/described_routes/new_user_profile.text?user_id=dojo&format=json"
40
34
  assert_equal("new_user_profile new_user_profile GET http://www.example.com/users/dojo/profile/new.json", body.chomp)
@@ -27,16 +27,7 @@ class RakeTasksTest < Test::Unit::TestCase
27
27
  assert_equal(read_fixture("yaml"), DescribedRoutes::RakeTaskMethods.yaml)
28
28
  end
29
29
 
30
- def test_yaml_short
31
- assert_equal(read_fixture("yaml_short"), DescribedRoutes::RakeTaskMethods.yaml_short)
32
- end
33
-
34
30
  def test_xml
35
31
  assert_equal(read_fixture("xml"), DescribedRoutes::RakeTaskMethods.xml)
36
32
  end
37
-
38
- def test_parsed_hook
39
- DescribedRoutes::RailsRoutes.parsed_hook = lambda {|a| a.reject{|h| h["name"] =~ /^admin/}}
40
- assert_equal(read_fixture("yaml_short_no_admin"), DescribedRoutes::RakeTaskMethods.yaml_short)
41
- end
42
33
  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.1
4
+ version: 0.5.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-20 00:00:00 +01:00
12
+ date: 2009-05-22 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -70,7 +70,7 @@ files:
70
70
  - lib/described_routes/rails_controller.rb
71
71
  - lib/described_routes/rails_routes.rb
72
72
  - lib/described_routes/rake_task_methods.rb
73
- - lib/described_routes/resource_template.rb
73
+ - lib/resource_template.rb
74
74
  - lib/tasks/described_routes.rb
75
75
  - script/console
76
76
  - script/destroy
@@ -100,13 +100,10 @@ files:
100
100
  - test_rails_app/test/fixtures/build_time/described_routes.text
101
101
  - test_rails_app/test/fixtures/build_time/described_routes.xml
102
102
  - test_rails_app/test/fixtures/build_time/described_routes.yaml
103
- - test_rails_app/test/fixtures/build_time/described_routes.yaml_short
104
- - test_rails_app/test/fixtures/build_time/described_routes.yaml_short_no_admin
105
103
  - test_rails_app/test/fixtures/run_time/described_routes.json
106
104
  - test_rails_app/test/fixtures/run_time/described_routes.text
107
105
  - test_rails_app/test/fixtures/run_time/described_routes.xml
108
106
  - test_rails_app/test/fixtures/run_time/described_routes.yaml
109
- - test_rails_app/test/fixtures/run_time/described_routes.yaml_short
110
107
  - test_rails_app/test/integration/described_routes_run_time_test.rb
111
108
  - test_rails_app/test/integration/rake_tasks_test.rb
112
109
  - test_rails_app/test/test_helper.rb
@@ -1,248 +0,0 @@
1
- require "json"
2
- require "addressable/template"
3
-
4
- module DescribedRoutes
5
- class ResourceTemplate
6
- # The template's name. Optional. Making these unique across the application is helpful for clients
7
- # that may wish to pick out nested templates by name.
8
- attr_reader :name
9
-
10
- # Optional attribute that describes a resource's relationship to its parent. For example:
11
- # * a nested route to a resource's edit page would have rel of "edit"
12
- # * a nested collection of articles under a "user" resource would have have a rel of "articles"
13
- # Collection members generally don't need a rel as they are identified by their params
14
- attr_reader :rel
15
-
16
- # A template for generating URIs.
17
- attr_reader :uri_template
18
-
19
- # A template for generating paths relative to the application's base.
20
- attr_reader :path_template
21
-
22
- # The parameters required by the path template
23
- attr_reader :params
24
-
25
- # Optional paramaters that may be used by the path template
26
- attr_reader :optional_params
27
-
28
- # "options" in the sense of the HTTP option request - i.e. a list of HTTP methods. Optional.
29
- attr_reader :options
30
-
31
- # An optional list of nested resource templates
32
- attr_reader :resource_templates
33
-
34
- # Initialize a ResourceTemplate. See the attribute descriptions above for explanations of the parameters.
35
- def initialize(name, rel, uri_template, path_template, params, optional_params, options, resource_templates)
36
- @name, @rel, @uri_template, @path_template = name, rel, uri_template, path_template
37
- @params = params || []
38
- @optional_params = optional_params || []
39
- @options = options || []
40
- @resource_templates = resource_templates || []
41
- end
42
-
43
- # Create a ResourceTemplate from its Hash representation
44
- def self.from_hash(hash)
45
- attributes = %w(name rel uri_template path_template params optional_params options).map{|k| hash[k]}
46
- if hash["resource_templates"]
47
- attributes << hash["resource_templates"].map{|h| from_hash(h)} if hash["resource_templates"]
48
- else
49
- attributes << nil
50
- end
51
- self.new(*attributes)
52
- end
53
-
54
- # Convert to a hash (equivalent to its JSON or YAML representation)
55
- def to_hash
56
- hash = {}
57
- hash["name"] = name if name && !name.empty?
58
- hash["rel"] = rel if rel && !rel.empty?
59
- hash["uri_template"] = uri_template if uri_template && !uri_template.empty?
60
- hash["path_template"] = path_template if path_template && !path_template.empty?
61
-
62
- hash["params"] = params if params && !params.empty?
63
- hash["optional_params"] = optional_params if optional_params && !optional_params.empty?
64
-
65
- hash["options"] = options if options && !options.empty?
66
-
67
- hashes = DescribedRoutes::ResourceTemplate.to_parsed(resource_templates)
68
- hash["resource_templates"] = hashes if hashes && !hashes.empty?
69
-
70
- hash
71
- end
72
-
73
- # Convert to JSON
74
- def to_json
75
- to_hash.to_json
76
- end
77
-
78
- # Convert to YAML
79
- def to_yaml
80
- to_hash.to_yaml
81
- end
82
-
83
- #
84
- # Produces the XML format, given an XML builder object and an array of ResourceTemplate objects
85
- #
86
- def to_xml(xm)
87
- xm.ResourceTemplate do |xm|
88
- value_tag(xm, "rel")
89
- value_tag(xm, "name")
90
- value_tag(xm, "path_template")
91
- value_tag(xm, "uri_template")
92
-
93
- list_tag(xm, params, "Params", "param")
94
- list_tag(xm, optional_params, "OptionalParams", "param")
95
-
96
- # could use a list of elements here, but let's follow HTTP's lead and reduce the verbosity
97
- xm.options(options.join(", ")) unless options.empty?
98
-
99
- self.class.to_xml(xm, resource_templates) unless resource_templates.empty?
100
- end
101
- xm
102
- end
103
-
104
- def value_tag(xm, tag) #:nodoc:
105
- value = self.send(tag.to_sym)
106
- xm.tag!(tag, value) unless value.blank?
107
- end
108
-
109
- def list_tag(xm, collection, collection_tag, member_tag) #:nodoc:
110
- unless collection.nil? or collection.empty?
111
- xm.tag!(collection_tag) do |xm|
112
- collection.each do |value|
113
- xm.tag!(member_tag, value)
114
- end
115
- end
116
- end
117
- end
118
-
119
- # Convert an array of ResourceTemplate objects to array of hashes equivalent to their JSON or YAML representations
120
- def self.to_parsed(resource_templates)
121
- resource_templates.map{|resource_template| resource_template.to_hash}
122
- end
123
-
124
- # Convert an array of ResourceTemplate objects to JSON
125
- def self.to_json(resource_templates)
126
- self.to_parsed(resource_templates).to_json
127
- end
128
-
129
- # Convert an array of ResourceTemplate objects to YAML
130
- def self.to_yaml(resource_templates)
131
- self.to_parsed(resource_templates).to_yaml
132
- end
133
-
134
- # Create an array of ResourceTemplate objects from a JSON string
135
- def self.parse_json(json)
136
- self.from_parsed(JSON.parse(json))
137
- end
138
-
139
- # Create an array of ResourceTemplate objects from a JSON string
140
- def self.parse_yaml(yaml)
141
- self.from_parsed(YAML::load(yaml))
142
- end
143
-
144
- # Create an array of ResourceTemplate objects from an array of hashes
145
- def self.from_parsed(parsed)
146
- raise ArgumentError.new("not an array") unless parsed.kind_of?(Array)
147
-
148
- parsed.map do |hash|
149
- ResourceTemplate.from_hash(hash)
150
- end
151
- end
152
-
153
- #
154
- # Produces the XML format, given an XML builder object and an array of ResourceTemplate objects
155
- #
156
- def self.to_xml(xm, resource_templates)
157
- xm.ResourceTemplates do |xm|
158
- resource_templates.each do |resource_template|
159
- resource_template.to_xml(xm)
160
- end
161
- end
162
- xm
163
- end
164
-
165
- # Get a hash of all named ResourceTemplate objects contained in the supplied collection, keyed by name
166
- def self.all_by_name(resource_templates, h = {})
167
- resource_templates.inject(h) do |hash, resource_template|
168
- hash[resource_template.name] = resource_template if resource_template.name
169
- all_by_name(resource_template.resource_templates, hash)
170
- hash
171
- end
172
- h
173
- end
174
-
175
- # for #to_text
176
- def self.to_table(resource_templates, parent_template = nil, t = [], indent = '')
177
- resource_templates.inject(t) do |table, resource_template|
178
- if parent_template
179
- link = (resource_template.rel || '')
180
- new_params = resource_template.params - parent_template.params
181
- else
182
- link = resource_template.name
183
- new_params = resource_template.params
184
- end
185
- link += new_params.map{|p| "{#{p}}"}.join(', ')
186
- table << [
187
- indent + link,
188
- resource_template.name || '',
189
- resource_template.options.join(', '),
190
- resource_template.uri_template || resource_template.path_template
191
- ]
192
- to_table(resource_template.resource_templates, resource_template, t, indent + ' ')
193
- end
194
- t
195
- end
196
-
197
- # text report
198
- def self.to_text(resource_templates)
199
- table = self.to_table(resource_templates)
200
-
201
- 0.upto(2) do |i|
202
- width = table.map{|row| row[i].length}.max
203
- table.each do |row|
204
- row[i] = row[i].ljust(width)
205
- end
206
- end
207
-
208
- table.map{|row| row.join(' ')}.join("\n") + "\n"
209
- end
210
-
211
- # returns params and any optional_params in order, removing the parent's params
212
- def positional_params(parent)
213
- all_params = params + optional_params
214
- if parent
215
- all_params - parent.params
216
- else
217
- all_params
218
- end
219
- end
220
-
221
- # Partially expand the path_template or uri_template of the given resource templates with the given params,
222
- # returning new resource templates
223
- def self.partial_expand(resource_templates, actual_params)
224
- resource_templates.map do |resource_template|
225
- resource_template.partial_expand(actual_params)
226
- end
227
- end
228
-
229
- # Return a new resource template with the path_template or uri_template partially expanded with the given params
230
- def partial_expand(actual_params)
231
- self.class.new(
232
- name,
233
- rel,
234
- partial_expand_uri_template(uri_template, actual_params),
235
- partial_expand_uri_template(path_template, actual_params),
236
- params - actual_params.keys,
237
- optional_params - actual_params.keys,
238
- options,
239
- self.class.partial_expand(resource_templates, actual_params))
240
- end
241
-
242
- # Partially expand a URI template
243
- def partial_expand_uri_template(template, params)#:nodoc:
244
- template && Addressable::Template.new(template).partial_expand(params).pattern
245
- end
246
- end
247
- end
248
-
@@ -1,72 +0,0 @@
1
- ---
2
- - name: root
3
- path_template: /
4
- - name: admin_products
5
- - name: new_admin_product
6
- path_template: /admin/products/new{-prefix|.|format}
7
- rel: new_admin_product
8
- - name: admin_product
9
- - name: edit_admin_product
10
- path_template: /admin/products/{product_id}/edit{-prefix|.|format}
11
- rel: edit
12
- path_template: /admin/products/{product_id}{-prefix|.|format}
13
- path_template: /admin/products{-prefix|.|format}
14
- - name: described_routes
15
- - name: new_described_route
16
- path_template: /described_routes/new{-prefix|.|format}
17
- rel: new_described_route
18
- - name: described_route
19
- - name: edit_described_route
20
- path_template: /described_routes/{route_name}/edit{-prefix|.|format}
21
- rel: edit
22
- path_template: /described_routes/{route_name}{-prefix|.|format}
23
- path_template: /described_routes{-prefix|.|format}
24
- - name: pages
25
- - name: new_page
26
- path_template: /pages/new{-prefix|.|format}
27
- rel: new_page
28
- - name: page
29
- - name: edit_page
30
- path_template: /pages/{page_id}/edit{-prefix|.|format}
31
- rel: edit
32
- - name: summary_page
33
- path_template: /pages/{page_id}/summary{-prefix|.|format}
34
- rel: summary
35
- - name: toggle_visibility_page
36
- path_template: /pages/{page_id}/toggle_visibility{-prefix|.|format}
37
- rel: toggle_visibility
38
- path_template: /pages/{page_id}{-prefix|.|format}
39
- path_template: /pages{-prefix|.|format}
40
- - name: users
41
- - name: new_user
42
- path_template: /users/new{-prefix|.|format}
43
- rel: new_user
44
- - name: user
45
- - name: edit_user
46
- path_template: /users/{user_id}/edit{-prefix|.|format}
47
- rel: edit
48
- - name: user_articles
49
- - name: new_user_article
50
- path_template: /users/{user_id}/articles/new{-prefix|.|format}
51
- rel: new_user_article
52
- - name: recent_user_articles
53
- path_template: /users/{user_id}/articles/recent{-prefix|.|format}
54
- rel: recent
55
- - name: user_article
56
- - name: edit_user_article
57
- path_template: /users/{user_id}/articles/{article_id}/edit{-prefix|.|format}
58
- rel: edit
59
- path_template: /users/{user_id}/articles/{article_id}{-prefix|.|format}
60
- path_template: /users/{user_id}/articles{-prefix|.|format}
61
- rel: articles
62
- - name: user_profile
63
- - name: edit_user_profile
64
- path_template: /users/{user_id}/profile/edit{-prefix|.|format}
65
- rel: edit
66
- - name: new_user_profile
67
- path_template: /users/{user_id}/profile/new{-prefix|.|format}
68
- rel: new
69
- path_template: /users/{user_id}/profile{-prefix|.|format}
70
- rel: profile
71
- path_template: /users/{user_id}{-prefix|.|format}
72
- path_template: /users{-prefix|.|format}
@@ -1,62 +0,0 @@
1
- ---
2
- - name: root
3
- path_template: /
4
- - name: described_routes
5
- - name: new_described_route
6
- path_template: /described_routes/new{-prefix|.|format}
7
- rel: new_described_route
8
- - name: described_route
9
- - name: edit_described_route
10
- path_template: /described_routes/{route_name}/edit{-prefix|.|format}
11
- rel: edit
12
- path_template: /described_routes/{route_name}{-prefix|.|format}
13
- path_template: /described_routes{-prefix|.|format}
14
- - name: pages
15
- - name: new_page
16
- path_template: /pages/new{-prefix|.|format}
17
- rel: new_page
18
- - name: page
19
- - name: edit_page
20
- path_template: /pages/{page_id}/edit{-prefix|.|format}
21
- rel: edit
22
- - name: summary_page
23
- path_template: /pages/{page_id}/summary{-prefix|.|format}
24
- rel: summary
25
- - name: toggle_visibility_page
26
- path_template: /pages/{page_id}/toggle_visibility{-prefix|.|format}
27
- rel: toggle_visibility
28
- path_template: /pages/{page_id}{-prefix|.|format}
29
- path_template: /pages{-prefix|.|format}
30
- - name: users
31
- - name: new_user
32
- path_template: /users/new{-prefix|.|format}
33
- rel: new_user
34
- - name: user
35
- - name: edit_user
36
- path_template: /users/{user_id}/edit{-prefix|.|format}
37
- rel: edit
38
- - name: user_articles
39
- - name: new_user_article
40
- path_template: /users/{user_id}/articles/new{-prefix|.|format}
41
- rel: new_user_article
42
- - name: recent_user_articles
43
- path_template: /users/{user_id}/articles/recent{-prefix|.|format}
44
- rel: recent
45
- - name: user_article
46
- - name: edit_user_article
47
- path_template: /users/{user_id}/articles/{article_id}/edit{-prefix|.|format}
48
- rel: edit
49
- path_template: /users/{user_id}/articles/{article_id}{-prefix|.|format}
50
- path_template: /users/{user_id}/articles{-prefix|.|format}
51
- rel: articles
52
- - name: user_profile
53
- - name: edit_user_profile
54
- path_template: /users/{user_id}/profile/edit{-prefix|.|format}
55
- rel: edit
56
- - name: new_user_profile
57
- path_template: /users/{user_id}/profile/new{-prefix|.|format}
58
- rel: new
59
- path_template: /users/{user_id}/profile{-prefix|.|format}
60
- rel: profile
61
- path_template: /users/{user_id}{-prefix|.|format}
62
- path_template: /users{-prefix|.|format}
@@ -1,99 +0,0 @@
1
- ---
2
- - name: root
3
- path_template: /
4
- uri_template: http://www.example.com/
5
- - name: admin_products
6
- - name: new_admin_product
7
- path_template: /admin/products/new{-prefix|.|format}
8
- uri_template: http://www.example.com/admin/products/new{-prefix|.|format}
9
- rel: new_admin_product
10
- - name: admin_product
11
- - name: edit_admin_product
12
- path_template: /admin/products/{product_id}/edit{-prefix|.|format}
13
- uri_template: http://www.example.com/admin/products/{product_id}/edit{-prefix|.|format}
14
- rel: edit
15
- path_template: /admin/products/{product_id}{-prefix|.|format}
16
- uri_template: http://www.example.com/admin/products/{product_id}{-prefix|.|format}
17
- path_template: /admin/products{-prefix|.|format}
18
- uri_template: http://www.example.com/admin/products{-prefix|.|format}
19
- - name: described_routes
20
- - name: new_described_route
21
- path_template: /described_routes/new{-prefix|.|format}
22
- uri_template: http://www.example.com/described_routes/new{-prefix|.|format}
23
- rel: new_described_route
24
- - name: described_route
25
- - name: edit_described_route
26
- path_template: /described_routes/{route_name}/edit{-prefix|.|format}
27
- uri_template: http://www.example.com/described_routes/{route_name}/edit{-prefix|.|format}
28
- rel: edit
29
- path_template: /described_routes/{route_name}{-prefix|.|format}
30
- uri_template: http://www.example.com/described_routes/{route_name}{-prefix|.|format}
31
- path_template: /described_routes{-prefix|.|format}
32
- uri_template: http://www.example.com/described_routes{-prefix|.|format}
33
- - name: pages
34
- - name: new_page
35
- path_template: /pages/new{-prefix|.|format}
36
- uri_template: http://www.example.com/pages/new{-prefix|.|format}
37
- rel: new_page
38
- - name: page
39
- - name: edit_page
40
- path_template: /pages/{page_id}/edit{-prefix|.|format}
41
- uri_template: http://www.example.com/pages/{page_id}/edit{-prefix|.|format}
42
- rel: edit
43
- - name: summary_page
44
- path_template: /pages/{page_id}/summary{-prefix|.|format}
45
- uri_template: http://www.example.com/pages/{page_id}/summary{-prefix|.|format}
46
- rel: summary
47
- - name: toggle_visibility_page
48
- path_template: /pages/{page_id}/toggle_visibility{-prefix|.|format}
49
- uri_template: http://www.example.com/pages/{page_id}/toggle_visibility{-prefix|.|format}
50
- rel: toggle_visibility
51
- path_template: /pages/{page_id}{-prefix|.|format}
52
- uri_template: http://www.example.com/pages/{page_id}{-prefix|.|format}
53
- path_template: /pages{-prefix|.|format}
54
- uri_template: http://www.example.com/pages{-prefix|.|format}
55
- - name: users
56
- - name: new_user
57
- path_template: /users/new{-prefix|.|format}
58
- uri_template: http://www.example.com/users/new{-prefix|.|format}
59
- rel: new_user
60
- - name: user
61
- - name: edit_user
62
- path_template: /users/{user_id}/edit{-prefix|.|format}
63
- uri_template: http://www.example.com/users/{user_id}/edit{-prefix|.|format}
64
- rel: edit
65
- - name: user_articles
66
- - name: new_user_article
67
- path_template: /users/{user_id}/articles/new{-prefix|.|format}
68
- uri_template: http://www.example.com/users/{user_id}/articles/new{-prefix|.|format}
69
- rel: new_user_article
70
- - name: recent_user_articles
71
- path_template: /users/{user_id}/articles/recent{-prefix|.|format}
72
- uri_template: http://www.example.com/users/{user_id}/articles/recent{-prefix|.|format}
73
- rel: recent
74
- - name: user_article
75
- - name: edit_user_article
76
- path_template: /users/{user_id}/articles/{article_id}/edit{-prefix|.|format}
77
- uri_template: http://www.example.com/users/{user_id}/articles/{article_id}/edit{-prefix|.|format}
78
- rel: edit
79
- path_template: /users/{user_id}/articles/{article_id}{-prefix|.|format}
80
- uri_template: http://www.example.com/users/{user_id}/articles/{article_id}{-prefix|.|format}
81
- path_template: /users/{user_id}/articles{-prefix|.|format}
82
- uri_template: http://www.example.com/users/{user_id}/articles{-prefix|.|format}
83
- rel: articles
84
- - name: user_profile
85
- - name: edit_user_profile
86
- path_template: /users/{user_id}/profile/edit{-prefix|.|format}
87
- uri_template: http://www.example.com/users/{user_id}/profile/edit{-prefix|.|format}
88
- rel: edit
89
- - name: new_user_profile
90
- path_template: /users/{user_id}/profile/new{-prefix|.|format}
91
- uri_template: http://www.example.com/users/{user_id}/profile/new{-prefix|.|format}
92
- rel: new
93
- path_template: /users/{user_id}/profile{-prefix|.|format}
94
- uri_template: http://www.example.com/users/{user_id}/profile{-prefix|.|format}
95
- rel: profile
96
- path_template: /users/{user_id}{-prefix|.|format}
97
- uri_template: http://www.example.com/users/{user_id}{-prefix|.|format}
98
- path_template: /users{-prefix|.|format}
99
- uri_template: http://www.example.com/users{-prefix|.|format}