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.
- checksums.yaml +7 -0
- data/CHANGES.md +1091 -0
- data/FEATURES +16 -0
- data/README.md +174 -0
- data/bin/railroader +8 -0
- data/lib/railroader/app_tree.rb +191 -0
- data/lib/railroader/call_index.rb +219 -0
- data/lib/railroader/checks/base_check.rb +505 -0
- data/lib/railroader/checks/check_basic_auth.rb +88 -0
- data/lib/railroader/checks/check_basic_auth_timing_attack.rb +33 -0
- data/lib/railroader/checks/check_content_tag.rb +200 -0
- data/lib/railroader/checks/check_create_with.rb +74 -0
- data/lib/railroader/checks/check_cross_site_scripting.rb +381 -0
- data/lib/railroader/checks/check_default_routes.rb +86 -0
- data/lib/railroader/checks/check_deserialize.rb +56 -0
- data/lib/railroader/checks/check_detailed_exceptions.rb +55 -0
- data/lib/railroader/checks/check_digest_dos.rb +38 -0
- data/lib/railroader/checks/check_divide_by_zero.rb +42 -0
- data/lib/railroader/checks/check_dynamic_finders.rb +48 -0
- data/lib/railroader/checks/check_escape_function.rb +21 -0
- data/lib/railroader/checks/check_evaluation.rb +35 -0
- data/lib/railroader/checks/check_execute.rb +189 -0
- data/lib/railroader/checks/check_file_access.rb +71 -0
- data/lib/railroader/checks/check_file_disclosure.rb +35 -0
- data/lib/railroader/checks/check_filter_skipping.rb +31 -0
- data/lib/railroader/checks/check_forgery_setting.rb +81 -0
- data/lib/railroader/checks/check_header_dos.rb +31 -0
- data/lib/railroader/checks/check_i18n_xss.rb +48 -0
- data/lib/railroader/checks/check_jruby_xml.rb +36 -0
- data/lib/railroader/checks/check_json_encoding.rb +47 -0
- data/lib/railroader/checks/check_json_parsing.rb +107 -0
- data/lib/railroader/checks/check_link_to.rb +132 -0
- data/lib/railroader/checks/check_link_to_href.rb +146 -0
- data/lib/railroader/checks/check_mail_to.rb +49 -0
- data/lib/railroader/checks/check_mass_assignment.rb +196 -0
- data/lib/railroader/checks/check_mime_type_dos.rb +39 -0
- data/lib/railroader/checks/check_model_attr_accessible.rb +55 -0
- data/lib/railroader/checks/check_model_attributes.rb +119 -0
- data/lib/railroader/checks/check_model_serialize.rb +67 -0
- data/lib/railroader/checks/check_nested_attributes.rb +38 -0
- data/lib/railroader/checks/check_nested_attributes_bypass.rb +58 -0
- data/lib/railroader/checks/check_number_to_currency.rb +74 -0
- data/lib/railroader/checks/check_permit_attributes.rb +43 -0
- data/lib/railroader/checks/check_quote_table_name.rb +40 -0
- data/lib/railroader/checks/check_redirect.rb +256 -0
- data/lib/railroader/checks/check_regex_dos.rb +68 -0
- data/lib/railroader/checks/check_render.rb +97 -0
- data/lib/railroader/checks/check_render_dos.rb +37 -0
- data/lib/railroader/checks/check_render_inline.rb +53 -0
- data/lib/railroader/checks/check_response_splitting.rb +21 -0
- data/lib/railroader/checks/check_route_dos.rb +42 -0
- data/lib/railroader/checks/check_safe_buffer_manipulation.rb +31 -0
- data/lib/railroader/checks/check_sanitize_methods.rb +112 -0
- data/lib/railroader/checks/check_secrets.rb +40 -0
- data/lib/railroader/checks/check_select_tag.rb +59 -0
- data/lib/railroader/checks/check_select_vulnerability.rb +60 -0
- data/lib/railroader/checks/check_send.rb +47 -0
- data/lib/railroader/checks/check_send_file.rb +19 -0
- data/lib/railroader/checks/check_session_manipulation.rb +35 -0
- data/lib/railroader/checks/check_session_settings.rb +176 -0
- data/lib/railroader/checks/check_simple_format.rb +58 -0
- data/lib/railroader/checks/check_single_quotes.rb +101 -0
- data/lib/railroader/checks/check_skip_before_filter.rb +60 -0
- data/lib/railroader/checks/check_sql.rb +700 -0
- data/lib/railroader/checks/check_sql_cves.rb +106 -0
- data/lib/railroader/checks/check_ssl_verify.rb +48 -0
- data/lib/railroader/checks/check_strip_tags.rb +89 -0
- data/lib/railroader/checks/check_symbol_dos.rb +71 -0
- data/lib/railroader/checks/check_symbol_dos_cve.rb +30 -0
- data/lib/railroader/checks/check_translate_bug.rb +45 -0
- data/lib/railroader/checks/check_unsafe_reflection.rb +50 -0
- data/lib/railroader/checks/check_unscoped_find.rb +57 -0
- data/lib/railroader/checks/check_validation_regex.rb +116 -0
- data/lib/railroader/checks/check_weak_hash.rb +148 -0
- data/lib/railroader/checks/check_without_protection.rb +80 -0
- data/lib/railroader/checks/check_xml_dos.rb +45 -0
- data/lib/railroader/checks/check_yaml_parsing.rb +121 -0
- data/lib/railroader/checks.rb +209 -0
- data/lib/railroader/codeclimate/engine_configuration.rb +97 -0
- data/lib/railroader/commandline.rb +179 -0
- data/lib/railroader/differ.rb +66 -0
- data/lib/railroader/file_parser.rb +54 -0
- data/lib/railroader/format/style.css +133 -0
- data/lib/railroader/options.rb +339 -0
- data/lib/railroader/parsers/rails2_erubis.rb +6 -0
- data/lib/railroader/parsers/rails2_xss_plugin_erubis.rb +48 -0
- data/lib/railroader/parsers/rails3_erubis.rb +81 -0
- data/lib/railroader/parsers/template_parser.rb +108 -0
- data/lib/railroader/processor.rb +102 -0
- data/lib/railroader/processors/alias_processor.rb +1229 -0
- data/lib/railroader/processors/base_processor.rb +295 -0
- data/lib/railroader/processors/config_processor.rb +14 -0
- data/lib/railroader/processors/controller_alias_processor.rb +278 -0
- data/lib/railroader/processors/controller_processor.rb +249 -0
- data/lib/railroader/processors/erb_template_processor.rb +77 -0
- data/lib/railroader/processors/erubis_template_processor.rb +92 -0
- data/lib/railroader/processors/gem_processor.rb +64 -0
- data/lib/railroader/processors/haml_template_processor.rb +191 -0
- data/lib/railroader/processors/lib/basic_processor.rb +37 -0
- data/lib/railroader/processors/lib/call_conversion_helper.rb +90 -0
- data/lib/railroader/processors/lib/find_all_calls.rb +224 -0
- data/lib/railroader/processors/lib/find_call.rb +183 -0
- data/lib/railroader/processors/lib/find_return_value.rb +166 -0
- data/lib/railroader/processors/lib/module_helper.rb +111 -0
- data/lib/railroader/processors/lib/processor_helper.rb +88 -0
- data/lib/railroader/processors/lib/rails2_config_processor.rb +145 -0
- data/lib/railroader/processors/lib/rails2_route_processor.rb +313 -0
- data/lib/railroader/processors/lib/rails3_config_processor.rb +132 -0
- data/lib/railroader/processors/lib/rails3_route_processor.rb +308 -0
- data/lib/railroader/processors/lib/render_helper.rb +181 -0
- data/lib/railroader/processors/lib/render_path.rb +107 -0
- data/lib/railroader/processors/lib/route_helper.rb +68 -0
- data/lib/railroader/processors/lib/safe_call_helper.rb +16 -0
- data/lib/railroader/processors/library_processor.rb +74 -0
- data/lib/railroader/processors/model_processor.rb +91 -0
- data/lib/railroader/processors/output_processor.rb +144 -0
- data/lib/railroader/processors/route_processor.rb +17 -0
- data/lib/railroader/processors/slim_template_processor.rb +111 -0
- data/lib/railroader/processors/template_alias_processor.rb +118 -0
- data/lib/railroader/processors/template_processor.rb +85 -0
- data/lib/railroader/report/config/remediation.yml +71 -0
- data/lib/railroader/report/ignore/config.rb +153 -0
- data/lib/railroader/report/ignore/interactive.rb +362 -0
- data/lib/railroader/report/pager.rb +112 -0
- data/lib/railroader/report/renderer.rb +24 -0
- data/lib/railroader/report/report_base.rb +292 -0
- data/lib/railroader/report/report_codeclimate.rb +79 -0
- data/lib/railroader/report/report_csv.rb +55 -0
- data/lib/railroader/report/report_hash.rb +23 -0
- data/lib/railroader/report/report_html.rb +216 -0
- data/lib/railroader/report/report_json.rb +45 -0
- data/lib/railroader/report/report_markdown.rb +107 -0
- data/lib/railroader/report/report_table.rb +117 -0
- data/lib/railroader/report/report_tabs.rb +17 -0
- data/lib/railroader/report/report_text.rb +198 -0
- data/lib/railroader/report/templates/controller_overview.html.erb +22 -0
- data/lib/railroader/report/templates/controller_warnings.html.erb +21 -0
- data/lib/railroader/report/templates/error_overview.html.erb +29 -0
- data/lib/railroader/report/templates/header.html.erb +58 -0
- data/lib/railroader/report/templates/ignored_warnings.html.erb +25 -0
- data/lib/railroader/report/templates/model_warnings.html.erb +21 -0
- data/lib/railroader/report/templates/overview.html.erb +38 -0
- data/lib/railroader/report/templates/security_warnings.html.erb +23 -0
- data/lib/railroader/report/templates/template_overview.html.erb +21 -0
- data/lib/railroader/report/templates/view_warnings.html.erb +34 -0
- data/lib/railroader/report/templates/warning_overview.html.erb +17 -0
- data/lib/railroader/report.rb +88 -0
- data/lib/railroader/rescanner.rb +483 -0
- data/lib/railroader/scanner.rb +321 -0
- data/lib/railroader/tracker/collection.rb +93 -0
- data/lib/railroader/tracker/config.rb +154 -0
- data/lib/railroader/tracker/constants.rb +171 -0
- data/lib/railroader/tracker/controller.rb +161 -0
- data/lib/railroader/tracker/library.rb +17 -0
- data/lib/railroader/tracker/model.rb +90 -0
- data/lib/railroader/tracker/template.rb +33 -0
- data/lib/railroader/tracker.rb +362 -0
- data/lib/railroader/util.rb +503 -0
- data/lib/railroader/version.rb +3 -0
- data/lib/railroader/warning.rb +294 -0
- data/lib/railroader/warning_codes.rb +117 -0
- data/lib/railroader.rb +544 -0
- data/lib/ruby_parser/bm_sexp.rb +626 -0
- data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
- metadata +386 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Railroader::RouteHelper
|
|
2
|
+
#Manage Controller prefixes
|
|
3
|
+
#@prefix is an Array, but this method returns a string
|
|
4
|
+
#suitable for prefixing onto a controller name.
|
|
5
|
+
def prefix
|
|
6
|
+
if @prefix.length > 0
|
|
7
|
+
@prefix.join("::") << "::"
|
|
8
|
+
else
|
|
9
|
+
''
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
#Sets the controller name to a proper class name.
|
|
14
|
+
#For example
|
|
15
|
+
# self.current_controller = :session
|
|
16
|
+
# @controller == :SessionController #true
|
|
17
|
+
#
|
|
18
|
+
#Also prepends the prefix if there is one set.
|
|
19
|
+
def current_controller= name
|
|
20
|
+
@current_controller = (prefix + camelize(name) + "Controller").to_sym
|
|
21
|
+
@tracker.routes[@current_controller] ||= Set.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#Add route to controller. If a controller is specified,
|
|
25
|
+
#the current controller will be set to that controller.
|
|
26
|
+
#If no controller is specified, uses current controller value.
|
|
27
|
+
def add_route route, controller = nil
|
|
28
|
+
if node_type? route, :str, :lit
|
|
29
|
+
route = route.value
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
return unless route.is_a? String or route.is_a? Symbol
|
|
33
|
+
|
|
34
|
+
if route.is_a? String and controller.nil? and route.include? ":controller"
|
|
35
|
+
controller = ":controller"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
route = route.to_sym
|
|
39
|
+
|
|
40
|
+
if controller
|
|
41
|
+
self.current_controller = controller
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
routes = @tracker.routes[@current_controller]
|
|
45
|
+
|
|
46
|
+
if routes and not routes.include? :allow_all_actions
|
|
47
|
+
routes << route
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
#Add default routes
|
|
52
|
+
def add_resources_routes
|
|
53
|
+
existing_routes = @tracker.routes[@current_controller]
|
|
54
|
+
|
|
55
|
+
unless existing_routes.is_a? Array and existing_routes.first == :allow_all_actions
|
|
56
|
+
existing_routes.merge [:index, :new, :create, :show, :edit, :update, :destroy]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#Add default routes minus :index
|
|
61
|
+
def add_resource_routes
|
|
62
|
+
existing_routes = @tracker.routes[@current_controller]
|
|
63
|
+
|
|
64
|
+
unless existing_routes.is_a? Array and existing_routes.first == :allow_all_actions
|
|
65
|
+
existing_routes.merge [:new, :create, :show, :edit, :update, :destroy]
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Railroader
|
|
2
|
+
module SafeCallHelper
|
|
3
|
+
[[:process_safe_call, :process_call],
|
|
4
|
+
[:process_safe_attrasgn, :process_attrasgn],
|
|
5
|
+
[:process_safe_op_asgn, :process_op_asgn],
|
|
6
|
+
[:process_safe_op_asgn2, :process_op_asgn2]].each do |call, replacement|
|
|
7
|
+
define_method(call) do |exp|
|
|
8
|
+
if self.respond_to? replacement
|
|
9
|
+
self.send(replacement, exp)
|
|
10
|
+
else
|
|
11
|
+
process_default exp
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'railroader/processors/base_processor'
|
|
2
|
+
require 'railroader/processors/alias_processor'
|
|
3
|
+
require 'railroader/processors/lib/module_helper'
|
|
4
|
+
require 'railroader/tracker/library'
|
|
5
|
+
|
|
6
|
+
#Process generic library and stores it in Tracker.libs
|
|
7
|
+
class Railroader::LibraryProcessor < Railroader::BaseProcessor
|
|
8
|
+
include Railroader::ModuleHelper
|
|
9
|
+
|
|
10
|
+
def initialize tracker
|
|
11
|
+
super
|
|
12
|
+
@file_name = nil
|
|
13
|
+
@alias_processor = Railroader::AliasProcessor.new tracker
|
|
14
|
+
@current_module = nil
|
|
15
|
+
@current_class = nil
|
|
16
|
+
@intializer_env = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def process_library src, file_name = nil
|
|
20
|
+
@file_name = file_name
|
|
21
|
+
process src
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def process_class exp
|
|
25
|
+
handle_class exp, @tracker.libs, Railroader::Library
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def process_module exp
|
|
29
|
+
handle_module exp, Railroader::Library
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def process_defn exp
|
|
33
|
+
if exp.method_name == :initialize
|
|
34
|
+
@alias_processor.process_safely exp.body_list
|
|
35
|
+
@initializer_env = @alias_processor.only_ivars
|
|
36
|
+
elsif node_type? exp, :defn
|
|
37
|
+
exp = @alias_processor.process_safely exp, @initializer_env
|
|
38
|
+
else
|
|
39
|
+
exp = @alias_processor.process exp
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if @current_class
|
|
43
|
+
exp.body = process_all! exp.body
|
|
44
|
+
@current_class.add_method :public, exp.method_name, exp, @file_name
|
|
45
|
+
elsif @current_module
|
|
46
|
+
exp.body = process_all! exp.body
|
|
47
|
+
@current_module.add_method :public, exp.method_name, exp, @file_name
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
exp
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
alias process_defs process_defn
|
|
54
|
+
|
|
55
|
+
def process_call exp
|
|
56
|
+
if process_call_defn? exp
|
|
57
|
+
exp
|
|
58
|
+
else
|
|
59
|
+
process_default exp
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def process_iter exp
|
|
64
|
+
res = process_default exp
|
|
65
|
+
|
|
66
|
+
if node_type? res, :iter and call? exp.block_call # sometimes this changes after processing
|
|
67
|
+
if exp.block_call.method == :included and (@current_module or @current_class)
|
|
68
|
+
(@current_module || @current_class).options[:included] = res.block
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
res
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require 'railroader/processors/base_processor'
|
|
2
|
+
require 'railroader/processors/lib/module_helper'
|
|
3
|
+
require 'railroader/tracker/model'
|
|
4
|
+
|
|
5
|
+
#Processes models. Puts results in tracker.models
|
|
6
|
+
class Railroader::ModelProcessor < Railroader::BaseProcessor
|
|
7
|
+
include Railroader::ModuleHelper
|
|
8
|
+
|
|
9
|
+
def initialize tracker
|
|
10
|
+
super
|
|
11
|
+
@current_class = nil
|
|
12
|
+
@current_method = nil
|
|
13
|
+
@current_module = nil
|
|
14
|
+
@visibility = :public
|
|
15
|
+
@file_name = nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
#Process model source
|
|
19
|
+
def process_model src, file_name = nil
|
|
20
|
+
@file_name = file_name
|
|
21
|
+
process src
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#s(:class, NAME, PARENT, BODY)
|
|
25
|
+
def process_class exp
|
|
26
|
+
name = class_name(exp.class_name)
|
|
27
|
+
parent = class_name(exp.parent_name)
|
|
28
|
+
|
|
29
|
+
#If inside an inner class we treat it as a library.
|
|
30
|
+
if @current_class
|
|
31
|
+
Railroader.debug "[Notice] Treating inner class as library: #{name}"
|
|
32
|
+
Railroader::LibraryProcessor.new(@tracker).process_library exp, @file_name
|
|
33
|
+
return exp
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
handle_class exp, @tracker.models, Railroader::Model
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def process_module exp
|
|
40
|
+
handle_module exp, Railroader::Model
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
#Handle calls outside of methods,
|
|
44
|
+
#such as include, attr_accessible, private, etc.
|
|
45
|
+
def process_call exp
|
|
46
|
+
return exp unless @current_class
|
|
47
|
+
return exp if process_call_defn? exp
|
|
48
|
+
|
|
49
|
+
target = exp.target
|
|
50
|
+
if sexp? target
|
|
51
|
+
target = process target
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
method = exp.method
|
|
55
|
+
first_arg = exp.first_arg
|
|
56
|
+
|
|
57
|
+
#Methods called inside class definition
|
|
58
|
+
#like attr_* and other settings
|
|
59
|
+
if @current_method.nil? and target.nil?
|
|
60
|
+
if first_arg.nil?
|
|
61
|
+
case method
|
|
62
|
+
when :private, :protected, :public
|
|
63
|
+
@visibility = method
|
|
64
|
+
when :attr_accessible
|
|
65
|
+
@current_class.set_attr_accessible
|
|
66
|
+
else
|
|
67
|
+
#??
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
case method
|
|
71
|
+
when :include
|
|
72
|
+
@current_class.add_include class_name(first_arg) if @current_class
|
|
73
|
+
when :attr_accessible
|
|
74
|
+
@current_class.set_attr_accessible exp
|
|
75
|
+
when :attr_protected
|
|
76
|
+
@current_class.set_attr_protected exp
|
|
77
|
+
else
|
|
78
|
+
if @current_class
|
|
79
|
+
@current_class.add_option method, exp
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
exp
|
|
85
|
+
else
|
|
86
|
+
call = make_call target, method, process_all!(exp.args)
|
|
87
|
+
call.line(exp.line)
|
|
88
|
+
call
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Railroader.load_railroader_dependency 'ruby2ruby'
|
|
2
|
+
require 'railroader/util'
|
|
3
|
+
|
|
4
|
+
#Produces formatted output strings from Sexps.
|
|
5
|
+
#Recommended usage is
|
|
6
|
+
#
|
|
7
|
+
# OutputProcessor.new.format(Sexp.new(:str, "hello"))
|
|
8
|
+
class Railroader::OutputProcessor < Ruby2Ruby
|
|
9
|
+
include Railroader::Util
|
|
10
|
+
|
|
11
|
+
#Copies +exp+ and then formats it.
|
|
12
|
+
def format exp, user_input = nil, &block
|
|
13
|
+
@user_input = user_input
|
|
14
|
+
@user_input_block = block
|
|
15
|
+
process(exp.deep_clone) || "[Format Error]"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias process_safely format
|
|
19
|
+
|
|
20
|
+
def process exp
|
|
21
|
+
begin
|
|
22
|
+
if @user_input and @user_input == exp
|
|
23
|
+
@user_input_block.call(exp, super(exp))
|
|
24
|
+
else
|
|
25
|
+
super exp if sexp? exp and not exp.empty?
|
|
26
|
+
end
|
|
27
|
+
rescue => e
|
|
28
|
+
Railroader.debug "While formatting #{exp}: #{e}\n#{e.backtrace.join("\n")}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def process_ignore exp
|
|
33
|
+
"[ignored]"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def process_params exp
|
|
37
|
+
"params"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def process_session exp
|
|
41
|
+
"session"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def process_cookies exp
|
|
45
|
+
"cookies"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def process_rlist exp
|
|
49
|
+
out = exp.map do |e|
|
|
50
|
+
res = process e
|
|
51
|
+
if res == ""
|
|
52
|
+
nil
|
|
53
|
+
else
|
|
54
|
+
res
|
|
55
|
+
end
|
|
56
|
+
end.compact.join("\n")
|
|
57
|
+
|
|
58
|
+
out
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def process_defn exp
|
|
62
|
+
# Copied from Ruby2Ruby except without the whole
|
|
63
|
+
# "convert methods to attr_*" stuff
|
|
64
|
+
exp = exp.deep_clone
|
|
65
|
+
exp.shift
|
|
66
|
+
name = exp.shift
|
|
67
|
+
args = process exp.shift
|
|
68
|
+
args = "" if args == "()"
|
|
69
|
+
|
|
70
|
+
exp.shift if exp == s(s(:nil)) # empty it out of a default nil expression
|
|
71
|
+
|
|
72
|
+
body = []
|
|
73
|
+
until exp.empty? do
|
|
74
|
+
body << indent(process(exp.shift))
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
body << indent("# do nothing") if body.empty?
|
|
78
|
+
|
|
79
|
+
body = body.join("\n")
|
|
80
|
+
|
|
81
|
+
return "def #{name}#{args}\n#{body}\nend".gsub(/\n\s*\n+/, "\n")
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def process_iter exp
|
|
85
|
+
call = process exp[1]
|
|
86
|
+
block = process_rlist exp[3..-1]
|
|
87
|
+
out = "#{call} do\n #{block}\n end"
|
|
88
|
+
|
|
89
|
+
out
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def process_output exp
|
|
93
|
+
output_format exp, "Output"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def process_escaped_output exp
|
|
97
|
+
output_format exp, "Escaped Output"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def process_format exp
|
|
102
|
+
output_format exp, "Format"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def process_format_escaped exp
|
|
106
|
+
output_format exp, "Escaped"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def output_format exp, tag
|
|
110
|
+
out = if exp[1].node_type == :str or exp[1].node_type == :ignore
|
|
111
|
+
""
|
|
112
|
+
else
|
|
113
|
+
res = process exp[1]
|
|
114
|
+
|
|
115
|
+
if res == ""
|
|
116
|
+
""
|
|
117
|
+
else
|
|
118
|
+
"[#{tag}] #{res}"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
out
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def process_const exp
|
|
126
|
+
if exp[1] == Railroader::Tracker::UNKNOWN_MODEL
|
|
127
|
+
"(Unresolved Model)"
|
|
128
|
+
else
|
|
129
|
+
out = exp[1].to_s
|
|
130
|
+
out
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def process_render exp
|
|
135
|
+
exp = exp.deep_clone
|
|
136
|
+
exp.shift
|
|
137
|
+
|
|
138
|
+
exp[1] = process exp[1] if sexp? exp[1]
|
|
139
|
+
exp[2] = process exp[2] if sexp? exp[2]
|
|
140
|
+
out = "render(#{exp[0]} => #{exp[1]}, #{exp[2]})"
|
|
141
|
+
|
|
142
|
+
out
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'railroader/processors/base_processor'
|
|
2
|
+
require 'railroader/processors/alias_processor'
|
|
3
|
+
require 'railroader/processors/lib/route_helper'
|
|
4
|
+
require 'railroader/util'
|
|
5
|
+
require 'railroader/processors/lib/rails3_route_processor.rb'
|
|
6
|
+
require 'railroader/processors/lib/rails2_route_processor.rb'
|
|
7
|
+
require 'set'
|
|
8
|
+
|
|
9
|
+
class Railroader::RoutesProcessor
|
|
10
|
+
def self.new tracker
|
|
11
|
+
if tracker.options[:rails3]
|
|
12
|
+
Railroader::Rails3RoutesProcessor.new tracker
|
|
13
|
+
else
|
|
14
|
+
Railroader::Rails2RoutesProcessor.new tracker
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
require 'railroader/processors/template_processor'
|
|
2
|
+
require 'railroader/processors/lib/render_helper'
|
|
3
|
+
|
|
4
|
+
class Railroader::SlimTemplateProcessor < Railroader::TemplateProcessor
|
|
5
|
+
include Railroader::RenderHelper
|
|
6
|
+
|
|
7
|
+
SAFE_BUFFER = s(:call, s(:colon2, s(:const, :ActiveSupport), :SafeBuffer), :new)
|
|
8
|
+
OUTPUT_BUFFER = s(:ivar, :@output_buffer)
|
|
9
|
+
TEMPLE_UTILS = s(:colon2, s(:colon3, :Temple), :Utils)
|
|
10
|
+
ATTR_MERGE = s(:call, s(:call, s(:array), :reject, s(:block_pass, s(:lit, :empty?))), :join, s(:str, " "))
|
|
11
|
+
|
|
12
|
+
def process_call exp
|
|
13
|
+
target = exp.target
|
|
14
|
+
method = exp.method
|
|
15
|
+
|
|
16
|
+
if method == :safe_concat and (target == SAFE_BUFFER or target == OUTPUT_BUFFER)
|
|
17
|
+
arg = normalize_output(exp.first_arg)
|
|
18
|
+
|
|
19
|
+
if is_escaped? arg
|
|
20
|
+
add_escaped_output arg.first_arg
|
|
21
|
+
elsif string? arg
|
|
22
|
+
ignore
|
|
23
|
+
elsif render? arg
|
|
24
|
+
add_output make_render_in_view arg
|
|
25
|
+
elsif string_interp? arg
|
|
26
|
+
process_inside_interp arg
|
|
27
|
+
elsif node_type? arg, :ignore
|
|
28
|
+
ignore
|
|
29
|
+
elsif internal_variable? arg
|
|
30
|
+
ignore
|
|
31
|
+
elsif arg == ATTR_MERGE
|
|
32
|
+
ignore
|
|
33
|
+
else
|
|
34
|
+
add_output arg
|
|
35
|
+
end
|
|
36
|
+
elsif is_escaped? exp
|
|
37
|
+
add_escaped_output arg
|
|
38
|
+
elsif target == nil and method == :render
|
|
39
|
+
exp.arglist = process exp.arglist
|
|
40
|
+
make_render_in_view exp
|
|
41
|
+
else
|
|
42
|
+
exp.arglist = process exp.arglist
|
|
43
|
+
exp
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
#Slim likes to interpolate output into strings then pass them to safe_concat.
|
|
48
|
+
#Better to pull those values out directly.
|
|
49
|
+
def process_inside_interp exp
|
|
50
|
+
exp.map! do |e|
|
|
51
|
+
if node_type? e, :evstr
|
|
52
|
+
e.value = process_interp_output e.value
|
|
53
|
+
e
|
|
54
|
+
else
|
|
55
|
+
e
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
exp
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def process_interp_output exp
|
|
63
|
+
if sexp? exp
|
|
64
|
+
if node_type? exp, :if
|
|
65
|
+
process_interp_output exp.then_clause
|
|
66
|
+
process_interp_output exp.else_clause
|
|
67
|
+
elsif exp == SAFE_BUFFER
|
|
68
|
+
ignore
|
|
69
|
+
elsif render? exp
|
|
70
|
+
add_output make_render_in_view exp
|
|
71
|
+
elsif node_type? :output, :escaped_output
|
|
72
|
+
exp
|
|
73
|
+
elsif is_escaped? exp
|
|
74
|
+
add_escaped_output exp
|
|
75
|
+
else
|
|
76
|
+
add_output exp
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def add_escaped_output exp
|
|
82
|
+
exp = normalize_output(exp)
|
|
83
|
+
|
|
84
|
+
return exp if string? exp or internal_variable? exp
|
|
85
|
+
|
|
86
|
+
super exp
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def is_escaped? exp
|
|
90
|
+
call? exp and
|
|
91
|
+
exp.target == TEMPLE_UTILS and
|
|
92
|
+
(exp.method == :escape_html or exp.method == :escape_html_safe)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def internal_variable? exp
|
|
96
|
+
node_type? exp, :lvar and
|
|
97
|
+
exp.value =~ /^_(temple_|slim_)/
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def render? exp
|
|
101
|
+
call? exp and
|
|
102
|
+
exp.target.nil? and
|
|
103
|
+
exp.method == :render
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def process_render exp
|
|
107
|
+
#Still confused as to why this is not needed in other template processors
|
|
108
|
+
#but is needed here
|
|
109
|
+
exp
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
require 'railroader/processors/alias_processor'
|
|
3
|
+
require 'railroader/processors/lib/render_helper'
|
|
4
|
+
require 'railroader/processors/lib/render_path'
|
|
5
|
+
require 'railroader/tracker'
|
|
6
|
+
|
|
7
|
+
#Processes aliasing in templates.
|
|
8
|
+
#Handles calls to +render+.
|
|
9
|
+
class Railroader::TemplateAliasProcessor < Railroader::AliasProcessor
|
|
10
|
+
include Railroader::RenderHelper
|
|
11
|
+
|
|
12
|
+
FORM_METHODS = Set[:form_for, :remote_form_for, :form_remote_for]
|
|
13
|
+
|
|
14
|
+
def initialize tracker, template, called_from = nil
|
|
15
|
+
super tracker
|
|
16
|
+
@template = template
|
|
17
|
+
@called_from = called_from
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
#Process template
|
|
21
|
+
def process_template name, args, _, line = nil, file_name = nil
|
|
22
|
+
@file_name = file_name || relative_path(@template.file || @tracker.templates[@template.name])
|
|
23
|
+
|
|
24
|
+
if @called_from
|
|
25
|
+
if @called_from.include_template? name
|
|
26
|
+
Railroader.debug "Skipping circular render from #{@template.name} to #{name}"
|
|
27
|
+
return
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
super name, args, @called_from.dup.add_template_render(@template.name, line, @file_name)
|
|
31
|
+
else
|
|
32
|
+
super name, args, Railroader::RenderPath.new.add_template_render(@template.name, line, @file_name)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#Determine template name
|
|
37
|
+
def template_name name
|
|
38
|
+
if !name.to_s.include?('/') && @template.name.to_s.include?('/')
|
|
39
|
+
name = "#{@template.name.to_s.match(/^(.*\/).*$/)[1]}#{name}"
|
|
40
|
+
end
|
|
41
|
+
name
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
UNKNOWN_MODEL_CALL = Sexp.new(:call, Sexp.new(:const, Railroader::Tracker::UNKNOWN_MODEL), :new)
|
|
45
|
+
FORM_BUILDER_CALL = Sexp.new(:call, Sexp.new(:const, :FormBuilder), :new)
|
|
46
|
+
|
|
47
|
+
#Looks for form methods and iterating over collections of Models
|
|
48
|
+
def process_iter exp
|
|
49
|
+
process_default exp
|
|
50
|
+
|
|
51
|
+
call = exp.block_call
|
|
52
|
+
|
|
53
|
+
if call? call
|
|
54
|
+
target = call.target
|
|
55
|
+
method = call.method
|
|
56
|
+
arg = exp.block_args.first_param
|
|
57
|
+
block = exp.block
|
|
58
|
+
|
|
59
|
+
#Check for e.g. Model.find.each do ... end
|
|
60
|
+
if method == :each and arg and block and model = get_model_target(target)
|
|
61
|
+
if arg.is_a? Symbol
|
|
62
|
+
if model == target.target
|
|
63
|
+
env[Sexp.new(:lvar, arg)] = Sexp.new(:call, model, :new)
|
|
64
|
+
else
|
|
65
|
+
env[Sexp.new(:lvar, arg)] = UNKNOWN_MODEL_CALL
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
process block if sexp? block
|
|
69
|
+
end
|
|
70
|
+
elsif FORM_METHODS.include? method
|
|
71
|
+
if arg.is_a? Symbol
|
|
72
|
+
env[Sexp.new(:lvar, arg)] = FORM_BUILDER_CALL
|
|
73
|
+
|
|
74
|
+
process block if sexp? block
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
exp
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
COLLECTION_METHODS = [:all, :find, :select, :where]
|
|
83
|
+
|
|
84
|
+
#Checks if +exp+ is a call to Model.all or Model.find*
|
|
85
|
+
def get_model_target exp
|
|
86
|
+
if call? exp
|
|
87
|
+
target = exp.target
|
|
88
|
+
|
|
89
|
+
if COLLECTION_METHODS.include? exp.method or exp.method.to_s[0,4] == "find"
|
|
90
|
+
models = Set.new @tracker.models.keys
|
|
91
|
+
name = class_name target
|
|
92
|
+
return target if models.include?(name)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
return get_model_target(target)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
#Ignore `<<` calls on template variables which are used by the templating
|
|
102
|
+
#library (HAML, ERB, etc.)
|
|
103
|
+
def find_push_target exp
|
|
104
|
+
if sexp? exp
|
|
105
|
+
if exp.node_type == :lvar and (exp.value == :_buf or exp.value == :_erbout)
|
|
106
|
+
return nil
|
|
107
|
+
elsif exp.node_type == :ivar and exp.value == :@output_buffer
|
|
108
|
+
return nil
|
|
109
|
+
elsif exp.node_type == :call and call? exp.target and
|
|
110
|
+
exp.target.method == :_hamlout and exp.method == :buffer
|
|
111
|
+
|
|
112
|
+
return nil
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
super
|
|
117
|
+
end
|
|
118
|
+
end
|