princelab/mspire

View on GitHub
lib/mspire/cv/paramable.rb

Summary

Maintainability
A
1 hr
Test Coverage
require 'cv/param'
require 'mspire/cv/param'
require 'nokogiri'
require 'andand'

module Mspire
  module CV
    module Paramable

      attr_accessor :cv_params

      alias_method :cv_params, :params
      alias_method :cv_params=, :params=

      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

      # 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)
        self
      end

      def replace_many!(describe_many_arg, &block)
        reject!(&block).describe_many!(describe_many_arg)
      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 = []
      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 objects 
      # returns the next child node after the paramable elements or nil if none
      def describe_from_xml!(xml_node, ref_hash=nil)
        # TODO: this was merely cleaned up from Paramable and should be
        # re-factored
        return nil unless (child_n = xml_node.child) 
        loop do
          array = 
            case child_n.name
            when 'cvParam'
              @cv_params << Mspire::CV::Param[ child_n[:accession], child_n[:value] ]
            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
      #
      #     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 ]
        else
          @cv_params << arg
        end
        self
      end

      # iterates over @params and calls .to_xml on each object.
      def to_xml(xml)
        self.cv_params.each do |obj|
          obj.to_xml(xml)
        end
        xml
      end

    end
  end
end