described_routes 0.0.2
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 +4 -0
- data/Manifest.txt +12 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +95 -0
- data/Rakefile +37 -0
- data/lib/described_routes.rb +91 -0
- data/lib/tasks/described_routes.rb +29 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/test_described_routes.rb +11 -0
- data/test/test_helper.rb +3 -0
- data/test/test_resource_template.rb +2 -0
- metadata +92 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/PostInstall.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
= described_routes README
|
2
|
+
|
3
|
+
== DESCRIPTION:
|
4
|
+
|
5
|
+
Outputs hierarchical, framework-neutral descriptions of Rails routes in JSON, YAML and XML formats for potential consumption by client applications (e.g. those based on path-to[http://github.com/asplake/path-to/tree]).
|
6
|
+
|
7
|
+
== SYNOPSIS:
|
8
|
+
|
9
|
+
In your Rakefile:
|
10
|
+
|
11
|
+
require 'tasks/described_routes'
|
12
|
+
|
13
|
+
Then:
|
14
|
+
|
15
|
+
$ rake --tasks described_routes
|
16
|
+
rake described_routes:json # Describe resource structure in JSON format
|
17
|
+
rake described_routes:ruby # Describe resource structure as a Ruby literal
|
18
|
+
rake described_routes:xml # Describe resource structure in XML format
|
19
|
+
rake described_routes:yaml # Describe resource structure in YAML format
|
20
|
+
rake described_routes:yaml_short # Describe resource structure in YAML format (basic structure only)
|
21
|
+
|
22
|
+
For a flavour, try the short form:
|
23
|
+
|
24
|
+
$ rake described_routes:yaml_short
|
25
|
+
- name: users
|
26
|
+
path_template: /users{-prefix|.|format}
|
27
|
+
resources:
|
28
|
+
- name: user
|
29
|
+
path_template: /users/{user_id}{-prefix|.|format}
|
30
|
+
resources:
|
31
|
+
- name: user_articles
|
32
|
+
rel: articles
|
33
|
+
path_template: /users/{user_id}/articles{-prefix|.|format}
|
34
|
+
resources:
|
35
|
+
- name: user_article
|
36
|
+
path_template: /users/{user_id}/articles/{article_id}{-prefix|.|format}
|
37
|
+
resources:
|
38
|
+
- name: edit_user_article
|
39
|
+
path_template: /users/{user_id}/articles/{article_id}/edit{-prefix|.|format}
|
40
|
+
rel: edit
|
41
|
+
- name: new_user_article
|
42
|
+
path_template: /users/{user_id}/articles/new{-prefix|.|format}
|
43
|
+
rel: new
|
44
|
+
- name: recent_user_articles
|
45
|
+
path_template: /users/{user_id}/articles/recent{-prefix|.|format}
|
46
|
+
rel: recent
|
47
|
+
- name: edit_user
|
48
|
+
path_template: /users/{user_id}/edit{-prefix|.|format}
|
49
|
+
rel: edit
|
50
|
+
|
51
|
+
The above YAML is an abbreviated form that shows only name, rel, path_template for each resource in the hierarchy. The full form includes parameter lists (both mandatory and optional) and options (i.e. HTTP methods).
|
52
|
+
|
53
|
+
== DATA STRUCTURES and FORMATS
|
54
|
+
|
55
|
+
=== Natural structure
|
56
|
+
|
57
|
+
The YAML, JSON and Ruby representations appear as simple array and hash structures (which is what they're generated from internally). Each resource is represented by a hash of attributes (one of which may be a list of child resources); the top level structure is an array of the resources that don't have parents.
|
58
|
+
|
59
|
+
Attributes:
|
60
|
+
|
61
|
+
+name+:: A Rails-generated route name
|
62
|
+
+rel+:: An indication of a child resource's relationship to its parent
|
63
|
+
+options+:: A list of HTTP methods supported by the resource
|
64
|
+
+path_template+:: A template for the resource's path, in the style of URI Template but as a relative path
|
65
|
+
+params+:: A list of parameters required by path_template
|
66
|
+
+optional_params+:: A list of optional parameters that may be incorporated by the path_template
|
67
|
+
|
68
|
+
Empty or blank attributes are omitted.
|
69
|
+
|
70
|
+
Note that only named routes are considered. Pre-Rails 2.3 "formatted routes" are explicitly excluded, and for Rails 2.3 onwards, <tt>"format"</tt> is the only entry likely to appear in the optional_parameters attribute.
|
71
|
+
|
72
|
+
=== XML
|
73
|
+
|
74
|
+
This follows the natural structure but with the following modifications:
|
75
|
+
|
76
|
+
* A +Resource+ element for each resource
|
77
|
+
* A +Resources+ element for each list of resources (top level or subresources)
|
78
|
+
* +Params+ and +OptionalParams+ elements for +params+ and +optional_params+, each containing +param+ elements
|
79
|
+
* A single +options+ element contains the applicable HTTP methods as a comma-separated list
|
80
|
+
|
81
|
+
== REQUIREMENTS:
|
82
|
+
|
83
|
+
Rails. Note however that the output format is not Rails-specific.
|
84
|
+
|
85
|
+
== INSTALL:
|
86
|
+
|
87
|
+
sudo gem install described_routes
|
88
|
+
|
89
|
+
Then add the following to your Rakefile:
|
90
|
+
|
91
|
+
require "tasks/described_routes"
|
92
|
+
|
93
|
+
== Author
|
94
|
+
|
95
|
+
Mike Burrows (asplake), email mailto:mjb@asplake.co.uk, website positiveincline.com[http://positiveincline.com] (see articles tagged described_routes[http://positiveincline.com/?tag=described_routes])
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
|
2
|
+
$:.push File.dirname(__FILE__) + '/lib'
|
3
|
+
require 'described_routes'
|
4
|
+
|
5
|
+
# undefined method `empty?' for nil:NilClass
|
6
|
+
# /Library/Ruby/Site/1.8/rubygems/specification.rb:886:in `validate'
|
7
|
+
class NilClass
|
8
|
+
def empty?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Generate all the Rake tasks
|
14
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
15
|
+
$hoe = Hoe.new('described_routes', DescribedRoutes::VERSION) do |p|
|
16
|
+
p.developer('Mike Burrows', 'mjb@asplake.co.uk')
|
17
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
18
|
+
p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
|
19
|
+
p.rubyforge_name = 'describedroutes' # TODO this is default value
|
20
|
+
# p.extra_deps = [
|
21
|
+
# ['activesupport','>= 2.0.2'],
|
22
|
+
# ]
|
23
|
+
p.extra_dev_deps = [
|
24
|
+
['newgem', ">= #{::Newgem::VERSION}"]
|
25
|
+
]
|
26
|
+
|
27
|
+
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
28
|
+
path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
|
29
|
+
p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
|
30
|
+
p.rsync_args = '-av --delete --ignore-errors'
|
31
|
+
end
|
32
|
+
|
33
|
+
require 'newgem/tasks' # load /tasks/*.rake
|
34
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
35
|
+
|
36
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
37
|
+
# task :default => [:spec, :features]
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'described_routes/resource_template'
|
2
|
+
|
3
|
+
module DescribedRoutes
|
4
|
+
# rubygem version
|
5
|
+
VERSION = "0.0.2"
|
6
|
+
|
7
|
+
# Convert an array of ResourceTemplate objects to array of hashes equivalent to their JSON or YAML representations
|
8
|
+
def self.to_parsed(resource_templates)
|
9
|
+
resource_templates.map{|resource_template| resource_template.to_hash}
|
10
|
+
end
|
11
|
+
|
12
|
+
# Convert an array of ResourceTemplate objects to JSON
|
13
|
+
def self.to_json(resource_templates)
|
14
|
+
self.to_parsed(resource_templates).to_json
|
15
|
+
end
|
16
|
+
|
17
|
+
# Convert an array of ResourceTemplate objects to YAML
|
18
|
+
def self.to_yaml(resource_templates)
|
19
|
+
self.to_parsed(resource_templates).to_yaml
|
20
|
+
end
|
21
|
+
|
22
|
+
# Create an array of ResourceTemplate objects from a JSON string
|
23
|
+
def self.parse_json(json)
|
24
|
+
self.from_parsed(JSON.parse(json))
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create an array of ResourceTemplate objects from a JSON string
|
28
|
+
def self.parse_yaml(yaml)
|
29
|
+
self.from_parsed(YAML::load(yaml))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Create an array of ResourceTemplate objects from an array of hashes
|
33
|
+
def self.from_parsed(parsed)
|
34
|
+
raise ArgumentError.new("not an array") unless parsed.kind_of?(Array)
|
35
|
+
|
36
|
+
parsed.map do |hash|
|
37
|
+
ResourceTemplate.from_hash(hash)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Produces the XML format, given an XML builder object and an array of ResourceTemplate objects
|
43
|
+
#
|
44
|
+
def self.to_xml(xm, resource_templates)
|
45
|
+
xm.ResourceTemplates do |xm|
|
46
|
+
resource_templates.each do |resource_template|
|
47
|
+
xm.ResourceTemplate do |xm|
|
48
|
+
value_tag(xm, resource_template, "rel")
|
49
|
+
value_tag(xm, resource_template, "name")
|
50
|
+
value_tag(xm, resource_template, "path_template")
|
51
|
+
|
52
|
+
list_tag(xm, resource_template["params"], "Params", "param")
|
53
|
+
list_tag(xm, resource_template["optional_params"], "OptionalParams", "param")
|
54
|
+
|
55
|
+
# could use a list of elements here, but let's follow HTTP's lead and reduce the verbosity
|
56
|
+
options = resource_template["options"] || []
|
57
|
+
xm.options(options.join(", ")) unless options.empty?
|
58
|
+
|
59
|
+
resource_templates = resource_template["resource_templates"] || []
|
60
|
+
to_xml(xm, resource_templates) unless resource_templates.empty?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
xm
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.value_tag(xm, h, tag) #:nodoc:
|
68
|
+
value = h[tag]
|
69
|
+
xm.tag!(tag, value) unless value.blank?
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.list_tag(xm, collection, collection_tag, member_tag) #:nodoc:
|
73
|
+
unless collection.nil? or collection.empty?
|
74
|
+
xm.tag!(collection_tag) do |xm|
|
75
|
+
collection.each do |value|
|
76
|
+
xm.tag!(member_tag, value)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get a hash of all named ResourceTemplate objects contained in the supplied collection, keyed by name
|
83
|
+
def self.all_by_name(resource_templates, h = {})
|
84
|
+
resource_templates.inject(h) do |hash, resource_template|
|
85
|
+
hash[resource_template.name] = resource_template if resource_template.name
|
86
|
+
all_by_name(resource_template.resource_templates, hash)
|
87
|
+
hash
|
88
|
+
end
|
89
|
+
h
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'tasks/rails'
|
2
|
+
require 'described_routes/rails_routes'
|
3
|
+
|
4
|
+
namespace :described_routes do
|
5
|
+
desc "Describe resource structure as a Ruby literal"
|
6
|
+
desc "Describe resource structure in JSON format"
|
7
|
+
|
8
|
+
task :json => :environment do
|
9
|
+
puts DescribedRoutes::RailsRoutes.get_resources.to_json
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Describe resource structure in YAML format"
|
13
|
+
task :yaml => :environment do
|
14
|
+
puts DescribedRoutes::RailsRoutes.get_resources.to_yaml
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Describe resource structure in YAML format (basic structure only)"
|
18
|
+
task :yaml_short => :environment do
|
19
|
+
puts DescribedRoutes::RailsRoutes.get_resources.to_yaml.grep(/name|rel|path_template|resources/)
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Describe resource structure in XML format"
|
23
|
+
task :xml => :environment do
|
24
|
+
puts DescribedRoutes::to_xml(
|
25
|
+
Builder::XmlMarkup.new(:indent => 2),
|
26
|
+
DescribedRoutes::RailsRoutes.get_resources
|
27
|
+
).target!
|
28
|
+
end
|
29
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/described_routes.rb'}"
|
9
|
+
puts "Loading described_routes gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: described_routes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Burrows
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-27 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: newgem
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.3.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
version:
|
35
|
+
description: Outputs hierarchical, framework-neutral descriptions of Rails routes in JSON, YAML and XML formats for potential consumption by client applications (e.g. those based on path-to[http://github.com/asplake/path-to/tree]).
|
36
|
+
email:
|
37
|
+
- mjb@asplake.co.uk
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- History.txt
|
44
|
+
- Manifest.txt
|
45
|
+
- PostInstall.txt
|
46
|
+
- README.rdoc
|
47
|
+
files:
|
48
|
+
- History.txt
|
49
|
+
- Manifest.txt
|
50
|
+
- PostInstall.txt
|
51
|
+
- README.rdoc
|
52
|
+
- Rakefile
|
53
|
+
- lib/described_routes.rb
|
54
|
+
- lib/tasks/described_routes.rb
|
55
|
+
- script/console
|
56
|
+
- script/destroy
|
57
|
+
- script/generate
|
58
|
+
- test/test_described_routes.rb
|
59
|
+
- test/test_helper.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage:
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message: PostInstall.txt
|
65
|
+
rdoc_options:
|
66
|
+
- --main
|
67
|
+
- README.rdoc
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
version:
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: "0"
|
81
|
+
version:
|
82
|
+
requirements: []
|
83
|
+
|
84
|
+
rubyforge_project: describedroutes
|
85
|
+
rubygems_version: 1.3.2
|
86
|
+
signing_key:
|
87
|
+
specification_version: 3
|
88
|
+
summary: Outputs hierarchical, framework-neutral descriptions of Rails routes in JSON, YAML and XML formats for potential consumption by client applications (e.g
|
89
|
+
test_files:
|
90
|
+
- test/test_described_routes.rb
|
91
|
+
- test/test_helper.rb
|
92
|
+
- test/test_resource_template.rb
|