class Smooth::Resource::Router
Constants
- Verbs
Attributes
descriptions[R]
resource[R]
rules[R]
table[R]
Public Class Methods
new(resource, _options = {})
click to toggle source
# File lib/smooth/resource/router.rb, line 9 def initialize(resource, _options = {}) @resource = resource @table = {} @descriptions = {} @rules = [] end
Public Instance Methods
apply_to(sinatra)
click to toggle source
# File lib/smooth/resource/router.rb, line 72 def apply_to(sinatra) router = self user_finder = resource.api.method(:lookup_current_user).to_proc policy_finder = resource.api.method(:lookup_policy).to_proc router.rules.each do |_| options, _ = _ handler = methods_table.method(options[:name]) sinatra.send options[:method], options[:pattern] do |*args| begin request = { headers: headers, params: params, user: user_finder.call(params, headers), policy: policy_finder.call(params, headers), args: args } rescue => exception halt 500, {}, { error: exception.message, backtrace: exception.backtrace, stage: 'request' }.to_json end begin response = handler.call(request.to_mash) body response.body headers response.headers status response.status rescue => exception halt 500, {}, { error: exception.message, backtrace: exception.backtrace, stage: 'response' }.to_json end end end end
build_methods_table()
click to toggle source
# File lib/smooth/resource/router.rb, line 109 def build_methods_table router = self @methods_table_class = Class.new do k = self router.rules.each do |_| options, block = _ method_name = options.fetch(:name) k.send :define_method, method_name, (block || router.lookup_handler_for(options[:method], options[:to])) end end end
counter()
click to toggle source
# File lib/smooth/resource/router.rb, line 124 def counter @counter ||= 0 @counter += 1 end
define_route(request_method, route_pattern, *args, &block)
click to toggle source
# File lib/smooth/resource/router.rb, line 158 def define_route(request_method, route_pattern, *args, &block) request_method = Verbs.fetch(request_method.to_sym, :get) bucket = table[request_method] ||= {} options = args.extract_options! name = options.fetch(:as, "#{ request_method }_#{ counter }") describe_route(request_method, route_pattern) rules << bucket[route_pattern] = [ options.merge(name: name, method: request_method, args: args, pattern: route_pattern, template: Smooth.util.uri_template(route_pattern)), block ] end
desc(description, *_args)
click to toggle source
# File lib/smooth/resource/router.rb, line 133 def desc(description, *_args) descriptions[:current] = description end
describe_route(request_method, route_pattern)
click to toggle source
# File lib/smooth/resource/router.rb, line 173 def describe_route(request_method, route_pattern) documentation = descriptions[request_method] ||= {} if description = descriptions[:current] documentation[route_pattern] = description descriptions.delete(:current) end end
expand_routes(from_attributes = {})
click to toggle source
# File lib/smooth/resource/router.rb, line 38 def expand_routes(from_attributes = {}) route_patterns_table.reduce({}) do |memo, p| route_name, details = p memo[route_name] = Smooth.util.expand_url_template(details[:template], from_attributes) memo end end
interface_documentation()
click to toggle source
I may be getting this in a convoluted way may be easier to build up naturally
# File lib/smooth/resource/router.rb, line 18 def interface_documentation descriptions.keys.reduce({}) do |memo, verb| routes = descriptions[verb] routes.each do |_| pattern, description = _ memo["#{ verb.to_s.upcase } #{ pattern }"] = description end memo end end
lookup_handler_for(method, signifier)
click to toggle source
Allows for a configuration syntax like
routes do
get "/books", :to => :query
end
the lookup_handler_for
method will attempt to discern which object is best suited to handle the request based on the http verb and the signifier
# File lib/smooth/resource/router.rb, line 191 def lookup_handler_for(method, signifier) method = method.to_sym signifier = signifier.to_sym resource = self.resource case when method == :get && signifier == :query ->(req) { resource.fetch(:query, :default).respond_to_request(req) } when (method == :show || method == :get) && signifier == :show ->(req) { resource.fetch(:query, :default).respond_to_find_request(req) } when method == :get ->(req) { resource.fetch(:query, signifier).respond_to_request(req) } # Mutation Methods when method == :put || method == :post || method == :delete ->(req) { resource.fetch(:command, signifier).respond_to_request(req) } else ->(req) { Smooth::ErrorResponse.new('Unable to find matching route', req) } end end
method_missing(meth, *args, &block)
click to toggle source
Calls superclass method
# File lib/smooth/resource/router.rb, line 149 def method_missing(meth, *args, &block) if Verbs.keys.include?(meth.to_sym) pattern = args.shift define_route(meth, pattern, *args, &block) else super end end
methods_table()
click to toggle source
# File lib/smooth/resource/router.rb, line 129 def methods_table @methods_table ||= (@methods_table_class || build_methods_table).new end
patterns()
click to toggle source
# File lib/smooth/resource/router.rb, line 64 def patterns rules.flatten.compact.map { |r| r.fetch(:pattern) } end
route_patterns_table()
click to toggle source
# File lib/smooth/resource/router.rb, line 46 def route_patterns_table return @route_patterns_table if @route_patterns_table @route_patterns_table = rules.flatten.compact.reduce({}) do |memo, rule| memo.tap do name = rule[:name] pattern = rule[:pattern] template = rule[:template] memo[name] = { pattern: pattern, template: template, variables: Array(template.variables) } end end end
route_table()
click to toggle source
# File lib/smooth/resource/router.rb, line 30 def route_table @route_table ||= route_patterns_table.reduce({}) do |memo, p| route_name, details = p memo[route_name] = details[:pattern] memo end end
uri_templates()
click to toggle source
# File lib/smooth/resource/router.rb, line 68 def uri_templates rules.flatten.compact.map { |r| r.fetch(:template) } end