ontohub/ontohub

View on GitHub
lib/router_constraints.rb

Summary

Maintainability
A
1 hr
Test Coverage
class RouterConstraint
  def params(request)
    request.send(:env)["action_dispatch.request.path_parameters"]
  end

  def set_path_parameters(request, new_params)
    params = params(request)
    controller = params[:controller]
    action     = params[:action]

    params.except!(*params.keys).merge!(
      controller: controller,
      action:     action).merge!(new_params)
  end

  def add_path_parameters(request, add_params)
    set_path_parameters(request, params(request).merge(add_params))
  end
end


class FilesRouterConstraint < RouterConstraint
  def matches?(request)
    return false if Repository.find_by_path(request.params[:repository_id]).nil?

    result = !RepositoryFile.find_with_path(
      params_path_without_format(request)).nil?

    set_params_path_without_format(request) if result

    return result
  end

  protected
  def params_path_without_format(request)
    @params = request.send(:env)["action_dispatch.request.path_parameters"]
    @path   = @params[:path]
    @path  += ".#{@params[:format]}" if @params[:format]

    @params.merge({ path: @path }).except(:format)
  end

  def set_params_path_without_format(request)
    params_path_without_format(request)
    @params.merge!({ path: @path }).except!(:format)
  end
end

class LocIdRouterConstraint < RouterConstraint
  ELEMENTS_CACHE_CLEARING_INTERVAL = 1.minute
  @elements_cache_clear_at = Time.now + ELEMENTS_CACHE_CLEARING_INTERVAL
  @elements_cache = {}

  def initialize(find_in_klass, **map)
    @find_in_klass = find_in_klass
    @map = map
    super()
  end

  def matches?(request, path = nil)
    path ||= Journey::Router::Utils.
      unescape_uri(request.original_fullpath)
    # retrieves the hierarchy and member portions of loc/id's
    hierarchy_member = path.split('?', 2).first.split('///', 2).first
    element =
      elements_cache[hierarchy_member] ||
      LocIdBaseModel.find_with_locid(hierarchy_member)

    if element.is_a?(@find_in_klass)
      elements_cache.delete(hierarchy_member)
      clear_elements_cache if elements_cache_clearing_scheduled?
      assign_path_parameters(request, element)

      true
    else
      if !elements_cache.key?(hierarchy_member) && element
        elements_cache[hierarchy_member] = element
      end
      false
    end
  end

  def elements_cache
    self.class.instance_variable_get(:@elements_cache)
  end

  # To keep the memory footprint low in case of unproper removal of cached
  # elements, we clear the cache periodically. This prevents memory leaks.
  def clear_elements_cache
    next_clearing = Time.now + ELEMENTS_CACHE_CLEARING_INTERVAL
    self.class.instance_variable_set(:@elements_cache_clear_at, next_clearing)

    self.class.instance_variable_set(:@elements_cache, {})
  end

  def elements_cache_clearing_scheduled?
    Time.now > self.class.instance_variable_get(:@elements_cache_clear_at)
  end

  def assign_path_parameters(request, element)
    ontology = element.is_a?(Ontology) ? element : element.ontology

    proof_attempt = element.proof_attempt if @map[:proof_attempt]
    theorem = element.theorem if @map[:theorem]

    path_params = {repository_id: ontology.repository.to_param}
    %i(proof_attempt theorem ontology element).each do |p|
      path_params[@map[p]] = binding.local_variable_get(p).id if @map[p]
    end

    add_path_parameters(request, path_params)
  end
end

class RefLocIdRouterConstraint < LocIdRouterConstraint
  def matches?(request)
    params = params(request)
    result = OntologyVersionFinder.
      applicable_reference?(params[:reference])
    path = Journey::Router::Utils.unescape_uri(request.original_fullpath)
    result && update_version_id!(request, path.dup)
  end

  def update_version_id!(request, path)
    version = OntologyVersionFinder.find(path)
    version_id = version.try(:to_param)
    ontology_id = version.try(:ontology).try(:to_param)
    add_path_parameters(request, id: version_id, ontology_id: ontology_id)
    !! version_id
  end
end

class MMTRouterConstraint < LocIdRouterConstraint
  def matches?(request)
    path = request.original_fullpath.
      # Convert MMT to standard Loc/Id
      gsub(/\?+/, '//').
      # Prune ref-portion
      sub('/ref/mmt', '')
    super(request, path)
  end
end

class IRIRouterConstraint < RouterConstraint
  def matches?(request, path = nil)
    path ||= Journey::Router::Utils.
      unescape_uri(request.original_fullpath)
    ontology = Ontology.find_with_iri(path)
    result = !ontology.nil?

    if result
      set_path_parameters(request,
        repository_id: ontology.repository.to_param, id: ontology.id)
    end

    return result
  end
end

class RefIRIRouterConstraint < IRIRouterConstraint
  def matches?(request)
    # remove the ref/:version_number portion from path
    path = Journey::Router::Utils.unescape_uri(request.original_fullpath).
      sub(%r{\A/ref/\d+/}, '')

    super(request, path)
  end
end

class MIMERouterConstraint < RouterConstraint
  attr_accessor :mime_types

  def initialize(*mime_types)
    self.mime_types = mime_types.flatten.map { |m| Mime::Type.lookup(m) }
    super()
  end

  # In some cases request.accepts == [nil] (e.g. cucumber tests),
  # in these cases we will default to true.
  def matches?(request)
    highest_mime = request.accepts.first
    highest_mime ? mime_types.any? { |m| highest_mime == m } : true
  end
end

class GroupedConstraint
  attr_accessor :constraints

  def initialize(*args)
    self.constraints = args.flatten
  end

  def matches?(request)
    constraints.all? { |c| c.matches?(request) }
  end
end