C0 code coverage information
Generated on Sat Feb 02 17:44:25 +0100 2008 with rcov 0.8.1.2
Code reported as executed by Ruby looks like this...
and this: this line is also marked as covered.
Lines considered as run by rcov, but not reported by Ruby, look like this,
and this: these lines were inferred by rcov (using simple heuristics).
Finally, here's a line marked as not executed.
1 # Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
2 # All files in this distribution are subject to the terms of the Ruby license.
3
4 module Ramaze
5 class Controller
6 FILTER = [ :cached, :routed, :default ] unless defined?(FILTER)
7
8 class << self
9
10 # Resolve an absolute path in the application by passing it to each
11 # element of Ramaze::Controller::FILTER.
12 # Elements in exclude_filter are excluded from handling.
13 # If an element does not respond to call it will be sent to self
14 # instead, in either case with path as argument.
15
16 def resolve(path, *exclude_filter)
17 (FILTER - exclude_filter.flatten).each do |filter|
18 answer =
19 if filter.respond_to?(:call)
20 filter.call(path)
21 else
22 send(filter.to_s, path)
23 end
24 return answer if answer
25 end
26
27 raise_no_filter(path)
28 end
29
30 # Default element of FILTER.
31 # Looks up the path in Cache.resolved and returns it if found.
32
33 def cached(path)
34 if found = Cache.resolved[path]
35 if found.respond_to?(:relaxed_hash)
36 return found.dup
37 else
38 Inform.warn("Found faulty `#{path}' in Cache.resolved, deleting it for sanity.")
39 Cache.resolved.delete path
40 end
41 end
42
43 nil
44 end
45
46 # Routing filter
47 # Loops over Route.trait[:routes] to find a matching route
48
49 def routed(path)
50 Route.trait[:routes].each do |key, val|
51 if key.is_a?(Regexp)
52 if md = path.match(key)
53 new_path = val % md.to_a[1..-1]
54 return resolve(new_path, :routed)
55 end
56
57 elsif val.respond_to?(:call)
58 if new_path = val.call(path, request)
59 return resolve(new_path, :routed)
60 end
61
62 elsif val.is_a?(String)
63 return resolve(val, :routed) if path == key
64
65 else
66 Inform.error "Invalid route #{key} => #{val}"
67 end
68 end
69
70 nil
71 end
72
73 # Default element of FILTER.
74 # The default handler that tries to find the best match for the given
75 # path in terms of Controller/method/template and given arguments.
76 # If a match is found it will be cached for further use.
77
78 def default(path)
79 mapping = Global.mapping
80 controllers = Global.controllers
81
82 raise_no_controller(path) if controllers.empty? or mapping.empty?
83
84 patterns = Cache.patterns[path] ||= pattern_for(path)
85 first_controller = nil
86
87 patterns.each do |controller, method, params|
88 if controller = mapping[controller]
89 first_controller ||= controller
90
91 action = controller.resolve_action(method, *params)
92 template = action.template
93
94 valid_action = (action.method or (params.empty? && template))
95
96 if valid_action
97 Cache.resolved[path] = action
98 return action.dup
99 end
100 end
101 end
102
103 raise_no_action(first_controller, path) if first_controller
104 raise_no_controller(path)
105 end
106
107 # Try to produce an Action from the given path and paremters with the
108 # appropiate template if one exists.
109
110 def resolve_action(path, *parameter)
111 path, parameter = path.to_s, parameter.map{|e| e.to_s}
112 if alternate_template = trait["#{path}_template"]
113 t_controller, t_path = *alternate_template
114 template = t_controller.resolve_template(t_path)
115 end
116
117 method, params = resolve_method(path, *parameter)
118
119 if method or parameter.empty?
120 template ||= resolve_template(path)
121 end
122
123 Action.create :path => path,
124 :method => method,
125 :params => params,
126 :template => template,
127 :controller => self
128 end
129
130 # Search the #template_paths for a fitting template for path.
131 # Only the first found possibility for the generated glob is returned.
132
133 def resolve_template(path)
134 path = path.to_s
135 path_converted = path.split('__').inject{|s,v| s/v}
136 possible_paths = [path, path_converted].compact
137
138 paths = template_paths.map{|pa| possible_paths.map{|a| pa/a } }.flatten.uniq
139 glob = "{#{paths.join(',')}}.{#{extension_order.join(',')}}"
140
141 Dir[glob].first
142 end
143
144 # Composes an array with the template-paths to look up in the right order.
145 # Usually this is composed of Global.template_root and the mapping of the
146 # controller.
147
148 def template_paths
149 @template_root ||= Global.template_root / Global.mapping.invert[self]
150 [ @template_root ].flatten
151 end
152
153 # Based on methodname and arity, tries to find the right method on current controller.
154 def resolve_method(name, *params)
155 if method = [ name, name.gsub('__','/') ].find{|n|
156 cached_action_methods.include?(n) }
157 arity = instance_method(method).arity
158 if params.size == arity or arity < 0
159 return method, params
160 end
161 end
162 return nil, []
163 end
164
165 def cached_action_methods
166 Cache.action_methods[self] ||= action_methods
167 end
168
169 # methodnames that may be used for current controller.
170 def action_methods
171 exclude = Controller.trait[:exclude_action_modules]
172
173 ancs = (ancestors - exclude).select{|a| a.is_a?(Module) }
174 meths = ancs.map{|a|
175 a.instance_methods(false).map{|iv| iv.to_s }
176 }.flatten.uniq
177 # fix for facets/more/paramix
178 meths - ancs.map{|a| a.to_s}
179 end
180
181 # Generate all possible permutations for given path.
182 def pattern_for(path)
183 atoms = path.to_s.split('/').grep(/\S/)
184 atoms.unshift('')
185 patterns, joiner = [], '/'
186
187 atoms.size.times do |enum|
188 enum += 1
189 pattern = atoms.dup
190
191 controller = pattern[0, enum].join(joiner)
192 controller.gsub!(/^__/, '/')
193 controller = "/" if controller == ""
194
195 pattern = pattern[enum..-1]
196 args, temp = [], []
197
198 patterns << [controller, 'index', atoms[enum..-1]]
199
200 until pattern.empty?
201 args << pattern.shift
202 joined = args.join('__')
203 patterns << [controller, joined, pattern.dup]
204 patterns << [controller, "#{joined}__index", pattern.dup]
205 end
206 end
207
208 patterns.reverse!
209 end
210
211 # Uses custom defined engines and all available engines and throws it
212 # against the extensions for the template to find the most likely
213 # templating-engine to use ordered by priority and likelyhood.
214 def extension_order
215 t_extensions = Template::ENGINES
216 all_extensions = t_extensions.values.flatten
217
218 if engine = trait[:engine]
219 c_extensions = t_extensions.select{|k,v| k == engine}.map{|k,v| v}.flatten
220 return (c_extensions + all_extensions).uniq
221 end
222
223 all_extensions
224 end
225
226 def raise_no_filter(path)
227 raise Ramaze::Error::NoFilter, "No Filter found for `#{path}'"
228 end
229
230 # Raises Ramaze::Error::NoController
231
232 def raise_no_controller(path)
233 raise Ramaze::Error::NoController, "No Controller found for `#{path}'"
234 end
235
236 # Raises Ramaze::Error::NoAction
237
238 def raise_no_action(controller, path)
239 Thread.current[:controller] = controller
240 raise Ramaze::Error::NoAction, "No Action found for `#{path}' on #{controller}"
241 end
242 end
243 end
244 end
Generated using the rcov code coverage analysis tool for Ruby version 0.8.1.2.