Jump To …

filters.rb

Newman::Filters provides the standard filtering mechanisms for Newman applications.

Unless you are building a server-side extension for Newman, you probably only need to be familiar with how these filter methods are used and can treat their implementation details as a black box.

Newman::Filters is part of Newman’s external interface.

module Newman 
  module Filters
    

    

Newman::Filters#to takes a filter_type, a pattern, and an action and then registers a callback which gets run for each new request the application handles. If the filter matches the incoming message, the action block gets run in the context of a Newman::Controller object. Otherwise, the action block does not get run at all.

Currently, the only supported filter_type is :tag, which leverages the + extension syntax for email addresses to filter out emails with certain tags in their TO field. For example, we could build a filter that responds to messages sent to USERNAME+ping@HOST using the following filter setup:

to(:tag, “ping”) do
  respond(:subject => “pong”)
end

Because this method runs the pattern through Newman::Application#compile_regex, it can also be used in combination with Newman::Application#match to do more complex matching. For example, the code below could be used to support complex TO field mappings, such as USERNAME+somelist.subscribe@HOST:

match :list_id, “[^.]+”

to(:tag, “{list_id}.subscribe”) do
  list = load_list(params[:list_id]) 

  if list.subscriber?(sender)
    # send failure email, already subscribed
  else
    # add user to list and send success email
  end
end

Note that currently everything before the + in the email address is ignored, and that the domain is hardcoded to match the Controller#domain, which currently directly references the service.domain setting. It’d be nice to make this a bit more flexible and also support other filter types such as a match against the whole email address at some point in the future.

    def to(filter_type, pattern, &action)
      raise NotImplementedError unless filter_type == :tag

      regex = compile_regex(pattern)

      callback action, ->(controller) {
        controller.request.to.each do |e| 
          md = e.match(/\+#{regex}@#{Regexp.escape(controller.domain)}/)
          return md if md
        end

        false
      }
    end

Newman::Filters#subject takes a filter_type, a pattern, and an action and then registers a callback which gets run for each new request the application handles. If the filter matches the incoming message, the action block gets run in the context of a Newman::Controller object. Otherwise, the action block does not get run at all.

Currently, the only supported filter_type is :match, which matches the pattern against the full SUBJECT field. This can be used for simple subject based filtering, such as the code shown below:

subject(:match, “what stories do you know?”) do
  respond :subject => “All of Jester’s stories”,
         :body => story_library.map { |e| e.title }.join(“\n”)
end

Because this method runs the pattern through Newman::Application#compile_regex, it can also be used in combination with Newman::Application#match to do more complex matching, such as in the following example:

match :genre, ‘\S+’
match :title, ‘.*’

subject(:match, “a {genre} story ‘{title}’”) do
  story_library.add_story(:genre => params[:genre],
                          :title => params[:title],
                          :body => request.body.to_s)

  respond :subject => “Jester saved ‘#{params[:title]}’”
end

It’d be nice to support more kinds of matching strategies at some point in the future, so be sure to let us know if you have ideas.

    def subject(filter_type, pattern, &action)
      raise NotImplementedError unless filter_type == :match

      regex = compile_regex(pattern)

      callback action, ->(controller) {
        subject = controller.request.subject

        return false unless subject

        subject.match(/#{regex}/) || false
      }
    end
  end
end