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,503 @@
1
+ require 'set'
2
+ require 'pathname'
3
+
4
+ #This is a mixin containing utility methods.
5
+ module Railroader::Util
6
+
7
+ QUERY_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request), :query_parameters)
8
+
9
+ PATH_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request), :path_parameters)
10
+
11
+ REQUEST_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request), :request_parameters)
12
+
13
+ REQUEST_PARAMS = Sexp.new(:call, Sexp.new(:call, nil, :request), :parameters)
14
+
15
+ REQUEST_ENV = Sexp.new(:call, Sexp.new(:call, nil, :request), :env)
16
+
17
+ PARAMETERS = Sexp.new(:call, nil, :params)
18
+
19
+ COOKIES = Sexp.new(:call, nil, :cookies)
20
+
21
+ REQUEST_COOKIES = s(:call, s(:call, nil, :request), :cookies)
22
+
23
+ SESSION = Sexp.new(:call, nil, :session)
24
+
25
+ ALL_PARAMETERS = Set[PARAMETERS, QUERY_PARAMETERS, PATH_PARAMETERS, REQUEST_PARAMETERS, REQUEST_PARAMS]
26
+
27
+ ALL_COOKIES = Set[COOKIES, REQUEST_COOKIES]
28
+
29
+ SAFE_LITERAL = s(:lit, :BRAKEMAN_SAFE_LITERAL)
30
+
31
+ #Convert a string from "something_like_this" to "SomethingLikeThis"
32
+ #
33
+ #Taken from ActiveSupport.
34
+ def camelize lower_case_and_underscored_word
35
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
36
+ end
37
+
38
+ #Convert a string from "Something::LikeThis" to "something/like_this"
39
+ #
40
+ #Taken from ActiveSupport.
41
+ def underscore camel_cased_word
42
+ camel_cased_word.to_s.gsub(/::/, '/').
43
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
44
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
45
+ tr("-", "_").
46
+ downcase
47
+ end
48
+
49
+ # stupid simple, used to delegate to ActiveSupport
50
+ def pluralize word
51
+ word + "s"
52
+ end
53
+
54
+ #Returns a class name as a Symbol.
55
+ #If class name cannot be determined, returns _exp_.
56
+ def class_name exp
57
+ case exp
58
+ when Sexp
59
+ case exp.node_type
60
+ when :const
61
+ exp.value
62
+ when :lvar
63
+ exp.value.to_sym
64
+ when :colon2
65
+ "#{class_name(exp.lhs)}::#{exp.rhs}".to_sym
66
+ when :colon3
67
+ "::#{exp.value}".to_sym
68
+ when :self
69
+ @current_class || @current_module || nil
70
+ else
71
+ exp
72
+ end
73
+ when Symbol
74
+ exp
75
+ when nil
76
+ nil
77
+ else
78
+ exp
79
+ end
80
+ end
81
+
82
+ #Takes an Sexp like
83
+ # (:hash, (:lit, :key), (:str, "value"))
84
+ #and yields the key and value pairs to the given block.
85
+ #
86
+ #For example:
87
+ #
88
+ # h = Sexp.new(:hash, (:lit, :name), (:str, "bob"), (:lit, :name), (:str, "jane"))
89
+ # names = []
90
+ # hash_iterate(h) do |key, value|
91
+ # if symbol? key and key[1] == :name
92
+ # names << value[1]
93
+ # end
94
+ # end
95
+ # names #["bob"]
96
+ def hash_iterate hash
97
+ 1.step(hash.length - 1, 2) do |i|
98
+ yield hash[i], hash[i + 1]
99
+ end
100
+ end
101
+
102
+ #Insert value into Hash Sexp
103
+ def hash_insert hash, key, value
104
+ index = 1
105
+ hash_iterate hash.dup do |k,v|
106
+ if k == key
107
+ hash[index + 1] = value
108
+ return hash
109
+ end
110
+ index += 2
111
+ end
112
+
113
+ hash << key << value
114
+
115
+ hash
116
+ end
117
+
118
+ #Get value from hash using key.
119
+ #
120
+ #If _key_ is a Symbol, it will be converted to a Sexp(:lit, key).
121
+ def hash_access hash, key
122
+ if key.is_a? Symbol
123
+ key = Sexp.new(:lit, key)
124
+ end
125
+
126
+ if index = hash.find_index(key) and index > 0
127
+ return hash[index + 1]
128
+ end
129
+
130
+ nil
131
+ end
132
+
133
+ #These are never modified
134
+ PARAMS_SEXP = Sexp.new(:params)
135
+ SESSION_SEXP = Sexp.new(:session)
136
+ COOKIES_SEXP = Sexp.new(:cookies)
137
+
138
+ #Adds params, session, and cookies to environment
139
+ #so they can be replaced by their respective Sexps.
140
+ def set_env_defaults
141
+ @env[PARAMETERS] = PARAMS_SEXP
142
+ @env[SESSION] = SESSION_SEXP
143
+ @env[COOKIES] = COOKIES_SEXP
144
+ end
145
+
146
+ #Check if _exp_ represents a hash: s(:hash, {...})
147
+ #This also includes pseudo hashes params, session, and cookies.
148
+ def hash? exp
149
+ exp.is_a? Sexp and (exp.node_type == :hash or
150
+ exp.node_type == :params or
151
+ exp.node_type == :session or
152
+ exp.node_type == :cookies)
153
+ end
154
+
155
+ #Check if _exp_ represents an array: s(:array, [...])
156
+ def array? exp
157
+ exp.is_a? Sexp and exp.node_type == :array
158
+ end
159
+
160
+ #Check if _exp_ represents a String: s(:str, "...")
161
+ def string? exp
162
+ exp.is_a? Sexp and exp.node_type == :str
163
+ end
164
+
165
+ def string_interp? exp
166
+ exp.is_a? Sexp and exp.node_type == :dstr
167
+ end
168
+
169
+ #Check if _exp_ represents a Symbol: s(:lit, :...)
170
+ def symbol? exp
171
+ exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Symbol
172
+ end
173
+
174
+ #Check if _exp_ represents a method call: s(:call, ...)
175
+ def call? exp
176
+ exp.is_a? Sexp and
177
+ (exp.node_type == :call or exp.node_type == :safe_call)
178
+ end
179
+
180
+ #Check if _exp_ represents a Regexp: s(:lit, /.../)
181
+ def regexp? exp
182
+ exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Regexp
183
+ end
184
+
185
+ #Check if _exp_ represents an Integer: s(:lit, ...)
186
+ def integer? exp
187
+ exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Integer
188
+ end
189
+
190
+ #Check if _exp_ represents a number: s(:lit, ...)
191
+ def number? exp
192
+ exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Numeric
193
+ end
194
+
195
+ #Check if _exp_ represents a result: s(:result, ...)
196
+ def result? exp
197
+ exp.is_a? Sexp and exp.node_type == :result
198
+ end
199
+
200
+ #Check if _exp_ represents a :true, :lit, or :string node
201
+ def true? exp
202
+ exp.is_a? Sexp and (exp.node_type == :true or
203
+ exp.node_type == :lit or
204
+ exp.node_type == :string)
205
+ end
206
+
207
+ #Check if _exp_ represents a :false or :nil node
208
+ def false? exp
209
+ exp.is_a? Sexp and (exp.node_type == :false or
210
+ exp.node_type == :nil)
211
+ end
212
+
213
+ #Check if _exp_ represents a block of code
214
+ def block? exp
215
+ exp.is_a? Sexp and (exp.node_type == :block or
216
+ exp.node_type == :rlist)
217
+ end
218
+
219
+ #Check if _exp_ is a params hash
220
+ def params? exp
221
+ if exp.is_a? Sexp
222
+ return true if exp.node_type == :params or ALL_PARAMETERS.include? exp
223
+
224
+ if call? exp
225
+ if params? exp[1]
226
+ return true
227
+ elsif exp[2] == :[]
228
+ return params? exp[1]
229
+ end
230
+ end
231
+ end
232
+
233
+ false
234
+ end
235
+
236
+ def cookies? exp
237
+ if exp.is_a? Sexp
238
+ return true if exp.node_type == :cookies or ALL_COOKIES.include? exp
239
+
240
+ if call? exp
241
+ if cookies? exp[1]
242
+ return true
243
+ elsif exp[2] == :[]
244
+ return cookies? exp[1]
245
+ end
246
+ end
247
+ end
248
+
249
+ false
250
+ end
251
+
252
+ def request_env? exp
253
+ call? exp and (exp == REQUEST_ENV or exp[1] == REQUEST_ENV)
254
+ end
255
+
256
+ #Check if exp is params, cookies, or request_env
257
+ def request_value? exp
258
+ params? exp or
259
+ cookies? exp or
260
+ request_env? exp
261
+ end
262
+
263
+ def constant? exp
264
+ node_type? exp, :const, :colon2, :colon3
265
+ end
266
+
267
+ #Check if _exp_ is a Sexp.
268
+ def sexp? exp
269
+ exp.is_a? Sexp
270
+ end
271
+
272
+ #Check if _exp_ is a Sexp and the node type matches one of the given types.
273
+ def node_type? exp, *types
274
+ exp.is_a? Sexp and types.include? exp.node_type
275
+ end
276
+
277
+ #Returns true if the given _exp_ contains a :class node.
278
+ #
279
+ #Useful for checking if a module is just a module or if it is a namespace.
280
+ def contains_class? exp
281
+ todo = [exp]
282
+
283
+ until todo.empty?
284
+ current = todo.shift
285
+
286
+ if node_type? current, :class
287
+ return true
288
+ elsif sexp? current
289
+ todo = current[1..-1].concat todo
290
+ end
291
+ end
292
+
293
+ false
294
+ end
295
+
296
+ def make_call target, method, *args
297
+ call = Sexp.new(:call, target, method)
298
+
299
+ if args.empty? or args.first.empty?
300
+ #nothing to do
301
+ elsif node_type? args.first, :arglist
302
+ call.concat args.first[1..-1]
303
+ elsif args.first.node_type.is_a? Sexp #just a list of args
304
+ call.concat args.first
305
+ else
306
+ call.concat args
307
+ end
308
+
309
+ call
310
+ end
311
+
312
+ def safe_literal line = nil
313
+ s(:lit, :BRAKEMAN_SAFE_LITERAL).line(line || 0)
314
+ end
315
+
316
+ def safe_literal? exp
317
+ exp == SAFE_LITERAL
318
+ end
319
+
320
+ def safe_literal_target? exp
321
+ if call? exp
322
+ safe_literal_target? exp.target
323
+ else
324
+ safe_literal? exp
325
+ end
326
+ end
327
+
328
+ def rails_version
329
+ @tracker.config.rails_version
330
+ end
331
+
332
+ #Return file name related to given warning. Uses +warning.file+ if it exists
333
+ def file_for warning, tracker = nil
334
+ if tracker.nil?
335
+ tracker = @tracker || self.tracker
336
+ end
337
+
338
+ if warning.file
339
+ File.expand_path warning.file, tracker.app_path
340
+ elsif warning.template and warning.template.file
341
+ warning.template.file
342
+ else
343
+ case warning.warning_set
344
+ when :controller
345
+ file_by_name warning.controller, :controller, tracker
346
+ when :template
347
+ file_by_name warning.template.name, :template, tracker
348
+ when :model
349
+ file_by_name warning.model, :model, tracker
350
+ when :warning
351
+ file_by_name warning.class, nil, tracker
352
+ else
353
+ nil
354
+ end
355
+ end
356
+ end
357
+
358
+ #Attempt to determine path to context file based on the reported name
359
+ #in the warning.
360
+ #
361
+ #For example,
362
+ #
363
+ # file_by_name FileController #=> "/rails/root/app/controllers/file_controller.rb
364
+ def file_by_name name, type, tracker = nil
365
+ return nil unless name
366
+ string_name = name.to_s
367
+ name = name.to_sym
368
+
369
+ unless type
370
+ if string_name =~ /Controller$/
371
+ type = :controller
372
+ elsif camelize(string_name) == string_name # This is not always true
373
+ type = :model
374
+ else
375
+ type = :template
376
+ end
377
+ end
378
+
379
+ path = tracker.app_path
380
+
381
+ case type
382
+ when :controller
383
+ if tracker.controllers[name]
384
+ path = tracker.controllers[name].file
385
+ else
386
+ path += "/app/controllers/#{underscore(string_name)}.rb"
387
+ end
388
+ when :model
389
+ if tracker.models[name]
390
+ path = tracker.models[name].file
391
+ else
392
+ path += "/app/models/#{underscore(string_name)}.rb"
393
+ end
394
+ when :template
395
+ if tracker.templates[name] and tracker.templates[name].file
396
+ path = tracker.templates[name].file
397
+ elsif string_name.include? " "
398
+ name = string_name.split[0].to_sym
399
+ path = file_for tracker, name, :template
400
+ else
401
+ path = nil
402
+ end
403
+ end
404
+
405
+ path
406
+ end
407
+
408
+ #Return array of lines surrounding the warning location from the original
409
+ #file.
410
+ def context_for app_tree, warning, tracker = nil
411
+ file = file_for warning, tracker
412
+ context = []
413
+ return context unless warning.line and file and @app_tree.path_exists? file
414
+
415
+ current_line = 0
416
+ start_line = warning.line - 5
417
+ end_line = warning.line + 5
418
+
419
+ start_line = 1 if start_line < 0
420
+
421
+ File.open file do |f|
422
+ f.each_line do |line|
423
+ current_line += 1
424
+
425
+ next if line.strip == ""
426
+
427
+ if current_line > end_line
428
+ break
429
+ end
430
+
431
+ if current_line >= start_line
432
+ context << [current_line, line]
433
+ end
434
+ end
435
+ end
436
+
437
+ context
438
+ end
439
+
440
+ def relative_path file
441
+ pname = Pathname.new file
442
+ if file and not file.empty? and pname.absolute?
443
+ pname.relative_path_from(Pathname.new(@tracker.app_path)).to_s
444
+ else
445
+ file
446
+ end
447
+ end
448
+
449
+ #Convert path/filename to view name
450
+ #
451
+ # views/test/something.html.erb -> test/something
452
+ def template_path_to_name path
453
+ names = path.split("/")
454
+ names.last.gsub!(/(\.(html|js)\..*|\.(rhtml|haml|erb|slim))$/, '')
455
+ names[(names.index("views") + 1)..-1].join("/").to_sym
456
+ end
457
+
458
+ def github_url file, line=nil
459
+ if repo_url = @tracker.options[:github_url] and file and not file.empty? and file.start_with? '/'
460
+ url = "#{repo_url}/#{relative_path(file)}"
461
+ url << "#L#{line}" if line
462
+ else
463
+ nil
464
+ end
465
+ end
466
+
467
+ def truncate_table str
468
+ @terminal_width ||= if @tracker.options[:table_width]
469
+ @tracker.options[:table_width]
470
+ elsif $stdin && $stdin.tty?
471
+ Railroader.load_railroader_dependency 'highline'
472
+ ::HighLine.new.terminal_size[0]
473
+ else
474
+ 80
475
+ end
476
+ lines = str.lines
477
+
478
+ lines.map do |line|
479
+ if line.chomp.length > @terminal_width
480
+ line[0..(@terminal_width - 3)] + ">>\n"
481
+ else
482
+ line
483
+ end
484
+ end.join
485
+ end
486
+
487
+ # rely on Terminal::Table to build the structure, extract the data out in CSV format
488
+ def table_to_csv table
489
+ return "" unless table
490
+
491
+ Railroader.load_railroader_dependency 'terminal-table'
492
+ headings = table.headings
493
+ if headings.is_a? Array
494
+ headings = headings.first
495
+ end
496
+
497
+ output = CSV.generate_line(headings.cells.map{|cell| cell.to_s.strip})
498
+ table.rows.each do |row|
499
+ output << CSV.generate_line(row.cells.map{|cell| cell.to_s.strip})
500
+ end
501
+ output
502
+ end
503
+ end
@@ -0,0 +1,3 @@
1
+ module Railroader
2
+ Version = "4.3.4"
3
+ end