<commit_before>require 'set'
module Bundler
  class Graph
    GRAPH_NAME = :Gemfile

    def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png")
      @env               = env
      @output_file       = output_file
      @show_version      = show_version
      @show_requirements = show_requirements
      @output_format     = output_format

      @groups            = []
      @relations         = Hash.new {|h, k| h[k] = Set.new}
      @node_options      = {}
      @edge_options      = {}

      _populate_relations
    end

    attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format

    def viz
      GraphVizClient.new(self).run
    end

    private

    def _populate_relations
      relations = Hash.new {|h, k| h[k] = Set.new}
      parent_dependencies = _groups.values.to_set.flatten
      while true
        if parent_dependencies.empty?
          break
        else
          tmp = Set.new
          parent_dependencies.each do |dependency|
            child_dependencies = dependency.to_spec.runtime_dependencies.to_set
            relations[dependency.name] += child_dependencies.to_set
            @relations[dependency.name] += child_dependencies.map(&:name).to_set
            tmp += child_dependencies

            @node_options[dependency.name] = _make_label(dependency, :node)
            child_dependencies.each do |c_dependency|
              @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge)
            end
          end
          parent_dependencies = tmp
        end
      end
      @relations
    end

    def _groups
      relations = Hash.new {|h, k| h[k] = Set.new}
      @env.current_dependencies.each do |dependency|
        dependency.groups.each do |group|
          relations[group.to_s].add(dependency)
          @relations[group.to_s].add(dependency.name)

          @node_options[group.to_s] ||= _make_label(group, :node)
          @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge)
        end
      end
      @groups = relations.keys
      relations
    end

    def _make_label(symbol_or_string_or_dependency, element_type)
      case element_type.to_sym
      when :node
        if symbol_or_string_or_dependency.is_a?(Gem::Dependency)
          label = symbol_or_string_or_dependency.name.dup
          label << "\n#{symbol_or_string_or_dependency.to_spec.version.to_s}" if @show_version
        else
          label = symbol_or_string_or_dependency.to_s
        end
      when :edge
        label = nil
        if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements
          tmp = symbol_or_string_or_dependency.requirements_list.join(", ")
          label = tmp if tmp != ">= 0"
        end
      else
        raise ArgumentError, "2nd argument is invalid"
      end
      label.nil? ? {} : { :label => label }
    end

    class GraphVizClient
      def initialize(graph_instance)
        @graph_name    = graph_instance.class::GRAPH_NAME
        @groups        = graph_instance.groups
        @relations     = graph_instance.relations
        @node_options  = graph_instance.node_options
        @edge_options  = graph_instance.edge_options
        @output_file   = graph_instance.output_file
        @output_format = graph_instance.output_format
      end

      def g
        require 'graphviz'
        @g ||= ::GraphViz.digraph(@graph_name, {:concentrate => true, :normalize => true, :nodesep => 0.55}) do |g|
          g.edge[:weight]   = 2
          g.edge[:fontname] = g.node[:fontname] = 'Arial, Helvetica, SansSerif'<commit_msg>fix bundle viz error with git<commit_after>require 'set'
module Bundler
  class Graph
    GRAPH_NAME = :Gemfile

    def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png")
      @env               = env
      @output_file       = output_file
      @show_version      = show_version
      @show_requirements = show_requirements
      @output_format     = output_format

      @groups            = []
      @relations         = Hash.new {|h, k| h[k] = Set.new}
      @node_options      = {}
      @edge_options      = {}

      _patching_gem_dependency_class
      _populate_relations
    end

    attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format

    def viz
      GraphVizClient.new(self).run
    end

    private

    def _populate_relations
      parent_dependencies = _groups.values.to_set.flatten
      while true
        if parent_dependencies.empty?
          break
        else
          tmp = Set.new
          parent_dependencies.each do |dependency|
            child_dependencies = dependency.to_spec.runtime_dependencies.to_set
            @relations[dependency.name] += child_dependencies.map(&:name).to_set
            tmp += child_dependencies

            @node_options[dependency.name] = _make_label(dependency, :node)
            child_dependencies.each do |c_dependency|
              @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge)
            end
          end
          parent_dependencies = tmp
        end
      end
    end

    def _groups
      relations = Hash.new {|h, k| h[k] = Set.new}
      @env.current_dependencies.each do |dependency|
        dependency.groups.each do |group|
          relations[group.to_s].add(dependency)
          @relations[group.to_s].add(dependency.name)

          @node_options[group.to_s] ||= _make_label(group, :node)
          @edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge)
        end
      end
      @groups = relations.keys
      relations
    end

    def _make_label(symbol_or_string_or_dependency, element_type)
      case element_type.to_sym
      when :node
        if symbol_or_string_or_dependency.is_a?(Gem::Dependency)
          label = symbol_or_string_or_dependency.name.dup
          label << "\n#{symbol_or_string_or_dependency.to_spec.version.to_s}" if @show_version
        else
          label = symbol_or_string_or_dependency.to_s
        end
      when :edge
        label = nil
        if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements
          tmp = symbol_or_string_or_dependency.requirements_list.join(", ")
          label = tmp if tmp != ">= 0"
        end
      else
        raise ArgumentError, "2nd argument is invalid"
      end
      label.nil? ? {} : { :label => label }
    end

    def _patching_gem_dependency_class
      # method borrow from rubygems/dependency.rb
      # redefinition of matching_specs will also redefine to_spec and to_specs
      Gem::Dependency.class_eval do
        def matching_specs platform_only = false
          matches = Bundler.load.specs.select { |spec|
            self.name === spec.name and # TODO: == instead of ===
              requirement.satisfied_by? spec.version
          }

          if platform_only
            matches.reject! { |spec|
              not Gem::Platform.match spec.platform
            }
          end

          matches = matches.sort_by { |s| s.sort_obj } # HACK: shouldn't be needed
        end
      end
    end

    class GraphVizClient
      def initialize(graph_instance)
        @graph_name    = graph_instance.class::GRAPH_NAME
        @groups        = graph_instance.groups
        @relations     = graph_instance.relations
        @node_options  = graph_instance.node_options
        @edge_options  = graph_instance.edge_options
        @output_file   = graph_instance.output_file
        @output_format = graph_instance.output_format
      end

      def g
        require 'graphviz'
        @g ||= ::GraphViz.digraph(@graph_name, {:concentrate => true, :normalize => true, :nodesep => 0.55}) do |g|
          g.edge[:weight]   = 2
          g.edge[:fontname] = g.node[:fontname] = 'Arial, Helvetica, SansSerif'
{'fraction_non_alphanumeric': 0.0920854271356784, 'fraction_numerical': 0.001507537688442211, 'mean_word_length': 2.317083333333333, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 13, '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': '2184084', 'n_tokens_mistral': 2454, 'n_tokens_neox': 2337, 'n_words': 467}