require 'thread'
require 'active_support'
require 'active_support/version'
if ::ActiveSupport::VERSION::MAJOR >= 3
require 'active_support/core_ext'
end
require 'remote_table'
require 'errata/erratum'
class Errata
CORRECTIONS = %w{delete replace simplify transform truncate reject}
attr_reader :lazy_load_table_options
attr_reader :lazy_load_responder_class_name
# Arguments
# * :responder (required) - normally you pass this something like Guru.new, which should respond to questions like #is_a_bentley?. If you pass a string, it will be lazily constantized and a new object initialized from it; for example, 'Guru' will lead to 'Guru'.constantize.new.
# * :table - takes something that acts like a RemoteTable
# If and only if you don't pass :table, all other options will be passed to a new RemoteTable (for example, :url, etc.)
def initialize(options = {})
options = options.symbolize_keys
responder = options.delete :responder
raise "[errata] :responder is required" unless responder
if responder.is_a?(::String)
@lazy_load_responder_mutex = ::Mutex.new
@lazy_load_responder_class_name = responder
else
::Kernel.warn %{[errata] Passing an object as :responder is deprecated. It's recommended to pass a class name instead, which will be constantized and instantiated with no arguments.}
@responder = responder
end
if table = options.delete(:table)
::Kernel.warn %{[errata] Passing :table is deprecated. It's recommended to pass table options instead.}
@table = table
else
@lazy_load_table_options = options
end
@set_rejections_and_corrections_mutex = ::Mutex.new
end
def rejects?(row)
rejections.any? { |erratum| erratum.targets?(row) }
end
def correct!(row)
corrections.each { |erratum| erratum.correct!(row) }
nil
end
def responder
@responder || @lazy_load_responder_mutex.synchronize do
@responder ||= lazy_load_responder_class_name.constantize.new
end
end
private
def set_rejections_and_corrections!
return if @set_rejections_and_corrections == true
@set_rejections_and_corrections_mutex.synchronize do
return if @set_rejections_and_corrections == true
if @table
table = @table
@table = nil # won't need this again
else
table = ::RemoteTable.new lazy_load_table_options
end
rejections = []
corrections = []
table.each do |erratum_initializer|
erratum_initializer = erratum_initializer.symbolize_keys
action = erratum_initializer[:action].downcase
if action == 'reject'
rejections << Erratum::Reject.new(responder, erratum_initializer)
elsif CORRECTIONS.include?(action)
corrections << Erratum.const_get(action.camelcase).new(responder, erratum_initializer)
end
end
@rejections = rejections
@corrections = corrections
@set_rejections_and_corrections = true
end
end
def rejections
set_rejections_and_corrections!
@rejections
end
def corrections
set_rejections_and_corrections!
@corrections
end
end