brakeman 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/FEATURES +16 -0
- data/README.md +112 -0
- data/WARNING_TYPES +69 -0
- data/bin/brakeman +266 -0
- data/lib/checks.rb +67 -0
- data/lib/checks/base_check.rb +338 -0
- data/lib/checks/check_cross_site_scripting.rb +216 -0
- data/lib/checks/check_default_routes.rb +29 -0
- data/lib/checks/check_evaluation.rb +29 -0
- data/lib/checks/check_execute.rb +110 -0
- data/lib/checks/check_file_access.rb +46 -0
- data/lib/checks/check_forgery_setting.rb +25 -0
- data/lib/checks/check_mass_assignment.rb +72 -0
- data/lib/checks/check_model_attributes.rb +36 -0
- data/lib/checks/check_redirect.rb +98 -0
- data/lib/checks/check_render.rb +65 -0
- data/lib/checks/check_send_file.rb +15 -0
- data/lib/checks/check_session_settings.rb +36 -0
- data/lib/checks/check_sql.rb +124 -0
- data/lib/checks/check_validation_regex.rb +60 -0
- data/lib/format/style.css +105 -0
- data/lib/processor.rb +83 -0
- data/lib/processors/alias_processor.rb +384 -0
- data/lib/processors/base_processor.rb +235 -0
- data/lib/processors/config_processor.rb +146 -0
- data/lib/processors/controller_alias_processor.rb +222 -0
- data/lib/processors/controller_processor.rb +175 -0
- data/lib/processors/erb_template_processor.rb +84 -0
- data/lib/processors/erubis_template_processor.rb +62 -0
- data/lib/processors/haml_template_processor.rb +115 -0
- data/lib/processors/lib/find_call.rb +176 -0
- data/lib/processors/lib/find_model_call.rb +39 -0
- data/lib/processors/lib/processor_helper.rb +36 -0
- data/lib/processors/lib/render_helper.rb +118 -0
- data/lib/processors/library_processor.rb +117 -0
- data/lib/processors/model_processor.rb +125 -0
- data/lib/processors/output_processor.rb +204 -0
- data/lib/processors/params_processor.rb +77 -0
- data/lib/processors/route_processor.rb +338 -0
- data/lib/processors/template_alias_processor.rb +86 -0
- data/lib/processors/template_processor.rb +55 -0
- data/lib/report.rb +628 -0
- data/lib/scanner.rb +232 -0
- data/lib/tracker.rb +144 -0
- data/lib/util.rb +141 -0
- data/lib/warning.rb +97 -0
- metadata +191 -0
data/lib/scanner.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
begin
|
3
|
+
require 'ruby_parser'
|
4
|
+
require 'haml'
|
5
|
+
require 'erb'
|
6
|
+
require 'erubis'
|
7
|
+
require 'processor'
|
8
|
+
rescue LoadError => e
|
9
|
+
$stderr.puts e.message
|
10
|
+
$stderr.puts "Please install the appropriate dependency."
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
|
14
|
+
#Erubis processor which ignores any output which is plain text.
|
15
|
+
class ScannerErubis < Erubis::Eruby
|
16
|
+
include Erubis::NoTextEnhancer
|
17
|
+
end
|
18
|
+
|
19
|
+
#Scans the Rails application.
|
20
|
+
class Scanner
|
21
|
+
|
22
|
+
#Pass in path to the root of the Rails application
|
23
|
+
def initialize path
|
24
|
+
@path = path
|
25
|
+
@app_path = path + "/app/"
|
26
|
+
@processor = Processor.new
|
27
|
+
end
|
28
|
+
|
29
|
+
#Returns the Tracker generated from the scan
|
30
|
+
def tracker
|
31
|
+
@processor.tracked_events
|
32
|
+
end
|
33
|
+
|
34
|
+
#Process everything in the Rails application
|
35
|
+
def process
|
36
|
+
warn "Processing configuration..."
|
37
|
+
process_config
|
38
|
+
warn "Processing initializers..."
|
39
|
+
process_initializers
|
40
|
+
warn "Processing libs..."
|
41
|
+
process_libs
|
42
|
+
warn "Processing routes..."
|
43
|
+
process_routes
|
44
|
+
warn "Processing templates..."
|
45
|
+
process_templates
|
46
|
+
warn "Processing models..."
|
47
|
+
process_models
|
48
|
+
warn "Processing controllers..."
|
49
|
+
process_controllers
|
50
|
+
tracker
|
51
|
+
end
|
52
|
+
|
53
|
+
#Process config/environment.rb and config/gems.rb
|
54
|
+
#
|
55
|
+
#Stores parsed information in tracker.config
|
56
|
+
def process_config
|
57
|
+
@processor.process_config(RubyParser.new.parse(File.read("#@path/config/environment.rb")))
|
58
|
+
|
59
|
+
if File.exists? "#@path/config/gems.rb"
|
60
|
+
@processor.process_config(RubyParser.new.parse(File.read("#@path/config/gems.rb")))
|
61
|
+
end
|
62
|
+
|
63
|
+
if File.exists? "#@path/vendor/plugins/rails_xss"
|
64
|
+
tracker.config[:escape_html] = true
|
65
|
+
warn "[Notice] Escaping HTML by default"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
#Process all the .rb files in config/initializers/
|
70
|
+
#
|
71
|
+
#Adds parsed information to tracker.initializers
|
72
|
+
def process_initializers
|
73
|
+
Dir.glob(@path + "/config/initializers/**/*.rb").sort.each do |f|
|
74
|
+
begin
|
75
|
+
@processor.process_initializer(f, RubyParser.new.parse(File.read(f)))
|
76
|
+
rescue Racc::ParseError => e
|
77
|
+
tracker.error e, "could not parse #{f}"
|
78
|
+
rescue Exception => e
|
79
|
+
tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
#Process all .rb in lib/
|
85
|
+
#
|
86
|
+
#Adds parsed information to tracker.libs.
|
87
|
+
def process_libs
|
88
|
+
Dir.glob(@path + "/lib/**/*.rb").sort.each do |f|
|
89
|
+
begin
|
90
|
+
@processor.process_lib RubyParser.new.parse(File.read(f)), f
|
91
|
+
rescue Racc::ParseError => e
|
92
|
+
tracker.error e, "could not parse #{f}"
|
93
|
+
rescue Exception => e
|
94
|
+
tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
#Process config/routes.rb
|
100
|
+
#
|
101
|
+
#Adds parsed information to tracker.routes
|
102
|
+
def process_routes
|
103
|
+
if File.exists? "#@path/config/routes.rb"
|
104
|
+
@processor.process_routes RubyParser.new.parse(File.read("#@path/config/routes.rb"))
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
#Process all .rb files in controllers/
|
109
|
+
#
|
110
|
+
#Adds processed controllers to tracker.controllers
|
111
|
+
def process_controllers
|
112
|
+
Dir.glob(@app_path + "/controllers/**/*.rb").sort.each do |f|
|
113
|
+
begin
|
114
|
+
@processor.process_controller(RubyParser.new.parse(File.read(f)), f)
|
115
|
+
rescue Racc::ParseError => e
|
116
|
+
tracker.error e, "could not parse #{f}"
|
117
|
+
rescue Exception => e
|
118
|
+
tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
tracker.controllers.each do |name, controller|
|
123
|
+
@processor.process_controller_alias controller[:src]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
#Process all views and partials in views/
|
128
|
+
#
|
129
|
+
#Adds processed views to tracker.views
|
130
|
+
def process_templates
|
131
|
+
|
132
|
+
views_path = @app_path + "/views/**/*.{html.erb,html.haml,rhtml,js.erb}"
|
133
|
+
$stdout.sync = true
|
134
|
+
count = 0
|
135
|
+
|
136
|
+
Dir.glob(views_path).sort.each do |f|
|
137
|
+
count += 1
|
138
|
+
type = f.match(/.*\.(erb|haml|rhtml)$/)[1].to_sym
|
139
|
+
type = :erb if type == :rhtml
|
140
|
+
name = template_path_to_name f
|
141
|
+
|
142
|
+
begin
|
143
|
+
if type == :erb
|
144
|
+
if tracker.config[:escape_html]
|
145
|
+
src = RailsXSSErubis.new(File.read(f)).src
|
146
|
+
elsif tracker.config[:erubis]
|
147
|
+
src = ScannerErubis.new(File.read(f)).src
|
148
|
+
else
|
149
|
+
src = ERB.new(File.read(f), nil, "-").src
|
150
|
+
end
|
151
|
+
parsed = RubyParser.new.parse src
|
152
|
+
elsif type == :haml
|
153
|
+
src = Haml::Engine.new(File.read(f),
|
154
|
+
:escape_html => !!tracker.config[:escape_html]).precompiled
|
155
|
+
parsed = RubyParser.new.parse src
|
156
|
+
else
|
157
|
+
tracker.error "Unkown template type in #{f}"
|
158
|
+
end
|
159
|
+
|
160
|
+
@processor.process_template(name, parsed, type, nil, f)
|
161
|
+
|
162
|
+
rescue Racc::ParseError => e
|
163
|
+
tracker.error e, "could not parse #{f}"
|
164
|
+
rescue Haml::Error => e
|
165
|
+
tracker.error e, ["While compiling HAML in #{f}"] << e.backtrace
|
166
|
+
rescue Exception => e
|
167
|
+
tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
tracker.templates.keys.dup.each do |name|
|
172
|
+
@processor.process_template_alias tracker.templates[name]
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
#Convert path/filename to view name
|
178
|
+
#
|
179
|
+
# views/test/something.html.erb -> test/something
|
180
|
+
def template_path_to_name path
|
181
|
+
names = path.split("/")
|
182
|
+
names.last.gsub!(/(\.(html|js)\..*|\.rhtml)$/, '')
|
183
|
+
names[(names.index("views") + 1)..-1].join("/").to_sym
|
184
|
+
end
|
185
|
+
|
186
|
+
#Process all the .rb files in models/
|
187
|
+
#
|
188
|
+
#Adds the processed models to tracker.models
|
189
|
+
def process_models
|
190
|
+
Dir.glob(@app_path + "/models/*.rb").sort.each do |f|
|
191
|
+
begin
|
192
|
+
@processor.process_model(RubyParser.new.parse(File.read(f)), f)
|
193
|
+
rescue Racc::ParseError => e
|
194
|
+
tracker.error e, "could not parse #{f}"
|
195
|
+
rescue Exception => e
|
196
|
+
tracker.error e.exception(e.message + "\nWhile processing #{f}"), e.backtrace
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
#This is from the rails_xss plugin,
|
203
|
+
#except we don't care about plain text.
|
204
|
+
class RailsXSSErubis < ::Erubis::Eruby
|
205
|
+
include Erubis::NoTextEnhancer
|
206
|
+
|
207
|
+
#Initializes output buffer.
|
208
|
+
def add_preamble(src)
|
209
|
+
src << "@output_buffer = ActionView::SafeBuffer.new;\n"
|
210
|
+
end
|
211
|
+
|
212
|
+
#This does nothing.
|
213
|
+
def add_text(src, text)
|
214
|
+
# src << "@output_buffer << ('" << escape_text(text) << "'.html_safe!);"
|
215
|
+
end
|
216
|
+
|
217
|
+
#Add an expression to the output buffer _without_ escaping.
|
218
|
+
def add_expr_literal(src, code)
|
219
|
+
src << '@output_buffer << ((' << code << ').to_s);'
|
220
|
+
end
|
221
|
+
|
222
|
+
#Add an expression to the output buffer after escaping it.
|
223
|
+
def add_expr_escaped(src, code)
|
224
|
+
src << '@output_buffer << ' << escaped_expr(code) << ';'
|
225
|
+
end
|
226
|
+
|
227
|
+
#Add code to output buffer.
|
228
|
+
def add_postamble(src)
|
229
|
+
src << '@output_buffer.to_s'
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
data/lib/tracker.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'checks'
|
3
|
+
require 'report'
|
4
|
+
require 'processors/lib/find_call'
|
5
|
+
require 'processors/lib/find_model_call'
|
6
|
+
|
7
|
+
#The Tracker keeps track of all the processed information.
|
8
|
+
class Tracker
|
9
|
+
attr_accessor :controllers, :templates, :models, :errors,
|
10
|
+
:checks, :initializers, :config, :routes, :processor, :libs,
|
11
|
+
:template_cache
|
12
|
+
|
13
|
+
#Place holder when there should be a model, but it is not
|
14
|
+
#clear what model it will be.
|
15
|
+
UNKNOWN_MODEL = :BrakemanUnresolvedModel
|
16
|
+
|
17
|
+
#Creates a new Tracker.
|
18
|
+
#
|
19
|
+
#The Processor argument is only used by other Processors
|
20
|
+
#that might need to access it.
|
21
|
+
def initialize processor = nil
|
22
|
+
@processor = processor
|
23
|
+
@config = {}
|
24
|
+
@templates = {}
|
25
|
+
@controllers = {}
|
26
|
+
#Initialize models with the unknown model so
|
27
|
+
#we can match models later without knowing precisely what
|
28
|
+
#class they are.
|
29
|
+
@models = { UNKNOWN_MODEL => { :name => UNKNOWN_MODEL,
|
30
|
+
:parent => nil,
|
31
|
+
:includes => [],
|
32
|
+
:public => {},
|
33
|
+
:private => {},
|
34
|
+
:protected => {},
|
35
|
+
:options => {} } }
|
36
|
+
@routes = {}
|
37
|
+
@initializers = {}
|
38
|
+
@errors = []
|
39
|
+
@libs = {}
|
40
|
+
@checks = nil
|
41
|
+
@template_cache = Set.new
|
42
|
+
end
|
43
|
+
|
44
|
+
#Add an error to the list. If no backtrace is given,
|
45
|
+
#the one from the exception will be used.
|
46
|
+
def error exception, backtrace = nil
|
47
|
+
backtrace ||= exception.backtrace
|
48
|
+
unless backtrace.is_a? Array
|
49
|
+
backtrace = [ backtrace ]
|
50
|
+
end
|
51
|
+
|
52
|
+
@errors << { :error => exception.to_s.gsub("\n", " "), :backtrace => backtrace }
|
53
|
+
end
|
54
|
+
|
55
|
+
#Run a set of checks on the current information. Results will be stored
|
56
|
+
#in Tracker#checks.
|
57
|
+
def run_checks
|
58
|
+
@checks = Checks.run_checks(self)
|
59
|
+
end
|
60
|
+
|
61
|
+
#Iterate over all methods in controllers and models.
|
62
|
+
def each_method
|
63
|
+
[self.controllers, self.models].each do |set|
|
64
|
+
set.each do |set_name, info|
|
65
|
+
[:private, :public, :protected].each do |visibility|
|
66
|
+
info[visibility].each do |method_name, definition|
|
67
|
+
if definition.node_type == :selfdef
|
68
|
+
method_name = "#{definition[1]}.#{method_name}"
|
69
|
+
end
|
70
|
+
|
71
|
+
yield definition, set_name, method_name
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
#Iterates over each template, yielding the name and the template.
|
80
|
+
#Prioritizes templates which have been rendered.
|
81
|
+
def each_template
|
82
|
+
if @processed.nil?
|
83
|
+
@processed, @rest = templates.keys.partition { |k| k.to_s.include? "." }
|
84
|
+
end
|
85
|
+
|
86
|
+
@processed.each do |k|
|
87
|
+
yield k, templates[k]
|
88
|
+
end
|
89
|
+
|
90
|
+
@rest.each do |k|
|
91
|
+
yield k, templates[k]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
#Find a method call.
|
96
|
+
#
|
97
|
+
#See FindCall for details on arguments.
|
98
|
+
def find_call target, method
|
99
|
+
finder = FindCall.new target, method
|
100
|
+
|
101
|
+
self.each_method do |definition, set_name, method_name|
|
102
|
+
finder.process_source definition, set_name, method_name
|
103
|
+
end
|
104
|
+
|
105
|
+
self.each_template do |name, template|
|
106
|
+
finder.process_source template[:src], nil, nil, template
|
107
|
+
end
|
108
|
+
|
109
|
+
finder.matches
|
110
|
+
end
|
111
|
+
|
112
|
+
#Finds method call on models.
|
113
|
+
#
|
114
|
+
#See FindCall for details on arguments.
|
115
|
+
def find_model_find target
|
116
|
+
finder = FindModelCall.new target
|
117
|
+
|
118
|
+
self.each_method do |definition, set_name, method_name|
|
119
|
+
finder.process_source definition, set_name, method_name
|
120
|
+
end
|
121
|
+
|
122
|
+
self.each_template do |name, template|
|
123
|
+
finder.process_source template[:src], nil, nil, template
|
124
|
+
end
|
125
|
+
|
126
|
+
finder.matches
|
127
|
+
end
|
128
|
+
|
129
|
+
#Similar to Tracker#find_call, but searches the initializers
|
130
|
+
def check_initializers target, method
|
131
|
+
finder = FindCall.new target, method
|
132
|
+
|
133
|
+
initializers.each do |name, initializer|
|
134
|
+
finder.process_source initializer
|
135
|
+
end
|
136
|
+
|
137
|
+
finder.matches
|
138
|
+
end
|
139
|
+
|
140
|
+
#Returns a Report with this Tracker's information
|
141
|
+
def report
|
142
|
+
Report.new(self)
|
143
|
+
end
|
144
|
+
end
|
data/lib/util.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'sexp_processor'
|
2
|
+
require 'set'
|
3
|
+
require 'active_support/inflector'
|
4
|
+
|
5
|
+
#This is a mixin containing utility methods.
|
6
|
+
module Util
|
7
|
+
|
8
|
+
QUERY_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request, Sexp.new(:arglist)), :query_parameters, Sexp.new(:arglist))
|
9
|
+
|
10
|
+
PATH_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request, Sexp.new(:arglist)), :path_parameters, Sexp.new(:arglist))
|
11
|
+
|
12
|
+
REQUEST_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request, Sexp.new(:arglist)), :request_parameters, Sexp.new(:arglist))
|
13
|
+
|
14
|
+
PARAMETERS = Sexp.new(:call, nil, :params, Sexp.new(:arglist))
|
15
|
+
|
16
|
+
COOKIES = Sexp.new(:call, nil, :cookies, Sexp.new(:arglist))
|
17
|
+
|
18
|
+
SESSION = Sexp.new(:call, nil, :session, Sexp.new(:arglist))
|
19
|
+
|
20
|
+
ALL_PARAMETERS = Set.new([PARAMETERS, QUERY_PARAMETERS, PATH_PARAMETERS, REQUEST_PARAMETERS])
|
21
|
+
|
22
|
+
#Convert a string from "something_like_this" to "SomethingLikeThis"
|
23
|
+
#
|
24
|
+
#Taken from ActiveSupport.
|
25
|
+
def camelize lower_case_and_underscored_word
|
26
|
+
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
27
|
+
end
|
28
|
+
|
29
|
+
#Convert a string from "Something::LikeThis" to "something/like_this"
|
30
|
+
#
|
31
|
+
#Taken from ActiveSupport.
|
32
|
+
def underscore camel_cased_word
|
33
|
+
camel_cased_word.to_s.gsub(/::/, '/').
|
34
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
35
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
36
|
+
tr("-", "_").
|
37
|
+
downcase
|
38
|
+
end
|
39
|
+
|
40
|
+
#Use ActiveSupport::Inflector to pluralize a word.
|
41
|
+
def pluralize word
|
42
|
+
ActiveSupport::Inflector.pluralize word
|
43
|
+
end
|
44
|
+
|
45
|
+
#Takes an Sexp like
|
46
|
+
# (:hash, (:lit, :key), (:str, "value"))
|
47
|
+
#and yields the key and value pairs to the given block.
|
48
|
+
#
|
49
|
+
#For example:
|
50
|
+
#
|
51
|
+
# h = Sexp.new(:hash, (:lit, :name), (:str, "bob"), (:lit, :name), (:str, "jane"))
|
52
|
+
# names = []
|
53
|
+
# hash_iterate(h) do |key, value|
|
54
|
+
# if symbol? key and key[1] == :name
|
55
|
+
# names << value[1]
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
# names #["bob"]
|
59
|
+
def hash_iterate hash
|
60
|
+
1.step(hash.length - 1, 2) do |i|
|
61
|
+
yield hash[i], hash[i + 1]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#Insert value into Hash Sexp
|
66
|
+
def hash_insert hash, key, value
|
67
|
+
index = 0
|
68
|
+
hash_iterate hash.dup do |k,v|
|
69
|
+
index += 1
|
70
|
+
if k == key and index % 2 == 1
|
71
|
+
hash[index + 1] = value
|
72
|
+
return hash
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
hash << key << value
|
77
|
+
|
78
|
+
hash
|
79
|
+
end
|
80
|
+
|
81
|
+
#Adds params, session, and cookies to environment
|
82
|
+
#so they can be replaced by their respective Sexps.
|
83
|
+
def set_env_defaults
|
84
|
+
@env[PARAMETERS] = Sexp.new(:params)
|
85
|
+
@env[SESSION] = Sexp.new(:session)
|
86
|
+
@env[COOKIES] = Sexp.new(:cookies)
|
87
|
+
end
|
88
|
+
|
89
|
+
#Check if _exp_ represents a hash: s(:hash, {...})
|
90
|
+
#This also includes pseudo hashes params, session, and cookies.
|
91
|
+
def hash? exp
|
92
|
+
exp.is_a? Sexp and (exp.node_type == :hash or
|
93
|
+
exp.node_type == :params or
|
94
|
+
exp.node_type == :session or
|
95
|
+
exp.node_type == :cookies)
|
96
|
+
end
|
97
|
+
|
98
|
+
#Check if _exp_ represents an array: s(:array, [...])
|
99
|
+
def array? exp
|
100
|
+
exp.is_a? Sexp and exp.node_type == :array
|
101
|
+
end
|
102
|
+
|
103
|
+
#Check if _exp_ represents a String: s(:str, "...")
|
104
|
+
def string? exp
|
105
|
+
exp.is_a? Sexp and exp.node_type == :str
|
106
|
+
end
|
107
|
+
|
108
|
+
#Check if _exp_ represents a Symbol: s(:lit, :...)
|
109
|
+
def symbol? exp
|
110
|
+
exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Symbol
|
111
|
+
end
|
112
|
+
|
113
|
+
#Check if _exp_ represents a method call: s(:call, ...)
|
114
|
+
def call? exp
|
115
|
+
exp.is_a? Sexp and exp.node_type == :call
|
116
|
+
end
|
117
|
+
|
118
|
+
#Check if _exp_ represents a Regexp: s(:lit, /.../)
|
119
|
+
def regexp? exp
|
120
|
+
exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Regexp
|
121
|
+
end
|
122
|
+
|
123
|
+
#Check if _exp_ represents an Integer: s(:lit, ...)
|
124
|
+
def integer? exp
|
125
|
+
exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Integer
|
126
|
+
end
|
127
|
+
|
128
|
+
#Check if _exp_ is a params hash
|
129
|
+
def params? exp
|
130
|
+
exp.is_a? Sexp and exp.node_type == :params
|
131
|
+
end
|
132
|
+
|
133
|
+
def cookies? exp
|
134
|
+
exp.is_a? Sexp and exp.node_type == :cookies
|
135
|
+
end
|
136
|
+
|
137
|
+
#Check if _exp_ is a Sexp.
|
138
|
+
def sexp? exp
|
139
|
+
exp.is_a? Sexp
|
140
|
+
end
|
141
|
+
end
|