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