lib/errata.rb in errata-1.0.3 vs lib/errata.rb in errata-1.1.0

- old
+ new

@@ -1,56 +1,102 @@ +require 'thread' + require 'active_support' require 'active_support/version' -%w{ - active_support/core_ext/hash/keys - active_support/core_ext/hash/slice -}.each do |active_support_3_requirement| - require active_support_3_requirement -end if ::ActiveSupport::VERSION::MAJOR == 3 +if ::ActiveSupport::VERSION::MAJOR >= 3 + require 'active_support/core_ext' +end require 'remote_table' +require 'errata/erratum' + class Errata - autoload :Erratum, 'errata/erratum' - - ERRATUM_TYPES = %w{delete replace simplify transform truncate reject} + CORRECTIONS = %w{delete replace simplify transform truncate reject} - attr_reader :options - + attr_reader :lazy_load_table_options + attr_reader :lazy_load_responder_class_name + # Arguments - # * <tt>'responder'</tt> (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. - # * <tt>'table'</tt> - takes something that acts like a RemoteTable - # If and only if you don't pass <tt>'table'</tt>, all other options will be passed to a new RemoteTable (for example, <tt>'url'</tt>, etc.) + # * <tt>:responder</tt> (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. + # * <tt>:table</tt> - takes something that acts like a RemoteTable + # If and only if you don't pass <tt>:table</tt>, all other options will be passed to a new RemoteTable (for example, <tt>:url</tt>, etc.) def initialize(options = {}) - @options = options.dup - @options.stringify_keys! + 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 responder - options['responder'].is_a?(::String) ? options['responder'].constantize.new : options['responder'] - end - + def rejects?(row) rejections.any? { |erratum| erratum.targets?(row) } end def correct!(row) corrections.each { |erratum| erratum.correct!(row) } nil end - - def errata - @errata ||= (options['table'] ? options['table'] : ::RemoteTable.new(options.except('responder'))).inject([]) do |memo, erratum_description| - if ERRATUM_TYPES.include? erratum_description['action'] - memo.push "::Errata::Erratum::#{erratum_description['action'].camelcase}".constantize.new self, erratum_description + + 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 - memo + + 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 - errata.select { |erratum| erratum.is_a? ::Errata::Erratum::Reject } + set_rejections_and_corrections! + @rejections end def corrections - errata.select { |erratum| not erratum.is_a? ::Errata::Erratum::Reject } + set_rejections_and_corrections! + @corrections end end