lib/usher/util/generate.rb in usher-0.5.4 vs lib/usher/util/generate.rb in usher-0.5.5

- old
+ new

@@ -1,48 +1,124 @@ -require 'rack' +class Usher + module Util + class Generators -unless Rack::Utils.respond_to?(:uri_escape) - module Rack + class Generic - module Utils + attr_accessor :usher - def uri_escape(s) - s.to_s.gsub(/([^:\/?\[\]\-_~\.!\$&'\(\)\*\+,;=@a-zA-Z0-9]+)/n) { - '%'<<$1.unpack('H2'*$1.size).join('%').upcase - }.tr(' ', '+') - end - module_function :uri_escape + def generate(name, params) + generate_path_for_base_params(@usher.named_routes[name].find_matching_path(params), params) + end - def uri_unescape(s) - gsub(/((?:%[0-9a-fA-F]{2})+)/n){ - [$1.delete('%')].pack('H*') - } + def generate_path_for_base_params(path, params) + raise UnrecognizedException.new unless path + + result = '' + path.parts.each do |part| + case part + when Route::Variable::Glob + value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new) + value.each_with_index do |current_value, index| + part.valid!(current_value) + result << current_value.to_s + result << usher.delimiters.first if index != value.size - 1 + end + when Route::Variable + value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new) + part.valid!(value) + result << value.to_s + else + result << part + end + end + result + end + end - module_function :uri_unescape - end - end -end + class URL < Generic -class Usher - module Util - class Generators - - class URL - - attr_accessor :usher + def initialize + require File.join(File.dirname(__FILE__), 'rack-mixins') + end def generate_full(routing_lookup, request, params = nil) path = path_for_routing_lookup(routing_lookup, params) result = generate_start(path, request) result << generate_path(path, params) end + # Generates a completed URL based on a +route+ or set of optional +params+ + # + # set = Usher.new + # route = set.add_named_route(:test_route, '/:controller/:action') + # set.generator.generate(nil, {:controller => 'c', :action => 'a'}) == '/c/a' => true + # set.generator.generate(:test_route, {:controller => 'c', :action => 'a'}) == '/c/a' => true + # set.generator.generate(route.primary_path, {:controller => 'c', :action => 'a'}) == '/c/a' => true def generate(routing_lookup, params = nil) generate_path(path_for_routing_lookup(routing_lookup, params), params) end + def generate_path(path, params = nil) + params = Array(params) if params.is_a?(String) + if params.is_a?(Array) + given_size = params.size + extra_params = params.last.is_a?(Hash) ? params.pop : nil + params = Hash[*path.dynamic_parts.inject([]){|a, dynamic_part| a.concat([dynamic_part.name, params.shift || raise(MissingParameterException.new("got #{given_size}, expected #{path.dynamic_parts.size} parameters"))]); a}] + params.merge!(extra_params) if extra_params + end + + result = Rack::Utils.uri_escape(generate_path_for_base_params(path, params)) + unless params.nil? || params.empty? + extra_params = generate_extra_params(params, result[??]) + result << extra_params + end + result + end + + def generation_module + build_module! + @generation_module + end + + def build_module! + unless @generation_module + @generation_module = Module.new + @generation_module.module_eval <<-END_EVAL + @@generator = nil + def self.generator=(generator) + @@generator = generator + end + END_EVAL + @generation_module.generator = self + + @generation_module.module_eval <<-END_EVAL + def respond_to?(method_name) + if match = Regexp.new('^(.*?)_(path|url)$').match(method_name.to_s) + @@generator.usher.named_routes.key?(match.group(1)) + else + super + end + end + END_EVAL + + + usher.named_routes.each do |name, route| + @generation_module.module_eval <<-END_EVAL + def #{name}_url(name, request, params = nil) + @@generator.generate_full(name, request, options) + end + + def #{name}_path(name, params = nil) + @@generator.generate(name, options) + end + END_EVAL + end + end + end + def generate_start(path, request) result = (path.route.generate_with && path.route.generate_with.scheme || request.scheme).dup result << '://' result << (path.route.generate_with && path.route.generate_with.host) ? path.route.generate_with.host : request.host port = path.route.generate_with && path.route.generate_with.port || request.port @@ -51,79 +127,44 @@ else result << ':' << port.to_s unless port == 80 end result end - + def path_for_routing_lookup(routing_lookup, params = {}) path = case routing_lookup when Symbol - route = @usher.named_routes[routing_lookup] + route = @usher.named_routes[routing_lookup] + raise UnrecognizedException unless route route.find_matching_path(params || {}) when Route - routing_lookup.find_matching_path(params || {}) + routing_lookup.find_matching_path(params) when nil - params.is_a?(Hash) ? @usher.path_for_options(params) : raise + params.is_a?(Hash) ? usher.path_for_options(params) : raise when Route::Path routing_lookup end end - - # Generates a completed URL based on a +route+ or set of optional +params+ - # - # set = Usher.new - # route = set.add_named_route(:test_route, '/:controller/:action') - # set.generate_url(nil, {:controller => 'c', :action => 'a'}) == '/c/a' => true - # set.generate_url(:test_route, {:controller => 'c', :action => 'a'}) == '/c/a' => true - # set.generate_url(route.primary_path, {:controller => 'c', :action => 'a'}) == '/c/a' => true - def generate_path(path, params = nil) - raise UnrecognizedException.new unless path - params = Array(params) if params.is_a?(String) - if params.is_a?(Array) - given_size = params.size - extra_params = params.last.is_a?(Hash) ? params.pop : nil - params = Hash[*path.dynamic_parts.inject([]){|a, dynamic_part| a.concat([dynamic_part.name, params.shift || raise(MissingParameterException.new("got #{given_size}, expected #{path.dynamic_parts.size} parameters"))]); a}] - params.merge!(extra_params) if extra_params - end - result = '' - path.parts.each do |part| - case part - when Route::Variable::Glob - value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new) - value.each_with_index do |current_value, index| - part.valid!(current_value) - result << current_value.to_s - result << '/' if index != value.size - 1 + def generate_extra_params(params, has_question_mark) + extra_params_result = '' + + params.each do |k,v| + case v + when Array + v.each do |v_part| + extra_params_result << (has_question_mark ? '&' : has_question_mark = true && '?') << Rack::Utils.escape("#{k.to_s}[]") << '=' << Rack::Utils.escape(v_part.to_s) end - when Route::Variable - value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new) - part.valid!(value) - result << value.to_s else - result << part + extra_params_result << (has_question_mark ? '&' : has_question_mark = true && '?') << Rack::Utils.escape(k.to_s) << '=' << Rack::Utils.escape(v.to_s) end end - result = Rack::Utils.uri_escape(result) - - unless params.nil? || params.empty? - has_query = result[??] - params.each do |k,v| - case v - when Array - v.each do |v_part| - result << (has_query ? '&' : has_query = true && '?') << Rack::Utils.escape("#{k.to_s}[]") << '=' << Rack::Utils.escape(v_part.to_s) - end - else - result << (has_query ? '&' : has_query = true && '?') << Rack::Utils.escape(k.to_s) << '=' << Rack::Utils.escape(v.to_s) - end - end - end - result + extra_params_result end - + end - + end end -end \ No newline at end of file +end +