<commit_before>require 'set'
require 'caruby/util/inflector'
require 'caruby/util/validation'

module CaTissue
  resource_import Java::edu.wustl.catissuecore.domain.AbstractSpecimen
  
  class AbstractSpecimen
    # Sets the specimen type to the specified value. The value can be a permissible caTissue String value or
    # the shortcut symbols :fresh, :fixed and :frozen.
    #
    # @param [String, Symbol, nil] value the value to set
    def specimen_type=(value)
      value = value.to_s.capitalize_first + ' Tissue' if Symbol === value
      setSpecimenType(value)
    end

    add_attribute_aliases(:parent => :parent_specimen,
     :children => :child_specimens,
     :events => :specimen_events,
     :specimen_event_parameters => :specimen_events,
     :event_parameters => :specimen_events,
     :characteristics => :specimen_characteristics)

    # @quirk caTissue initial_quantity must be set (cf. Bug #160)
    add_attribute_defaults(:initial_quantity => 0.0, :pathological_status => 'Not Specified', :specimen_type => 'Not Specified')

    add_mandatory_attributes(:lineage, :pathological_status, :specimen_class, :specimen_type, :specimen_characteristics)

    # @quirk caTissue Specimen characteristics are auto-generated but SpecimenRequirement
    #   characteristics are not. It is safe to set the :autogenerated flag for both
    #   AbstractSpecimen subclasses. This results in an unnecessary SpecimenRequirement
    #   create database query, but SpecimenRequirement create is rare and there is no harm.
    #
    # @quirk caTissue Specimen characteristics is cascaded but is not an exclusive dependent,
    #   since it is shared by aliquots.
    #
    # @quirk caTissue Bug 166: API update Specimen ignores a SpecimenCharacteristics with a
    #   different id. Guard against updating a Specimen with a SpecimenCharacteristics whose id
    #   differs from the existing id.
    #
    # @quirk caTissue Unlike other dependents, AbstractSpecimen characteristics, events and child
    #   specimens have cascade style 'all'. This implies that an AbstractSpecimen update does not
    #   create a referenced dependent. AbstractSpecimen create cascades to create and AbstractSpecimen
    #   update cascades to update, but AbstractSpecimen update does not cascade to create.
    #   The :no_cascade_update_to_create flag is set to handle this feature of cascade style 'all'.
    qualify_attribute(:specimen_characteristics, :cascaded, :fetched, :autogenerated, :no_cascade_update_to_create)

    # The :no_cascade_update_to_create flag is set since events has cascade style 'all'.
    add_dependent_attribute(:specimen_events, :create_only, :disjoint, :no_cascade_update_to_create)
   
    set_attribute_inverse(:parent_specimen, :child_specimens)
    
    add_dependent_attribute(:child_specimens, :unfetched, :no_cascade_update_to_create)

    class SpecimenClass
      TISSUE = 'Tissue'
      FLUID = 'Fluid'
      MOLECULAR = 'Molecular'
      CELL = 'Cell'

      EXTENT = Set.new([TISSUE, FLUID, MOLECULAR, CELL])

      UNIT_HASH = {TISSUE => 'gm', FLUID => 'ml', MOLECULAR => 'ug'}

      # @return whether the value is an accepted tissue class value
      def self.include?(value)
        EXTENT.include?(value)
      end
    end

    # Initializes this AbstractSpecimen. The default +specimen_class+ is inferred from this
    # AbstractSpecimen instance's subclass.
    def initialize
      super
      self.specimen_class ||= infer_specimen_class(self.class)
    end

    # @return whether this specimen is derived from a parent specimen
    def derived?
      not parent.nil?
    end

    # @return whether this specimen is an aliquot
    def aliquot?
      lineage ||= default_lineage
      lineage == 'Aliquot'
    end

    # @return this specimen's aliquots
    def aliquots
      children.filter { |child| child.aliquot? }
    end

    # @return whether this specimen's type is 'Fresh Tissue'
    def fresh?
      specimen_type == 'Fresh Tissue'
    end

    # @return whether this specimen's type starts with 'Fixed'
    def fixed?
      specimen_type =~ /^Fixed/
    end

    # @return whether this specimen's type starts with 'Frozen'
    def frozen?
      specimen_type =~ /^Frozen/
    end

    # @return <AbstractSpecimen> the transitive closure consisting of this AbstractSpecimen
    # and all AbstractSpecimen in the derivation hierarcy.
    def closure
      children.inject([self]) { |coll, spc| coll.concat(spc.closure) }
    end

    # Returns the standard unit for this specimen
    def standard_unit
      self.specimen_class ||= infer_specimen_class(self.class)
      SpecimenClass::UNIT_HASH[self.specimen_class]
    end

    # Derives a specimen from this specimen. The params are described in {Specimen#create_specimen},
    # with one addition: an optional :count, the optional number of specimens to derive.
    #
    # If the :count parameter is greater than one and the :specimen_class,
    # :specimen_type and :specimen_characteristics parameters are not set to values
    # which differ from the respective values for this Specimen, then the specimen is
    # aliquoted, otherwise the derived specimens are created independently, e.g.:
    #   spc = Specimen.create_specimen(:specimen_class => :tissue, :specimen_type => :frozen)
    #   spc.derive(:count => 1) #=> not aliquoted
    #   spc.derive(:count => 2) #=> aliquoted
    #   spc.derive(:specimen_type => 'Frozen Specimen') #=> two aliquots
    #
    # The default derived _initial_quantity_ is the parent specimen _available_quantity_
    # divided by _count_ for aliquots, zero otherwise. If the child _specimen_class_
    # is the same as this Specimen class, then this parent Specimen's _available_quantity_
    # is decremented by the child _initial_quantity_, e.g.:
    #   spc.available_quantity #=> 4
    #   spc.derive(:initial_quantity => 1)
    #   spc.available_quantity #=> 3
    #   spc.derive(:count => 2, :specimen_type => 'Frozen Tissue')
    #   spc.derive(:count => 2) #=> two aliquots with quantity 1 each
    #   spc.available_quantity #=> 0
    #
    # The default derived specimen label is _label_+_+_n_, where _label_ is this specimen's
    # label and _n_ is this specimen's child count after including the new derived specimen,
    # e.g. 3090_3 for the third child in parent specimen with label 3090.
    #
    # @return the new derived specimen if _count_ is one, otherwise an Array of _count_ derived specimens
    # @raise [ValidationError] if an aliquoted parent available quantity is not greater than zero<commit_msg>Fix comment.<commit_after>require 'set'
require 'caruby/util/inflector'
require 'caruby/util/validation'

module CaTissue
  resource_import Java::edu.wustl.catissuecore.domain.AbstractSpecimen
  
  class AbstractSpecimen
    # Sets the specimen type to the specified value. The value can be a permissible caTissue String value or
    # the shortcut symbols :fresh, :fixed and :frozen.
    #
    # @param [String, Symbol, nil] value the value to set
    def specimen_type=(value)
      value = value.to_s.capitalize_first + ' Tissue' if Symbol === value
      setSpecimenType(value)
    end

    add_attribute_aliases(:parent => :parent_specimen,
     :children => :child_specimens,
     :events => :specimen_events,
     :specimen_event_parameters => :specimen_events,
     :event_parameters => :specimen_events,
     :characteristics => :specimen_characteristics)

    # @quirk caTissue initial_quantity must be set (cf. Bug #160)
    add_attribute_defaults(:initial_quantity => 0.0, :pathological_status => 'Not Specified', :specimen_type => 'Not Specified')

    add_mandatory_attributes(:lineage, :pathological_status, :specimen_class, :specimen_type, :specimen_characteristics)

    # @quirk caTissue Specimen characteristics are auto-generated but SpecimenRequirement
    #   characteristics are not. It is safe to set the :autogenerated flag for both
    #   AbstractSpecimen subclasses. This results in an unnecessary SpecimenRequirement
    #   create database query, but SpecimenRequirement create is rare and there is no harm.
    #
    # @quirk caTissue Specimen characteristics is cascaded but is not an exclusive dependent,
    #   since it is shared by aliquots.
    #
    # @quirk caTissue Bug 166: API update Specimen ignores a SpecimenCharacteristics with a
    #   different id. Guard against updating a Specimen with a SpecimenCharacteristics whose id
    #   differs from the existing id.
    #
    # @quirk caTissue Unlike other dependents, AbstractSpecimen characteristics, events and child
    #   specimens have cascade style 'all'. This implies that an AbstractSpecimen update does not
    #   create a referenced dependent. AbstractSpecimen create cascades to create and AbstractSpecimen
    #   update cascades to update, but AbstractSpecimen update does not cascade to create.
    #   The :no_cascade_update_to_create flag is set to handle this feature of cascade style 'all'.
    qualify_attribute(:specimen_characteristics, :cascaded, :fetched, :autogenerated, :no_cascade_update_to_create)

    # The :no_cascade_update_to_create flag is set since events has cascade style 'all'.
    add_dependent_attribute(:specimen_events, :create_only, :disjoint, :no_cascade_update_to_create)
   
    set_attribute_inverse(:parent_specimen, :child_specimens)
    
    add_dependent_attribute(:child_specimens, :unfetched, :no_cascade_update_to_create)

    class SpecimenClass
      TISSUE = 'Tissue'
      FLUID = 'Fluid'
      MOLECULAR = 'Molecular'
      CELL = 'Cell'

      EXTENT = Set.new([TISSUE, FLUID, MOLECULAR, CELL])

      UNIT_HASH = {TISSUE => 'gm', FLUID => 'ml', MOLECULAR => 'ug'}

      # @return whether the value is an accepted tissue class value
      def self.include?(value)
        EXTENT.include?(value)
      end
    end

    # Initializes this AbstractSpecimen. The default +specimen_class+ is inferred from this
    # AbstractSpecimen instance's subclass.
    def initialize
      super
      self.specimen_class ||= infer_specimen_class(self.class)
    end

    # @return whether this specimen is derived from a parent specimen
    def derived?
      not parent.nil?
    end

    # @return whether this specimen is an aliquot
    def aliquot?
      lineage ||= default_lineage
      lineage == 'Aliquot'
    end

    # @return this specimen's aliquots
    def aliquots
      children.filter { |child| child.aliquot? }
    end

    # @return whether this specimen's type is 'Fresh Tissue'
    def fresh?
      specimen_type == 'Fresh Tissue'
    end

    # @return whether this specimen's type starts with 'Fixed'
    def fixed?
      specimen_type =~ /^Fixed/
    end

    # @return whether this specimen's type starts with 'Frozen'
    def frozen?
      specimen_type =~ /^Frozen/
    end

    # @return <AbstractSpecimen> the transitive closure consisting of this AbstractSpecimen
    # and all AbstractSpecimen in the derivation hierarcy.
    def closure
      children.inject([self]) { |coll, spc| coll.concat(spc.closure) }
    end

    # Returns the standard unit for this specimen
    def standard_unit
      self.specimen_class ||= infer_specimen_class(self.class)
      SpecimenClass::UNIT_HASH[self.specimen_class]
    end

    # Derives a new specimen from this specimen. The parameters are described in
    # {Specimen.create_specimen}, with one addition:
    # * +:count+(+Integer+) - the optional number of specimens to derive
    #
    # If the :count parameter is greater than one and the :specimen_class,
    # :specimen_type and :specimen_characteristics parameters are not set to values
    # which differ from the respective values for this Specimen, then the specimen is
    # aliquoted, otherwise the derived specimens are created independently, e.g.:
    #   spc = Specimen.create_specimen(:specimen_class => :tissue, :specimen_type => :frozen)
    #   spc.derive(:count => 1) #=> not aliquoted
    #   spc.derive(:count => 2) #=> aliquoted
    #   spc.derive(:specimen_type => 'Frozen Specimen') #=> two aliquots
    #
    # The default derived _initial_quantity_ is the parent specimen _available_quantity_
    # divided by _count_ for aliquots, zero otherwise. If the child _specimen_class_
    # is the same as this Specimen class, then this parent Specimen's _available_quantity_
    # is decremented by the child _initial_quantity_, e.g.:
    #   spc.available_quantity #=> 4
    #   spc.derive(:initial_quantity => 1)
    #   spc.available_quantity #=> 3
    #   spc.derive(:count => 2, :specimen_type => 'Frozen Tissue')
    #   spc.derive(:count => 2) #=> two aliquots with quantity 1 each
    #   spc.available_quantity #=> 0
    #
    # The default derived specimen label is _label_+_+_n_, where _label_ is this specimen's
    # label and _n_ is this specimen's child count after including the new derived specimen,
    # e.g. 3090_3 for the third child in parent specimen with label 3090.
    #
    # @return the new derived specimen if _count_ is one, otherwise an Array of _count_ derived specimens
    # @raise [ValidationError] if an aliquoted parent available quantity is not greater than zero
{'fraction_non_alphanumeric': 0.07647863767675232, 'fraction_numerical': 0.003953170138360954, 'mean_word_length': 3.5519031141868513, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1873076', 'n_tokens_mistral': 4018, 'n_tokens_neox': 3758, 'n_words': 1289}