described_routes 0.4.1 → 0.5.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,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}