merb 0.3.4 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|