lib/mspire/paramable.rb
require 'cv/param'
require 'mspire/user_param'
require 'mspire/cv/param'
require 'nokogiri'
require 'andand'
module Mspire
module Paramable
attr_accessor :cv_params
attr_accessor :user_params
attr_accessor :ref_param_groups
def params
cv_params + ref_param_groups.flat_map(&:params) + user_params
end
def each_param(&block)
return enum_for __method__ unless block
cv_params.each(&block)
ref_param_groups.flat_map(&:params).each(&block)
user_params.each(&block)
nil
end
def params?
cv_params.size > 0 ||
ref_param_groups.any? {|group| group.params.size > 0 } ||
user_params.size > 0
end
def each_accessionable_param(&block)
return enum_for __method__ unless block
cv_params.each(&block)
ref_param_groups.flat_map(&:params).each(&block)
nil
end
def accessionable_params
cv_params + ref_param_groups.flat_map(&:params)
end
# yields each current param. If the return value is not false or nil,
# it is deleted (i.e., any true value and it is deleted). Then adds the
# given parameter or makes a new one by accession number.
def replace!(*describe_args, &block)
reject!(&block).describe!(*describe_args)
end
# returns self
def reject!(&block)
cv_params.reject!(&block)
ref_param_groups.each {|group| group.reject!(&block) }
user_params.reject!(&block)
self
end
def replace_many!(describe_many_arg, &block)
reject!(&block).describe_many!(describe_many_arg)
end
#def params_by_name
# params.index_by &:name
#end
#def params_by_accession
# accessionable_params.index_by &:accession
#end
# returns the value if the param exists by that name. Returns true if
# the param exists but has no value. returns false if no param
def fetch(name)
param = each_param.find {|param| param.name == name}
if param
param.value || true
else
false
end
end
# returns the value if the param exists with that accession. Returns
# true if the param exists but has no value. returns false if no param
# with that accession.
def fetch_by_accession(acc)
param = accessionable_params.find {|v| v.accession == acc }
if param
param.value || true
else
false
end
end
alias_method :fetch_by_acc, :fetch_by_accession
def param?(name)
params.any? {|param| param.name == name }
end
def initialize
@cv_params = []
@user_params = []
@ref_param_groups = []
end
alias_method :params_init, :initialize
def param_by_accession(acc)
each_accessionable_param.find {|v| v.accession == acc }
end
alias_method :param_by_acc, :param_by_accession
# takes an array of values, each of which is fed into describe!
# returns self.
def describe_many!(array)
array.each do |arg|
if arg.is_a?(Array)
describe!(*arg)
else
describe!(arg)
end
end
self
end
# reads the paramable nodes and returns self. Use this if your element
# does not have anything besides paramable elements.
def describe_self_from_xml!(xml_node, ref_hash=nil)
describe_from_xml!(xml_node, ref_hash)
self
end
# takes a node with children that are cvParam, userParam or
# referenceableParamGroupRef and a hash containing
# referenceableParamGroup objects indexed by id. The only time ref_hash
# should be left nil is for the referenceableParamGroup itself.
#
# All param elements are required to appear before other elements, so
# the code walks through each child node to see if it is a paramable
# element. The first child node that is not paramable is returned (or
# nil if none)
#
# returns the next child node after the paramable elements or nil if none
def describe_from_xml!(xml_node, ref_hash=nil)
return nil unless (child_n = xml_node.child)
loop do
array =
case child_n.name
when 'referenceableParamGroupRef'
@ref_param_groups << ref_hash[child_n[:ref]]
when 'cvParam'
@cv_params << Mspire::CV::Param[ child_n[:accession], child_n[:value] ]
when 'userParam'
@user_params << Mspire::UserParam.new(child_n[:name], child_n[:value], child_n[:type])
else # assumes that the above precede any following children as per the spec
break
end
if (unit_acc = child_n[:unitAccession])
array.last.unit = ::CV::Param.new(child_n[:unitCvRef], unit_acc, child_n[:unitName])
end
break unless child_n = child_n.next
end
child_n
end
# Expects arguments describing a single CV::Param, Mspire::UserParam, or
# Mspire::Mzml::ReferenceableParamGroup
#
# obj.describe! 'MS:1000130' # a positive scan
# obj.describe! CV::Param['MS:1000130'] # same behavior
#
# # base peak intensity, units=number of counts
# obj.describe! "MS:1000505", 1524.5865478515625, 'MS:1000131'
#
# returns self
def describe!(*args)
return self if args.first.nil?
case (arg=args.first)
when String
@cv_params << Mspire::CV::Param[ *args ]
when Mspire::Mzml::ReferenceableParamGroup
@ref_param_groups << arg
else
if arg.is_a?(Mspire::UserParam)
@user_params << arg
else
@cv_params << arg
end
end
self
end
# iterates over @params and calls .to_xml on each object.
def to_xml(xml)
[:ref_param_groups, :cv_params, :user_params].each do |kind|
self.send(kind).each do |obj|
obj.to_xml(xml)
end
end
xml
end
end
end