class Stockboy::Job
This class wraps up the main interface for the process of fetching, parsing and sorting data. When used with a predefined template file, you can pass the name of the template to define it. This is the common way to use Stockboy:
job = Stockboy::Job.define('my_template') if job.process job.records[:update].each do |r| # ... end job.records[:cancel].each do |r| # ... end end
Attributes
List of all records, filtered or not
@return [Array<CandidateRecord>]
Configures the mapping & translation of raw data fields
@return [AttributeMap]
List of filters for sorting processed records
@return [FilterChain]
Filters
are applied in order, first match will capture the record. Records that don't match any
Defines the data source for receiving data
@return [Provider]
Defines the format for parsing received data
@return [Reader]
Lists of records grouped by filter key
@return [Hash{Symbol=>Array}]
List of records not matched by any filter
@return [Array<CandidateRecord>]
Public Class Methods
Instantiate a job configured by DSL
template file
@param template_name [String] File basename from template load path @yield instance for further configuration or processing @see Configuration#template_load_paths
# File lib/stockboy/job.rb, line 100 def self.define(template_name) return nil unless template = TemplateFile.read(template_name) job = Configurator.new(template, TemplateFile.find(template_name)).to_job yield job if block_given? job end
Initialize a new job
@param [Hash] params @option params [Provider] :provider @option params [Reader] :reader @option params [AttributeMap] :attributes @option params [Array,FilterChain] :filters @yield instance for further configuration or processing
# File lib/stockboy/job.rb, line 83 def initialize(params={}, &block) @provider = params[:provider] @reader = params[:reader] @attributes = params[:attributes] || AttributeMap.new @filters = FilterChain.new params[:filters] @triggers = Hash.new { |h,k| h[k] = [] } @triggers.replace params[:triggers] if params[:triggers] yield self if block_given? reset end
Public Instance Methods
Replace existing attribute map
@param new_attributes [Stockboy::AttributeMap] @return [Stockboy::AttributeMap]
# File lib/stockboy/job.rb, line 179 def attributes=(new_attributes) @attributes = new_attributes reset @attributes end
# File lib/stockboy/job.rb, line 119 def data(&block) provider.data(&block) end
# File lib/stockboy/job.rb, line 123 def data?(reduction=:all?) provider.data?(reduction) end
Replace existing filters
@param new_filters [Array] @return [Stockboy::FilterChain]
# File lib/stockboy/job.rb, line 168 def filters=(new_filters) @filters.replace new_filters reset @filters end
Overview of the job configuration; tries to be less noisy by hiding sub-element details.
@return [String]
# File lib/stockboy/job.rb, line 198 def inspect prov = "provider=#{Providers.all.key(provider.class) || provider.class}" read = "reader=#{Readers.all.key(reader.class) || reader.class}" attr = "attributes=#{attributes.map(&:to)}" filt = "filters=#{filters.keys}" cnts = "record_counts=#{record_counts}" "#<#{self.class}:#{self.object_id} #{prov}, #{read}, #{attr}, #{filt}, #{cnts}>" end
# File lib/stockboy/job.rb, line 155 def method_missing(name, *args) if triggers.key?(name) trigger(name, *args) else super end end
Fetch data and process it into groups of filtered records
@return [Boolean] Success or failure
# File lib/stockboy/job.rb, line 111 def process with_query_caching do load_records yield @records if block_given? end provider.errors.empty? end
Has the job been processed successfully?
@return [Boolean]
# File lib/stockboy/job.rb, line 189 def processed? !!@processed end
Counts of processed records grouped by filter key
@return [Hash{Symbol=>Integer}]
# File lib/stockboy/job.rb, line 140 def record_counts @records.reduce(Hash.new) { |a, (k,v)| a[k] = v.size; a } end
Count of all processed records
@!attribute [r] total_records
@return [Integer]
# File lib/stockboy/job.rb, line 132 def total_records @all_records.size end
# File lib/stockboy/job.rb, line 148 def trigger(key, *args) return nil unless triggers.key?(key) triggers[key].each do |c| c.call(self, *args) end end
# File lib/stockboy/job.rb, line 144 def triggers=(new_triggers) @triggers.replace new_triggers end
Private Instance Methods
# File lib/stockboy/job.rb, line 237 def each_reader_row return to_enum(__method__) unless block_given? with_provider_data do |data| reader.parse(data).each do |row| yield row end end end
# File lib/stockboy/job.rb, line 225 def load_all_records each_reader_row do |row| @all_records << CandidateRecord.new(row, @attributes) end end
# File lib/stockboy/job.rb, line 217 def load_records reset load_all_records return unless provider.data? partition_all_records @processed = true end
# File lib/stockboy/job.rb, line 231 def partition_all_records @all_records.each do |record| record_partition(record) << record end end
# File lib/stockboy/job.rb, line 262 def record_partition(record) if key = record.partition(filters) @records[key] else @unfiltered_records end end
# File lib/stockboy/job.rb, line 209 def reset @records = filters.reset @all_records = [] @unfiltered_records = [] @processed = false true end
Allows for a data method that either yields or returns giving preference to the yield. It will ignore the data return value if it has yielded.
# File lib/stockboy/job.rb, line 249 def with_provider_data return to_enum(__method__) unless block_given? yielded = nil provider.data do |data| if data yielded = true yield data end end return if yielded yield(provider.data) if provider.data? end
# File lib/stockboy/job.rb, line 270 def with_query_caching if defined? ActiveRecord ActiveRecord::Base.cache { yield } else yield end end