summaryrefslogtreecommitdiff
path: root/lib/rbot/core/utils/filters.rb
blob: 5744b732a2914fc4d787c6615988e18eca982c0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#-- vim:sw=2:et
#++
#
# :title: Stream filters
#
# Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
# Copyright:: (C) 2008 Giuseppe Bilotta
# License:: GPL v2
#
# This file collects methods to handle 'stream filters', a generic mechanism
# to transform text+attributes into other text+attributes

module ::Irc
  class Bot

    # The DataStream class. A DataStream is just a Hash. The :text key has
    # a special meaning because it's the value that will be used when
    # converting to String
    class DataStream < Hash

      def initialize(hsh={})
        self.replace(hsh)
      end

      # Returns the :text key
      def to_s
        return self[:text]
      end
    end

    # The DataFilter class. A DataFilter is a wrapper around a block
    # that can be run on a DataStream to process it. The block is supposed to
    # return another DataStream object
    class DataFilter
      def initialize(&block)
        raise "No block provided" unless block_given?
        @block = block
      end

      def call(stream)
        @block.call(stream)
      end
      alias :run :call
      alias :filter :call
    end

    # This method processes the DataStream _stream_ with the filters _name_.
    # _name_ can be either a single Symbol (filter name), or an Array of
    # Symbols, in which case the output of each filter will be used as input
    # for the next
    #
    def filter(name, stream={})
      @filters ||= {}
      names = (Symbol === name ? [name] : name.dup)
      ds = (DataStream === stream ? stream : DataStream.new(stream))
      return ds if names.empty?
      # check if filters exist
      missing = names - @filters.keys
      raise "Missing filters: #{missing.join(', ')}" unless missing.empty?
      fs = @filters.values_at(*names)
      fs.inject(ds) { |mid, f| mid = f.call(mid) }
    end

    # This method is used to register a new filter
    def register_filter(name, &block)
      raise "No block provided" unless block_given?
      @filters ||= {}
      @filters[name.to_sym] = DataFilter.new &block
    end

    # This method clears the filter list and installs the identity filter
    def clear_filters
      @filters ||= {}
      @filters.clear
      register_filter(:identity) { |stream| stream }
    end
  end
end