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,22 @@
1
+ <h2>Controllers</h2>
2
+
3
+ <table>
4
+ <thead>
5
+ <tr>
6
+ <th>Name</th>
7
+ <th>Parent</th>
8
+ <th>Includes</th>
9
+ <th>Routes</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% controller_rows.each do |row| %>
14
+ <tr>
15
+ <td><%= row['Name'] %></td>
16
+ <td><%= row['Parent'] %></td>
17
+ <td><%= row['Includes'] %></td>
18
+ <td><%= row['Routes'] %></td>
19
+ </tr>
20
+ <% end %>
21
+ </tbody>
22
+ </table>
@@ -0,0 +1,21 @@
1
+ <p>Controller Warnings</p>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Confidence</th>
6
+ <th>Controller</th>
7
+ <th>Warning Type</th>
8
+ <th>Message</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% warnings.each do |warning| %>
13
+ <tr>
14
+ <td><%= warning['Confidence']%></td>
15
+ <td><%= warning['Controller']%></td>
16
+ <td><%= warning['Warning Type']%></td>
17
+ <td><%= warning['Message']%></td>
18
+ </tr>
19
+ <% end %>
20
+ </tbody>
21
+ </table>
@@ -0,0 +1,29 @@
1
+ <div onClick="toggle('errors_table');"> <h2>Exceptions raised during the analysis (click to see them)</h2 ></div>
2
+ <div>
3
+ <div id='errors_table' style='display:none'>
4
+ <table>
5
+ <thead>
6
+ <tr>
7
+ <th>Error</th>
8
+ <th>Location</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% tracker.errors.each do |warning| %>
13
+ <tr>
14
+ <td><%= CGI.escapeHTML warning[:error] %></td>
15
+ <td>
16
+ <% if tracker.options[:debug] %>
17
+ <% warning[:backtrace].each do |line| %>
18
+ <%= line %><br/>
19
+ <% end %>
20
+ <% else %>
21
+ <%= warning[:backtrace][0] %>
22
+ <% end %>
23
+ </td>
24
+ </tr>
25
+ <% end %>
26
+ </tbody>
27
+ </table>
28
+ </div>
29
+ </div>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE HTML SYSTEM>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <title>Railroader Report</title>
6
+ <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
7
+ <script type="text/javascript" src="https://cdn.datatables.net/1.10.9/js/jquery.dataTables.min.js"></script>
8
+ <script type="text/javascript">
9
+ function toggle(context) {
10
+ var elem = document.getElementById(context);
11
+
12
+ if (elem.style.display != "block")
13
+ elem.style.display = "block";
14
+ else
15
+ elem.style.display = "none";
16
+
17
+ elem.parentNode.scrollIntoView();
18
+ }
19
+
20
+ $(document).ready(function() {
21
+ $('table').DataTable({
22
+ searching: false,
23
+ paging: false,
24
+ info: false
25
+ });
26
+ });
27
+ </script>
28
+ <style>
29
+ <%= css %>
30
+ </style>
31
+ </head>
32
+ <body>
33
+
34
+ <h1>Railroader Report</h1>
35
+ <table>
36
+ <thead>
37
+ <tr>
38
+ <th>Application Path</th>
39
+ <th>Rails Version</th>
40
+ <th>Railroader Version</th>
41
+ <th>Report Time</th>
42
+ <th>Checks Performed</th>
43
+ </tr>
44
+ </thead>
45
+ <tbody>
46
+ <tr>
47
+ <td><%= tracker.app_path %></td>
48
+ <td><%= rails_version %></td>
49
+ <td><%= railroader_version %>
50
+ <td>
51
+ <%= tracker.start_time %><br><br>
52
+ <%= tracker.duration %> seconds
53
+ </td>
54
+ <td><%= checks.checks_run.sort.join(", ") %></td>
55
+ </tr>
56
+ </tbody>
57
+ </table>
58
+ <br>
@@ -0,0 +1,25 @@
1
+ <div onClick="toggle('ignored_table');"> <h2><%= warnings.length %> Ignored Warnings (click to see them)</h2 ></div>
2
+ <div>
3
+ <table style="display:none" id="ignored_table">
4
+ <thead>
5
+ <tr>
6
+ <th>Confidence</th>
7
+ <th>File</th>
8
+ <th>Warning Type</th>
9
+ <th>Message</th>
10
+ <th>Note</th>
11
+ </tr>
12
+ </thead>
13
+ <tbody>
14
+ <% warnings.each do |warning| %>
15
+ <tr>
16
+ <td><%= warning['Confidence']%></td>
17
+ <td><%= warning['File']%></td>
18
+ <td><%= warning['Warning Type']%></td>
19
+ <td><%= warning['Message']%></td>
20
+ <td><%= warning['Note']%></td>
21
+ </tr>
22
+ <% end %>
23
+ </tbody>
24
+ </table>
25
+ </div>
@@ -0,0 +1,21 @@
1
+ <p>Model Warnings</p>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Confidence</th>
6
+ <th>Model</th>
7
+ <th>Warning Type</th>
8
+ <th>Message</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% warnings.each do |warning| %>
13
+ <tr>
14
+ <td><%= warning['Confidence']%></td>
15
+ <td><%= warning['Model']%></td>
16
+ <td><%= warning['Warning Type']%></td>
17
+ <td><%= warning['Message']%></td>
18
+ </tr>
19
+ <% end %>
20
+ </tbody>
21
+ </table>
@@ -0,0 +1,38 @@
1
+ <h2 id='summary'>Summary</h2>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Scanned/Reported</th>
6
+ <th>Total</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody>
10
+ <tr>
11
+ <td>Controllers</td>
12
+ <td><%= tracker.controllers.length %></td>
13
+ </tr>
14
+ <tr>
15
+ <td>Models</td>
16
+ <td><%= tracker.models.length - 1 %></td>
17
+ </tr>
18
+ <tr>
19
+ <td>Templates</td>
20
+ <td><%= number_of_templates %></td>
21
+ </tr>
22
+ <tr>
23
+ <td>Errors</td>
24
+ <td><%= tracker.errors.length %></td>
25
+ </tr>
26
+ <tr>
27
+ <td>Security Warnings</td>
28
+ <td><%= warnings %> <span class='high-confidence'>(<%= warnings_summary[:high_confidence] %>)</span></td>
29
+ </tr>
30
+ <% if warnings_summary['Ignored Warnings'] %>
31
+ <tr>
32
+ <td>Ignored Warnings</td>
33
+ <td><%= ignored_warnings %></td>
34
+ </tr>
35
+ <% end %>
36
+ </tbody>
37
+ </table>
38
+ <br>
@@ -0,0 +1,23 @@
1
+ <h2>Security Warnings</h2>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Confidence</th>
6
+ <th>Class</th>
7
+ <th>Method</th>
8
+ <th>Warning Type</th>
9
+ <th>Message</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% warnings.each do |warning| %>
14
+ <tr>
15
+ <td><%= warning['Confidence']%></td>
16
+ <td><%= warning['Class']%></td>
17
+ <td><%= warning['Method']%></td>
18
+ <td><%= warning['Warning Type']%></td>
19
+ <td><%= warning['Message']%></td>
20
+ </tr>
21
+ <% end %>
22
+ </tbody>
23
+ </table>
@@ -0,0 +1,21 @@
1
+ <h2>Templates</h2>
2
+
3
+ <% template_rows.each do |template| %>
4
+
5
+ <p><%= template[0] %></p>
6
+ <table>
7
+ <thead>
8
+ <tr>
9
+ <th>Output</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% template[1].each do |call| %>
14
+ <tr>
15
+ <td><%= call %></td>
16
+ </tr>
17
+ <% end %>
18
+ </tbody>
19
+ </table>
20
+
21
+ <% end %>
@@ -0,0 +1,34 @@
1
+ <p>View Warnings</p>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Confidence</th>
6
+ <th>Template</th>
7
+ <th>Warning Type</th>
8
+ <th>Message</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% warnings.each_with_index do |warning, i| %>
13
+ <tr>
14
+ <td><%= warning['Confidence']%></td>
15
+ <td>
16
+ <% if warning['Called From'] and warning['Called From'].length > 1 %>
17
+ <div class="template_name" onClick="toggle('callers<%= i %>')" >
18
+ <div>
19
+ <%= warning['Template'] %>
20
+ </div>
21
+ <div class="render_path" id="callers<%= i %>" >
22
+ <%= warning['Called From'].join(' &rarr; ') %> &rarr; <%= warning['Template Name'] %>
23
+ </div>
24
+ </div>
25
+ <% else %>
26
+ <%= warning['Template']%>
27
+ <% end %>
28
+ </td>
29
+ <td><%= warning['Warning Type']%></td>
30
+ <td><%= warning['Message']%></td>
31
+ </tr>
32
+ <% end %>
33
+ </tbody>
34
+ </table>
@@ -0,0 +1,17 @@
1
+ <table>
2
+ <thead>
3
+ <tr>
4
+ <th>Warning Type</th>
5
+ <th>Total</th>
6
+ </tr>
7
+ </thead>
8
+ <tbody>
9
+ <% types.sort.each do |warning_type| %>
10
+ <tr>
11
+ <td><%= warning_type %></td>
12
+ <td><%= warnings_summary[warning_type] %></td>
13
+ </tr>
14
+ <% end %>
15
+ </tbody>
16
+ </table>
17
+ <br>
@@ -0,0 +1,88 @@
1
+ require 'railroader/report/report_base'
2
+
3
+ #Generates a report based on the Tracker and the results of
4
+ #Tracker#run_checks. Be sure to +run_checks+ before generating
5
+ #a report.
6
+ class Railroader::Report
7
+ attr_reader :tracker
8
+
9
+ VALID_FORMATS = [:to_html, :to_pdf, :to_csv, :to_json, :to_tabs, :to_hash, :to_s, :to_markdown, :to_codeclimate, :to_plain, :to_text]
10
+
11
+ def initialize app_tree, tracker
12
+ @app_tree = app_tree
13
+ @tracker = tracker
14
+ end
15
+
16
+ def format format
17
+ reporter = case format
18
+ when :to_codeclimate
19
+ require_report 'codeclimate'
20
+ Railroader::Report::CodeClimate
21
+ when :to_csv
22
+ require_report 'csv'
23
+ Railroader::Report::CSV
24
+ when :to_html
25
+ require_report 'html'
26
+ Railroader::Report::HTML
27
+ when :to_json
28
+ return self.to_json
29
+ when :to_tabs
30
+ require_report 'tabs'
31
+ Railroader::Report::Tabs
32
+ when :to_hash
33
+ require_report 'hash'
34
+ Railroader::Report::Hash
35
+ when :to_markdown
36
+ return self.to_markdown
37
+ when :to_plain, :to_text, :to_s
38
+ return self.to_plain
39
+ when :to_table
40
+ return self.to_table
41
+ when :to_pdf
42
+ raise "PDF output is not yet supported."
43
+ else
44
+ raise "Invalid format: #{format}. Should be one of #{VALID_FORMATS.inspect}"
45
+ end
46
+
47
+ generate(reporter)
48
+ end
49
+
50
+ def method_missing method, *args
51
+ if VALID_FORMATS.include? method
52
+ format method
53
+ else
54
+ super
55
+ end
56
+ end
57
+
58
+ def require_report type
59
+ require "railroader/report/report_#{type}"
60
+ end
61
+
62
+ def to_json
63
+ require_report 'json'
64
+ generate Railroader::Report::JSON
65
+ end
66
+
67
+ def to_table
68
+ require_report 'table'
69
+ generate Railroader::Report::Table
70
+ end
71
+
72
+ def to_markdown
73
+ require_report 'markdown'
74
+ generate Railroader::Report::Markdown
75
+ end
76
+
77
+ def to_text
78
+ require_report 'text'
79
+ generate Railroader::Report::Text
80
+ end
81
+
82
+ alias to_plain to_text
83
+ alias to_s to_text
84
+
85
+ def generate reporter
86
+ reporter.new(@app_tree, @tracker).generate_report
87
+ end
88
+ end