class ACH::Component

Base class for ACH::File and ACH::Batch. Every component has its own number of entities, header and control records. So it provides ACH::Component#header, ACH::Component#control, ACH::Component.has_many methods to manage them.

Example

class File < Component
  has_many :batches
  # implementation
end

Attributes

attributes[R]

Public Class Methods

has_many(plural_name, options = {}) click to toggle source

Creates a has_many association.

Example

class File < Component
  has_many :batches
end

file = File.new do
  batch :foo => 1, :bar => 2
end

file.batches  # => [#<Batch ...>]

The example above extends File with batches and batch instance methods:

  • batch is used to add new instance of Batch.

  • batches is used to get an array of batches which belong to file.

@param [Symbol] plural_name @param [Hash] options

# File lib/ach/component.rb, line 195
def self.has_many(plural_name, options = {})
  association = HasManyAssociation.new(plural_name, options)

  association_variable_name = "@#{plural_name}_association"
  association.delegation_methods.each do |method_name|
    delegate method_name, :to => association_variable_name
  end

  after_initialize_hooks << lambda{ instance_variable_set(association_variable_name, association.for(self)) }
end
inherited(klass) click to toggle source

When inherited, clone class-related properties.

@param [Class] klass

# File lib/ach/component.rb, line 41
def self.inherited(klass)
  klass.default_attributes = default_attributes.dup
  klass.after_initialize_hooks = after_initialize_hooks.dup
end
method_missing(meth, *args) click to toggle source

Uses method_missing pattern to specify default attributes for a Component. If method name is one of the defined rules, saves it to default_attributes hash.

These attributes are passed to inner components in a cascade way, i.e. when ACH File was defined with default value for ‘company_name’, this value will be passed to every Batch component within file, and from every Batch to corresponding batch header record.

Note that default values may be overwritten when building records.

@param [Symbol] meth @param [*Object] args

Calls superclass method
# File lib/ach/component.rb, line 59
def self.method_missing(meth, *args)
  if Formatter.defined?(meth)
    default_attributes[meth] = args.first
  else
    super
  end
end
new(fields = {}) click to toggle source

Initialize component with field values. If block is given, it is evaluated in context of component, allowing setting fields via method calls and declarations of nested components.

@param [Hash] fields @raise [UnknownAttributeError]

# File lib/ach/component.rb, line 73
def initialize(fields = {})
  @attributes = self.class.default_attributes.dup
  fields.each do |name, value|
    raise UnknownAttributeError.new(name, self) unless Formatter.defined?(name)
    @attributes[name] = value
  end
  after_initialize
  instance_eval(&Proc.new) if block_given?
end

Public Instance Methods

after_initialize() click to toggle source

Execute all Proc objects contained in the after_initialize_hooks array in the context of the object.

# File lib/ach/component.rb, line 171
def after_initialize
  self.class.after_initialize_hooks.each{ |hook| instance_exec(&hook) }
end
build_control(str) click to toggle source

Build a component-related Control record from a given string.

@param [String] str @return [ACH::Record::Base]

# File lib/ach/component.rb, line 151
def build_control(str)
  @control = self.class::Control.from_s(str)
end
build_header(str) click to toggle source

Build a component (File or Batch) related Header record from a given string.

@param [String] str @return [ACH::Record::Base]

# File lib/ach/component.rb, line 132
def build_header(str)
  @header = self.class::Header.from_s(str)
end
control() click to toggle source

Build a component-related Control record.

@return [ACH::Record::Base]

# File lib/ach/component.rb, line 139
def control
  @control ||= begin
    klass  = self.class::Control
    fields = klass.fields.select{ |f| respond_to?(f) || attributes[f] }
    klass.new Hash[*fields.zip(fields.map{ |f| send(f) }).flatten]
  end
end
fields_for(klass) click to toggle source

Return a set of fields, that is a subset of attributes that can be used to initialize an instance of a klass. Component uses attributes itself.

@param [Class] klass @return [Hash]

# File lib/ach/component.rb, line 160
def fields_for(klass)
  if klass < Component
    attributes
  else
    attrs = attributes.find_all{ |k, v| klass.fields.include?(k) && attributes[k] }
    Hash[*attrs.flatten]
  end
end
header(fields = {}) click to toggle source

Sets header fields if fields or block passed. Returns header record.

Example 1

header :foo => "value 1", :bar => "value 2"

Example 2

header do
  foo "value 1"
  bar "value 2"
end

Example 3

header # => just returns a header object
# File lib/ach/component.rb, line 119
def header(fields = {})
  before_header
  merged_fields = fields_for(self.class::Header).merge(fields)
  @header ||= self.class::Header.new(merged_fields)
  @header.tap do |head|
    head.instance_eval(&Proc.new) if block_given?
  end
end
method_missing(meth, *args) click to toggle source

Missing messages are treated as accessor methods for a component if their message name is defined by {ACH::Formatter}.

@param [Symbol] meth @param [*Object] args @return [String]

Calls superclass method
# File lib/ach/component.rb, line 89
def method_missing(meth, *args)
  if Formatter.defined?(meth)
    args.empty? ? @attributes[meth] : (@attributes[meth] = args.first)
  else
    super
  end
end

Private Instance Methods

before_header() click to toggle source

Hook that is called whenever component header record is created. To be overridden in subclasses.

# File lib/ach/component.rb, line 99
def before_header
end