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

all_records[R]

List of all records, filtered or not

@return [Array<CandidateRecord>]

attributes[R]

Configures the mapping & translation of raw data fields

@return [AttributeMap]

filters[R]

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

provider[RW]

Defines the data source for receiving data

@return [Provider]

reader[RW]

Defines the format for parsing received data

@return [Reader]

records[R]

Lists of records grouped by filter key

@return [Hash{Symbol=>Array}]

triggers[R]
unfiltered_records[R]

List of records not matched by any filter

@return [Array<CandidateRecord>]

Public Class Methods

define(template_name) { |job| ... } click to toggle source

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
new(params={}) { |self| ... } click to toggle source

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

attributes=(new_attributes) click to toggle source

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
data(&block) click to toggle source
# File lib/stockboy/job.rb, line 119
def data(&block)
  provider.data(&block)
end
data?(reduction=:all?) click to toggle source
# File lib/stockboy/job.rb, line 123
def data?(reduction=:all?)
  provider.data?(reduction)
end
filters=(new_filters) click to toggle source

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
inspect() click to toggle source

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
method_missing(name, *args) click to toggle source
Calls superclass method
# File lib/stockboy/job.rb, line 155
def method_missing(name, *args)
  if triggers.key?(name)
    trigger(name, *args)
  else
    super
  end
end
process() { |records| ... } click to toggle source

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
processed?() click to toggle source

Has the job been processed successfully?

@return [Boolean]

# File lib/stockboy/job.rb, line 189
def processed?
  !!@processed
end
record_counts() click to toggle source

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
total_records() click to toggle source

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
trigger(key, *args) click to toggle source
# 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
triggers=(new_triggers) click to toggle source
# File lib/stockboy/job.rb, line 144
def triggers=(new_triggers)
  @triggers.replace new_triggers
end

Private Instance Methods

each_reader_row() { |row| ... } click to toggle source
# 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
load_all_records() click to toggle source
# File lib/stockboy/job.rb, line 225
def load_all_records
  each_reader_row do |row|
    @all_records << CandidateRecord.new(row, @attributes)
  end
end
load_records() click to toggle source
# File lib/stockboy/job.rb, line 217
def load_records
  reset
  load_all_records
  return unless provider.data?
  partition_all_records
  @processed = true
end
partition_all_records() click to toggle source
# File lib/stockboy/job.rb, line 231
def partition_all_records
  @all_records.each do |record|
    record_partition(record) << record
  end
end
record_partition(record) click to toggle source
# File lib/stockboy/job.rb, line 262
def record_partition(record)
  if key = record.partition(filters)
    @records[key]
  else
    @unfiltered_records
  end
end
reset() click to toggle source
# File lib/stockboy/job.rb, line 209
def reset
  @records = filters.reset
  @all_records = []
  @unfiltered_records = []
  @processed = false
  true
end
with_provider_data() { |data| ... } click to toggle source

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
with_query_caching() { || ... } click to toggle source
# File lib/stockboy/job.rb, line 270
def with_query_caching
  if defined? ActiveRecord
    ActiveRecord::Base.cache { yield }
  else
    yield
  end
end