Module: DescribedRoutes::RailsRoutes
- Defined in:
- lib/described_routes/rails_routes.rb
Defined Under Namespace
Classes: RailsResourceTemplates
Class Method Summary collapse
-
.get_parsed_rails_resources(base_url = nil) ⇒ Object
Takes the routes from Rails and produces the required tree structure.
-
.get_rails_resources ⇒ Object
Based on the implementation of “rake routes”.
-
.get_resource_templates(base_url = nil, routing = nil) ⇒ Object
Process Rails routes and return an array of ResourceTemplate objects.
-
.make_key_tree(sorted_keys, &is_prefix) ⇒ Object
Turns a sorted array of strings into a tree structure as follows:.
-
.map_key_tree(tree, &blk) ⇒ Object
Depth-first tree traversal.
Class Method Details
.get_parsed_rails_resources(base_url = nil) ⇒ Object
Takes the routes from Rails and produces the required tree structure. Returns the “parsed” format - i.e. a representation in Ruby Array and Hash objects
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/described_routes/rails_routes.rb', line 137 def self.get_parsed_rails_resources(base_url = nil) #:nodoc: base_url = base_url.sub(/\/$/, '') if base_url resources = get_rails_resources resources.delete_if{|k, v| v["name"].blank? or v["name"] =~ /^formatted/} key_tree = make_key_tree(resources.keys.sort){|possible_prefix, key| key[0...possible_prefix.length] == possible_prefix && possible_prefix != "/" } tree = map_key_tree(key_tree) do |key, children| resource = resources[key] resource.delete("options") if resource["options"] == [""] resource["uri_template"] = base_url + resource["path_template"] if base_url && resource["path_template"] # compare parent and child names, and populate "rel" with either # 1) a prefix (probably an action name) # 2) a suffix (probably a nested resource) # 3) the child's name if the parent and child's params are identical # If none of the above applies, the child must be identifable by parameter name = resource["name"] prefix = /^(.*)_#{name}$/ suffix = /^#{name}_(.*)$/ children.each do |child| child_name = child["name"] if child_name =~ prefix child["rel"] = $1 elsif child_name =~ suffix child["rel"] = $1 elsif child["params"] == resource["params"] child["rel"] = child["name"] end end controller = resource["controller"] unless children.empty? resource["resource_templates"] = children.sort_by{|c| [ (c["controller"] == controller) ? "" : c["controller"], # group by controller, parent controller first (c["params"] || []).length, # fewer params first c["name"] # make determininistic ] } end resource end end |
.get_rails_resources ⇒ Object
Based on the implementation of “rake routes”. Returns a hash of Rails path specifications (slightly normalized) mapped to hashes of the attributes we need.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/described_routes/rails_routes.rb', line 54 def self.get_rails_resources #:nodoc: ActionController::Routing::Routes.routes.inject({}) do |resources, route| name = ActionController::Routing::Routes.named_routes.routes.index(route).to_s controller = route.parameter_shell[:controller] action = route.parameter_shell[:action] = [route.conditions[:method]].flatten.map{|option| option.to_s.upcase} segs = route.segments.inject("") {|str,s| str << s.to_s } segs.chop! if segs.length > 1 # prefix :id parameters consistently # TODO - probably a better way to do this, just need a pattern that matches :id and not :id[a-zA-Z0-9_]+ id_name = nil segs.gsub!(/:[a-zA-Z0-9_]+/) do |match| if match == ":id" && controller id_name = (controller == "described_routes/rails") ? "route_name" : "#{controller.singularize.sub(/.*\//, "")}_id" ':' + id_name else match end end # ignore optional format parameter when comparing paths key = segs.sub("(.:format)", "") if resources[key] # we've seen the (normalised) path before; add to options resources[key]["options"] += else template = segs # collect & format mandatory parameters params = [] template.gsub!(/:[a-zA-Z0-9_]+/) do |match| param = match[1..-1] param = controller.singularize.sub(/.*\//, "") + "_id" if param == "id" && controller params << param "{#{param}}" end # collect & format optional format parameter optional_params = [] template.sub!("(.{format})") do |match| optional_params << "format" "{-prefix|.|format}" end params -= optional_params # so now we have (for example): # segs #=> "/users/:user_id/edit(.:format)" (was "/users/:id") # key #=> "/users/:user_id/edit" # template #=> "/users/{user_id}/edit" # params #=> ["user_id"] # optional_params #=> ["format"] # action #=> "edit" # options #=> ["GET"] # name #=> "edit_user" # controller #=> "rails" # id_name #=> "user_id" # create a new route hash resource = { "path_template" => template, "options" => , "controller" => controller, "action" => action, "id_name" => id_name } resource["params"] = params unless params.empty? resource["optional_params"] = optional_params unless optional_params.empty? resources[key] = resource end # this may be the first time we've seen a good name for this key resources[key]["name"] ||= name unless name.blank? or name =~ /^formatted/ resources end end |
.get_resource_templates(base_url = nil, routing = nil) ⇒ Object
Process Rails routes and return an array of ResourceTemplate objects.
44 45 46 47 48 |
# File 'lib/described_routes/rails_routes.rb', line 44 def self.get_resource_templates(base_url=nil, routing=nil) parsed = get_parsed_rails_resources(base_url) parsed = parsed_hook.call(parsed) if parsed_hook RailsResourceTemplates.new(parsed) end |
.make_key_tree(sorted_keys, &is_prefix) ⇒ Object
Turns a sorted array of strings into a tree structure as follows:
make_key_tree(["/", "/a", "/a/b", "/a/b/c", "/a/d", "/b"]){|possible_prefix, route|
route[0...possible_prefix.length] == possible_prefix && possible_prefix != "/"
}
=> [["/", []], ["/a", [["/a/b", [["/a/b/c", []]]], ["/a/d", []]]], ["/b", []]]
Note that in the example (as in is actual usage in this module), we choose not to to have the root resource (“/”) as the parent of all other resources.
211 212 213 214 215 216 217 218 219 |
# File 'lib/described_routes/rails_routes.rb', line 211 def self.make_key_tree(sorted_keys, &is_prefix) #:nodoc: head, *tail = sorted_keys if head children, siblings = tail.partition{|p| is_prefix.call(head, p)} [[head, make_key_tree(children, &is_prefix)]] + make_key_tree(siblings, &is_prefix) else [] end end |
.map_key_tree(tree, &blk) ⇒ Object
Depth-first tree traversal
tree = [["/", []], ["/a", [["/a/b", [["/a/b/c", []]]], ["/a/d", []]]], ["/b", []]]
map_key_tree(tree){|key, processed_children| {key => processed_children}}
# => [{"/"=>[]}, {"/a"=>[{"/a/b"=>[{"/a/b/c"=>[]}]}, {"/a/d"=>[]}]}, {"/b"=>[]}]
193 194 195 196 197 198 |
# File 'lib/described_routes/rails_routes.rb', line 193 def self.map_key_tree(tree, &blk) #:nodoc: tree.map do |pair| key, children = pair blk.call(key, map_key_tree(children, &blk)) end end |