halcyon 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +5 -0
- data/lib/halcyon.rb +42 -24
- data/lib/halcyon/application.rb +134 -45
- data/lib/halcyon/application/hooks.rb +38 -0
- data/lib/halcyon/config.rb +252 -0
- data/lib/halcyon/config/file.rb +100 -0
- data/lib/halcyon/config/helpers.rb +180 -0
- data/lib/halcyon/config/paths.rb +73 -0
- data/lib/halcyon/controller.rb +168 -38
- data/lib/halcyon/exceptions.rb +3 -2
- data/lib/halcyon/runner.rb +8 -99
- data/lib/halcyon/runner/commands.rb +3 -4
- data/lib/rack/jsonp.rb +38 -0
- data/spec/halcyon/application_spec.rb +9 -15
- data/spec/halcyon/config_spec.rb +157 -0
- data/spec/halcyon/controller_spec.rb +70 -11
- data/spec/halcyon/halcyon_spec.rb +8 -8
- data/spec/halcyon/router_spec.rb +3 -3
- data/spec/halcyon/runner_spec.rb +10 -26
- data/spec/spec_helper.rb +34 -8
- data/support/generators/halcyon/templates/config/init.rb +42 -0
- data/support/generators/halcyon_flat/templates/app.rb +5 -12
- metadata +17 -5
- data/support/generators/halcyon/templates/config/config.yml +0 -36
- data/support/generators/halcyon/templates/config/init/environment.rb +0 -11
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Halcyon
|
4
|
+
class Config
|
5
|
+
|
6
|
+
# Class to assist with loading configuration from a file.
|
7
|
+
#
|
8
|
+
# Examples:
|
9
|
+
#
|
10
|
+
# Halcyon::Config::File.new(file_name_or_path).to_hash #=> {...}
|
11
|
+
#
|
12
|
+
class File
|
13
|
+
|
14
|
+
attr_accessor :path
|
15
|
+
attr_accessor :content
|
16
|
+
|
17
|
+
# Creates a profile with the default paths.
|
18
|
+
#
|
19
|
+
# * +file+ is the path to the file.
|
20
|
+
# * +filter_config+ specifies whether to filter the contents through ERB
|
21
|
+
# before parsing it.
|
22
|
+
#
|
23
|
+
def initialize(file, filter_config = true)
|
24
|
+
if ::File.exist?(file)
|
25
|
+
self.path = file
|
26
|
+
elsif ::File.exist?(Halcyon.paths.for(:config)/file)
|
27
|
+
self.path = Halcyon.paths.for(:config)/file
|
28
|
+
else
|
29
|
+
raise ArgumentError.new("Could not find #{self.path} (it does not exist).")
|
30
|
+
end
|
31
|
+
self.content = self.filter(::File.read(self.path), filter_config)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the loaded configuration file's contents parsed by the
|
35
|
+
# marshal format loader (defaulting to YAML, also providing JSON).
|
36
|
+
#
|
37
|
+
# Examples:
|
38
|
+
#
|
39
|
+
# p = Halcyon.paths.for(:config)/'config.yml'
|
40
|
+
# c = Halcyon::Config::File.new(p)
|
41
|
+
# c.to_hash #=> the contents of the config file parsed as YAML
|
42
|
+
# c.to_hash(:from_json) #=> same as above only parsed as JSON
|
43
|
+
# # parsing errors will happen if you try to use the wrong marshal
|
44
|
+
# # load method
|
45
|
+
#
|
46
|
+
def to_hash(from = :from_yaml)
|
47
|
+
case from
|
48
|
+
when :from_yaml
|
49
|
+
require 'yaml'
|
50
|
+
YAML.load(self.content)
|
51
|
+
when :from_json
|
52
|
+
JSON.parse(self.content)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Filters the contents through ERB.
|
57
|
+
#
|
58
|
+
def filter(content, filter_through_erb)
|
59
|
+
content = ERB.new(content).result if filter_through_erb
|
60
|
+
content
|
61
|
+
end
|
62
|
+
|
63
|
+
def inspect
|
64
|
+
"#<Halcyon::Config::File #{self.path}>"
|
65
|
+
end
|
66
|
+
|
67
|
+
class << self
|
68
|
+
|
69
|
+
# Provides a convenient way to load the configuration and return the
|
70
|
+
# appropriate hash contents.
|
71
|
+
#
|
72
|
+
def load(path)
|
73
|
+
file = File.new(path)
|
74
|
+
case path
|
75
|
+
when /\.(yaml|yml)/
|
76
|
+
file.to_hash
|
77
|
+
when /\.(json)/
|
78
|
+
file.to_hash(:from_json)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Loads the configuration file and parses it's contents as YAML.
|
83
|
+
# This is a shortcut method.
|
84
|
+
#
|
85
|
+
def load_from_yaml(path)
|
86
|
+
self.new(path).to_hash
|
87
|
+
end
|
88
|
+
|
89
|
+
# Loads the configuration file and parses it's contents as JSON.
|
90
|
+
# This is a shortcut method.
|
91
|
+
#
|
92
|
+
def load_from_json(path)
|
93
|
+
self.new(path).to_hash(:from_json)
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module Halcyon
|
2
|
+
class Config
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
# Extends the target class with the Configurable and Accessors helpers.
|
6
|
+
def self.included(target)
|
7
|
+
target.extend(Configurable)
|
8
|
+
target.extend(Accessors)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Provides several convenience accessors for configuration values,
|
12
|
+
# including these:
|
13
|
+
# * <tt>app</tt>: the app name
|
14
|
+
# * <tt>root</tt>: the application working directory
|
15
|
+
# * <tt>db</tt>: database configuration settings
|
16
|
+
#
|
17
|
+
module Accessors
|
18
|
+
|
19
|
+
# Accesses the <tt>app</tt> config value which is the constantized
|
20
|
+
# version of the application name (which can be set manually in the
|
21
|
+
# config file as <tt>app: NameOfApp</tt>, defaulting to a camel case
|
22
|
+
# version of the application directory name).
|
23
|
+
#
|
24
|
+
def app
|
25
|
+
self.config[:app] || ::File.dirname(self.root).camel_case
|
26
|
+
end
|
27
|
+
|
28
|
+
# Sets the application name.
|
29
|
+
#
|
30
|
+
def app=(name)
|
31
|
+
self.config[:app] = name
|
32
|
+
end
|
33
|
+
|
34
|
+
# Accesses the <tt>root</tt> config value which is the root of the
|
35
|
+
# current Halcyon application (usually <tt>Dir.pwd</tt>).
|
36
|
+
#
|
37
|
+
# Defaults to <tt>Dir.pwd</tt>
|
38
|
+
#
|
39
|
+
def root
|
40
|
+
self.config[:root] || Dir.pwd rescue Dir.pwd
|
41
|
+
end
|
42
|
+
|
43
|
+
# Sets the application root.
|
44
|
+
#
|
45
|
+
def root=(path)
|
46
|
+
self.config[:root] = path
|
47
|
+
end
|
48
|
+
|
49
|
+
# Accesses the <tt>db</tt> config value. Intended to contain the
|
50
|
+
# database configuration values for whichever ORM is used.
|
51
|
+
#
|
52
|
+
def db
|
53
|
+
self.config[:db]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sets the database settings.
|
57
|
+
#
|
58
|
+
def db=(config)
|
59
|
+
self.config[:db] = config
|
60
|
+
end
|
61
|
+
|
62
|
+
# Accesses the <tt>environment</tt> config value. Intended to contain
|
63
|
+
# the environment the application is running in.
|
64
|
+
#
|
65
|
+
# Defaults to the <tt>development</tt> environment.
|
66
|
+
#
|
67
|
+
def environment
|
68
|
+
self.config[:environment] || :development
|
69
|
+
end
|
70
|
+
alias_method :env, :environment
|
71
|
+
|
72
|
+
# Sets the environment config value.
|
73
|
+
#
|
74
|
+
def environment=(env)
|
75
|
+
self.config[:environment] = env.to_sym
|
76
|
+
end
|
77
|
+
alias_method :env=, :environment=
|
78
|
+
|
79
|
+
# Provides a proxy to the Halcyon::Config::Paths instance.
|
80
|
+
#
|
81
|
+
def paths
|
82
|
+
self.config[:paths]
|
83
|
+
end
|
84
|
+
|
85
|
+
# Provides a proxy to the hooks hash.
|
86
|
+
#
|
87
|
+
def hooks
|
88
|
+
self.config[:hooks]
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
# Provides dynamic creation of configuration attribute accessors.
|
94
|
+
#
|
95
|
+
module Configurable
|
96
|
+
|
97
|
+
# Defines a dynamic accessor for configuration attributes.
|
98
|
+
#
|
99
|
+
# Examples:
|
100
|
+
#
|
101
|
+
# Halcyon.configurable(:db)
|
102
|
+
# Halcyon.db = {...}
|
103
|
+
# Halcyon.config[:db] #=> {...}
|
104
|
+
# Halcyon.config[:db] = true
|
105
|
+
# Halcyon.db #=> true
|
106
|
+
#
|
107
|
+
def configurable(attribute)
|
108
|
+
eval <<-"end;"
|
109
|
+
def #{attribute.to_s}
|
110
|
+
Halcyon.config[:#{attribute.to_s}]
|
111
|
+
end
|
112
|
+
def #{attribute.to_s}=(value)
|
113
|
+
value = value.to_mash if value.is_a?(Hash)
|
114
|
+
Halcyon.config[:#{attribute.to_s}] = value
|
115
|
+
end
|
116
|
+
end;
|
117
|
+
end
|
118
|
+
alias_method :configurable_attr, :configurable
|
119
|
+
|
120
|
+
# Defines a dynamic reader for configuration attributes, accepting
|
121
|
+
# either a string or a block to perform the action.
|
122
|
+
#
|
123
|
+
# Examples:
|
124
|
+
#
|
125
|
+
# Halcyon.configurable_reader(:foo) do
|
126
|
+
# self.config[:foo].to_sym
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
# OR
|
130
|
+
#
|
131
|
+
# Halcyon.configurable_reader(:foo, "Halcyon.config[%s].to_sym")
|
132
|
+
#
|
133
|
+
def configurable_reader(attribute, code=nil, &block)
|
134
|
+
if block_given? and not code
|
135
|
+
Halcyon.class.send(:define_method, attribute.to_sym, block)
|
136
|
+
elsif code and not block_given?
|
137
|
+
Halcyon.class.send(:eval, <<-"end;")
|
138
|
+
def #{attribute.to_s}
|
139
|
+
#{code % [attribute.to_sym.inspect]}
|
140
|
+
end
|
141
|
+
end;
|
142
|
+
else
|
143
|
+
raise ArgumentError.new("Either a block or a code string should be supplied.")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
alias_method :configurable_attr_reader, :configurable_reader
|
147
|
+
|
148
|
+
# Defines a dynamic writer for configuration attributes, accepting
|
149
|
+
# either a string or a block to perform the action.
|
150
|
+
#
|
151
|
+
# Examples:
|
152
|
+
#
|
153
|
+
# Halcyon.configurable_writer(:foo) do |val|
|
154
|
+
# self.config[:foo] = val.to_sym
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# OR
|
158
|
+
#
|
159
|
+
# Halcyon.configurable_reader(:foo, "Halcyon.config[%s] = value.to_sym")
|
160
|
+
#
|
161
|
+
def configurable_writer(attribute, code=nil, &block)
|
162
|
+
if block_given? and not code
|
163
|
+
Halcyon.class.send(:define_method, :"#{attribute}=", block)
|
164
|
+
elsif code and not block_given?
|
165
|
+
Halcyon.class.send(:eval, <<-"end;")
|
166
|
+
def #{attribute.to_s}=(value)
|
167
|
+
#{code % [attribute.to_sym.inspect]}
|
168
|
+
end
|
169
|
+
end;
|
170
|
+
else
|
171
|
+
raise ArgumentError.new("Either a block or a code string should be supplied.")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
alias_method :configurable_attr_writer, :configurable_writer
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Halcyon
|
2
|
+
class Config
|
3
|
+
class Paths
|
4
|
+
|
5
|
+
attr_accessor :paths
|
6
|
+
|
7
|
+
# Creates a profile with the default paths.
|
8
|
+
def initialize(paths={})
|
9
|
+
self.paths = Mash.new(self.defaults.merge(paths))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Gets the path for the specified entity.
|
13
|
+
#
|
14
|
+
# Examples:
|
15
|
+
#
|
16
|
+
# Halcyon.paths.for(:log) #=> "/path/to/app/log/"
|
17
|
+
#
|
18
|
+
def for(key)
|
19
|
+
self.paths[key] or raise ArgumentError.new("Path is not defined")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Alias to <tt>for</tt>.
|
23
|
+
#
|
24
|
+
def [](key)
|
25
|
+
self.for(key)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Defines a path for the specified entity.
|
29
|
+
#
|
30
|
+
# Examples:
|
31
|
+
#
|
32
|
+
# Halcyon.paths.define(:tmp, Halcyon.root/'tmp')
|
33
|
+
#
|
34
|
+
# OR
|
35
|
+
#
|
36
|
+
# Halcyon.paths.define(:tmp => Halcyon.root/'tmp')
|
37
|
+
#
|
38
|
+
def define(key_or_hash, value = nil)
|
39
|
+
if key_or_hash.is_a?(Hash) and value.nil?
|
40
|
+
key_or_hash.keys.each do |key|
|
41
|
+
self.define(key, key_or_hash[key])
|
42
|
+
end
|
43
|
+
else
|
44
|
+
self.paths[key_or_hash] = value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Alias for <tt>define</tt>.
|
49
|
+
#
|
50
|
+
def []=(key, value)
|
51
|
+
self.define(key, value)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Default paths.
|
55
|
+
#
|
56
|
+
def defaults
|
57
|
+
{
|
58
|
+
:controller => Halcyon.root/'app',
|
59
|
+
:model => Halcyon.root/'app'/'models',
|
60
|
+
:lib => Halcyon.root/'lib',
|
61
|
+
:config => Halcyon.root/'config',
|
62
|
+
:init => Halcyon.root/'config'/'init',
|
63
|
+
:log => Halcyon.root/'log'
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def inspect
|
68
|
+
"#<Halcyon::Config::Paths #{self.paths.keys.join(', ')}>"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/halcyon/controller.rb
CHANGED
@@ -12,28 +12,27 @@ module Halcyon
|
|
12
12
|
# Sets the <tt>@env</tt> and <tt>@request</tt> instance variables, used by
|
13
13
|
# various helping methods.
|
14
14
|
# +env+ the request environment details
|
15
|
+
#
|
15
16
|
def initialize(env)
|
16
17
|
@env = env
|
17
18
|
@request = Rack::Request.new(@env)
|
18
19
|
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
raise NotImplemented.new
|
30
|
-
end
|
31
|
-
|
21
|
+
# Used internally.
|
22
|
+
#
|
23
|
+
# Dispatches the action specified, including all filters.
|
24
|
+
#
|
25
|
+
def _dispatch(action)
|
26
|
+
_run_filters(:before, action)
|
27
|
+
response = send(action)
|
28
|
+
_run_filters(:after, action)
|
29
|
+
response
|
32
30
|
end
|
33
31
|
|
34
32
|
# Returns the request params and the route params.
|
35
33
|
#
|
36
34
|
# Returns Hash:{route_params, get_params, post_params}.to_mash
|
35
|
+
#
|
37
36
|
def params
|
38
37
|
self.request.params.merge(self.env['halcyon.route']).to_mash
|
39
38
|
end
|
@@ -41,6 +40,7 @@ module Halcyon
|
|
41
40
|
# Returns any POST params, excluding GET and route params.
|
42
41
|
#
|
43
42
|
# Returns Hash:{...}.to_mash
|
43
|
+
#
|
44
44
|
def post
|
45
45
|
self.request.POST.to_mash
|
46
46
|
end
|
@@ -48,6 +48,7 @@ module Halcyon
|
|
48
48
|
# Returns any GET params, excluding POST and route params.
|
49
49
|
#
|
50
50
|
# Returns Hash:{...}.to_mash
|
51
|
+
#
|
51
52
|
def get
|
52
53
|
self.request.GET.to_mash
|
53
54
|
end
|
@@ -55,6 +56,7 @@ module Halcyon
|
|
55
56
|
# Returns query params (usually the GET params).
|
56
57
|
#
|
57
58
|
# Returns Hash:{...}.to_mash
|
59
|
+
#
|
58
60
|
def query_params
|
59
61
|
Rack::Utils.parse_query(self.env['QUERY_STRING']).to_mash
|
60
62
|
end
|
@@ -62,6 +64,7 @@ module Halcyon
|
|
62
64
|
# The path of the request URL.
|
63
65
|
#
|
64
66
|
# Returns String:/path/of/request
|
67
|
+
#
|
65
68
|
def uri
|
66
69
|
# special parsing is done to remove the protocol, host, and port that
|
67
70
|
# some Handlers leave in there. (Fixes inconsistencies.)
|
@@ -71,10 +74,77 @@ module Halcyon
|
|
71
74
|
# The request method.
|
72
75
|
#
|
73
76
|
# Returns Symbol:get|post|put|delete
|
77
|
+
#
|
74
78
|
def method
|
75
79
|
self.env['REQUEST_METHOD'].downcase.to_sym
|
76
80
|
end
|
77
81
|
|
82
|
+
# Returns the name of the controller in path form.
|
83
|
+
#
|
84
|
+
def self.controller_name
|
85
|
+
@controller_name ||= self.name.to_const_path
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns the name of the controller in path form.
|
89
|
+
#
|
90
|
+
def controller_name
|
91
|
+
self.class.controller_name
|
92
|
+
end
|
93
|
+
|
94
|
+
# Generates a URL based on the given name and passed
|
95
|
+
# options. Used with named routes and resources:
|
96
|
+
#
|
97
|
+
# url(:users) # => "/users"
|
98
|
+
# url(:admin_permissons) # => "/admin/permissions"
|
99
|
+
# url(:user, @user) # => "/users/1"
|
100
|
+
#
|
101
|
+
# Based on the identical method of Merb's controller.
|
102
|
+
#
|
103
|
+
def url(name, rparams={})
|
104
|
+
Halcyon::Application::Router.generate(name, rparams,
|
105
|
+
{ :controller => controller_name,
|
106
|
+
:action => method
|
107
|
+
}
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
111
|
+
#--
|
112
|
+
# Responders
|
113
|
+
#++
|
114
|
+
|
115
|
+
# Responds with the correct status and body specified.
|
116
|
+
#
|
117
|
+
# * +state+ a snake-case symbol of the status (ie, <tt>:not_found</tt>,
|
118
|
+
# <tt>:unprocessable_entity</tt>, or <tt>:forbidden</tt>)
|
119
|
+
# * +body+ the response body (if the default is insufficient)
|
120
|
+
#
|
121
|
+
# Examples:
|
122
|
+
#
|
123
|
+
# class Foos < Application
|
124
|
+
# def show
|
125
|
+
# if (foo = Foo[params[:id]])
|
126
|
+
# ok(foo)
|
127
|
+
# else
|
128
|
+
# status :not_found
|
129
|
+
# end
|
130
|
+
# end
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# The above example is the same as <tt>raise NotFound.new</tt>.
|
134
|
+
#
|
135
|
+
# If the state specified is not found, it will
|
136
|
+
# <tt>raise ServiceUnavailable.new</tt> (a <tt>503</tt> error). The error
|
137
|
+
# is then logged along with the backtrace.
|
138
|
+
#
|
139
|
+
def status(state, body = nil)
|
140
|
+
raise Halcyon::Exceptions.const_get(state.to_s.camel_case.to_sym).new(body)
|
141
|
+
rescue NameError => e
|
142
|
+
self.logger.error "Invalid status #{state.inspect} specified."
|
143
|
+
self.logger.error "Backtrace:\n" << e.backtrace.join("\n\t")
|
144
|
+
raise Halcyon::Exceptions::ServiceUnavailable.new
|
145
|
+
end
|
146
|
+
alias_method :error, :status
|
147
|
+
|
78
148
|
# Formats message into the standard success response hash, with a status of
|
79
149
|
# 200 (the standard success response).
|
80
150
|
# +body+ the body of the response
|
@@ -93,8 +163,9 @@ module Halcyon
|
|
93
163
|
# <tt>success</tt>
|
94
164
|
#
|
95
165
|
# Returns Hash:{:status=>200, :body=>body}
|
96
|
-
|
97
|
-
|
166
|
+
#
|
167
|
+
def ok(body='OK', headers = {})
|
168
|
+
{:status => 200, :body => body, :headers => headers}
|
98
169
|
end
|
99
170
|
alias_method :success, :ok
|
100
171
|
|
@@ -118,34 +189,93 @@ module Halcyon
|
|
118
189
|
# <tt>missing</tt>
|
119
190
|
#
|
120
191
|
# Returns Hash:{:status=>404, :body=>body}
|
121
|
-
|
122
|
-
|
192
|
+
#
|
193
|
+
def not_found(body='Not Found', headers = {})
|
194
|
+
{:status => 404, :body => body, :headers => headers}
|
123
195
|
end
|
124
196
|
alias_method :missing, :not_found
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
197
|
+
|
198
|
+
#--
|
199
|
+
# Filters
|
200
|
+
#++
|
201
|
+
|
202
|
+
class << self
|
203
|
+
|
204
|
+
# Creates +filters+ accessor method and initializes the +@filters+
|
205
|
+
# attribute with the necessary structure.
|
206
|
+
#
|
207
|
+
def filters
|
208
|
+
@filters ||= {:before => [], :after => []}
|
209
|
+
end
|
210
|
+
|
211
|
+
# Sets up filters for the method defined in the controllers.
|
212
|
+
#
|
213
|
+
# Examples
|
214
|
+
#
|
215
|
+
# class Foos < Application
|
216
|
+
# before :foo do
|
217
|
+
# #
|
218
|
+
# end
|
219
|
+
# after :blah, :only => [:foo]
|
220
|
+
# def foo
|
221
|
+
# # the block is called before the method is called
|
222
|
+
# # and the method is called after the method is called
|
223
|
+
# end
|
224
|
+
# private
|
225
|
+
# def blah
|
226
|
+
# #
|
227
|
+
# end
|
228
|
+
# end
|
229
|
+
#
|
230
|
+
# Options
|
231
|
+
# * +method_or_filter+ either the method to run before
|
232
|
+
#
|
233
|
+
def before method_or_filter, options={}, &block
|
234
|
+
_add_filter(:before, method_or_filter, options, block)
|
235
|
+
end
|
236
|
+
|
237
|
+
# See documentation for the +before+ method.
|
238
|
+
#
|
239
|
+
def after method_or_filter, options={}, &block
|
240
|
+
_add_filter(:after, method_or_filter, options, block)
|
241
|
+
end
|
242
|
+
|
243
|
+
# Used internally to save the filters, applied when called.
|
244
|
+
#
|
245
|
+
def _add_filter(where, method_or_filter, options, block)
|
246
|
+
self.filters[where] << [method_or_filter, options, block]
|
247
|
+
end
|
248
|
+
|
129
249
|
end
|
130
|
-
|
131
|
-
#
|
132
|
-
|
133
|
-
|
250
|
+
|
251
|
+
# Used internally.
|
252
|
+
#
|
253
|
+
# Applies the filters defined by the +before+ and +after+ class methods.
|
254
|
+
#
|
255
|
+
# +where+ specifies whether to apply <tt>:before</tt> or <tt>:after</tt>
|
256
|
+
# filters
|
257
|
+
# +action+ the routed action (for testing filter applicability)
|
258
|
+
#
|
259
|
+
def _run_filters(where, action)
|
260
|
+
self.class.filters[where].each do |(method_or_filter, options, block)|
|
261
|
+
if block
|
262
|
+
block.call(self) if _filter_condition_met?(method_or_filter, options, action)
|
263
|
+
else
|
264
|
+
send(method_or_filter) if _filter_condition_met?(method_or_filter, options, action)
|
265
|
+
end
|
266
|
+
end
|
134
267
|
end
|
135
|
-
|
136
|
-
#
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
{ :controller => controller_name,
|
147
|
-
:action => method
|
148
|
-
}
|
268
|
+
|
269
|
+
# Used internally.
|
270
|
+
#
|
271
|
+
# Tests whether a filter should be run for an action or not.
|
272
|
+
#
|
273
|
+
def _filter_condition_met?(method_or_filter, options, action)
|
274
|
+
(
|
275
|
+
options[:only] and options[:only].include?(action)) or
|
276
|
+
(options[:except] and !options[:except].include?(action)
|
277
|
+
) or (
|
278
|
+
method_or_filter == action
|
149
279
|
)
|
150
280
|
end
|
151
281
|
|