public
Description: The Git TextMate Bundle
Homepage: http://tim.theenchanter.com/
Clone URL: git://github.com/timcharper/git-tmbundle.git
git-tmbundle / Support / tmvc / lib / application_controller.rb
100644 176 lines (145 sloc) 4.309 kb
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
require 'stringio'
require 'thread'
 
class StringIO
  def retrieve_and_clear
    s = self.string
    self.string = ""
    s
  end
end
 
class ApplicationController
  include ApplicationHelper
  attr_accessor :params
  class << self
    attr_writer :layouts_conditions
    
    def filters
      @filters ||= {:before => [], :after => []}
    end
    
    def before_filter(method)
      filters[:before] << [method, nil]
    end
    
    def layouts_conditions
      @layouts_conditions ||= []
    end
    
    def layout(layout, conditions = {})
      layout = "/layouts/#{layout}" if layout && !layout.to_s.include?("/")
      raise "bad params!" unless conditions.is_a?(Hash)
      layouts_conditions << [layout, conditions]
    end
    
    def layout_for_action(action)
      return "/layouts/application" if layouts_conditions.empty?
      
      layouts_conditions.each do |layout, condition|
        if condition[:except]
          next if [condition[:only]].flatten.map{|c| c.to_s}.include?(action.to_s)
        end
        
        if condition[:only]
          next unless [condition[:only]].flatten.map{|c| c.to_s}.include?(action.to_s)
        end
        
        return layout
      end
      nil
    end
  end
  
  def initialize
    @output_buffer = StringIO.new
  end
  
  def puts(*args)
    @output_buffer.puts(*args)
  end
  
  def flush
    return if @capturing
    start_layout
    Object::STDOUT << @output_buffer.string
    Object::flush
    @output_buffer.truncate(0)
  end
  
  def start_layout
    return if @layout_rendered
    @layout_rendered = true
    this_actions_layout = self.class.layout_for_action(params[:action])
    return unless this_actions_layout
    
    current_body_output = @output_buffer.retrieve_and_clear
    render(this_actions_layout) { @layout_text_begin = @output_buffer.retrieve_and_clear }
    @layout_text_end = @output_buffer.retrieve_and_clear
    @output_buffer << @layout_text_begin << current_body_output
    @layout_text_begin = nil
  end
  
  def end_layout
    return unless @layout_rendered && @layout_text_end
    @output_buffer << @layout_text_end
    @layout_text_end = nil
  end
  
  def with_filters(&block)
    self.class.filters[:before].each do |method, options|
      return false unless send(method)
    end
    yield
    self.class.filters[:after].each do |method, options|
      return false unless send(method)
    end
  end
  
  def call(action, _params = {})
    at_exit { flush }
    self.params = _params
    params[:action] = action.to_s
    @output_buffer = params.delete(:__output_buffer__) if params[:__output_buffer__]
    with_filters { send(action) }
    flush
    end_layout
    flush
  end
  
  def self.call(action, params = {})
    new.call(action, params)
  end
  
  def render(__name__, __options__ = {}, &block)
    __name__ = "#{__name__}.html.erb" unless __name__.include?(".")
    __sub_dir__ = __name__.include?("/") ? "" : self.class.template_root
    __template_path__ = File.join( VIEWS_ROOT, __sub_dir__, __name__)
    ___template___ = File.read( __template_path__)
    
    if __options__[:locals]
      __v__ = __options__[:locals].values
      eval(__options__[:locals].keys * ", " + " = __v__.length == 1 ? __v__[0] : __v__")
    end
    
    __erb__ = ERBStdout.new(___template___, nil, "-", "@output_buffer")
    __erb__.filename = __template_path__
    __erb__.run(binding)
  end
  
  def render_component(params = {})
    dispatch(params.merge(:layout => false, :__output_buffer__ => @output_buffer))
  end
  
  def self.template_root
    to_s.gsub("::", "/").underscore.gsub(/_controller$/, "")
  end
  
  def content_for(name, &block)
    var_name = "@content_for_#{name}"
    content = instance_variable_get(var_name) || ""
    @capturing = true
    previous_content = @output_buffer.retrieve_and_clear
    yield
    content << @output_buffer.retrieve_and_clear
    @output_buffer << previous_content
    instance_variable_set(var_name, content)
    @capturing = false
    ""
  end
  
  def output_discard
    $exit_status = EXIT_DISCARD
  end
  
  def output_show_html
    $exit_status = EXIT_SHOW_HTML
  end
end
 
class Mutex
  def pass_lock
    Thread.pass
    lock
  end
  
  def unlock_pass
    Thread.pass
    unlock
  end
  
  def wait_for_lock
    pass_lock
    unlock_pass
  end
end