module Rad class AliasRouter include AbstractRouter class TreeHash < Hash attr_accessor :meta end def initialize @route_methods, @paths, @classes = {}, TreeHash.new, {} end def add als, options = {} # parsing options # als, options = als.to_s, options.to_openobject als = als.to_s als.must =~ /^\// klass = options.delete(:class) || raise("no class!") method = options.delete(:method) || raise("no method!") method = method.must_be.a Symbol url_root = parse_url_root options prefix = parse_prefix options raise "unknown options :#{options.to_h.keys.join(': ')}!" unless options.empty? raise "you can't use '/' alias with :url_root!" if als == '/' and url_root # logic meta = { class: klass, method: method, path: als, url_root: url_root, prefix: prefix } route_methods["#{als[1..-1]}_path"] = meta (classes[klass] ||= {})[method] = meta parts = als[1..-1].split('/') parts << '' if parts.empty? tree_iterator = paths parts.reverse.each do |part| tree_iterator = (tree_iterator[part] ||= TreeHash.new) raise "alias '#{als}' conflicted with another alias!" if tree_iterator.meta end tree_iterator.meta = meta end def encode klass, method, params if meta = classes[klass].try(:[], method) path = meta[:path] path = encode_prefix_params! path, params, meta path = encode_url_root! path, meta return path, params else nil end end def decode path, params parts = path[1..-1].split('/') parts << '' if parts.empty? tree_iterator = paths # checking for first part part = parts.pop tree_iterator = tree_iterator[part] return nil unless tree_iterator # checking for exact match while part = parts.pop tmp = tree_iterator[part] unless tmp parts << part break end tree_iterator = tmp end meta = tree_iterator.meta decode_prefix_params! parts, params, meta decode_url_root! parts, meta return meta[:class], meta[:method], params end def encode_method route_method if meta = route_methods[route_method] return meta[:class], meta[:method] else nil end end protected attr_accessor :paths, :route_methods, :classes end end Rad::Routes::Configurator.class_eval do def alias *args, &block alias_router = @router.routes[:alias_router] raise "There's no AliasRouter (use config to add it)!" unless alias_router alias_router.add *args, &block end end