merb 0.3.4 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +206 -197
- data/Rakefile +12 -21
- data/bin/merb +1 -1
- data/examples/skeleton/Rakefile +6 -20
- data/examples/skeleton/dist/app/mailers/layout/application.erb +1 -0
- data/examples/skeleton/dist/conf/database.yml +23 -0
- data/examples/skeleton/dist/conf/environments/development.rb +1 -0
- data/examples/skeleton/dist/conf/environments/production.rb +1 -0
- data/examples/skeleton/dist/conf/environments/test.rb +1 -0
- data/examples/skeleton/dist/conf/merb.yml +32 -28
- data/examples/skeleton/dist/conf/merb_init.rb +16 -13
- data/examples/skeleton/dist/conf/router.rb +9 -9
- data/examples/skeleton/dist/schema/migrations/001_add_sessions_table.rb +2 -2
- data/lib/merb.rb +23 -18
- data/lib/merb/caching/fragment_cache.rb +3 -7
- data/lib/merb/caching/store/memcache.rb +20 -0
- data/lib/merb/core_ext/merb_array.rb +0 -0
- data/lib/merb/core_ext/merb_class.rb +44 -4
- data/lib/merb/core_ext/merb_enumerable.rb +43 -1
- data/lib/merb/core_ext/merb_hash.rb +200 -122
- data/lib/merb/core_ext/merb_kernel.rb +2 -0
- data/lib/merb/core_ext/merb_module.rb +41 -0
- data/lib/merb/core_ext/merb_numeric.rb +57 -5
- data/lib/merb/core_ext/merb_object.rb +172 -6
- data/lib/merb/generators/merb_app/merb_app.rb +15 -9
- data/lib/merb/merb_abstract_controller.rb +193 -0
- data/lib/merb/merb_constants.rb +26 -1
- data/lib/merb/merb_controller.rb +143 -234
- data/lib/merb/merb_dispatcher.rb +28 -20
- data/lib/merb/merb_drb_server.rb +2 -3
- data/lib/merb/merb_exceptions.rb +194 -49
- data/lib/merb/merb_handler.rb +34 -26
- data/lib/merb/merb_mail_controller.rb +200 -0
- data/lib/merb/merb_mailer.rb +33 -13
- data/lib/merb/merb_part_controller.rb +42 -0
- data/lib/merb/merb_plugins.rb +293 -0
- data/lib/merb/merb_request.rb +6 -4
- data/lib/merb/merb_router.rb +99 -65
- data/lib/merb/merb_server.rb +65 -21
- data/lib/merb/merb_upload_handler.rb +2 -1
- data/lib/merb/merb_view_context.rb +36 -15
- data/lib/merb/mixins/basic_authentication_mixin.rb +5 -5
- data/lib/merb/mixins/controller_mixin.rb +67 -28
- data/lib/merb/mixins/erubis_capture_mixin.rb +1 -8
- data/lib/merb/mixins/form_control_mixin.rb +280 -42
- data/lib/merb/mixins/render_mixin.rb +127 -45
- data/lib/merb/mixins/responder_mixin.rb +5 -7
- data/lib/merb/mixins/view_context_mixin.rb +260 -94
- data/lib/merb/session.rb +23 -0
- data/lib/merb/session/merb_ar_session.rb +28 -16
- data/lib/merb/session/merb_mem_cache_session.rb +108 -0
- data/lib/merb/session/merb_memory_session.rb +65 -20
- data/lib/merb/template/erubis.rb +22 -13
- data/lib/merb/template/haml.rb +5 -16
- data/lib/merb/template/markaby.rb +5 -3
- data/lib/merb/template/xml_builder.rb +17 -5
- data/lib/merb/test/merb_fake_request.rb +63 -0
- data/lib/merb/test/merb_multipart.rb +58 -0
- data/lib/tasks/db.rake +2 -0
- data/lib/tasks/merb.rake +20 -8
- metadata +24 -25
- data/examples/skeleton.tar +0 -0
@@ -1,20 +1,72 @@
|
|
1
1
|
class Numeric
|
2
|
+
|
3
|
+
# Converts a number to currency. Optionally, it allows localization of currency.
|
4
|
+
#
|
5
|
+
# 1.5.to_currency #=> "$1.50"
|
6
|
+
#
|
7
|
+
# You can also localize the symbol that appears before the number, the
|
8
|
+
# thousands delimiter, the decimal delimiter, and the symbol that appears
|
9
|
+
# after the number:
|
10
|
+
# 1.5.to_currency nil, ",", ".", "$USD" #=> "1.50$USD"
|
11
|
+
# 67_000.5.to_currency nil, ".", ",", "DM" #=> "67.000,50DM"
|
2
12
|
def to_currency(pre_symbol='$', thousands=',', decimal='.', post_symbol=nil) #:nodoc:
|
3
|
-
"#{pre_symbol}#{("%.2f" % self ).gsub(/(\d)(?=(?:\d{3})+(
|
13
|
+
"#{pre_symbol}#{("%.2f" % self ).gsub(".", decimal).gsub(/(\d)(?=(?:\d{3})+(?:$|[\\#{decimal}]))/,"\\1#{thousands}")}#{post_symbol}"
|
4
14
|
end
|
5
15
|
|
16
|
+
# Divides the number by 1,000,000
|
17
|
+
#
|
18
|
+
# 2.microseconds #=> 2.0e-06
|
6
19
|
def microseconds() Float(self * (10 ** -6)) end
|
20
|
+
# Divides the number by 1,000
|
21
|
+
#
|
22
|
+
# 2.milliseconds #=> 0.002
|
7
23
|
def milliseconds() Float(self * (10 ** -3)) end
|
24
|
+
# Returns the same number as is passed in
|
25
|
+
#
|
26
|
+
# 2.seconds #=> 2
|
8
27
|
def seconds() self end
|
28
|
+
# Multiplies the number by 60
|
29
|
+
#
|
30
|
+
# 2.minutes #=> 120
|
9
31
|
def minutes() 60 * seconds end
|
32
|
+
# Multiplies the number by 60 minutes
|
33
|
+
#
|
34
|
+
# 2.hours #=> 7200
|
10
35
|
def hours() 60 * minutes end
|
36
|
+
# Multiples the number by 24 hours
|
37
|
+
#
|
38
|
+
# 2.days #=> 172800
|
11
39
|
def days() 24 * hours end
|
40
|
+
# Multiples the number by 7 days
|
41
|
+
#
|
42
|
+
# 2.weeks #=> 1209600
|
12
43
|
def weeks() 7 * days end
|
44
|
+
# Multiples the number by 30 days
|
45
|
+
#
|
46
|
+
# 2.months #=> 5184000
|
13
47
|
def months() 30 * days end
|
48
|
+
# Multiplies the number by 365 days
|
49
|
+
#
|
50
|
+
# 2.years #=> 63072000
|
14
51
|
def years() 365 * days end
|
52
|
+
# Multiplies the number by 10 years
|
53
|
+
#
|
54
|
+
# 2.decades #=> 630720000
|
15
55
|
def decades() 10 * years end
|
16
|
-
|
17
|
-
%w{ microseconds milliseconds seconds minutes hours days weeks months years decades
|
18
|
-
}.each{ |m| mm = m.chop; alias_method mm, m }
|
19
56
|
|
20
|
-
|
57
|
+
# Each of the time extensions also works in the singular:
|
58
|
+
#
|
59
|
+
# 1.day #=> 86400
|
60
|
+
# 1.hour #=> 3600
|
61
|
+
alias_method :microsecond, :microseconds
|
62
|
+
alias_method :millisecond, :milliseconds
|
63
|
+
alias_method :second, :seconds
|
64
|
+
alias_method :minute, :minutes
|
65
|
+
alias_method :hour, :hours
|
66
|
+
alias_method :day, :days
|
67
|
+
alias_method :week, :weeks
|
68
|
+
alias_method :month, :months
|
69
|
+
alias_method :year, :years
|
70
|
+
alias_method :decade, :decades
|
71
|
+
|
72
|
+
end
|
@@ -1,27 +1,193 @@
|
|
1
1
|
class Object
|
2
2
|
|
3
|
+
# Yields <tt>value</tt> to the passed block and returns the value.
|
4
|
+
# The object passed in as the value parameter is also passed to the block
|
5
|
+
# as a parameter.
|
6
|
+
#
|
7
|
+
# returning({}) do |hsh|
|
8
|
+
# hsh.merge!((:bar => :baz))
|
9
|
+
# end #=> {:bar => :baz}
|
3
10
|
def returning(value)
|
4
11
|
yield(value)
|
5
12
|
value
|
6
13
|
end
|
7
14
|
|
15
|
+
# Extracts the singleton class, so that metaprogramming can be done on it.
|
16
|
+
#
|
17
|
+
# Let's look at two code snippets:
|
18
|
+
#
|
19
|
+
# class MyString < String; end
|
20
|
+
#
|
21
|
+
# MyString.instance_eval do
|
22
|
+
# define_method :foo do
|
23
|
+
# puts self
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# MyString.meta_class.instance_eval do
|
28
|
+
# define_method :bar do
|
29
|
+
# puts self
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# def String.add_meta_var(var)
|
34
|
+
# self.meta_class.instance_eval do
|
35
|
+
# define_method var do
|
36
|
+
# puts "HELLO"
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# MyString.new("Hello").foo #=> "Hello"
|
42
|
+
# MyString.new("Hello").bar #=> NoMethodError: undefined method `bar' for "Hello":MyString
|
43
|
+
# MyString.foo #=> NoMethodError: undefined method `foo' for MyString:Class
|
44
|
+
# MyString.bar #=> MyString
|
45
|
+
# String.bar #=> NoMethodError: undefined method `bar' for String:Class
|
46
|
+
#
|
47
|
+
# MyString.add_meta_var(:x)
|
48
|
+
# MyString.x #=> HELLO
|
49
|
+
#
|
50
|
+
# As you can see, using #meta_class allows you to execute code (and here, define
|
51
|
+
# a method) on the metaclass itself. It also allows you to define class methods that can
|
52
|
+
# be run on subclasses, and then be able to execute code on the metaclass of the subclass
|
53
|
+
# (here MyString).
|
54
|
+
#
|
55
|
+
# In this case, we were able to define a class method (add_meta_var) on String that was
|
56
|
+
# executable by the MyString subclass. It was then able to define a method on the subclass
|
57
|
+
# by adding it to the MyString metaclass.
|
58
|
+
#
|
59
|
+
# For more information, you can check out _why's excellent article at:
|
60
|
+
# http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
|
8
61
|
def meta_class() class << self; self end end
|
9
62
|
|
63
|
+
# Runs instance_eval on the metaclass (see Object#meta_class).
|
64
|
+
#
|
65
|
+
# String.meta_eval do
|
66
|
+
# define_method :zoo do
|
67
|
+
# puts "zoo"
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# String.zoo # => "zoo"
|
10
72
|
def meta_eval(&blk) meta_class.instance_eval( &blk ) end
|
11
73
|
|
74
|
+
# Defines a method on the metaclass (see Object#meta_class).
|
75
|
+
#
|
76
|
+
# String.meta_def :zoo do
|
77
|
+
# puts "zoo"
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# String.zoo #=> "zoo"
|
81
|
+
#
|
82
|
+
# If the class inherits from another class, it will only be defined
|
83
|
+
# on the direct class meta_def is called on.
|
84
|
+
#
|
85
|
+
# class Foo; end
|
86
|
+
# class Bar < Foo; end
|
87
|
+
# class Baz < Foo; end
|
88
|
+
#
|
89
|
+
# Bar.meta_def :q do; "Q"; end
|
90
|
+
# Foo.q #=> undefined method `r' for Foo:Class
|
91
|
+
# Bar.q #=> "Q"
|
92
|
+
# Baz.q #=> undefined method `r' for Baz:Class
|
93
|
+
#
|
94
|
+
# See Object#class_def for a comprehensive example containing meta_def
|
12
95
|
def meta_def(name, &blk) meta_eval { define_method name, &blk } end
|
13
96
|
|
97
|
+
# Defines a method on new instances of the class.
|
98
|
+
#
|
99
|
+
# String.class_def :zoo do
|
100
|
+
# puts "zoo"
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# "HELLO".zoo #=> "zoo"
|
104
|
+
#
|
105
|
+
# In combination with meta_def, you can do some pretty powerful
|
106
|
+
# things:
|
107
|
+
#
|
108
|
+
# require 'merb_object'
|
109
|
+
# class Foo
|
110
|
+
# def self.var
|
111
|
+
# @var
|
112
|
+
# end
|
113
|
+
# def self.make_var baz
|
114
|
+
# attr_accessor baz
|
115
|
+
# meta_def baz do |val|
|
116
|
+
# @var = val
|
117
|
+
# end
|
118
|
+
# class_def :initialize do
|
119
|
+
# instance_variable_set("@#{baz}", self.class.var)
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
# It might look a bit hairy, but here are some results that
|
125
|
+
# may help:
|
126
|
+
#
|
127
|
+
# class Bar < Foo
|
128
|
+
# make_var :foo
|
129
|
+
# foo "FOO"
|
130
|
+
# end
|
131
|
+
#
|
132
|
+
# Bar.new.foo #=> "FOO"
|
133
|
+
#
|
134
|
+
# Essentially, what's happening is that Foo.make_var has the
|
135
|
+
# following effects when some symbol (:foo) is passed in:
|
136
|
+
# * Adds a new :foo accessor (returning @foo)
|
137
|
+
# * Adds a new foo method on the **class**, allowing you to set
|
138
|
+
# a default value.
|
139
|
+
# * Sets @foo to that default value when new objects are
|
140
|
+
# initialized.
|
141
|
+
#
|
142
|
+
# In the case of the Bar class, the following occurred:
|
143
|
+
# * make_var :foo created a new :foo accessor
|
144
|
+
# * foo "FOO" set the default value of @foo to "FOO"
|
145
|
+
# * Bar.new created a new Bar object containing the
|
146
|
+
# instance variable @foo containing the default value
|
147
|
+
# "FOO"
|
14
148
|
def class_def name, &blk
|
15
|
-
|
149
|
+
class_eval { define_method name, &blk }
|
16
150
|
end
|
17
151
|
|
152
|
+
# Returns true if:
|
153
|
+
# * it's an empty array
|
154
|
+
# * !self evaluates to true
|
155
|
+
#
|
156
|
+
# [].blank? #=> true
|
157
|
+
# nil.blank? #=> true
|
158
|
+
# false.blank? #=> true
|
159
|
+
# [nil].blank? #=> false
|
18
160
|
def blank?
|
19
|
-
if
|
20
|
-
|
21
|
-
|
22
|
-
|
161
|
+
if respond_to?(:empty?) && respond_to?(:strip)
|
162
|
+
empty? or strip.empty?
|
163
|
+
elsif respond_to?(:empty?)
|
164
|
+
empty?
|
165
|
+
else
|
166
|
+
!self
|
167
|
+
end
|
23
168
|
end
|
24
169
|
|
170
|
+
def full_const_get(name)
|
171
|
+
list = name.split("::")
|
172
|
+
obj = Object
|
173
|
+
list.each {|x| obj = obj.const_get(x) }
|
174
|
+
obj
|
175
|
+
end
|
176
|
+
|
177
|
+
# An elegant way to refactor out common options
|
178
|
+
#
|
179
|
+
# with_options :order => 'created_at', :class_name => 'Comment' do |post|
|
180
|
+
# post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all
|
181
|
+
# post.has_many :unapproved_comments, :conditions => ['approved = ?', false]
|
182
|
+
# post.has_many :all_comments
|
183
|
+
# end
|
184
|
+
#
|
185
|
+
# Can also be used with an explicit reciever:
|
186
|
+
#
|
187
|
+
# map.with_options :controller => "people" do |people|
|
188
|
+
# people.connect "/people", :action => "index"
|
189
|
+
# people.connect "/people/:id", :action => "show"
|
190
|
+
# end
|
25
191
|
def with_options(options)
|
26
192
|
yield Merb::OptionMerger.new(self, options)
|
27
193
|
end
|
@@ -51,4 +217,4 @@ module Merb
|
|
51
217
|
end
|
52
218
|
end
|
53
219
|
end
|
54
|
-
end
|
220
|
+
end
|
@@ -1,17 +1,10 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'find'
|
3
3
|
|
4
|
-
begin
|
5
|
-
require 'archive/tar/minitar'
|
6
|
-
rescue LoadError
|
7
|
-
puts "You must gem install archive-tar-minitar to use the merb app generator"
|
8
|
-
exit!
|
9
|
-
end
|
10
|
-
|
11
4
|
module Merb
|
12
5
|
|
13
6
|
class AppGenerator
|
14
|
-
|
7
|
+
SKELETON_DIR = File.expand_path File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'examples/skeleton')
|
15
8
|
|
16
9
|
def self.run(path)
|
17
10
|
@path = path
|
@@ -23,7 +16,20 @@ module Merb
|
|
23
16
|
|
24
17
|
puts "Copying skeleton app to '#@path'"
|
25
18
|
# Unpacks 'test.tar' to 'x', creating 'x' if necessary.
|
26
|
-
|
19
|
+
FileUtils.cp_r(SKELETON_DIR, @path)
|
20
|
+
Find.find(@path) do |f|
|
21
|
+
FileUtils.rm_rf(f) if /\.svn$/ =~ f
|
22
|
+
end
|
23
|
+
public_path = File.expand_path(File.join(@path, "dist", "public"))
|
24
|
+
mailer_path = File.expand_path(File.join(@path, "dist", "app", "mailers"))
|
25
|
+
app_path = File.expand_path(File.join(@path, "dist", "app"))
|
26
|
+
FileUtils.mkdir_p(["#{mailer_path}/helpers",
|
27
|
+
"#{mailer_path}/views",
|
28
|
+
"#{@path}/log",
|
29
|
+
"#{app_path}/models",
|
30
|
+
"#{public_path}/javascripts",
|
31
|
+
"#{public_path}/stylesheets",
|
32
|
+
"#{public_path}/images"])
|
27
33
|
puts 'Done'
|
28
34
|
end
|
29
35
|
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/mixins/render_mixin'
|
2
|
+
|
3
|
+
module Merb
|
4
|
+
|
5
|
+
class AbstractController
|
6
|
+
include Merb::RenderMixin
|
7
|
+
|
8
|
+
class_inheritable_accessor :before_filters
|
9
|
+
class_inheritable_accessor :after_filters
|
10
|
+
|
11
|
+
# Holds internal execution times. Prefaced with an underscore to not
|
12
|
+
# conflict with user-defined controller instance variables.
|
13
|
+
attr_accessor :_benchmarks
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
@_benchmarks = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def dispatch(action=:to_s)
|
20
|
+
caught = catch(:halt) do
|
21
|
+
start = Time.now
|
22
|
+
result = call_filters(before_filters)
|
23
|
+
@_benchmarks[:before_filters_time] = Time.now - start if before_filters
|
24
|
+
result
|
25
|
+
end
|
26
|
+
@_body = case caught
|
27
|
+
when :filter_chain_completed
|
28
|
+
call_action(action)
|
29
|
+
when String
|
30
|
+
caught
|
31
|
+
when nil
|
32
|
+
filters_halted
|
33
|
+
when Symbol
|
34
|
+
send(caught)
|
35
|
+
when Proc
|
36
|
+
caught.call(self)
|
37
|
+
else
|
38
|
+
raise MerbControllerError, "The before filter chain is broken dude. wtf?"
|
39
|
+
end
|
40
|
+
start = Time.now
|
41
|
+
call_filters(after_filters)
|
42
|
+
@_benchmarks[:after_filters_time] = Time.now - start if after_filters
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def call_action(action)
|
48
|
+
send(action)
|
49
|
+
end
|
50
|
+
|
51
|
+
# calls a filter chain according to rules.
|
52
|
+
def call_filters(filter_set)
|
53
|
+
(filter_set || []).each do |(filter, rule)|
|
54
|
+
ok = false
|
55
|
+
if rule.has_key?(:only)
|
56
|
+
if rule[:only].include?(params[:action].intern)
|
57
|
+
ok = true
|
58
|
+
end
|
59
|
+
elsif rule.has_key?(:exclude)
|
60
|
+
if !rule[:exclude].include?(params[:action].intern)
|
61
|
+
ok = true
|
62
|
+
end
|
63
|
+
else
|
64
|
+
ok = true
|
65
|
+
end
|
66
|
+
if ok
|
67
|
+
case filter
|
68
|
+
when Symbol, String
|
69
|
+
send(filter)
|
70
|
+
when Proc
|
71
|
+
filter.call(self)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
return :filter_chain_completed
|
76
|
+
end
|
77
|
+
|
78
|
+
def finalize_session
|
79
|
+
# noop
|
80
|
+
end
|
81
|
+
|
82
|
+
def setup_session
|
83
|
+
# noop
|
84
|
+
end
|
85
|
+
|
86
|
+
# override this method on your controller classes to specialize
|
87
|
+
# the output when the filter chain is halted.
|
88
|
+
def filters_halted
|
89
|
+
"<html><body><h1>Filter Chain Halted!</h1></body></html>"
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
# #before is a class method that allows you to specify before filters in
|
94
|
+
# your controllers. Filters can either be a symbol or string that
|
95
|
+
# corresponds to a method name to call, or a proc object. if it is a method
|
96
|
+
# name that method will be called and if it is a proc it will be called
|
97
|
+
# with an argument of self where self is the current controller object.
|
98
|
+
# When you use a proc as a filter it needs to take one parameter.
|
99
|
+
#
|
100
|
+
# examples:
|
101
|
+
# before :some_filter
|
102
|
+
# before :authenticate, :exclude => [:login, :signup]
|
103
|
+
# before Proc.new {|c| c.some_method }, :only => :foo
|
104
|
+
#
|
105
|
+
# You can use either :only => :actionname or :exclude => [:this, :that]
|
106
|
+
# but not both at once. :only will only run before the listed actions
|
107
|
+
# and :exclude will run for every action that is not listed.
|
108
|
+
#
|
109
|
+
# Merb's before filter chain is very flexible. To halt the filter chain you
|
110
|
+
# use throw :halt. If throw is called with only one argument of :halt the
|
111
|
+
# return of the method filters_halted will be what is rendered to the view.
|
112
|
+
# You can overide filters_halted in your own controllers to control what it
|
113
|
+
# outputs. But the throw construct is much more powerful then just that.
|
114
|
+
# throw :halt can also take a second argument. Here is what that second arg
|
115
|
+
# can be and the behavior each type can have:
|
116
|
+
#
|
117
|
+
# * String:
|
118
|
+
# when the second arg is a string then that string will be what
|
119
|
+
# is rendered to the browser. Since merb's render method returns
|
120
|
+
# a string you can render a template or just use a plain string:
|
121
|
+
#
|
122
|
+
# throw :halt, "You don't have permissions to do that!"
|
123
|
+
# throw :halt, render(:action => :access_denied)
|
124
|
+
#
|
125
|
+
# * Symbol:
|
126
|
+
# If the second arg is a symbol then the method named after that
|
127
|
+
# symbol will be called
|
128
|
+
#
|
129
|
+
# throw :halt, :must_click_disclaimer
|
130
|
+
#
|
131
|
+
# * Proc:
|
132
|
+
#
|
133
|
+
# If the second arg is a Proc, it will be called and its return
|
134
|
+
# value will be what is rendered to the browser:
|
135
|
+
#
|
136
|
+
# throw :halt, Proc.new {|c| c.access_denied }
|
137
|
+
# throw :halt, Proc.new {|c| Tidy.new(c.index) }
|
138
|
+
#
|
139
|
+
def self.before(filter, opts={})
|
140
|
+
raise(ArgumentError,
|
141
|
+
"You can specify either :only or :exclude but
|
142
|
+
not both at the same time for the same filter."
|
143
|
+
) if opts.has_key?(:only) && opts.has_key?(:exclude)
|
144
|
+
|
145
|
+
opts = shuffle_filters!(opts)
|
146
|
+
|
147
|
+
case filter
|
148
|
+
when Symbol, String, Proc
|
149
|
+
(self.before_filters ||= []) << [filter, opts]
|
150
|
+
else
|
151
|
+
raise(ArgumentError,
|
152
|
+
'filters need to be either a Symbol, String or a Proc'
|
153
|
+
)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# #after is a class method that allows you to specify after filters in your
|
158
|
+
# controllers. Filters can either be a symbol or string that corresponds to
|
159
|
+
# a method name or a proc object. If it is a method name that method will
|
160
|
+
# be called and if it is a proc it will be called with an argument of self.
|
161
|
+
# When you use a proc as a filter it needs to take one parameter. You can
|
162
|
+
# gain access to the response body like so: after Proc.new {|c|
|
163
|
+
# Tidy.new(c.body) }, :only => :index
|
164
|
+
def self.after(filter, opts={})
|
165
|
+
raise(ArgumentError,
|
166
|
+
"You can specify either :only or :exclude but
|
167
|
+
not both at the same time for the same filter."
|
168
|
+
) if opts.has_key?(:only) && opts.has_key?(:exclude)
|
169
|
+
|
170
|
+
opts = shuffle_filters!(opts)
|
171
|
+
|
172
|
+
case filter
|
173
|
+
when Symbol, Proc, String
|
174
|
+
(self.after_filters ||= []) << [filter, opts]
|
175
|
+
else
|
176
|
+
raise(ArgumentError,
|
177
|
+
'After filters need to be either a Symbol, String or a Proc'
|
178
|
+
)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.shuffle_filters!(opts={})
|
183
|
+
if opts[:only] && opts[:only].is_a?(Symbol)
|
184
|
+
opts[:only] = [opts[:only]]
|
185
|
+
end
|
186
|
+
if opts[:exclude] && opts[:exclude].is_a?(Symbol)
|
187
|
+
opts[:exclude] = [opts[:exclude]]
|
188
|
+
end
|
189
|
+
return opts
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|