class Stockboy::CandidateRecord
Joins the raw data values to an attribute mapping to allow comparison of input/output values, conversion, and filtering
Public Class Methods
Initialize a new candidate record
@param [Hash] attrs Raw key-values from source data @param [AttributeMap] map Mapping and translations
# File lib/stockboy/candidate_record.rb, line 18 def initialize(attrs, map) @map = map @table = reuse_frozen_hash_keys(attrs, map) @tr_table = Hash.new @ignored_fields = [] freeze end
Public Instance Methods
Mapped output hash including ignored values
@return [Hash]
# File lib/stockboy/candidate_record.rb, line 44 def bulk_hash Hash.new.tap do |out| @map.each { |col| out[col.to] = translate(col) } end end
Data structure representing the record's raw input values
Values can be accessed like hash keys, or attribute names that correspond to a :from
attribute mapping option
@return [SourceRecord] @example
input = candidate.input input["RawEmail"] # => "ME@EXAMPLE.COM " input.email # => "ME@EXAMPLE.COM "
# File lib/stockboy/candidate_record.rb, line 96 def input SourceRecord.new(raw_hash, @table) end
Data structure representing the record's mapped & translated output values
@return [MappedRecord] @example
input = candidate.output output.email # => "me@example.com"
# File lib/stockboy/candidate_record.rb, line 107 def output MappedRecord.new(bulk_hash) end
Find the filter key that captures this record
@param [FilterChain] filters List of filters to apply @return [Symbol] Name of the matched filter
# File lib/stockboy/candidate_record.rb, line 75 def partition(filters={}) input, output = self.input, self.output filters.each_pair do |filter_key, f| if f.call(input, output) return filter_key end end nil end
Return the original values mapped to attribute keys
@return [Hash]
# File lib/stockboy/candidate_record.rb, line 54 def raw_hash Hash.new.tap do |out| @map.each { |col| out[col.to] = @table[col.from] } end end
Convert the mapped output to a hash
@return [Hash]
# File lib/stockboy/candidate_record.rb, line 30 def to_hash bulk_hash.tap do |out| tmp_context = SourceRecord.new(out, @table) @map.each_with_object(out) do |col| out.delete(col.to) if ignore?(col, tmp_context) end end end
Wrap the mapped attributes in a new ActiveModel or ActiveRecord object
@param [Class] model ActiveModel class @return [Class] ActiveModel class
# File lib/stockboy/candidate_record.rb, line 66 def to_model(model) model.new(attributes) end
Private Instance Methods
# File lib/stockboy/candidate_record.rb, line 131 def ignore?(col, context) return true if @ignored_fields.include? col.to if col.ignore?(context) @ignored_fields << col.to true else false end end
Optimization to reuse the same hash key string instances
The need for this is fixed for CSV in: bugs.ruby-lang.org/issues/9143 (ruby >= 2.1) and can be managed by applying str.freeze in other readers.
# File lib/stockboy/candidate_record.rb, line 157 def reuse_frozen_hash_keys(attrs, map) return attrs unless attrs.is_a? Hash attrs.reduce(Hash.new) do |new_hash, (field, value)| key = map.attribute_from(field).from new_hash[key] = value new_hash end end
Clean output values that are a subclass of a standard type
# File lib/stockboy/candidate_record.rb, line 143 def sanitize(value) case value when String # e.g. Nori::StringWithAttributes value.to_s else value end end
# File lib/stockboy/candidate_record.rb, line 113 def translate(col) @tr_table.fetch(col.to) do |key| return @tr_table[key] = sanitize(@table[col.from]) if col.translators.empty? fields = raw_hash tr_input = col.translators.reduce(input) do |value, tr| begin fields[key] = tr[value] SourceRecord.new(fields, @table) rescue translation_error = TranslationError.new(key, self) fields[key] = Stockboy.configuration.translation_error_handler.call(translation_error) break SourceRecord.new(fields, @table) end end @tr_table[key] = tr_input.public_send(key) end end