brakeman 0.0.2
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/FEATURES +16 -0
- data/README.md +112 -0
- data/WARNING_TYPES +69 -0
- data/bin/brakeman +266 -0
- data/lib/checks.rb +67 -0
- data/lib/checks/base_check.rb +338 -0
- data/lib/checks/check_cross_site_scripting.rb +216 -0
- data/lib/checks/check_default_routes.rb +29 -0
- data/lib/checks/check_evaluation.rb +29 -0
- data/lib/checks/check_execute.rb +110 -0
- data/lib/checks/check_file_access.rb +46 -0
- data/lib/checks/check_forgery_setting.rb +25 -0
- data/lib/checks/check_mass_assignment.rb +72 -0
- data/lib/checks/check_model_attributes.rb +36 -0
- data/lib/checks/check_redirect.rb +98 -0
- data/lib/checks/check_render.rb +65 -0
- data/lib/checks/check_send_file.rb +15 -0
- data/lib/checks/check_session_settings.rb +36 -0
- data/lib/checks/check_sql.rb +124 -0
- data/lib/checks/check_validation_regex.rb +60 -0
- data/lib/format/style.css +105 -0
- data/lib/processor.rb +83 -0
- data/lib/processors/alias_processor.rb +384 -0
- data/lib/processors/base_processor.rb +235 -0
- data/lib/processors/config_processor.rb +146 -0
- data/lib/processors/controller_alias_processor.rb +222 -0
- data/lib/processors/controller_processor.rb +175 -0
- data/lib/processors/erb_template_processor.rb +84 -0
- data/lib/processors/erubis_template_processor.rb +62 -0
- data/lib/processors/haml_template_processor.rb +115 -0
- data/lib/processors/lib/find_call.rb +176 -0
- data/lib/processors/lib/find_model_call.rb +39 -0
- data/lib/processors/lib/processor_helper.rb +36 -0
- data/lib/processors/lib/render_helper.rb +118 -0
- data/lib/processors/library_processor.rb +117 -0
- data/lib/processors/model_processor.rb +125 -0
- data/lib/processors/output_processor.rb +204 -0
- data/lib/processors/params_processor.rb +77 -0
- data/lib/processors/route_processor.rb +338 -0
- data/lib/processors/template_alias_processor.rb +86 -0
- data/lib/processors/template_processor.rb +55 -0
- data/lib/report.rb +628 -0
- data/lib/scanner.rb +232 -0
- data/lib/tracker.rb +144 -0
- data/lib/util.rb +141 -0
- data/lib/warning.rb +97 -0
- metadata +191 -0
@@ -0,0 +1,384 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sexp_processor'
|
3
|
+
require 'util'
|
4
|
+
require 'processors/lib/processor_helper'
|
5
|
+
|
6
|
+
#Returns an s-expression with aliases replaced with their value.
|
7
|
+
#This does not preserve semantics (due to side effects, etc.), but it makes
|
8
|
+
#processing easier when searching for various things.
|
9
|
+
class AliasProcessor < SexpProcessor
|
10
|
+
include ProcessorHelper
|
11
|
+
include Util
|
12
|
+
|
13
|
+
attr_reader :result
|
14
|
+
|
15
|
+
#Returns a new AliasProcessor with an empty environment.
|
16
|
+
#
|
17
|
+
#The recommended usage is:
|
18
|
+
#
|
19
|
+
# AliasProcessor.new.process_safely src
|
20
|
+
def initialize
|
21
|
+
super()
|
22
|
+
self.strict = false
|
23
|
+
self.auto_shift_type = false
|
24
|
+
self.require_empty = false
|
25
|
+
self.default_method = :process_default
|
26
|
+
self.warn_on_default = false
|
27
|
+
@env = SexpProcessor::Environment.new
|
28
|
+
set_env_defaults
|
29
|
+
end
|
30
|
+
|
31
|
+
#This method processes the given Sexp, but copies it first so
|
32
|
+
#the original argument will not be modified.
|
33
|
+
#
|
34
|
+
#_set_env_ should be an instance of SexpProcessor::Environment. If provided,
|
35
|
+
#it will be used as the starting environment.
|
36
|
+
#
|
37
|
+
#This method returns a new Sexp with variables replaced with their values,
|
38
|
+
#where possible.
|
39
|
+
def process_safely src, set_env = nil
|
40
|
+
@env = Marshal.load(Marshal.dump(set_env)) if set_env
|
41
|
+
@result = src.deep_clone
|
42
|
+
process @result
|
43
|
+
|
44
|
+
#Process again to propogate replaced variables and process more.
|
45
|
+
#For example,
|
46
|
+
# x = [1,2]
|
47
|
+
# y = [3,4]
|
48
|
+
# z = x + y
|
49
|
+
#
|
50
|
+
#After first pass:
|
51
|
+
#
|
52
|
+
# z = [1,2] + [3,4]
|
53
|
+
#
|
54
|
+
#After second pass:
|
55
|
+
#
|
56
|
+
# z = [1,2,3,4]
|
57
|
+
if set_env
|
58
|
+
@env = set_env
|
59
|
+
else
|
60
|
+
@env = SexpProcessor::Environment.new
|
61
|
+
end
|
62
|
+
|
63
|
+
process @result
|
64
|
+
|
65
|
+
@result
|
66
|
+
end
|
67
|
+
|
68
|
+
#Process a Sexp. If the Sexp has a value associated with it in the
|
69
|
+
#environment, that value will be returned.
|
70
|
+
def process_default exp
|
71
|
+
begin
|
72
|
+
type = exp.shift
|
73
|
+
exp.each_with_index do |e, i|
|
74
|
+
if sexp? e and not e.empty?
|
75
|
+
exp[i] = process e
|
76
|
+
else
|
77
|
+
e
|
78
|
+
end
|
79
|
+
end
|
80
|
+
rescue Exception => err
|
81
|
+
@tracker.error err if @tracker
|
82
|
+
ensure
|
83
|
+
#The type must be put back on, or else later processing
|
84
|
+
#will trip up on it
|
85
|
+
exp.unshift type
|
86
|
+
end
|
87
|
+
|
88
|
+
#Generic replace
|
89
|
+
if replacement = env[exp]
|
90
|
+
set_line replacement.deep_clone, exp.line
|
91
|
+
else
|
92
|
+
exp
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#Process a method call.
|
97
|
+
def process_call exp
|
98
|
+
target_var = exp[1]
|
99
|
+
exp = process_default exp
|
100
|
+
|
101
|
+
#In case it is replaced with something else
|
102
|
+
return exp unless call? exp
|
103
|
+
|
104
|
+
target = exp[1]
|
105
|
+
method = exp[2]
|
106
|
+
args = exp[3]
|
107
|
+
|
108
|
+
#See if it is possible to simplify some basic cases
|
109
|
+
#of addition/concatenation.
|
110
|
+
case method
|
111
|
+
when :+
|
112
|
+
if array? target and array? args[1]
|
113
|
+
joined = join_arrays target, args[1]
|
114
|
+
joined.line(exp.line)
|
115
|
+
exp = joined
|
116
|
+
elsif string? target and string? args[1]
|
117
|
+
joined = join_strings target, args[1]
|
118
|
+
joined.line(exp.line)
|
119
|
+
exp = joined
|
120
|
+
end
|
121
|
+
when :[]
|
122
|
+
if array? target
|
123
|
+
temp_exp = process_array_access target, args[1..-1]
|
124
|
+
exp = temp_exp if temp_exp
|
125
|
+
elsif hash? target
|
126
|
+
temp_exp = process_hash_access target, args[1..-1]
|
127
|
+
exp = temp_exp if temp_exp
|
128
|
+
end
|
129
|
+
when :merge!, :update
|
130
|
+
if hash? target and hash? args[1]
|
131
|
+
target = process_hash_merge! target, args[1]
|
132
|
+
env[target_var] = target
|
133
|
+
return target
|
134
|
+
end
|
135
|
+
when :merge
|
136
|
+
if hash? target and hash? args[1]
|
137
|
+
return process_hash_merge(target, args[1])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
exp
|
142
|
+
end
|
143
|
+
|
144
|
+
#Process a new scope.
|
145
|
+
def process_scope exp
|
146
|
+
env.scope do
|
147
|
+
process exp[1]
|
148
|
+
end
|
149
|
+
exp
|
150
|
+
end
|
151
|
+
|
152
|
+
#Start new scope for block.
|
153
|
+
def process_block exp
|
154
|
+
env.scope do
|
155
|
+
process_default exp
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
#Process a method definition.
|
160
|
+
def process_methdef exp
|
161
|
+
env.scope do
|
162
|
+
set_env_defaults
|
163
|
+
process exp[3]
|
164
|
+
end
|
165
|
+
exp
|
166
|
+
end
|
167
|
+
|
168
|
+
#Process a method definition on self.
|
169
|
+
def process_selfdef exp
|
170
|
+
env.scope do
|
171
|
+
set_env_defaults
|
172
|
+
process exp[4]
|
173
|
+
end
|
174
|
+
exp
|
175
|
+
end
|
176
|
+
|
177
|
+
alias process_defn process_methdef
|
178
|
+
alias process_defs process_selfdef
|
179
|
+
|
180
|
+
#Local assignment
|
181
|
+
# x = 1
|
182
|
+
def process_lasgn exp
|
183
|
+
exp[2] = process exp[2] if sexp? exp[2]
|
184
|
+
local = Sexp.new(:lvar, exp[1]).line(exp.line || -2)
|
185
|
+
env[local] = exp[2]
|
186
|
+
exp
|
187
|
+
end
|
188
|
+
|
189
|
+
#Instance variable assignment
|
190
|
+
# @x = 1
|
191
|
+
def process_iasgn exp
|
192
|
+
exp[2] = process exp[2]
|
193
|
+
ivar = Sexp.new(:ivar, exp[1]).line(exp.line)
|
194
|
+
env[ivar] = exp[2]
|
195
|
+
exp
|
196
|
+
end
|
197
|
+
|
198
|
+
#Global assignment
|
199
|
+
# $x = 1
|
200
|
+
def process_gasgn exp
|
201
|
+
match = Sexp.new(:gvar, exp[1])
|
202
|
+
value = exp[2] = process(exp[2])
|
203
|
+
env[match] = value
|
204
|
+
exp
|
205
|
+
end
|
206
|
+
|
207
|
+
#Class variable assignment
|
208
|
+
# @@x = 1
|
209
|
+
def process_cvdecl exp
|
210
|
+
match = Sexp.new(:cvar, exp[1])
|
211
|
+
value = exp[2] = process(exp[2])
|
212
|
+
env[match] = value
|
213
|
+
exp
|
214
|
+
end
|
215
|
+
|
216
|
+
#'Attribute' assignment
|
217
|
+
# x.y = 1
|
218
|
+
#or
|
219
|
+
# x[:y] = 1
|
220
|
+
def process_attrasgn exp
|
221
|
+
tar_variable = exp[1]
|
222
|
+
target = exp[1] = process(exp[1])
|
223
|
+
method = exp[2]
|
224
|
+
if method == :[]=
|
225
|
+
index = exp[3][1] = process(exp[3][1])
|
226
|
+
value = exp[3][2] = process(exp[3][2])
|
227
|
+
match = Sexp.new(:call, target, :[], Sexp.new(:arglist, index))
|
228
|
+
env[match] = value
|
229
|
+
|
230
|
+
if hash? target
|
231
|
+
env[tar_variable] = hash_insert target.deep_clone, index, value
|
232
|
+
end
|
233
|
+
elsif method.to_s[-1,1] == "="
|
234
|
+
value = exp[3][1] = process(exp[3][1])
|
235
|
+
#This is what we'll replace with the value
|
236
|
+
match = Sexp.new(:call, target, method.to_s[0..-2].to_sym, Sexp.new(:arglist))
|
237
|
+
env[match] = value
|
238
|
+
else
|
239
|
+
raise "Unrecognized assignment: #{exp}"
|
240
|
+
end
|
241
|
+
exp
|
242
|
+
end
|
243
|
+
|
244
|
+
#Merge values into hash when processing
|
245
|
+
#
|
246
|
+
# h.merge! :something => "value"
|
247
|
+
def process_hash_merge! hash, args
|
248
|
+
hash = hash.deep_clone
|
249
|
+
hash_iterate args do |key, replacement|
|
250
|
+
hash_insert hash, key, replacement
|
251
|
+
match = Sexp.new(:call, hash, :[], Sexp.new(:arglist, key))
|
252
|
+
env[match] = replacement
|
253
|
+
end
|
254
|
+
hash
|
255
|
+
end
|
256
|
+
|
257
|
+
#Return a new hash Sexp with the given values merged into it.
|
258
|
+
#
|
259
|
+
#+args+ should be a hash Sexp as well.
|
260
|
+
def process_hash_merge hash, args
|
261
|
+
hash = hash.deep_clone
|
262
|
+
hash_iterate args do |key, replacement|
|
263
|
+
hash_insert hash, key, replacement
|
264
|
+
end
|
265
|
+
hash
|
266
|
+
end
|
267
|
+
|
268
|
+
#Assignments like this
|
269
|
+
# x[:y] ||= 1
|
270
|
+
def process_op_asgn1 exp
|
271
|
+
return process_default(exp) if exp[3] != :"||"
|
272
|
+
|
273
|
+
target = exp[1] = process(exp[1])
|
274
|
+
index = exp[2][1] = process(exp[2][1])
|
275
|
+
value = exp[4] = process(exp[4])
|
276
|
+
match = Sexp.new(:call, target, :[], Sexp.new(:arglist, index))
|
277
|
+
|
278
|
+
unless env[match]
|
279
|
+
env[match] = value
|
280
|
+
end
|
281
|
+
|
282
|
+
exp
|
283
|
+
end
|
284
|
+
|
285
|
+
#Assignments like this
|
286
|
+
# x.y ||= 1
|
287
|
+
def process_op_asgn2 exp
|
288
|
+
return process_default(exp) if exp[3] != :"||"
|
289
|
+
|
290
|
+
target = exp[1] = process(exp[1])
|
291
|
+
value = exp[4] = process(exp[4])
|
292
|
+
method = exp[2]
|
293
|
+
|
294
|
+
match = Sexp.new(:call, target, method.to_s[0..-2].to_sym, Sexp.new(:arglist))
|
295
|
+
|
296
|
+
unless env[match]
|
297
|
+
env[match] = value
|
298
|
+
end
|
299
|
+
|
300
|
+
exp
|
301
|
+
end
|
302
|
+
|
303
|
+
#Constant assignments like
|
304
|
+
# BIG_CONSTANT = 234810983
|
305
|
+
def process_cdecl exp
|
306
|
+
if sexp? exp[2]
|
307
|
+
exp[2] = process exp[2]
|
308
|
+
end
|
309
|
+
|
310
|
+
if exp[1].is_a? Symbol
|
311
|
+
match = Sexp.new(:const, exp[1])
|
312
|
+
else
|
313
|
+
match = exp[1]
|
314
|
+
end
|
315
|
+
|
316
|
+
env[match] = exp[2]
|
317
|
+
|
318
|
+
exp
|
319
|
+
end
|
320
|
+
|
321
|
+
#Process single integer access to an array.
|
322
|
+
#
|
323
|
+
#Returns the value inside the array, if possible.
|
324
|
+
def process_array_access target, args
|
325
|
+
if args.length == 1 and integer? args[0]
|
326
|
+
index = args[0][1]
|
327
|
+
target[index + 1]
|
328
|
+
else
|
329
|
+
nil
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
#Process hash access by returning the value associated
|
334
|
+
#with the given arguments.
|
335
|
+
def process_hash_access target, args
|
336
|
+
if args.length == 1
|
337
|
+
index = args[0]
|
338
|
+
hash_iterate(target) do |key, value|
|
339
|
+
if key == index
|
340
|
+
return value
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
nil
|
346
|
+
end
|
347
|
+
|
348
|
+
#Join two array literals into one.
|
349
|
+
def join_arrays array1, array2
|
350
|
+
result = Sexp.new(:array)
|
351
|
+
result.concat array1[1..-1]
|
352
|
+
result.concat array2[1..-1]
|
353
|
+
end
|
354
|
+
|
355
|
+
#Join two string literals into one.
|
356
|
+
def join_strings string1, string2
|
357
|
+
result = Sexp.new(:str)
|
358
|
+
result[1] = string1[1] + string2[1]
|
359
|
+
result
|
360
|
+
end
|
361
|
+
|
362
|
+
#Returns a new SexpProcessor::Environment containing only instance variables.
|
363
|
+
#This is useful, for example, when processing views.
|
364
|
+
def only_ivars
|
365
|
+
res = SexpProcessor::Environment.new
|
366
|
+
env.all.each do |k, v|
|
367
|
+
res[k] = v if k.node_type == :ivar
|
368
|
+
end
|
369
|
+
res
|
370
|
+
end
|
371
|
+
|
372
|
+
#Set line nunber for +exp+ and every Sexp it contains. Used when replacing
|
373
|
+
#expressions, so warnings indicate the correct line.
|
374
|
+
def set_line exp, line_number
|
375
|
+
if sexp? exp
|
376
|
+
exp.line(line_number)
|
377
|
+
exp.each do |e|
|
378
|
+
set_line e, line_number
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
exp
|
383
|
+
end
|
384
|
+
end
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sexp_processor'
|
3
|
+
require 'processors/lib/processor_helper'
|
4
|
+
require 'util'
|
5
|
+
|
6
|
+
#Base processor for most processors.
|
7
|
+
class BaseProcessor < SexpProcessor
|
8
|
+
include ProcessorHelper
|
9
|
+
include Util
|
10
|
+
|
11
|
+
attr_reader :ignore
|
12
|
+
|
13
|
+
#Return a new Processor.
|
14
|
+
def initialize tracker
|
15
|
+
super()
|
16
|
+
self.strict = false
|
17
|
+
self.auto_shift_type = false
|
18
|
+
self.require_empty = false
|
19
|
+
self.default_method = :process_default
|
20
|
+
self.warn_on_default = false
|
21
|
+
@last = nil
|
22
|
+
@tracker = tracker
|
23
|
+
@ignore = Sexp.new :ignore
|
24
|
+
@current_template = @current_module = @current_class = @current_method = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
#Process a new scope. Removes expressions that are set to nil.
|
28
|
+
def process_scope exp
|
29
|
+
exp.shift
|
30
|
+
exp.map! do |e|
|
31
|
+
res = process e
|
32
|
+
if res.empty?
|
33
|
+
res = nil
|
34
|
+
else
|
35
|
+
res
|
36
|
+
end
|
37
|
+
end.compact
|
38
|
+
exp.unshift :scope
|
39
|
+
end
|
40
|
+
|
41
|
+
#Default processing.
|
42
|
+
def process_default exp
|
43
|
+
type = exp.shift
|
44
|
+
exp.each_with_index do |e, i|
|
45
|
+
if sexp? e and not e.empty?
|
46
|
+
exp[i] = process e
|
47
|
+
else
|
48
|
+
e
|
49
|
+
end
|
50
|
+
end
|
51
|
+
ensure
|
52
|
+
exp.unshift type
|
53
|
+
end
|
54
|
+
|
55
|
+
#Process an if statement.
|
56
|
+
def process_if exp
|
57
|
+
exp[1] = process exp[1]
|
58
|
+
exp[2] = process exp[2] if exp[2]
|
59
|
+
exp[3] = process exp[3] if exp[3]
|
60
|
+
exp
|
61
|
+
end
|
62
|
+
|
63
|
+
#Processes calls with blocks. Changes Sexp node type to :call_with_block
|
64
|
+
#
|
65
|
+
#s(:iter, CALL, {:lasgn|:masgn}, BLOCK)
|
66
|
+
def process_iter exp
|
67
|
+
call = process exp[1]
|
68
|
+
#deal with assignments somehow
|
69
|
+
if exp[3]
|
70
|
+
block = process exp[3]
|
71
|
+
block = nil if block.empty?
|
72
|
+
else
|
73
|
+
block = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
call = Sexp.new(:call_with_block, call, exp[2], block).compact
|
77
|
+
call.line(exp.line)
|
78
|
+
call
|
79
|
+
end
|
80
|
+
|
81
|
+
#String with interpolation. Changes Sexp node type to :string_interp
|
82
|
+
def process_dstr exp
|
83
|
+
exp.shift
|
84
|
+
exp.map! do |e|
|
85
|
+
if e.is_a? String
|
86
|
+
e
|
87
|
+
elsif e[1].is_a? String
|
88
|
+
e[1]
|
89
|
+
else
|
90
|
+
res = process e
|
91
|
+
if res.empty?
|
92
|
+
nil
|
93
|
+
else
|
94
|
+
res
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end.compact!
|
98
|
+
|
99
|
+
exp.unshift :string_interp
|
100
|
+
end
|
101
|
+
|
102
|
+
#Processes a block. Changes Sexp node type to :rlist
|
103
|
+
def process_block exp
|
104
|
+
exp.shift
|
105
|
+
|
106
|
+
exp.map! do |e|
|
107
|
+
process e
|
108
|
+
end
|
109
|
+
|
110
|
+
exp.unshift :rlist
|
111
|
+
end
|
112
|
+
|
113
|
+
#Processes the inside of an interpolated String.
|
114
|
+
#Changes Sexp node type to :string_eval
|
115
|
+
def process_evstr exp
|
116
|
+
exp[0] = :string_eval
|
117
|
+
exp[1] = process exp[1]
|
118
|
+
exp
|
119
|
+
end
|
120
|
+
|
121
|
+
#Processes an or keyword
|
122
|
+
def process_or exp
|
123
|
+
exp[1] = process exp[1]
|
124
|
+
exp[2] = process exp[2]
|
125
|
+
exp
|
126
|
+
end
|
127
|
+
|
128
|
+
#Processes an and keyword
|
129
|
+
def process_and exp
|
130
|
+
exp[1] = process exp[1]
|
131
|
+
exp[2] = process exp[2]
|
132
|
+
exp
|
133
|
+
end
|
134
|
+
|
135
|
+
#Processes a hash
|
136
|
+
def process_hash exp
|
137
|
+
exp.shift
|
138
|
+
exp.map! do |e|
|
139
|
+
if sexp? e
|
140
|
+
process e
|
141
|
+
else
|
142
|
+
e
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
exp.unshift :hash
|
147
|
+
end
|
148
|
+
|
149
|
+
#Processes the values in an argument list
|
150
|
+
def process_arglist exp
|
151
|
+
exp.shift
|
152
|
+
exp.map! do |e|
|
153
|
+
process e
|
154
|
+
end
|
155
|
+
|
156
|
+
exp.unshift :arglist
|
157
|
+
end
|
158
|
+
|
159
|
+
#Processes a local assignment
|
160
|
+
def process_lasgn exp
|
161
|
+
exp[2] = process exp[2]
|
162
|
+
exp
|
163
|
+
end
|
164
|
+
|
165
|
+
#Processes an instance variable assignment
|
166
|
+
def process_iasgn exp
|
167
|
+
exp[2] = process exp[2]
|
168
|
+
exp
|
169
|
+
end
|
170
|
+
|
171
|
+
#Processes an attribute assignment, which can be either x.y = 1 or x[:y] = 1
|
172
|
+
def process_attrasgn exp
|
173
|
+
exp[1] = process exp[1]
|
174
|
+
exp[3] = process exp[3]
|
175
|
+
exp
|
176
|
+
end
|
177
|
+
|
178
|
+
#Ignore ignore Sexps
|
179
|
+
def process_ignore exp
|
180
|
+
exp
|
181
|
+
end
|
182
|
+
|
183
|
+
#Generates :render node from call to render.
|
184
|
+
def make_render exp
|
185
|
+
render_type, value, rest = find_render_type exp[3]
|
186
|
+
rest = process rest
|
187
|
+
result = Sexp.new(:render, render_type, value, rest)
|
188
|
+
result.line(exp.line)
|
189
|
+
result
|
190
|
+
end
|
191
|
+
|
192
|
+
#Determines the type of a call to render.
|
193
|
+
#
|
194
|
+
#Possible types are:
|
195
|
+
#:action, :default :file, :inline, :js, :json, :nothing, :partial,
|
196
|
+
#:template, :text, :update, :xml
|
197
|
+
def find_render_type args
|
198
|
+
rest = Sexp.new(:hash)
|
199
|
+
type = nil
|
200
|
+
value = nil
|
201
|
+
|
202
|
+
if args.length == 2 and args[-1] == Sexp.new(:lit, :update)
|
203
|
+
return :update, nil, args[0..-2]
|
204
|
+
end
|
205
|
+
|
206
|
+
#Look for render :action, ... or render "action", ...
|
207
|
+
if string? args[1] or symbol? args[1]
|
208
|
+
type = :action
|
209
|
+
value = args[1]
|
210
|
+
elsif args[1].is_a? Symbol or args[1].is_a? String
|
211
|
+
type = :action
|
212
|
+
value = Sexp.new(:lit, args[1].to_sym)
|
213
|
+
elsif not hash? args[1]
|
214
|
+
type = :action
|
215
|
+
value = args[1]
|
216
|
+
end
|
217
|
+
|
218
|
+
if hash? args[-1]
|
219
|
+
hash_iterate(args[-1]) do |key, val|
|
220
|
+
case key[1]
|
221
|
+
when :action, :file, :inline, :js, :json, :nothing, :partial, :text, :update, :xml
|
222
|
+
type = key[1]
|
223
|
+
value = val
|
224
|
+
else
|
225
|
+
rest << key << val
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
type ||= :default
|
231
|
+
value ||= :default
|
232
|
+
args[-1] = rest
|
233
|
+
return type, value, rest
|
234
|
+
end
|
235
|
+
end
|