Class: ACH::Component

Inherits:
Object
  • Object
show all
Extended by:
ActiveSupport::Autoload
Includes:
Constants, Validations
Defined in:
lib/ach/component.rb

Overview

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

Direct Known Subclasses

Batch, File

Defined Under Namespace

Classes: HasManyAssociation, UnknownAttributeError

Constant Summary

Constants included from Constants

ACH::Constants::BATCH_ADDENDA_RECORD_TYPE, ACH::Constants::BATCH_CONTROL_RECORD_TYPE, ACH::Constants::BATCH_ENTRY_RECORD_TYPE, ACH::Constants::BATCH_HEADER_RECORD_TYPE, ACH::Constants::BLOCKING_FACTOR, ACH::Constants::FILE_CONTROL_RECORD_TYPE, ACH::Constants::FILE_HEADER_RECORD_TYPE, ACH::Constants::FORMAT_CODE, ACH::Constants::RECORD_SIZE, ACH::Constants::ROWS_DELIMITER

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Validations

#errors, #valid?

Constructor Details

#initialize(fields = {}) ⇒ Component

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.

Parameters:

  • fields (Hash) (defaults to: {})

Raises:



73
74
75
76
77
78
79
80
81
# 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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args) ⇒ String

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

Parameters:

  • meth (Symbol)
  • args (*Object)

Returns:

  • (String)


89
90
91
92
93
94
95
# 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

Instance Attribute Details

#attributesObject (readonly)

Returns the value of attribute attributes.



36
37
38
# File 'lib/ach/component.rb', line 36

def attributes
  @attributes
end

Class Method Details

.has_many(plural_name, options = {}) ⇒ Object

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.

Parameters:

  • plural_name (Symbol)
  • options (Hash) (defaults to: {})


195
196
197
198
199
200
201
202
203
204
# 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) ⇒ Object

When inherited, clone class-related properties.

Parameters:

  • klass (Class)


41
42
43
44
# 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) ⇒ Object

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.

Parameters:

  • meth (Symbol)
  • args (*Object)


59
60
61
62
63
64
65
# 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

Instance Method Details

#after_initializeObject

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



171
172
173
# File 'lib/ach/component.rb', line 171

def after_initialize
  self.class.after_initialize_hooks.each{ |hook| instance_exec(&hook) }
end

#build_control(str) ⇒ ACH::Record::Base

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

Parameters:

  • str (String)

Returns:



151
152
153
# File 'lib/ach/component.rb', line 151

def build_control(str)
  @control = self.class::Control.from_s(str)
end

#build_header(str) ⇒ ACH::Record::Base

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

Parameters:

  • str (String)

Returns:



132
133
134
# File 'lib/ach/component.rb', line 132

def build_header(str)
  @header = self.class::Header.from_s(str)
end

#controlACH::Record::Base

Build a component-related Control record.

Returns:



139
140
141
142
143
144
145
# 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) ⇒ Hash

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.

Parameters:

  • klass (Class)

Returns:

  • (Hash)


160
161
162
163
164
165
166
167
# 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 = {}) ⇒ Object

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


119
120
121
122
123
124
125
126
# 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