railroader 4.3.4

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.
Files changed (165) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +1091 -0
  3. data/FEATURES +16 -0
  4. data/README.md +174 -0
  5. data/bin/railroader +8 -0
  6. data/lib/railroader/app_tree.rb +191 -0
  7. data/lib/railroader/call_index.rb +219 -0
  8. data/lib/railroader/checks/base_check.rb +505 -0
  9. data/lib/railroader/checks/check_basic_auth.rb +88 -0
  10. data/lib/railroader/checks/check_basic_auth_timing_attack.rb +33 -0
  11. data/lib/railroader/checks/check_content_tag.rb +200 -0
  12. data/lib/railroader/checks/check_create_with.rb +74 -0
  13. data/lib/railroader/checks/check_cross_site_scripting.rb +381 -0
  14. data/lib/railroader/checks/check_default_routes.rb +86 -0
  15. data/lib/railroader/checks/check_deserialize.rb +56 -0
  16. data/lib/railroader/checks/check_detailed_exceptions.rb +55 -0
  17. data/lib/railroader/checks/check_digest_dos.rb +38 -0
  18. data/lib/railroader/checks/check_divide_by_zero.rb +42 -0
  19. data/lib/railroader/checks/check_dynamic_finders.rb +48 -0
  20. data/lib/railroader/checks/check_escape_function.rb +21 -0
  21. data/lib/railroader/checks/check_evaluation.rb +35 -0
  22. data/lib/railroader/checks/check_execute.rb +189 -0
  23. data/lib/railroader/checks/check_file_access.rb +71 -0
  24. data/lib/railroader/checks/check_file_disclosure.rb +35 -0
  25. data/lib/railroader/checks/check_filter_skipping.rb +31 -0
  26. data/lib/railroader/checks/check_forgery_setting.rb +81 -0
  27. data/lib/railroader/checks/check_header_dos.rb +31 -0
  28. data/lib/railroader/checks/check_i18n_xss.rb +48 -0
  29. data/lib/railroader/checks/check_jruby_xml.rb +36 -0
  30. data/lib/railroader/checks/check_json_encoding.rb +47 -0
  31. data/lib/railroader/checks/check_json_parsing.rb +107 -0
  32. data/lib/railroader/checks/check_link_to.rb +132 -0
  33. data/lib/railroader/checks/check_link_to_href.rb +146 -0
  34. data/lib/railroader/checks/check_mail_to.rb +49 -0
  35. data/lib/railroader/checks/check_mass_assignment.rb +196 -0
  36. data/lib/railroader/checks/check_mime_type_dos.rb +39 -0
  37. data/lib/railroader/checks/check_model_attr_accessible.rb +55 -0
  38. data/lib/railroader/checks/check_model_attributes.rb +119 -0
  39. data/lib/railroader/checks/check_model_serialize.rb +67 -0
  40. data/lib/railroader/checks/check_nested_attributes.rb +38 -0
  41. data/lib/railroader/checks/check_nested_attributes_bypass.rb +58 -0
  42. data/lib/railroader/checks/check_number_to_currency.rb +74 -0
  43. data/lib/railroader/checks/check_permit_attributes.rb +43 -0
  44. data/lib/railroader/checks/check_quote_table_name.rb +40 -0
  45. data/lib/railroader/checks/check_redirect.rb +256 -0
  46. data/lib/railroader/checks/check_regex_dos.rb +68 -0
  47. data/lib/railroader/checks/check_render.rb +97 -0
  48. data/lib/railroader/checks/check_render_dos.rb +37 -0
  49. data/lib/railroader/checks/check_render_inline.rb +53 -0
  50. data/lib/railroader/checks/check_response_splitting.rb +21 -0
  51. data/lib/railroader/checks/check_route_dos.rb +42 -0
  52. data/lib/railroader/checks/check_safe_buffer_manipulation.rb +31 -0
  53. data/lib/railroader/checks/check_sanitize_methods.rb +112 -0
  54. data/lib/railroader/checks/check_secrets.rb +40 -0
  55. data/lib/railroader/checks/check_select_tag.rb +59 -0
  56. data/lib/railroader/checks/check_select_vulnerability.rb +60 -0
  57. data/lib/railroader/checks/check_send.rb +47 -0
  58. data/lib/railroader/checks/check_send_file.rb +19 -0
  59. data/lib/railroader/checks/check_session_manipulation.rb +35 -0
  60. data/lib/railroader/checks/check_session_settings.rb +176 -0
  61. data/lib/railroader/checks/check_simple_format.rb +58 -0
  62. data/lib/railroader/checks/check_single_quotes.rb +101 -0
  63. data/lib/railroader/checks/check_skip_before_filter.rb +60 -0
  64. data/lib/railroader/checks/check_sql.rb +700 -0
  65. data/lib/railroader/checks/check_sql_cves.rb +106 -0
  66. data/lib/railroader/checks/check_ssl_verify.rb +48 -0
  67. data/lib/railroader/checks/check_strip_tags.rb +89 -0
  68. data/lib/railroader/checks/check_symbol_dos.rb +71 -0
  69. data/lib/railroader/checks/check_symbol_dos_cve.rb +30 -0
  70. data/lib/railroader/checks/check_translate_bug.rb +45 -0
  71. data/lib/railroader/checks/check_unsafe_reflection.rb +50 -0
  72. data/lib/railroader/checks/check_unscoped_find.rb +57 -0
  73. data/lib/railroader/checks/check_validation_regex.rb +116 -0
  74. data/lib/railroader/checks/check_weak_hash.rb +148 -0
  75. data/lib/railroader/checks/check_without_protection.rb +80 -0
  76. data/lib/railroader/checks/check_xml_dos.rb +45 -0
  77. data/lib/railroader/checks/check_yaml_parsing.rb +121 -0
  78. data/lib/railroader/checks.rb +209 -0
  79. data/lib/railroader/codeclimate/engine_configuration.rb +97 -0
  80. data/lib/railroader/commandline.rb +179 -0
  81. data/lib/railroader/differ.rb +66 -0
  82. data/lib/railroader/file_parser.rb +54 -0
  83. data/lib/railroader/format/style.css +133 -0
  84. data/lib/railroader/options.rb +339 -0
  85. data/lib/railroader/parsers/rails2_erubis.rb +6 -0
  86. data/lib/railroader/parsers/rails2_xss_plugin_erubis.rb +48 -0
  87. data/lib/railroader/parsers/rails3_erubis.rb +81 -0
  88. data/lib/railroader/parsers/template_parser.rb +108 -0
  89. data/lib/railroader/processor.rb +102 -0
  90. data/lib/railroader/processors/alias_processor.rb +1229 -0
  91. data/lib/railroader/processors/base_processor.rb +295 -0
  92. data/lib/railroader/processors/config_processor.rb +14 -0
  93. data/lib/railroader/processors/controller_alias_processor.rb +278 -0
  94. data/lib/railroader/processors/controller_processor.rb +249 -0
  95. data/lib/railroader/processors/erb_template_processor.rb +77 -0
  96. data/lib/railroader/processors/erubis_template_processor.rb +92 -0
  97. data/lib/railroader/processors/gem_processor.rb +64 -0
  98. data/lib/railroader/processors/haml_template_processor.rb +191 -0
  99. data/lib/railroader/processors/lib/basic_processor.rb +37 -0
  100. data/lib/railroader/processors/lib/call_conversion_helper.rb +90 -0
  101. data/lib/railroader/processors/lib/find_all_calls.rb +224 -0
  102. data/lib/railroader/processors/lib/find_call.rb +183 -0
  103. data/lib/railroader/processors/lib/find_return_value.rb +166 -0
  104. data/lib/railroader/processors/lib/module_helper.rb +111 -0
  105. data/lib/railroader/processors/lib/processor_helper.rb +88 -0
  106. data/lib/railroader/processors/lib/rails2_config_processor.rb +145 -0
  107. data/lib/railroader/processors/lib/rails2_route_processor.rb +313 -0
  108. data/lib/railroader/processors/lib/rails3_config_processor.rb +132 -0
  109. data/lib/railroader/processors/lib/rails3_route_processor.rb +308 -0
  110. data/lib/railroader/processors/lib/render_helper.rb +181 -0
  111. data/lib/railroader/processors/lib/render_path.rb +107 -0
  112. data/lib/railroader/processors/lib/route_helper.rb +68 -0
  113. data/lib/railroader/processors/lib/safe_call_helper.rb +16 -0
  114. data/lib/railroader/processors/library_processor.rb +74 -0
  115. data/lib/railroader/processors/model_processor.rb +91 -0
  116. data/lib/railroader/processors/output_processor.rb +144 -0
  117. data/lib/railroader/processors/route_processor.rb +17 -0
  118. data/lib/railroader/processors/slim_template_processor.rb +111 -0
  119. data/lib/railroader/processors/template_alias_processor.rb +118 -0
  120. data/lib/railroader/processors/template_processor.rb +85 -0
  121. data/lib/railroader/report/config/remediation.yml +71 -0
  122. data/lib/railroader/report/ignore/config.rb +153 -0
  123. data/lib/railroader/report/ignore/interactive.rb +362 -0
  124. data/lib/railroader/report/pager.rb +112 -0
  125. data/lib/railroader/report/renderer.rb +24 -0
  126. data/lib/railroader/report/report_base.rb +292 -0
  127. data/lib/railroader/report/report_codeclimate.rb +79 -0
  128. data/lib/railroader/report/report_csv.rb +55 -0
  129. data/lib/railroader/report/report_hash.rb +23 -0
  130. data/lib/railroader/report/report_html.rb +216 -0
  131. data/lib/railroader/report/report_json.rb +45 -0
  132. data/lib/railroader/report/report_markdown.rb +107 -0
  133. data/lib/railroader/report/report_table.rb +117 -0
  134. data/lib/railroader/report/report_tabs.rb +17 -0
  135. data/lib/railroader/report/report_text.rb +198 -0
  136. data/lib/railroader/report/templates/controller_overview.html.erb +22 -0
  137. data/lib/railroader/report/templates/controller_warnings.html.erb +21 -0
  138. data/lib/railroader/report/templates/error_overview.html.erb +29 -0
  139. data/lib/railroader/report/templates/header.html.erb +58 -0
  140. data/lib/railroader/report/templates/ignored_warnings.html.erb +25 -0
  141. data/lib/railroader/report/templates/model_warnings.html.erb +21 -0
  142. data/lib/railroader/report/templates/overview.html.erb +38 -0
  143. data/lib/railroader/report/templates/security_warnings.html.erb +23 -0
  144. data/lib/railroader/report/templates/template_overview.html.erb +21 -0
  145. data/lib/railroader/report/templates/view_warnings.html.erb +34 -0
  146. data/lib/railroader/report/templates/warning_overview.html.erb +17 -0
  147. data/lib/railroader/report.rb +88 -0
  148. data/lib/railroader/rescanner.rb +483 -0
  149. data/lib/railroader/scanner.rb +321 -0
  150. data/lib/railroader/tracker/collection.rb +93 -0
  151. data/lib/railroader/tracker/config.rb +154 -0
  152. data/lib/railroader/tracker/constants.rb +171 -0
  153. data/lib/railroader/tracker/controller.rb +161 -0
  154. data/lib/railroader/tracker/library.rb +17 -0
  155. data/lib/railroader/tracker/model.rb +90 -0
  156. data/lib/railroader/tracker/template.rb +33 -0
  157. data/lib/railroader/tracker.rb +362 -0
  158. data/lib/railroader/util.rb +503 -0
  159. data/lib/railroader/version.rb +3 -0
  160. data/lib/railroader/warning.rb +294 -0
  161. data/lib/railroader/warning_codes.rb +117 -0
  162. data/lib/railroader.rb +544 -0
  163. data/lib/ruby_parser/bm_sexp.rb +626 -0
  164. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  165. metadata +386 -0
@@ -0,0 +1,295 @@
1
+ require 'railroader/processors/lib/processor_helper'
2
+ require 'railroader/processors/lib/safe_call_helper'
3
+ require 'railroader/util'
4
+
5
+ #Base processor for most processors.
6
+ class Railroader::BaseProcessor < Railroader::SexpProcessor
7
+ include Railroader::ProcessorHelper
8
+ include Railroader::SafeCallHelper
9
+ include Railroader::Util
10
+
11
+ IGNORE = Sexp.new :ignore
12
+
13
+ #Return a new Processor.
14
+ def initialize tracker
15
+ super()
16
+ @last = nil
17
+ @tracker = tracker
18
+ @current_template = @current_module = @current_class = @current_method = @file_name = nil
19
+ end
20
+
21
+ def process_file exp, file_name
22
+ @file_name = file_name
23
+ process exp
24
+ end
25
+
26
+ def ignore
27
+ IGNORE
28
+ end
29
+
30
+ #Process a new scope. Removes expressions that are set to nil.
31
+ def process_scope exp
32
+ #NOPE?
33
+ end
34
+
35
+ #Default processing.
36
+ def process_default exp
37
+ exp = exp.dup
38
+
39
+ exp.each_with_index do |e, i|
40
+ exp[i] = process e if sexp? e and not e.empty?
41
+ end
42
+
43
+ exp
44
+ end
45
+
46
+ #Process an if statement.
47
+ def process_if exp
48
+ exp = exp.dup
49
+ condition = exp[1] = process exp.condition
50
+
51
+ if true? condition
52
+ exp[2] = process exp.then_clause if exp.then_clause
53
+ exp[3] = nil
54
+ elsif false? condition
55
+ exp[2] = nil
56
+ exp[3] = process exp.else_clause if exp.else_clause
57
+ else
58
+ exp[2] = process exp.then_clause if exp.then_clause
59
+ exp[3] = process exp.else_clause if exp.else_clause
60
+ end
61
+
62
+ exp
63
+ end
64
+
65
+ #Processes calls with blocks.
66
+ #
67
+ #s(:iter, CALL, {:lasgn|:masgn}, BLOCK)
68
+ def process_iter exp
69
+ exp = exp.dup
70
+ call = process exp.block_call
71
+ #deal with assignments somehow
72
+ if exp.block
73
+ block = process exp.block
74
+ block = nil if block.empty?
75
+ else
76
+ block = nil
77
+ end
78
+
79
+ call = Sexp.new(:iter, call, exp.block_args, block).compact
80
+ call.line(exp.line)
81
+ call
82
+ end
83
+
84
+ #String with interpolation.
85
+ def process_dstr exp
86
+ exp = exp.dup
87
+ exp.shift
88
+ exp.map! do |e|
89
+ if e.is_a? String
90
+ e
91
+ else
92
+ res = process e
93
+ if res.empty?
94
+ nil
95
+ else
96
+ res
97
+ end
98
+ end
99
+ end.compact!
100
+
101
+ exp.unshift :dstr
102
+ end
103
+
104
+ #Processes a block. Changes Sexp node type to :rlist
105
+ def process_block exp
106
+ exp = exp.dup
107
+ exp.shift
108
+
109
+ exp.map! do |e|
110
+ process e
111
+ end
112
+
113
+ exp.unshift :rlist
114
+ end
115
+
116
+ #Processes the inside of an interpolated String.
117
+ def process_evstr exp
118
+ exp = exp.dup
119
+ if exp[1]
120
+ exp[1] = process exp[1]
121
+ end
122
+
123
+ exp
124
+ end
125
+
126
+ #Processes a hash
127
+ def process_hash exp
128
+ exp = exp.dup
129
+ exp.shift
130
+ exp.map! do |e|
131
+ if sexp? e
132
+ process e
133
+ else
134
+ e
135
+ end
136
+ end
137
+
138
+ exp.unshift :hash
139
+ end
140
+
141
+ #Processes the values in an argument list
142
+ def process_arglist exp
143
+ exp = exp.dup
144
+ exp.shift
145
+ exp.map! do |e|
146
+ process e
147
+ end
148
+
149
+ exp.unshift :arglist
150
+ end
151
+
152
+ #Processes a local assignment
153
+ def process_lasgn exp
154
+ exp = exp.dup
155
+ exp.rhs = process exp.rhs
156
+ exp
157
+ end
158
+
159
+ alias :process_iasgn :process_lasgn
160
+
161
+ #Processes an instance variable assignment
162
+ def process_iasgn exp
163
+ exp = exp.dup
164
+ exp.rhs = process exp.rhs
165
+ exp
166
+ end
167
+
168
+ #Processes an attribute assignment, which can be either x.y = 1 or x[:y] = 1
169
+ def process_attrasgn exp
170
+ exp = exp.dup
171
+ exp.target = process exp.target
172
+ exp.arglist = process exp.arglist
173
+ exp
174
+ end
175
+
176
+ #Ignore ignore Sexps
177
+ def process_ignore exp
178
+ exp
179
+ end
180
+
181
+ def process_cdecl exp
182
+ if @tracker
183
+ @tracker.add_constant exp.lhs,
184
+ exp.rhs,
185
+ :file => current_file_name,
186
+ :module => @current_module,
187
+ :class => @current_class,
188
+ :method => @current_method
189
+ end
190
+
191
+ exp
192
+ end
193
+
194
+ #Convenience method for `make_render exp, true`
195
+ def make_render_in_view exp
196
+ make_render exp, true
197
+ end
198
+
199
+ #Generates :render node from call to render.
200
+ def make_render exp, in_view = false
201
+ render_type, value, rest = find_render_type exp, in_view
202
+ rest = process rest
203
+ result = Sexp.new(:render, render_type, value, rest)
204
+ result.line(exp.line)
205
+ result
206
+ end
207
+
208
+ #Determines the type of a call to render.
209
+ #
210
+ #Possible types are:
211
+ #:action, :default, :file, :inline, :js, :json, :nothing, :partial,
212
+ #:template, :text, :update, :xml
213
+ #
214
+ #And also :layout for inside templates
215
+ def find_render_type call, in_view = false
216
+ rest = Sexp.new(:hash)
217
+ type = nil
218
+ value = nil
219
+ first_arg = call.first_arg
220
+
221
+ if call.second_arg.nil? and first_arg == Sexp.new(:lit, :update)
222
+ return :update, nil, Sexp.new(:arglist, *call.args[0..-2]) #TODO HUH?
223
+ end
224
+
225
+ #Look for render :action, ... or render "action", ...
226
+ if string? first_arg or symbol? first_arg
227
+ if @current_template and @tracker.options[:rails3]
228
+ type = :partial
229
+ value = first_arg
230
+ else
231
+ type = :action
232
+ value = first_arg
233
+ end
234
+ elsif first_arg.is_a? Symbol or first_arg.is_a? String
235
+ type = :action
236
+ value = Sexp.new(:lit, first_arg.to_sym)
237
+ elsif first_arg.nil?
238
+ type = :default
239
+ elsif not hash? first_arg
240
+ type = :action
241
+ value = first_arg
242
+ end
243
+
244
+ types_in_hash = Set[:action, :file, :inline, :js, :json, :nothing, :partial, :template, :text, :update, :xml]
245
+
246
+ #render :layout => "blah" means something else when in a template
247
+ if in_view
248
+ types_in_hash << :layout
249
+ end
250
+
251
+ last_arg = call.last_arg
252
+
253
+ #Look for "type" of render in options hash
254
+ #For example, render :file => "blah"
255
+ if hash? last_arg
256
+ hash_iterate(last_arg) do |key, val|
257
+ if symbol? key and types_in_hash.include? key.value
258
+ type = key.value
259
+ value = val
260
+ else
261
+ rest << key << val
262
+ end
263
+ end
264
+ end
265
+
266
+ type ||= :default
267
+ value ||= :default
268
+
269
+ if type == :inline and string? value and not hash_access(rest, :type)
270
+ value, rest = make_inline_render(value, rest)
271
+ end
272
+
273
+ return type, value, rest
274
+ end
275
+
276
+ def make_inline_render value, options
277
+ require 'railroader/parsers/template_parser'
278
+
279
+ class_or_module = (@current_class || @current_module)
280
+
281
+ class_or_module = if class_or_module.nil?
282
+ "Unknown"
283
+ else
284
+ class_or_module.name
285
+ end
286
+
287
+ template_name = "#@current_method/inline@#{value.line}:#{class_or_module}".to_sym
288
+ type, ast = Railroader::TemplateParser.parse_inline_erb(@tracker, value.value)
289
+ ast = ast.deep_clone(value.line)
290
+ @tracker.processor.process_template(template_name, ast, type, nil, @file_name)
291
+ @tracker.processor.process_template_alias(@tracker.templates[template_name])
292
+
293
+ return s(:lit, template_name), options
294
+ end
295
+ end
@@ -0,0 +1,14 @@
1
+ require 'railroader/processors/base_processor'
2
+ require 'railroader/processors/alias_processor'
3
+ require 'railroader/processors/lib/rails3_config_processor.rb'
4
+ require 'railroader/processors/lib/rails2_config_processor.rb'
5
+
6
+ class Railroader::ConfigProcessor
7
+ def self.new tracker
8
+ if tracker.options[:rails3]
9
+ Railroader::Rails3ConfigProcessor.new tracker
10
+ else
11
+ Railroader::Rails2ConfigProcessor.new tracker
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,278 @@
1
+ require 'railroader/processors/alias_processor'
2
+ require 'railroader/processors/lib/render_helper'
3
+ require 'railroader/processors/lib/render_path'
4
+ require 'railroader/processors/lib/find_return_value'
5
+
6
+ #Processes aliasing in controllers, but includes following
7
+ #renders in routes and putting variables into templates
8
+ class Railroader::ControllerAliasProcessor < Railroader::AliasProcessor
9
+ include Railroader::RenderHelper
10
+
11
+ #If only_method is specified, only that method will be processed,
12
+ #other methods will be skipped.
13
+ #This is for rescanning just a single action.
14
+ def initialize app_tree, tracker, only_method = nil
15
+ super tracker
16
+ @app_tree = app_tree
17
+ @only_method = only_method
18
+ @rendered = false
19
+ @current_class = @current_module = @current_method = nil
20
+ @method_cache = {} #Cache method lookups
21
+ end
22
+
23
+ def process_controller name, src, file_name
24
+ if not node_type? src, :class
25
+ Railroader.debug "#{name} is not a class, it's a #{src.node_type}"
26
+ return
27
+ else
28
+ @current_class = name
29
+ @file_name = file_name
30
+
31
+ process_default src
32
+
33
+ process_mixins
34
+ end
35
+ end
36
+
37
+ #Process modules mixed into the controller, in case they contain actions.
38
+ def process_mixins
39
+ controller = @tracker.controllers[@current_class]
40
+
41
+ controller.includes.each do |i|
42
+ mixin = @tracker.libs[i]
43
+
44
+ next unless mixin
45
+
46
+ #Process methods in alphabetical order for consistency
47
+ methods = mixin.methods_public.keys.map { |n| n.to_s }.sort.map { |n| n.to_sym }
48
+
49
+ methods.each do |name|
50
+ #Need to process the method like it was in a controller in order
51
+ #to get the renders set
52
+ processor = Railroader::ControllerProcessor.new(@app_tree, @tracker)
53
+ method = mixin.get_method(name)[:src].deep_clone
54
+
55
+ if node_type? method, :defn
56
+ method = processor.process_defn method
57
+ else
58
+ #Should be a defn, but this will catch other cases
59
+ method = processor.process method
60
+ end
61
+
62
+ @file_name = mixin.file
63
+ #Then process it like any other method in the controller
64
+ process method
65
+ end
66
+ end
67
+ end
68
+
69
+ #Skip it, must be an inner class
70
+ def process_class exp
71
+ exp
72
+ end
73
+
74
+ #Processes a method definition, which may include
75
+ #processing any rendered templates.
76
+ def process_defn exp
77
+ meth_name = exp.method_name
78
+
79
+ Railroader.debug "Processing #{@current_class}##{meth_name}"
80
+
81
+ #Skip if instructed to only process a specific method
82
+ #(but don't skip if this method was called from elsewhere)
83
+ return exp if @current_method.nil? and @only_method and @only_method != meth_name
84
+
85
+ is_route = route? meth_name
86
+ other_method = @current_method
87
+ @current_method = meth_name
88
+ @rendered = false if is_route
89
+
90
+ meth_env do
91
+ if is_route
92
+ before_filter_list(@current_method, @current_class).each do |f|
93
+ process_before_filter f
94
+ end
95
+ end
96
+
97
+ process_all exp.body
98
+
99
+ if is_route and not @rendered
100
+ process_default_render exp
101
+ end
102
+ end
103
+
104
+ @current_method = other_method
105
+ exp
106
+ end
107
+
108
+ #Look for calls to head()
109
+ def process_call exp
110
+ exp = super
111
+ return exp unless call? exp
112
+
113
+ method = exp.method
114
+
115
+ if method == :head
116
+ @rendered = true
117
+ elsif exp.target.nil? and method == :template_exists?
118
+ env[exp.first_arg] = Sexp.new(:lit, :"railroader:existing_template")
119
+ elsif @tracker.options[:interprocedural] and
120
+ @current_method and (exp.target.nil? or exp.target.node_type == :self)
121
+
122
+ exp = get_call_value(exp)
123
+ end
124
+
125
+ exp
126
+ end
127
+
128
+ #Check for +respond_to+
129
+ def process_iter exp
130
+ super
131
+
132
+ if call? exp.block_call and exp.block_call.method == :respond_to
133
+ @rendered = true
134
+ end
135
+
136
+ exp
137
+ end
138
+
139
+ #Processes a call to a before filter.
140
+ #Basically, adds any instance variable assignments to the environment.
141
+ #TODO: method arguments?
142
+ def process_before_filter name
143
+ filter = find_method name, @current_class
144
+
145
+ if filter.nil?
146
+ Railroader.debug "[Notice] Could not find filter #{name}"
147
+ return
148
+ end
149
+
150
+ method = filter[:method]
151
+
152
+ if ivars = @tracker.filter_cache[[filter[:controller], name]]
153
+ ivars.each do |variable, value|
154
+ env[variable] = value
155
+ end
156
+ else
157
+ processor = Railroader::AliasProcessor.new @tracker
158
+ processor.process_safely(method.body_list, only_ivars(:include_request_vars))
159
+
160
+ ivars = processor.only_ivars(:include_request_vars).all
161
+
162
+ @tracker.filter_cache[[filter[:controller], name]] = ivars
163
+
164
+ ivars.each do |variable, value|
165
+ env[variable] = value
166
+ end
167
+ end
168
+ end
169
+
170
+ #Processes the default template for the current action
171
+ def process_default_render exp
172
+ process_layout
173
+ process_template template_name, nil, nil, nil
174
+ end
175
+
176
+ #Process template and add the current class and method name as called_from info
177
+ def process_template name, args, _, line
178
+ # If line is null, assume implicit render and set the end of the action
179
+ # method as the line number
180
+ if line.nil? and controller = @tracker.controllers[@current_class]
181
+ if meth = controller.get_method(@current_method)
182
+ if line = meth[:src] && meth[:src].last && meth[:src].last.line
183
+ line += 1
184
+ else
185
+ line = 1
186
+ end
187
+ end
188
+ end
189
+
190
+ render_path = Railroader::RenderPath.new.add_controller_render(@current_class, @current_method, line, relative_path(@file_name))
191
+ super name, args, render_path, line
192
+ end
193
+
194
+ #Turns a method name into a template name
195
+ def template_name name = nil
196
+ name ||= @current_method
197
+ name = name.to_s
198
+ if name.include? "/"
199
+ name
200
+ else
201
+ controller = @current_class.to_s.gsub("Controller", "")
202
+ controller.gsub!("::", "/")
203
+ underscore(controller + "/" + name.to_s)
204
+ end
205
+ end
206
+
207
+ #Determines default layout name
208
+ def layout_name
209
+ controller = @tracker.controllers[@current_class]
210
+
211
+ return controller.layout if controller.layout
212
+ return false if controller.layout == false
213
+
214
+ app_controller = @tracker.controllers[:ApplicationController]
215
+
216
+ return app_controller.layout if app_controller and app_controller.layout
217
+
218
+ nil
219
+ end
220
+
221
+ #Returns true if the given method name is also a route
222
+ def route? method
223
+ if @tracker.routes[:allow_all_actions] or @tracker.options[:assume_all_routes]
224
+ true
225
+ else
226
+ routes = @tracker.routes[@current_class]
227
+ routes and (routes.include? :allow_all_actions or routes.include? method)
228
+ end
229
+ end
230
+
231
+ #Get list of filters, including those that are inherited
232
+ def before_filter_list method, klass
233
+ controller = @tracker.controllers[klass]
234
+
235
+ if controller
236
+ controller.before_filter_list self, method
237
+ else
238
+ []
239
+ end
240
+ end
241
+
242
+ #Finds a method in the given class or a parent class
243
+ #
244
+ #Returns nil if the method could not be found.
245
+ #
246
+ #If found, returns hash table with controller name and method sexp.
247
+ def find_method method_name, klass
248
+ return nil if sexp? method_name
249
+ method_name = method_name.to_sym
250
+
251
+ if method = @method_cache[method_name]
252
+ return method
253
+ end
254
+
255
+ controller = @tracker.controllers[klass]
256
+ controller ||= @tracker.libs[klass]
257
+
258
+ if klass and controller
259
+ method = controller.get_method method_name
260
+
261
+ if method.nil?
262
+ controller.includes.each do |included|
263
+ method = find_method method_name, included
264
+ if method
265
+ @method_cache[method_name] = method
266
+ return method
267
+ end
268
+ end
269
+
270
+ @method_cache[method_name] = find_method method_name, controller.parent
271
+ else
272
+ @method_cache[method_name] = { :controller => controller.name, :method => method[:src] }
273
+ end
274
+ else
275
+ nil
276
+ end
277
+ end
278
+ end