<commit_before># frozen_string_literal: true

require "dry/system/components/bootable"
require "dry/system/errors"
require "dry/system/constants"
require "dry/system/lifecycle"
require "dry/system/booter/component_registry"
require "pathname"

module Dry
  module System
    # Default booter implementation
    #
    # This is currently configured by default for every System::Container.
    # Booter objects are responsible for loading system/boot files and expose
    # an API for calling lifecycle triggers.
    #
    # @api private
    class Booter
      attr_reader :paths

      attr_reader :booted

      attr_reader :components

      # @api private
      def initialize(paths)
        @paths = paths
        @booted = []
        @components = ComponentRegistry.new
      end

      # @api private
      def bootable?(component)
        !boot_file(component).nil?
      end

      # @api private
      def register_component(component)
        components.register(component)
        self
      end

      # @api private
      def finalize!
        boot_files.each do |path|
          load_component(path)
        end

        components.each do |component|
          start(component)
        end

        freeze
      end

      # @api private
      def shutdown
        components.each do |component|
          next unless booted.include?(component)

          stop(component)
        end
      end

      # @api private
      def init(name_or_component)
        with_component(name_or_component) do |component|
          call(component) do
            component.init.finalize
            yield if block_given?
          end

          self
        end
      end

      # @api private
      def start(name_or_component)
        with_component(name_or_component) do |component|
          return self if booted.include?(component)

          init(name_or_component) do
            component.start
          end

          booted << component.finalize

          self
        end
      end

      # @api private
      def stop(name_or_component)
        call(name_or_component) do |component|
          raise ComponentNotStartedError, name_or_component unless booted.include?(component)

          component.stop
          booted.delete(component)

          yield if block_given?
        end
      end

      # @api private
      def call(name_or_component)
        with_component(name_or_component) do |component|
          raise ComponentFileMismatchError, name unless component

          yield(component) if block_given?

          component
        end
      end

      # @api private
      def boot_dependency(component)
        boot_file = boot_file(component)

        start(boot_file.basename(".*").to_s.to_sym) if boot_file
      end

      # @api private
      def boot_files
        @boot_files ||= paths.each_with_object([[], []]) { |path, (boot_files, loaded)|<commit_msg>Document Booter#boot_files method as public<commit_after># frozen_string_literal: true

require "dry/system/components/bootable"
require "dry/system/errors"
require "dry/system/constants"
require "dry/system/lifecycle"
require "dry/system/booter/component_registry"
require "pathname"

module Dry
  module System
    # Default booter implementation
    #
    # This is currently configured by default for every System::Container.
    # Booter objects are responsible for loading system/boot files and expose
    # an API for calling lifecycle triggers.
    #
    # @api private
    class Booter
      attr_reader :paths

      attr_reader :booted

      attr_reader :components

      # @api private
      def initialize(paths)
        @paths = paths
        @booted = []
        @components = ComponentRegistry.new
      end

      # @api private
      def bootable?(component)
        !boot_file(component).nil?
      end

      # @api private
      def register_component(component)
        components.register(component)
        self
      end

      # @api private
      def finalize!
        boot_files.each do |path|
          load_component(path)
        end

        components.each do |component|
          start(component)
        end

        freeze
      end

      # @api private
      def shutdown
        components.each do |component|
          next unless booted.include?(component)

          stop(component)
        end
      end

      # @api private
      def init(name_or_component)
        with_component(name_or_component) do |component|
          call(component) do
            component.init.finalize
            yield if block_given?
          end

          self
        end
      end

      # @api private
      def start(name_or_component)
        with_component(name_or_component) do |component|
          return self if booted.include?(component)

          init(name_or_component) do
            component.start
          end

          booted << component.finalize

          self
        end
      end

      # @api private
      def stop(name_or_component)
        call(name_or_component) do |component|
          raise ComponentNotStartedError, name_or_component unless booted.include?(component)

          component.stop
          booted.delete(component)

          yield if block_given?
        end
      end

      # @api private
      def call(name_or_component)
        with_component(name_or_component) do |component|
          raise ComponentFileMismatchError, name unless component

          yield(component) if block_given?

          component
        end
      end

      # @api private
      def boot_dependency(component)
        boot_file = boot_file(component)

        start(boot_file.basename(".*").to_s.to_sym) if boot_file
      end

      # Returns all boot files within the configured paths
      #
      # Searches for files in the order of the configured paths. In the case of multiple
      # identically-named boot files within different paths, the file found first will be
      # returned, and other matching files will be discarded.
      #
      # @return [Array<Pathname>]
      # @api public
      def boot_files
        @boot_files ||= paths.each_with_object([[], []]) { |path, (boot_files, loaded)|
{'fraction_non_alphanumeric': 0.0681265206812652, 'fraction_numerical': 0.0, 'mean_word_length': 2.073778664007976, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4116965', 'n_tokens_mistral': 1689, 'n_tokens_neox': 1626, 'n_words': 452}