Jump To …

application.rb

Newman::Application provides the main entry point for Newman application developers, and exists to tie together various Newman objects in a convenient way.

For an fairly complete example of a Newman::Application object in use, be sure to check out Jester.

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

module Newman 
  class Application

    include Filters

    

A Newman::Application object is a blank slate upon creation, with fields set to hold callbacks, matchers, and extensions. A block may optionally be provided, which then gets executed within the context of the newly created Newman::Application instance. This is the common way of building applications, and is demonstrated by the example below:

ping_pong = Newman::Application.new do
  subject(“ping”) do
    respond(:subject => “pong”)
  end
end

Any method that can be called on a Newman::Application instance can be called within the provided block, including those methods mixed in by Newman::Filters.

    def initialize(&block)
      self.callbacks  = []
      self.matchers   = {}
      self.extensions = []

      instance_eval(&block) if block_given?
    end
    

    

Newman::Application#call accepts a hash of parameters which gets used to create a new Newman::Controller object. The controller is then extended by all of the modules stored in the extensions field on the application object, and is finally passed along to Newman::Application#trigger_callbacks, which does the magical work of figuring out which callbacks to run, if any.

This method is meant to be run by a Newman::Server object, and isn’t especially useful on its own.

    def call(params)
      controller = Controller.new(params)      
      extensions.each { |mod| controller.extend(mod) }
      trigger_callbacks(controller)
    end

   

Newman::Application#default is used to define a default callback which will run when no other callbacks match the incoming request. For example, you can define a callback such as the one below:

default do
  respond(:subject => “REQUEST NOT UNDERSTOOD”)
end

Unless you are building an application that will never fail to match at least one of its filters, you MUST set up a default callback if you want to avoid a possible application error. We know this is not exactly the most desireable behavior, and will try to fix this in a future version of Newman.

    def default(&callback)
      self.default_callback = callback
    end

    

Newman:::Application#use is used to register the extension modules that get mixed in to the controller objects created by Newman::Application#call. This allows an application object to provide extensions for use within its callbacks, as in the example shown below.

module ListLoader
  def load_list(name)
    store = Newman::Store.new(settings.application.list_db)
    Newman::MailingList.new(name, store)
  end
end

list_app = Newman::Application.new do
  use ListLoader

  match :list_id, “[^.]+”

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

    if list.subscriber?(sender)
      # send a failure message
    else
      # susbcribe the user and send a welcome message
    end
  end
end

This method is mainly meant to be used with pre-packaged extensions or more complicated forms of callback helpers. This example was just shown for the sake of its simplicity, but for similar use cases it would actually be better to use Newman::Application#helpers

    def use(extension)
      extensions << extension
    end

    

Newman::Application#helpers is used to build simple controller extensions, and is mostly just syntactic sugar. For example, rather than using an explicit module, the example shown in the Newman::Application#use documentation can be rewritten as follows:

list_app = Newman::Application.new do
  helpers do
    def load_list(name)
      store = Newman::Store.new(settings.application.list_db)
      Newman::MailingList.new(name, store)
    end
  end

  match :list_id, “[^.]+”

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

    if list.subscriber?(sender)
      # send a failure message
    else
      # susbcribe the user and send a welcome message
    end
  end
end

It’s important to note that for any controller extensions that might be reusable, or for more complicated logic, Newman::Application#use is probably a better tool to use.

    def helpers(&block)
      use Module.new(&block)
    end

    

Newman::Application#match is used to define patterns which are used for extracting callback parameters. An example is shown below:

jester = Newman::Application.new do
  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
end

Because Newman’s built in filters are designed to escape regular expression syntax by default, Newman::Application#match provides the only high-level mechanism for dynamic filter matches. Low level matching is possible via Newman::Application#callback, but would be an exercise in tedium for most application developers.

NOTE: Newman::Application#match converts the provided name to a string using to_s to make life easier for the internals. Because Newman::Application#matchers is an implementation detail, you probably don’t need to worry about this unless you’re hacking on Newman itself.

    def match(name, pattern)
      matchers[name.to_s] = pattern
    end

    

Newman::Application#callback is a low level feature for defining custom callbacks. For ideas on how to roll your own filters with it, see the implementation of the Newman::Filters module.

    def callback(action, filter)
      callbacks << { :filter   => filter, 
                     :action   => action }
    end

    

Newman::Application#compile_regex is used for converting pattern strings into a regular expression string suitable for use in filters. This method is a low-level feature, and is not meant for use by application developers. See the Newman::Filters module for how to use it to build your own callback filters.

    def compile_regex(pattern)
      Regexp.escape(pattern).
            gsub(/\\{(.*?)\\}/) { |m| "(?<#{$1}>#{matchers[$1]})" } 
    end

    

NOTE: Methods below this point in the file are implementation details, and should not be depended upon.

    private

    

Newman::Application#trigger_callbacks runs a two step process:

1) It grabs the filter Proc for each callback and executes it, passing in the provided controller. Any filter proc that returns a logically true value is selected to be run.

2) If the selection of matched_callbacks is empty, it executes the default callback in the context of a controller object. Otherwise, it runs each callback in sequence, in the context of a controller object.

    def trigger_callbacks(controller)
      match_data = {}

      matched_callbacks = callbacks.select do |e| 
        filter = e[:filter]
        match_data[e] = filter.call(controller)
      end

      if matched_callbacks.empty?
        controller.instance_exec(&default_callback) 
      else
        matched_callbacks.each do |e|
          action = e[:action]
          controller.params = match_data[e]
          controller.instance_exec(&action)
        end
      end
    end

    

These accessors have been made private to reflect the fact that Newman::Application is meant to be customized via its high level methods such as use, helpers, match, and callback. Any extensions of Newman::Application should rely on those methods and not directly reference these fields at all. If there is some functionality missing that needs to be added to the public API for you to build your extension, just let us know.

    attr_accessor :callbacks, :default_callback, :matchers, :extensions
  end
end