lib/apipie/extractor/collector.rb
module Apipie
module Extractor
class Collector
attr_reader :descriptions, :records
def initialize
@api_controllers_paths = Apipie.api_controllers_paths
@ignored = Apipie.configuration.ignored_by_recorder
@descriptions = Hash.new do |h, k|
h[k] = {:params => {}, :errors => Set.new}
end
@records = Hash.new { |h,k| h[k] = [] }
end
def controller_full_path(controller)
Apipie::Extractor.controller_path controller.controller_path
end
def ignore_call?(record)
return true unless record[:controller]
return true if @ignored.include?(record[:controller].name)
return true if @ignored.include?("#{Apipie.get_resource_id(record[:controller].name)}##{record[:action]}")
return true unless @api_controllers_paths.include?(controller_full_path(record[:controller]))
end
def handle_record(record)
if ignore_call?(record)
Extractor.logger.info("REST_API: skipping #{record_to_s(record)}")
else
add_to_records(record)
refine_description(record)
end
end
def add_to_records(record)
key = "#{Apipie.get_resource_id(record[:controller])}##{record[:action]}"
@records[key] << record
end
def refine_description(record)
description = @descriptions["#{record[:controller].name}##{record[:action]}"]
description[:controller] ||= record[:controller]
description[:action] ||= record[:action]
refine_errors_description(description, record)
refine_params_description(description[:params], record[:params])
end
def refine_errors_description(description, record)
if record[:code].to_i >= 300 && !description[:errors].any? { |e| e[:code].to_i == record[:code].to_i }
description[:errors] << {:code => record[:code]}
end
end
def refine_params_description(params_desc, recorded_params)
recorded_params.each do |key, value|
params_desc[key] ||= {}
param_desc = params_desc[key]
if value.nil?
param_desc[:allow_nil] = true
else
# we specify what type it might be. At the end the first type
# that left is taken as the more general one
unless param_desc[:type]
param_desc[:type] = [:bool, :boolean, :number]
param_desc[:type] << Hash if value.is_a? Hash
param_desc[:type] << :undef
end
if [:boolean, :bool].include?(param_desc[:type].first) && (! [true, false, 1, 0].include?(value))
param_desc[:type].shift
end
if param_desc[:type].first == :number && (key.to_s !~ /id$/ || !Apipie::Validator::NumberValidator.validate(value))
param_desc[:type].shift
end
if param_desc[:type].first == :decimal && (key.to_s !~ /id$/ || !Apipie::Validator::DecimalValidator.validate(value))
param_desc[:type].shift
end
end
if value.is_a? Hash
param_desc[:nested] ||= {}
refine_params_description(param_desc[:nested], value)
end
end
end
def finalize_descriptions
@descriptions.each_value do |desc|
add_routes_info(desc)
end
return @descriptions
end
def add_routes_info(desc)
api_prefix = Apipie.api_base_url.sub(%r{/$},"")
desc[:api] = Apipie::Extractor.apis_from_routes[[desc[:controller].name, desc[:action]]]
if desc[:api]
desc[:params].each do |name, param|
if desc[:api].all? { |a| a[:path].include?(":#{name}") }
param[:required] = true
end
end
end
end
def record_to_s(record)
"#{record[:controller]}##{record[:action]}"
end
end
end
end