class Cacofonix::Element

Public Class Methods

alias_accessor(new_accessor, old_accessor) click to toggle source
# File lib/cacofonix/core/element.rb, line 244
def self.alias_accessor(new_accessor, old_accessor)
  alias_method(new_accessor, old_accessor)
  alias_method("#{new_accessor}=", "#{old_accessor}=")
end
new(*) click to toggle source
Calls superclass method
# File lib/cacofonix/core/element.rb, line 259
def initialize(*)
  if self.class.xml_array_accessors
    self.class.xml_array_accessors.each do |attr|
      send :"#{attr}=", []
    end
  end

  super
end
onix_boolean_flag(name, tag_name, options = {}) click to toggle source

An accessor that treats an empty string as a true value – so that something like <NoContributor /> is recognised as “there is no contributor”.

# File lib/cacofonix/core/element.rb, line 60
def self.onix_boolean_flag(name, tag_name, options = {})
  options = options.merge(
    :from => tag_name,
    :to_xml => Cacofonix::Formatters.boolean
  )
  prep = lambda { |v| v ? true : false }
  xml_accessor(name, **options, &prep)
end
onix_code_from_list(name, tag_name, options = {}) click to toggle source

An accessor that maps a “code” string into an Cacofonix::Code object. A Code object can return the simple code (or “key”), or the value that is associated with it in ONIX code lists, and so on.

Required:

:list - integer referring to an ONIX Code List

Special options for Code instantiation are:

:length - how many digits to pad (default is taken from total list size)

As well as the normal accessor (x/x=), this will create a special accessor for the richer Code object (x_code/#x_code=). For example:

class Foo < Cacofonix::Element
  onix_code_from_list(:message_type, "MessageType", :list => 1)
end

foo = Foo.new

foo.message_type = 1

foo.message_type
>> 1

foo.message_type_code
>> #<Cacofonix::Code:.......>

foo.message_type_code.key
>> 1

foo.message_type_code.to_s
>> "01"

foo.message_type_code.value
>> "Early notification"
# File lib/cacofonix/core/element.rb, line 110
def self.onix_code_from_list(name, tag_name, options = {})
  unless list_number = options.delete(:list)
    raise Cacofonix::CodeListNotSpecified
  end
  code_opts = options.slice(:length, :enforce)
  options.delete(:enforce)
  prep = lambda { |value|
    Cacofonix::Code.new(list_number, value, code_opts)
  }
  options = options.merge(:from => tag_name)
  xml_accessor("#{name}_code", **options, &prep)

  define_method(name) do
    send("#{name}_code").key
  end

  define_method("#{name}=") do |val|
    val = prep.call(val)  unless val.kind_of?(Cacofonix::Code)
    send("#{name}_code=", val)
  end
end
onix_codes_from_list(name, tag_name, options = {}, &blk) click to toggle source

Like onix_code_from_list, but for an array of codes.

Required:

:list - integer referring to an ONIX Code List

One important caveat: when assigning to this accessor, you must pass in the complete array – if you assign an array that you later push or shift items into, you might get unexpected results.

Similar to onix_code_from_list, this creates a special accessor for the Code objects at (x_codes/#x_codes=). For example:

class Bar < Cacofonix::Element
  onix_codes_from_list(:identifiers, "Identifier", :list => 5)
end

bar = Bar.new

bar.identifiers = [1, 5, 13]

bar.identifiers_codes.collect { |ids| ids.value }
>> ["Proprietary", "ISMN-10", "LLCN"]

If a block is given, each value is passed into it first - return an array of the actual values.

# File lib/cacofonix/core/element.rb, line 159
def self.onix_codes_from_list(name, tag_name, options = {}, &blk)
  unless list_number = options.delete(:list)
    raise Cacofonix::CodeListNotSpecified
  end
  code_opts = options.slice(:length, :enforce)
  options.delete(:enforce)
  prep = lambda { |values|
    if block_given?
      values = [values].flatten.collect { |v| blk.call(v) }
    end
    [values].flatten.collect do |data|
      Cacofonix::Code.new(list_number, data, code_opts)
    end
  }
  options = options.merge(:from => tag_name, :as => [])
  xml_accessor("#{name}_codes", **options, &prep)

  define_method(name) do
    codes = send("#{name}_codes")
    codes ? codes.collect { |cd| cd.key } : nil
  end

  # FIXME: Hmm, adding to array? what happens with push, etc?
  define_method("#{name}=") do |vals|
    vals = [vals].flatten.collect { |v|
      v.kind_of?(Cacofonix::Code) ? v : prep.call(v)
    }.flatten
    send("#{name}_codes=", vals)
  end
end
onix_composite(name, klass, options = {}) click to toggle source

An accessor to an array of element instances.

Options:

:from - defaults to the class name, but you can override this.
:singular - accessor is not an array, just a single object.
# File lib/cacofonix/core/element.rb, line 18
def self.onix_composite(name, klass, options = {})
  options[:as] = options.delete(:singular) ? klass : [klass]
  options[:from] ||= klass.to_s.split("::").last
  xml_accessor(name, **options)
end
onix_date_accessor(name, tag_name, options = {}) click to toggle source

An accessor that treats the input/output as a date.

Options: none yet.

# File lib/cacofonix/core/element.rb, line 28
def self.onix_date_accessor(name, tag_name, options = {})
  options = options.merge(
    :from => tag_name,
    :to_xml => Cacofonix::Formatters.yyyymmdd
  )
  if options[:as].kind_of?(Array)
    prep = lambda { |vs|
      [vs].flatten.collect { |v| Date.parse(v) rescue nil }
    }
  else
    prep = lambda { |v| Date.parse(v) rescue nil }
  end
  xml_accessor(name, **options, &prep)
end
onix_space_separated_list(name, tag_name, options = {}) click to toggle source

An accessor that treats the input as a space-separated list, and creates an array for it.

# File lib/cacofonix/core/element.rb, line 46
def self.onix_space_separated_list(name, tag_name, options = {})
  options = options.merge(
    :from => tag_name,
    :to_xml => Cacofonix::Formatters.space_separated
  )
  prep = lambda { |v| v ? v.split : [] }
  xml_accessor(name, **options, &prep)
end
onix_spaced_codes_from_list(name, tag_name, options) click to toggle source

Sugar for a common case – country or territory codes.

# File lib/cacofonix/core/element.rb, line 193
def self.onix_spaced_codes_from_list(name, tag_name, options)
  options[:to_xml] ||= Cacofonix::Formatters.space_separated
  onix_codes_from_list(name, tag_name, options) { |v| v ? v.split : [] }
end
xml_accessor(attr, *args, **options) click to toggle source
Calls superclass method
# File lib/cacofonix/core/element.rb, line 250
def self.xml_accessor(attr, *args, **options)
  if options[:as] && options[:as].kind_of?(Array)
    xml_array_accessors(Array(xml_array_accessors) + [attr])
  end

  super
end

Public Instance Methods

fetch(composite_symbol, mthd, query) click to toggle source

Query a composite array within this element, looking for an attribute ('mthd') that has a value equal to 'query'.

The idea is that you can shorten this:

product.websites.detect { |ws| ws.website_role == 1 }

To this:

product.fetch(:websites, :website_role, 1)

Note: query may be an array of values, will return the first composite that matches one of them. So this:

product.websites.detect { |ws| ws.website_role == 1 } ||
  product.websites.detect { |ws| ws.website_role == 2 }

becomes this:

product.fetch(:websites, :website_role, [1, 2])
# File lib/cacofonix/core/element.rb, line 220
def fetch(composite_symbol, mthd, query)
  result = nil
  [query].flatten.each do |matcher|
    break  if result = send(composite_symbol).detect do |comp|
      comp.send(mthd) == matcher
    end
  end
  result
end
fetch_all(composite_symbol, mthd, query) click to toggle source

Queries a composite array like fetch, but returns all composites that have a match.

# File lib/cacofonix/core/element.rb, line 233
def fetch_all(composite_symbol, mthd, query)
  [query].flatten.inject([]) do |acc, matcher|
    comps = send(composite_symbol).select do |comp|
      comp.send(mthd) == matcher
    end
    acc += comps  if comps.any?
    acc
  end
end