class Rack::ForNow::Service

The ‘Service` class is the base classes for all the third-party services made available by `Rack::ForNow`.

@abstract The ‘Service` class is not meant to be used directly.

Attributes

parent_service[W]
subpath[W]

Public Class Methods

on(path) click to toggle source

Sets up a service to be installed on an arbitrary path

@example

map '/romeo' do
    run Rack::ForNow::GitHub.new('will').
          with(Rack::ForNow::Rubydoc). # this sets up `/romeo/docs`
          with(Rack::ForNow::Rubydoc.on('/documentation') # this sets up `/romeo/documentation`
end

@see with

@api public

@param [String] path the path under which the service is to be installed

@return [Service] the service, set up so to be installed on ‘path`

# File lib/rack/for_now.rb, line 84
def self.on(path)
        service = self.new
        service.subpath = path

        return service
end

Public Instance Methods

app() click to toggle source

@api private

# File lib/rack/for_now.rb, line 98
def app
        builder = Rack::Builder.new

        @subservices ||= {}
        @subservices.each do |path, service|
                builder.map('/' + path) { run service.main_app }
        end

        service = self
        builder.map('/') { run service.main_app }

        return builder.to_app
end
call(env) click to toggle source

@api private

# File lib/rack/for_now.rb, line 92
def call(env)
        @app ||= app
        @app.call(env)
end
default_subpath() click to toggle source

@return [String] the default path where the service will be mounted.

# File lib/rack/for_now.rb, line 13
def default_subpath
        self.class.const_get(:DEFAULT_SUBPATH)
end
infer_runtime_parameters(env) click to toggle source

Infer parameters from the Rack request.

@api private

@return void

# File lib/rack/for_now.rb, line 170
def infer_runtime_parameters(env)
        # TODO: provide a way to update also other parameters
        params = self.instance_variables.map(&:to_sym)
        if params.include?(:@project)
                @project ||= last_URL_segment(env)
        end
end
last_URL_segment(env) click to toggle source

@api private

# File lib/rack/for_now.rb, line 179
def last_URL_segment(env)
        path = env['SCRIPT_NAME'].to_s + env['PATH_NAME'].to_s
        segments = path.split('/')

        idx_last = (segments.last == subpath) ? -2 : -1
        return segments[idx_last]
end
main_app() click to toggle source

@api private

# File lib/rack/for_now.rb, line 113
def main_app
        lambda do |env|
                root_requested = env['PATH_INFO'].chomp('/').empty?
                if !root_requested
                        return [404, {'Content-Type' => 'text/plain', 'X-Cascade' => 'pass'}, ["Not Found: #{env['PATH_INFO']}"]]
                end

                set_parameters
                infer_runtime_parameters(env)

                destination_url = personalized(template_url)

                return [307, { 'Location' => destination_url }, [""]]
        end
end
parent_service() click to toggle source

@api private

# File lib/rack/for_now.rb, line 136
def parent_service
        return @parent_service || FakeService.new
end
personalized(url_template) click to toggle source

@api private

# File lib/rack/for_now.rb, line 188
def personalized(url_template)
        placeholders = url_template.scan(/\%\{(.*?)\}/).to_a.flatten.uniq
        values = Hash[placeholders.map { |placeholder| [placeholder, instance_variable_get("@#{placeholder}".to_sym)] }]

        values.each do |placeholder, value|
                if value.nil?
                        raise "Unset template variable #{placeholder} for #{self.class}"
                end
        end

        url = url_template
        values.each do |placeholder, value|
                url = url.gsub("%{#{placeholder}}", value)
        end

        return url
end
set_parameters() click to toggle source

Set the service parameters, inheriting from the parent service if needed.

@api private

@return void

# File lib/rack/for_now.rb, line 147
def set_parameters
        if parent_service.nil?
                return
        end

        params = self.instance_variables.map(&:to_sym)
        params -= [:@app, :@parent_service, :@subpath, :@subservices]
        params.reject! { |param_name| !self.instance_variable_get(param_name).nil? }

        methods = params.map { |param_name| param_name.to_s[1..-1].to_sym }

        params.each_with_index do |param_name, idx|
                value = parent_service.send(methods[idx])
                self.instance_variable_set(param_name, value)
        end
end
subpath() click to toggle source

@api private

# File lib/rack/for_now.rb, line 130
def subpath
        return @subpath || default_subpath
end
template_url() click to toggle source

@return [String] the template URL for the service.

# File lib/rack/for_now.rb, line 19
def template_url
        self.class.const_get(:TEMPLATE_URL)
end
with(*subservices) click to toggle source

Mounts a service on a subpath.

@example Mount a GitHub Issues redirect under ‘/romeo/issues` (default path)

map '/romeo' do
    run Rack::ForNow::GitHub.new('will').with(Rack::ForNow::GHIssues)
end

@example Mount a GitHub Issues redirect under ‘/romeo/bugs`

map '/romeo' do
    run Rack::ForNow::GitHub.new('will').with(Rack::ForNow::GHIssues.on('bugs'))
end

@example Mount multiple services

map '/romeo' do
    run Rack::ForNow::GitHub.new('will').
        with(Rack::ForNow::GHIssues, Rack::ForNow::Rubydoc).
        with(Rack::ForNow::GHPages.on('tutorial')).
end

@see .on

@api public

@param [Service, Class] subservices the services to mount

@return [Service] the service itself

# File lib/rack/for_now.rb, line 53
def with(*subservices)
        subservices.each do |subservice|
                subservice = subservice.new if subservice.is_a? Class

                subservice.parent_service = self

                @subservices ||= {}
                @subservices[subservice.subpath] = subservice
        end

        return self
end