<commit_before># -*- coding: utf-8 -*-

module Ircbot
  class PluginNotFound < RuntimeError; end

  class Plugins
    attr_reader :plugins
    attr_reader :client
    delegate :config, :debug, :to=>"client"

    def initialize(client = nil, plugins = nil)
      @client  = client  || Client::Standalone.new
      @plugins = Dictionary.new

      load Array(plugins)
    end

    ######################################################################
    ### Enumerable

    include Enumerable

    def each(&block)
      plugins.values.__send__(:each, &block)
    end

    ######################################################################
    ### Accessors

    def plugin!(plugin)
      case plugin
      when String, Symbol
        @plugins[plugin.to_s] or raise PluginNotFound, plugin.to_s
      when Plugin
        plugin
      else
        raise PluginNotFound, "#{plugin.class}(#{plugin})"
      end
    end
    alias :[] :plugin!

    def plugin(name)
      plugin!(name) rescue nil
    end

    def bot
      client
    end

    ######################################################################
    ### Operations

    def start(plugin)
      plugin!(plugin).running = true
    end

    def stop(plugin)
      plugin!(plugin).running = false
    end

    def delete(plugin)
      name = plugin.is_a?(Plugin) ? plugin.name : plugin.to_s
      plugin!(name)
      @plugins.delete(name)
    end

    ######################################################################
    ### IO

    def load(plugin)
      case plugin
      when Array
        plugin.each do |name|
          self << name
        end
      when Plugin
        plugin.plugins = self
        plugins[plugin.plugin_name] = plugin
        plugin.running = true
      when Class
        if plugin.ancestors.include?(Ircbot::Plugin)
          self << plugin.new(self)
        else
          raise ArgumentError, "#{plugin} is not Ircbot::Plugin"
        end
      when String, Symbol
        begin
          name = plugin.to_s
          self << eval_plugin(name)
        rescue Exception => e
          broadcast "Plugin error(#{name}): #{e}[#{e.class}]"
        end
      else
        raise NotImplementedError, "#<< for #{plugin.class}"
      end
      return self
    end
    alias :<< :load

    def eval_plugin(name)
      class_name = plugin_class_name(name)

      if Object.const_defined?(class_name)
        Object.send(:remove_const, class_name)
      end

      path = Ircbot.glob_for(:plugin, name).first or
        raise PluginNotFound, name.to_s

      script = path.read{}
      eval(script, Ircbot.toplevel_binding)

      return Object.const_get(class_name).new

    rescue NameError => e
      raise LoadError, "Expected #{path} to define #{class_name} (#{e})"
    end

    def active
      select(&:running)<commit_msg>Support plugins in sub-directory<commit_after># -*- coding: utf-8 -*-

module Ircbot
  class PluginNotFound < RuntimeError; end

  class Plugins
    attr_reader :plugins
    attr_reader :client
    delegate :config, :debug, :to=>"client"

    def initialize(client = nil, plugins = nil)
      @client  = client  || Client::Standalone.new
      @plugins = Dictionary.new

      load Array(plugins)
    end

    ######################################################################
    ### Enumerable

    include Enumerable

    def each(&block)
      plugins.values.__send__(:each, &block)
    end

    ######################################################################
    ### Accessors

    def plugin!(plugin)
      case plugin
      when String, Symbol
        @plugins[plugin.to_s] or raise PluginNotFound, plugin.to_s
      when Plugin
        plugin
      else
        raise PluginNotFound, "#{plugin.class}(#{plugin})"
      end
    end
    alias :[] :plugin!

    def plugin(name)
      plugin!(name) rescue nil
    end

    def bot
      client
    end

    ######################################################################
    ### Operations

    def start(plugin)
      plugin!(plugin).running = true
    end

    def stop(plugin)
      plugin!(plugin).running = false
    end

    def delete(plugin)
      name = plugin.is_a?(Plugin) ? plugin.name : plugin.to_s
      plugin!(name)
      @plugins.delete(name)
    end

    ######################################################################
    ### IO

    def load(plugin)
      case plugin
      when Array
        plugin.each do |name|
          self << name
        end
      when Plugin
        plugin.plugins = self
        plugins[plugin.plugin_name] = plugin
        plugin.running = true
      when Class
        if plugin.ancestors.include?(Ircbot::Plugin)
          self << plugin.new(self)
        else
          raise ArgumentError, "#{plugin} is not Ircbot::Plugin"
        end
      when String, Symbol
        begin
          name = plugin.to_s
          self << eval_plugin(name)
        rescue Exception => e
          broadcast "Plugin error(#{name}): #{e}[#{e.class}]"
        end
      else
        raise NotImplementedError, "#<< for #{plugin.class}"
      end
      return self
    end
    alias :<< :load

    def eval_plugin(name)
      class_name = plugin_class_name(name)

      if Object.const_defined?(class_name)
        Object.send(:remove_const, class_name)
      end

      path = Ircbot.glob_for(:plugin, name).first or
        raise PluginNotFound, name.to_s

      script = path.read{}
      Dir.chdir(path.parent) do
        eval(script, Ircbot.toplevel_binding)
      end

      return Object.const_get(class_name).new

    rescue NameError => e
      raise LoadError, "Expected #{path} to define #{class_name} (#{e})"
    end

    def active
      select(&:running)
{'fraction_non_alphanumeric': 0.189748990696858, 'fraction_numerical': 0.00035106196243637, 'mean_word_length': 2.3715976331360946, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 9, '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': '3475096', 'n_tokens_mistral': 1595, 'n_tokens_neox': 1525, 'n_words': 391}