class Railroader::ControllerProcessor

Processes controller. Results are put in tracker.controllers

Constants

FORMAT_HTML

Public Class Methods

new(app_tree, tracker) click to toggle source
Calls superclass method Railroader::BaseProcessor::new
# File lib/railroader/processors/controller_processor.rb, line 11
def initialize app_tree, tracker
  super(tracker)
  @app_tree = app_tree
  @current_class = nil
  @current_method = nil
  @current_module = nil
  @visibility = :public
  @file_name = nil
  @concerns = Set.new
end

Public Instance Methods

add_fake_filter(exp) click to toggle source

This is to handle before_filter do |controller| … end

We build a new method and process that the same way as usual methods and filters.

# File lib/railroader/processors/controller_processor.rb, line 191
def add_fake_filter exp
  unless @current_class
    Railroader.debug "Skipping before_filter outside controller: #{exp}"
    return exp
  end

  filter_name = ("fake_filter" + rand.to_s[/\d+$/]).to_sym
  args = exp.block_call.arglist
  args.insert(1, Sexp.new(:lit, filter_name))
  before_filter_call = make_call(nil, :before_filter, args)

  if exp.block_args.length > 1
    block_variable = exp.block_args[1]
  else
    block_variable = :temp
  end

  if node_type? exp.block, :block
    block_inner = exp.block[1..-1]
  else
    block_inner = [exp.block]
  end

  # Build Sexp for filter method
  body = Sexp.new(:lasgn,
                  block_variable,
                  Sexp.new(:call, Sexp.new(:const, @current_class.name), :new))

  filter_method = Sexp.new(:defn, filter_name, Sexp.new(:args), body).concat(block_inner).line(exp.line)

  vis = @visibility
  @visibility = :private
  process_defn filter_method
  @visibility = vis
  process before_filter_call
  exp
end
add_lambda_filter(exp) click to toggle source
# File lib/railroader/processors/controller_processor.rb, line 229
def add_lambda_filter exp
  # Convert into regular block call
  e = exp.dup
  lambda_node = e.delete_at(3)
  result = Sexp.new(:iter, e).line(e.line)

  # Add block arguments
  if node_type? lambda_node[2], :args
    result << lambda_node[2].last
  else
    result << s(:args)
  end

  # Add block contents
  if sexp? lambda_node[3]
    result << lambda_node[3]
  end

  add_fake_filter result
end
process_call(exp) click to toggle source

Look for specific calls inside the controller

# File lib/railroader/processors/controller_processor.rb, line 77
def process_call exp
  return exp if process_call_defn? exp

  target = exp.target
  if sexp? target
    target = process target
  end

  method = exp.method
  first_arg = exp.first_arg
  last_arg = exp.last_arg

  # Methods called inside class definition
  # like attr_* and other settings
  if @current_method.nil? and target.nil? and @current_class
    if first_arg.nil? # No args
      case method
      when :private, :protected, :public
        @visibility = method
      when :protect_from_forgery
        @current_class.options[:protect_from_forgery] = true
      else
        # ??
      end
    else
      case method
      when :include
        if @current_class
          concern = class_name(first_arg)
          @current_class.add_include concern
          process_concern concern
        end
      when :before_filter, :append_before_filter, :before_action, :append_before_action
        if node_type? exp.first_arg, :iter
          add_lambda_filter exp
        else
          @current_class.add_before_filter exp
        end
      when :prepend_before_filter, :prepend_before_action
        if node_type? exp.first_arg, :iter
          add_lambda_filter exp
        else
          @current_class.prepend_before_filter exp
        end
      when :skip_before_filter, :skip_filter, :skip_before_action, :skip_action_callback
        @current_class.skip_filter exp
      when :layout
        if string? last_arg
          # layout "some_layout"

          name = last_arg.value.to_s
          if @app_tree.layout_exists?(name)
            @current_class.layout = "layouts/#{name}"
          else
            Railroader.debug "[Notice] Layout not found: #{name}"
          end
        elsif node_type? last_arg, :nil, :false
          # layout :false or layout nil
          @current_class.layout = false
        end
      else
        @current_class.add_option method, exp
      end
    end

    exp
  elsif target == nil and method == :render
    make_render exp
  elsif exp == FORMAT_HTML and context[1] != :iter
    # This is an empty call to
    # format.html
    # Which renders the default template if no arguments
    # Need to make more generic, though.
    call = Sexp.new :render, :default, @current_method
    call.line(exp.line)
    call
  else
    call = make_call target, method, process_all!(exp.args)
    call.line(exp.line)
    call
  end
end
process_class(exp) click to toggle source

s(:class, NAME, PARENT, s(:scope …))

# File lib/railroader/processors/controller_processor.rb, line 29
def process_class exp
  name = class_name(exp.class_name)
  parent = class_name(exp.parent_name)

  # If inside a real controller, treat any other classes as libraries.
  # But if not inside a controller already, then the class may include
  # a real controller, so we can't take this shortcut.
  if @current_class and @current_class.name.to_s.end_with? "Controller"
    Railroader.debug "[Notice] Treating inner class as library: #{name}"
    Railroader::LibraryProcessor.new(@tracker).process_library exp, @file_name
    return exp
  end

  if not name.to_s.end_with? "Controller"
    Railroader.debug "[Notice] Adding noncontroller as library: #{name}"
    # Set the class to be a module in order to get the right namespacing.
    # Add class to libraries, in case it is needed later (e.g. it's used
    # as a parent class for a controller.)
    # However, still want to process it in this class, so have to set
    # @current_class to this not-really-a-controller thing.
    process_module exp, parent

    return exp
  end

  handle_class(exp, @tracker.controllers, Railroader::Controller) do
    set_layout_name
  end

  exp
end
process_concern(concern_name) click to toggle source
# File lib/railroader/processors/controller_processor.rb, line 65
def process_concern concern_name
  return unless @current_class

  if mod = @tracker.find_class(concern_name)
    if mod.options[:included] and not @concerns.include? concern_name
      @concerns << concern_name
      process mod.options[:included].deep_clone
    end
  end
end
process_controller(src, file_name = nil) click to toggle source

Use this method to process a Controller

# File lib/railroader/processors/controller_processor.rb, line 23
def process_controller src, file_name = nil
  @file_name = file_name
  process src
end
process_iter(exp) click to toggle source

Look for before_filters and add fake ones if necessary

Calls superclass method Railroader::BaseProcessor#process_iter
# File lib/railroader/processors/controller_processor.rb, line 161
def process_iter exp
  if @current_method.nil? and call? exp.block_call
    block_call_name = exp.block_call.method

    if block_call_name == :before_filter or block_call_name == :before_action
      add_fake_filter exp
    else
      super
    end
  else
    super
  end
end
process_module(exp, parent = nil) click to toggle source
# File lib/railroader/processors/controller_processor.rb, line 61
def process_module exp, parent = nil
  handle_module exp, Railroader::Controller, parent
end
set_layout_name() click to toggle source

Sets default layout for renders inside Controller

# File lib/railroader/processors/controller_processor.rb, line 176
def set_layout_name
  return if @current_class.layout

  name = underscore(@current_class.name.to_s.split("::")[-1].gsub("Controller", ''))

  # There is a layout for this Controller
  if @app_tree.layout_exists?(name)
    @current_class.layout = "layouts/#{name}"
  end
end