class Phenotype::Versioner

Attributes

env[R]
routes[R]
strategies[R]
versions[R]

Public Class Methods

new(routes: {}, strategies: [], env: {}) click to toggle source
# File lib/phenotype/versioner.rb, line 9
def initialize(routes: {}, strategies: [], env: {})
  @routes = routes
  @versions = routes.keys.sort.reverse
  @strategies = strategies
  @env = env
end

Public Instance Methods

call() click to toggle source
# File lib/phenotype/versioner.rb, line 16
def call # rubocop:disable Metrics/AbcSize
  return display_errors if errors?

  cascading_versions.each do |v|
    if strategies.first.instance_of?(PathStrategy) && version_mismatch?(v)
      env['PATH_INFO'] = updated_versioned_path(env['PATH_INFO'], v)
    end
    route = call_route(v)
    handler = ResponseHandler.new(route.block.call(env))
    return handler.response unless route.cascade? && handler.retry?
  end
end

Private Instance Methods

call_route(version) click to toggle source
# File lib/phenotype/versioner.rb, line 83
def call_route(version)
  routes.fetch(
    version,
    version_not_found_response("Unable to satisfy request for Version: #{current_version}")
  )
end
cascading_versions() click to toggle source
# File lib/phenotype/versioner.rb, line 67
def cascading_versions
  @cascading_versions ||= versions.select { |el| el <= current_version }
end
current_version() click to toggle source
# File lib/phenotype/versioner.rb, line 63
def current_version
  @current_version ||= strategies.detect { |strat| strat.version(env) }.version(env).to_i
end
default_response(status_code, message = '') click to toggle source
# File lib/phenotype/versioner.rb, line 90
def default_response(status_code, message = '')
  proc { [status_code, { 'Content-Type' => 'text/html' }, [message]] }
end
display_errors() click to toggle source
# File lib/phenotype/versioner.rb, line 49
def display_errors
  return no_strategy_response.call(env) if strategies.empty?
  return too_many_strategies_response.call(env) if too_many_strategies?
  return version_not_found_response.call(env) unless supported_version?
end
errors?() click to toggle source
# File lib/phenotype/versioner.rb, line 45
def errors?
  strategies.empty? || too_many_strategies? || !supported_version?
end
no_strategy_response() click to toggle source
# File lib/phenotype/versioner.rb, line 71
def no_strategy_response
  @no_strategy_response ||= default_response(406, 'No Strategies provided')
end
path_version() click to toggle source
# File lib/phenotype/versioner.rb, line 35
def path_version
  path = Rack::Request.new(env).path
  match = path.match(strategies.first.version_pattern)
  match&.captures&.first
end
supported_version?() click to toggle source
# File lib/phenotype/versioner.rb, line 59
def supported_version?
  @supported_version ||= versions.include?(current_version)
end
too_many_strategies?() click to toggle source
# File lib/phenotype/versioner.rb, line 55
def too_many_strategies?
  @too_many_strategies ||= strategies.size > 1
end
too_many_strategies_response() click to toggle source
# File lib/phenotype/versioner.rb, line 75
def too_many_strategies_response
  @too_many_strategies_response ||= default_response(400, 'Too mant strategies provided, Supports only one')
end
updated_versioned_path(path, version) click to toggle source
# File lib/phenotype/versioner.rb, line 41
def updated_versioned_path(path, version)
  path.sub(path_version, version.to_s)
end
version_mismatch?(version) click to toggle source
# File lib/phenotype/versioner.rb, line 31
def version_mismatch?(version)
  path_version && (path_version != version.to_s)
end
version_not_found_response(message = "Version: click to toggle source
# File lib/phenotype/versioner.rb, line 79
def version_not_found_response(message = "Version: #{current_version} is not found")
  default_response(406, message)
end