module Rad class Router inject( config: :config, workspace: :workspace ) attr_reader :routes, :format_processor def initialize class_variable, routes = {default_router: SimpleRouter.new}, format_processor = DefaultFormatProcessor.new @class_variable, @format_processor = class_variable, format_processor @routes = Dictionary.new routes.each do |k, v| k.must_be.present v.must_be.present v.must.respond_to(:decode) v.must.respond_to(:encode) @routes[k] = v end end def skip path_regexp=nil @skip ||= [] if path_regexp path_regexp.must_be.a Regexp @skip << path_regexp unless @skip.include? path_regexp else @skip end end def url_for *args if args.first.is_a?(Class) args.size.must_be.in 2..3 klass, method, options = args url_for_class(klass, method, (options || {})) else first = args.first.to_s if first !~ /^\// args.size.must_be.in 1..2 method, options = args url_for_class(nil, method, (options || {})) else args.size.must_be.in 1..2 path, options = args url_for_path(path, (options || {})) end end end def decode path, params path.first.must == '/' # params = params.to_openobject throw :skip, true if skip.any?{|path_regexp| path_regexp =~ path} path, format = format_processor.remove_format path if format_processor result = nil routes.each do |name, route| result = route.decode path, params break if result end raise "no route for '#{safe_workspace.path}' request!" unless result klass, method, params = result method ||= config.default_method params.must_be.defined method.must_be.a Symbol raise "Invalid route! No method '#{method}' for #{klass}!" unless klass.instance_methods.include? method raise "Invalid route! You try to call protected method '#{method}' for '#{path}'!" unless klass.public_instance_methods.include? method return klass, method, params end def encode klass, method, params = {} klass.must_be.defined method.must_be.a Symbol params = params.clone # method, params = method, params.to_openobject format = params.delete(:format) raise "Invalid route! No method '#{method}' for #{klass}!" unless klass.method_defined? method raise "Invalid route! You try to call protected method '#{method}' for '#{klass}'!" unless klass.method_defined? method inject_persistent_params! params result = nil routes.each do |name, route| result = route.encode klass, method, params break if result end raise "no route for '#{klass}.#{method}'!" unless result path, params = result path.must_be.defined params.must_be.defined path = format_processor.add_format path, format if format_processor and format return path, params end def encode_method route_method # method = method route_method.must_be.present result = nil routes.each do |name, route| result = route.respond_to :encode_method, route_method break if result end raise "no route for '#{route_method}' route method!" unless result klass, method = result klass.must_be.defined method.must_be.defined return klass, method end cache_method_with_params_in_production :encode_method def persist_params &block if block before = safe_workspace.persist_params? begin safe_workspace[:persist_params] = true block.call ensure safe_workspace.delete :persist_params unless before end else safe_workspace[:persist_params] = true end end def dont_persist_params &block if block before = safe_workspace.persist_params? begin safe_workspace.delete :persist_params block.call ensure safe_workspace[:persist_params] = true if before end else safe_workspace.delete :persist_params end end def persist_params? safe_workspace.persist_params? end def persistent_params; @persistent_params ||= [] end def url_for_path path, params # params = params.to_openobject # special params url = if params.include? :url_root (params.delete(:url_root) || "") + path else config.url_root! + path end host, port = params.delete(:host), params.delete(:port) format = params.delete(:format) # json params = {json: params.to_json} if params.delete :as_json #and !params.empty? # format if format params[:format] = format url.marks.format = format.to_s end # Delete 'nil' parameters to_delete = [] params.each{|k, v| to_delete << k if v.nil?} to_delete.each{|k| params.delete k} # build url delimiter = path.include?('?') ? '&' : '?' url << "#{delimiter}#{params.to_query}" unless params.empty? if host.blank? url else %{http://#{host}#{":#{port}" unless port.blank?}#{url}} end end def url_for_class klass, method, params klass ||= current_class # params = params.to_openobject # special params format = params[:format] path, params = encode klass, method, params url = url_for_path path, params url.marks.format = format.to_s if format url end protected # sometimes we need access to routes outside of conveyor :cycle, # for example in spec routing helpers, in that case we just ignore workspace and it's variables def safe_workspace if Micon.active? :cycle workspace else Workspace.new end end def current_class; safe_workspace[@class_variable] end DONOT_PERSIST = [:_, :_method] def inject_persistent_params! params persist = params.delete(:persist) # global persistent params unless cached_global_persistend_params = safe_workspace.cached_global_persistend_params cached_global_persistend_params, workspace_params = {}, safe_workspace.params if workspace_params persistent_params.collect!{|k| k} workspace_params.each do |k, v| cached_global_persistend_params[k] = v if persistent_params.include?(k) end safe_workspace.cached_global_persistend_params = cached_global_persistend_params end end cached_global_persistend_params.each do |k, v| params[k] = v unless params.include? k end # underscored persistent params if persist_params? unless cached_persistend_params = safe_workspace.cached_persistend_params cached_persistend_params, workspace_params = {}, safe_workspace.params if workspace_params workspace_params.each do |k, v| cached_persistend_params[k] = v if (k =~ /^_/) and !DONOT_PERSIST.include?(k) end safe_workspace.cached_persistend_params = cached_persistend_params end end cached_persistend_params.each do |k, v| params[k] = v unless params.include? k end end end end end