<commit_before>module Temple
  module Mixins
    # @api private
    module EngineDSL
      def chain_modified!
      end

      def append(*args, &block)
        chain << element(args, block)
        chain_modified!
      end

      def prepend(*args, &block)
        chain.unshift(element(args, block))
        chain_modified!
      end

      def remove(name)
        found = false
        chain.reject! do |i|
          equal = i.first == name
          found = true if equal
          equal
        end
        raise "#{name} not found" unless found
        chain_modified!
      end

      alias use append

      # DEPRECATED!
      #
      #    wildcard(:FilterName) { FilterClass.new(options) }
      #
      # is replaced by
      #
      #    use(:FilterName) { FilterClass.new(options) }
      #
      alias wildcard use

      def before(name, *args, &block)
        name = Class === name ? name.name.to_sym : name
        raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
        e = element(args, block)
        found, i = false, 0
        while i < chain.size
          if chain[i].first == name
            found = true
            chain.insert(i, e)
            i += 2
          else
            i += 1
          end
        end
        raise "#{name} not found" unless found
        chain_modified!
      end

      def after(name, *args, &block)
        name = Class === name ? name.name.to_sym : name
        raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
        e = element(args, block)
        found, i = false, 0
        while i < chain.size
          if chain[i].first == name
            found = true
            i += 1
            chain.insert(i, e)
          end
          i += 1
        end
        raise "#{name} not found" unless found
        chain_modified!
      end

      def replace(name, *args, &block)
        name = Class === name ? name.name.to_sym : name
        raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
        e = element(args, block)
        found = false
        chain.each_with_index do |c, i|
          if c.first == name
            found = true
            chain[i] = e
          end
        end
        raise "#{name} not found" unless found
        chain_modified!
      end

      def filter(name, *options)
        use(name, Temple::Filters.const_get(name), *options)
      end

      def generator(name, *options)
        use(name, Temple::Generators.const_get(name), *options)
      end

      private

      def define_chain_method(name, proc)
        if Class === self
          define_method(name, &proc)
          instance_method(name)
        else
          (class << self; self; end).class_eval { define_method(name, &proc) }
          method(name)
        end
      end

      def element(args, block)
        name = args.shift
        if Class === name
          filter = name
          name = filter.name.to_sym
        end
        raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name

        if block
          raise(ArgumentError, 'Class and block argument are not allowed at the same time') if filter
          filter = block
        end

        filter ||= args.shift
<commit_msg>Add EngineDSL#html<commit_after>module Temple
  module Mixins
    # @api private
    module EngineDSL
      def chain_modified!
      end

      def append(*args, &block)
        chain << element(args, block)
        chain_modified!
      end

      def prepend(*args, &block)
        chain.unshift(element(args, block))
        chain_modified!
      end

      def remove(name)
        found = false
        chain.reject! do |i|
          equal = i.first == name
          found = true if equal
          equal
        end
        raise "#{name} not found" unless found
        chain_modified!
      end

      alias use append

      # DEPRECATED!
      #
      #    wildcard(:FilterName) { FilterClass.new(options) }
      #
      # is replaced by
      #
      #    use(:FilterName) { FilterClass.new(options) }
      #
      alias wildcard use

      def before(name, *args, &block)
        name = Class === name ? name.name.to_sym : name
        raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
        e = element(args, block)
        found, i = false, 0
        while i < chain.size
          if chain[i].first == name
            found = true
            chain.insert(i, e)
            i += 2
          else
            i += 1
          end
        end
        raise "#{name} not found" unless found
        chain_modified!
      end

      def after(name, *args, &block)
        name = Class === name ? name.name.to_sym : name
        raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
        e = element(args, block)
        found, i = false, 0
        while i < chain.size
          if chain[i].first == name
            found = true
            i += 1
            chain.insert(i, e)
          end
          i += 1
        end
        raise "#{name} not found" unless found
        chain_modified!
      end

      def replace(name, *args, &block)
        name = Class === name ? name.name.to_sym : name
        raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
        e = element(args, block)
        found = false
        chain.each_with_index do |c, i|
          if c.first == name
            found = true
            chain[i] = e
          end
        end
        raise "#{name} not found" unless found
        chain_modified!
      end

      # Shortcuts to access namespaces
      { :filter    => Temple::Filters,
        :generator => Temple::Generators,
        :html      => Temple::HTML }.each do |method, mod|
        define_method(method) do |name, *options|
          use(name, mod.const_get(name), *options)
        end
      end

      private

      def define_chain_method(name, proc)
        if Class === self
          define_method(name, &proc)
          instance_method(name)
        else
          (class << self; self; end).class_eval { define_method(name, &proc) }
          method(name)
        end
      end

      def element(args, block)
        name = args.shift
        if Class === name
          filter = name
          name = filter.name.to_sym
        else
          raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
        end

        if block
          raise(ArgumentError, 'Class and block argument are not allowed at the same time') if filter
          filter = block
        end

        filter ||= args.shift

{'fraction_non_alphanumeric': 0.09191121704156115, 'fraction_numerical': 0.0017875763444063757, 'mean_word_length': 1.604344453064391, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 6, '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': '6321373', 'n_tokens_mistral': 1866, 'n_tokens_neox': 1825, 'n_words': 595}