<commit_before>module DbAgile
  module Core
    module Schema
      class Composite < SchemaObject
      
        # Creates a composite instance with parts
        def initialize(composite_parts = _default_parts)
          unless composite_parts.kind_of?(Hash)
            raise ArgumentError, "Composite parts must be a hash, got #{composite_parts.inspect}" 
          end
          _install_parts(composite_parts)
        end
      
        ############################################################################
        ### Private interface
        ############################################################################
        attr_reader :composite_parts
        protected   :composite_parts
        private
      
        # Creates defaut parts hash
        def _default_parts
          {}
        end
      
        # Make installation of parts
        def _install_parts(parts)
          meth = _install_eigenclass_methods?
          parts.each_pair{|k, v|
            v.send(:parent=, self)
            if meth
              eigenclazz = (class << self; self; end)
              eigenclazz.send(:define_method, k){ @composite_parts[k] }
            end
          }
          @composite_parts = parts
        end
      
        # Installs eigenclass methods on parts provided at construction
        def _install_eigenclass_methods?
          false
        end
        
        # Duplicates parts
        def _dup_parts
          dup_parts = {}
          @composite_parts.each_pair{|name, part| dup_parts[name] = part.dup}
          dup_parts
        end
        
        # Makes a sanity check on the composite
        def _sanity_check
          parts.each{|p| 
            raise "Expected #{p.to_yaml} to have me as parent. Has #{p.parent.to_yaml}"\
              unless p.parent == self
          }
        end
      
        ############################################################################
        ### Public interface
        ############################################################################
        public
      
        # @see DbAgile::Core::Schema
        def visit(&block)
          block.call(self, parent)
          parts.each{|p| p.visit(&block)}
        end
        
        ############################################################################
        ### SchemaObject
        ############################################################################
      
        # @see DbAgile::Core::SchemaObject
        def empty?(recurse = true)
          if recurse
            parts.all?{|p| p.composite? && p.empty?}
          else
            @composite_parts.empty?
          end
        end
      
        # @see DbAgile::Core::SchemaObject
        def part_keys
          @composite_parts.keys
        end
      
        # @see DbAgile::Core::SchemaObject
        def parts
          @composite_parts.values
        end
      
        # @see DbAgile::Core::SchemaObject
        def [](name)
          @composite_parts[name]
        end
      
        # @see DbAgile::Core::SchemaObject
        def []=(name, part, annotation = nil)
          if @composite_parts.key?(name)
            raise ArgumentError, "A part already exists with name '#{name}'" 
          end
          @composite_parts[name] = part
          part.send(:parent=, self)
          unless annotation.nil?
            part.visit{|p, parent| p.annotation = annotation}
          end
          part
        end
      
        ############################################################################
        ### About IO
        ############################################################################
      
        # @see DbAgile::Core::SchemaObject
        def to_yaml(opts = {})
          YAML::quick_emit(self, opts){|out|
            out.map("tag:yaml.org,2002:map") do |map|
              part_keys.sort{|k1, k2| k1.to_s <=> k2.to_s}.each{|k|
                map.add(k.to_s, self[k])
              }
            end
          }
        end
        
        # Returns a yaml string
        def yaml_say(env, 
                     options = {}, 
                     colors = DbAgile::Core::Schema::Computations::Merge::ANNOTATION_TO_COLOR, 
                     indent = 0)
          part_keys.sort{|k1, k2| k1.to_s <=> k2.to_s}.each{|k|
            mine = "  "*indent + k.to_s + ":"
            part = self[k]
            annotation = part.annotation.to_s.ljust(25)
            if part.composite?
              if part.annotation == :same and options[:skip_unchanged]
              else
                env.say(mine, colors[part.annotation])
                part.yaml_say(env, options, colors, indent+1)
              end
            else
              part_str = part.to_yaml
              part_str =~ /---\s*(.*)$/
              part_str = $1
              env.say(mine + " " + part_str, colors[part.annotation])
            end
          }
        end
      
        ############################################################################
        ### Equality and hash code
        ############################################################################
      
        # @see DbAgile::Core::SchemaObject
        def ==(other)
          return nil unless other.kind_of?(self.class)
          (@composite_parts == other.composite_parts)
        end
      
        # @see DbAgile::Core::SchemaObject
        def hash
          @composite_parts.hash
        end
      <commit_msg>Bug fix in skip_unchanged diff option.<commit_after>module DbAgile
  module Core
    module Schema
      class Composite < SchemaObject
      
        # Creates a composite instance with parts
        def initialize(composite_parts = _default_parts)
          unless composite_parts.kind_of?(Hash)
            raise ArgumentError, "Composite parts must be a hash, got #{composite_parts.inspect}" 
          end
          _install_parts(composite_parts)
        end
      
        ############################################################################
        ### Private interface
        ############################################################################
        attr_reader :composite_parts
        protected   :composite_parts
        private
      
        # Creates defaut parts hash
        def _default_parts
          {}
        end
      
        # Make installation of parts
        def _install_parts(parts)
          meth = _install_eigenclass_methods?
          parts.each_pair{|k, v|
            v.send(:parent=, self)
            if meth
              eigenclazz = (class << self; self; end)
              eigenclazz.send(:define_method, k){ @composite_parts[k] }
            end
          }
          @composite_parts = parts
        end
      
        # Installs eigenclass methods on parts provided at construction
        def _install_eigenclass_methods?
          false
        end
        
        # Duplicates parts
        def _dup_parts
          dup_parts = {}
          @composite_parts.each_pair{|name, part| dup_parts[name] = part.dup}
          dup_parts
        end
        
        # Makes a sanity check on the composite
        def _sanity_check
          parts.each{|p| 
            raise "Expected #{p.to_yaml} to have me as parent. Has #{p.parent.to_yaml}"\
              unless p.parent == self
          }
        end
      
        ############################################################################
        ### Public interface
        ############################################################################
        public
      
        # @see DbAgile::Core::Schema
        def visit(&block)
          block.call(self, parent)
          parts.each{|p| p.visit(&block)}
        end
        
        ############################################################################
        ### SchemaObject
        ############################################################################
      
        # @see DbAgile::Core::SchemaObject
        def empty?(recurse = true)
          if recurse
            parts.all?{|p| p.composite? && p.empty?}
          else
            @composite_parts.empty?
          end
        end
      
        # @see DbAgile::Core::SchemaObject
        def part_keys
          @composite_parts.keys
        end
      
        # @see DbAgile::Core::SchemaObject
        def parts
          @composite_parts.values
        end
      
        # @see DbAgile::Core::SchemaObject
        def [](name)
          @composite_parts[name]
        end
      
        # @see DbAgile::Core::SchemaObject
        def []=(name, part, annotation = nil)
          if @composite_parts.key?(name)
            raise ArgumentError, "A part already exists with name '#{name}'" 
          end
          @composite_parts[name] = part
          part.send(:parent=, self)
          unless annotation.nil?
            part.visit{|p, parent| p.annotation = annotation}
          end
          part
        end
      
        ############################################################################
        ### About IO
        ############################################################################
      
        # @see DbAgile::Core::SchemaObject
        def to_yaml(opts = {})
          YAML::quick_emit(self, opts){|out|
            out.map("tag:yaml.org,2002:map") do |map|
              part_keys.sort{|k1, k2| k1.to_s <=> k2.to_s}.each{|k|
                map.add(k.to_s, self[k])
              }
            end
          }
        end
        
        # Returns a yaml string
        def yaml_say(env, 
                     options = {}, 
                     colors = DbAgile::Core::Schema::Computations::Merge::ANNOTATION_TO_COLOR, 
                     indent = 0)
          part_keys.sort{|k1, k2| k1.to_s <=> k2.to_s}.each{|k|
            part = self[k]
            annotation = part.annotation.to_s.ljust(25)
            show_it = !(part.annotation == :same and options[:skip_unchanged])
            if show_it
              mine = "  "*indent + k.to_s + ":"
              if part.composite?
                env.say(mine, colors[part.annotation])
                part.yaml_say(env, options, colors, indent+1)
              else
                part_str = part.to_yaml
                part_str =~ /---\s*(.*)$/
                part_str = $1
                env.say(mine + " " + part_str, colors[part.annotation])
              end
            end
          }
        end
      
        ############################################################################
        ### Equality and hash code
        ############################################################################
      
        # @see DbAgile::Core::SchemaObject
        def ==(other)
          return nil unless other.kind_of?(self.class)
          (@composite_parts == other.composite_parts)
        end
      
        # @see DbAgile::Core::SchemaObject
        def hash
          @composite_parts.hash
        end
      
{'fraction_non_alphanumeric': 0.2186097627987911, 'fraction_numerical': 0.0031138382635772506, 'mean_word_length': 1.734785875281743, 'pattern_counts': {'":': 2, '<': 13, '<?xml version=': 0, '>': 7, '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': '2631528', 'n_tokens_mistral': 2847, 'n_tokens_neox': 2704, 'n_words': 578}