scrutinize 0.0.1
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/.gitignore +22 -0
- data/Gemfile +3 -0
- data/README.md +63 -0
- data/Rakefile +6 -0
- data/bin/scrutinize +52 -0
- data/lib/scrutinize/config.rb +110 -0
- data/lib/scrutinize/processor.rb +115 -0
- data/lib/scrutinize/trigger.rb +108 -0
- data/lib/scrutinize/version.rb +3 -0
- data/lib/scrutinize.rb +13 -0
- data/scrutinize.gemspec +21 -0
- data/spec/config_spec.rb +80 -0
- data/spec/trigger_spec.rb +96 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cf550ed5c9b1d869f4f069c695689781597ab6a8
|
4
|
+
data.tar.gz: ab23c15b94668a85694be5e2cda6b550f3f8f2d4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a34f3266961355ce8020f8013d32722e63e833aed7764068c99cba2432109d7ed87ec9f66a5d373ceb36249db0f8ebfb90127ac7fe49432982540fe04a19b6cb
|
7
|
+
data.tar.gz: eb8a279edc898a3188f2430c8c9708e2d5dcb097efc6b89a2e3a9df5af6cc228588f564a4256af080b215b1e7b2882fcdfcf3122d189ee4ce427c21b555e1deb
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Scrutinize
|
2
|
+
|
3
|
+
Ruby method call searcher.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```
|
8
|
+
Usage: scrutinize [options] [method_name ...]
|
9
|
+
-t, --targets=MANDATORY A comma separated list of targets to search for the next set of methods on
|
10
|
+
-m, --methods=MANDATORY A comma separated list of methods to search for on the last listed set of targets
|
11
|
+
-d, --directory=MANDATORY The directory to search
|
12
|
+
-c, --config=MANDATORY A YAML config file to load
|
13
|
+
-r, --ruby-version=MANDATORY The Ruby version of the files we're searching through
|
14
|
+
-h, --help Show this message
|
15
|
+
```
|
16
|
+
|
17
|
+
### Examples
|
18
|
+
|
19
|
+
**Search for calls to `puts` on any target:**
|
20
|
+
|
21
|
+
```
|
22
|
+
$ scrutinize puts
|
23
|
+
./lib/sinatra/base.rb:1136 @env['rack.errors'].puts
|
24
|
+
./lib/sinatra/base.rb:1416 $stderr.puts
|
25
|
+
./test/integration/app.rb:58 puts
|
26
|
+
...
|
27
|
+
```
|
28
|
+
|
29
|
+
**Search for calls to `puts` with *no* target:**
|
30
|
+
|
31
|
+
```
|
32
|
+
$ scrutinize -t SCRUTINIZE_NONE puts
|
33
|
+
./test/integration/app.rb:58 puts
|
34
|
+
```
|
35
|
+
|
36
|
+
**Search for calls to `read` or `write` on the `IO` or `File` modules:**
|
37
|
+
|
38
|
+
```
|
39
|
+
$ scrutinize -t IO,File -m read,binread
|
40
|
+
./lib/sinatra/base.rb:1275 IO.binread
|
41
|
+
./lib/sinatra/base.rb:1275 IO.read
|
42
|
+
./test/encoding_test.rb:13 File.read
|
43
|
+
...
|
44
|
+
```
|
45
|
+
|
46
|
+
**Search for calls to any method on the `IO` or `File` modules:**
|
47
|
+
|
48
|
+
```
|
49
|
+
$ scrutinize -t IO,File
|
50
|
+
./lib/sinatra/base.rb:44 File.fnmatch
|
51
|
+
./lib/sinatra/base.rb:1275 IO.read
|
52
|
+
./test/integration_helper.rb:26 File.expand_path
|
53
|
+
./test/integration_helper.rb:42 IO.popen
|
54
|
+
./test/yajl_test.rb:9 File.dirname
|
55
|
+
...
|
56
|
+
```
|
57
|
+
|
58
|
+
## Installation
|
59
|
+
|
60
|
+
```
|
61
|
+
bundle install
|
62
|
+
rake install
|
63
|
+
```
|
data/Rakefile
ADDED
data/bin/scrutinize
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
require 'scrutinize'
|
4
|
+
require 'optparse'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
options = {'triggers' => [], 'dir' => '.'}
|
8
|
+
last_trigger = {}
|
9
|
+
|
10
|
+
OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: scrutinize [options] [method_name ...]"
|
12
|
+
|
13
|
+
opts.on("-t", "--targets", "=MANDATORY", Array, "A comma separated list of targets to search for the next set of methods on") do |t|
|
14
|
+
if last_trigger['targets']
|
15
|
+
options['triggers'] << last_trigger
|
16
|
+
last_trigger = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
last_trigger['targets'] = t
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-m", "--methods", "=MANDATORY", Array, "A comma separated list of methods to search for on the last listed set of targets") do |m|
|
23
|
+
if last_trigger['methods']
|
24
|
+
options['triggers'] << last_trigger
|
25
|
+
last_trigger = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
last_trigger['methods'] = m
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-d", "--directory", "=MANDATORY", String, "The directory to search") do |d|
|
32
|
+
options['dir'] = d
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-c", "--config", "=MANDATORY", String, "A YAML config file to load") do |c|
|
36
|
+
options.merge! YAML.load File.read c
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-r", "--ruby-version", "=MANDATORY", String, "The Ruby version of the files we're searching through") do |r|
|
40
|
+
options['ruby_version'] = r
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
44
|
+
puts opts
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
end.parse!
|
48
|
+
|
49
|
+
last_trigger['methods'] = ARGV unless ARGV.empty?
|
50
|
+
options['triggers'] << last_trigger
|
51
|
+
|
52
|
+
Scrutinize.scan options
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'scrutinize/trigger'
|
2
|
+
|
3
|
+
module Scrutinize
|
4
|
+
class Config
|
5
|
+
KNOWN_VERSIONS = %w(ruby18 ruby19 ruby20 ruby21 ruby22)
|
6
|
+
|
7
|
+
def initialize(opts = {})
|
8
|
+
@options = opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](key)
|
12
|
+
@options[key]
|
13
|
+
end
|
14
|
+
|
15
|
+
def files
|
16
|
+
Dir.glob(File.join(@options['dir'], "**/*.rb"))
|
17
|
+
end
|
18
|
+
|
19
|
+
# Public: A Trigger object based on the configured options.
|
20
|
+
#
|
21
|
+
# Returns a Trigger.
|
22
|
+
def trigger
|
23
|
+
@trigger ||= begin
|
24
|
+
trigger = Scrutinize::Trigger.new
|
25
|
+
|
26
|
+
# Trigger configured at top level
|
27
|
+
keys = %w(methods method targets target)
|
28
|
+
unless (@options.keys & keys).empty?
|
29
|
+
trigger.add @options.select { |k,v| keys.include?(k) }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Trigger configured under trigger key
|
33
|
+
trigger.add @options['trigger'] if @options['trigger'].is_a?(Hash)
|
34
|
+
|
35
|
+
# Triggers configured under triggers key
|
36
|
+
if @options['triggers'].is_a? Array
|
37
|
+
@options['triggers'].each { |t| trigger.add t }
|
38
|
+
end
|
39
|
+
|
40
|
+
trigger
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Public: The normalized Ruby version, inferred from RUBY_VERSION and the
|
45
|
+
# configured version.
|
46
|
+
#
|
47
|
+
# Returns a String.
|
48
|
+
def ruby_version
|
49
|
+
@ruby_version ||= begin
|
50
|
+
version = @options['ruby_version'] || RUBY_VERSION
|
51
|
+
normalize_version version
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public: Set a new Ruby version.
|
56
|
+
#
|
57
|
+
# value - A String Ruby version.
|
58
|
+
#
|
59
|
+
# Returns the normalized value provided.
|
60
|
+
def ruby_version=(value)
|
61
|
+
normalize_version(value).tap do |version|
|
62
|
+
@ruby_version = @options['ruby_version'] = version
|
63
|
+
@ruby_parser = parser_for_version version
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Public: A Parser instance for the configured Ruby version.
|
68
|
+
#
|
69
|
+
# Returns a Parser.
|
70
|
+
def ruby_parser
|
71
|
+
@ruby_parser ||= parser_for_version ruby_version
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Normalize a Ruby version.
|
77
|
+
#
|
78
|
+
# version - A Ruby version String.
|
79
|
+
#
|
80
|
+
# Returns a String.
|
81
|
+
def normalize_version(version)
|
82
|
+
return version if KNOWN_VERSIONS.include?(version)
|
83
|
+
|
84
|
+
case version
|
85
|
+
when /^1\.8\./
|
86
|
+
'ruby18'
|
87
|
+
when /^1\.9\./
|
88
|
+
'ruby19'
|
89
|
+
when /^2\.0\./
|
90
|
+
'ruby20'
|
91
|
+
when /^2\.1\./
|
92
|
+
'ruby21'
|
93
|
+
when /^2\.2\./
|
94
|
+
'ruby22'
|
95
|
+
else
|
96
|
+
raise NotImplementedError
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Get the correct Parser class for a given Ruby version.
|
101
|
+
#
|
102
|
+
# version - A Ruby version String.
|
103
|
+
#
|
104
|
+
# Returns a Parser class.
|
105
|
+
def parser_for_version(version)
|
106
|
+
require "parser/#{version}"
|
107
|
+
Parser.const_get version.capitalize
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Scrutinize
|
2
|
+
class Processor
|
3
|
+
# Process a file with a Trigger.
|
4
|
+
#
|
5
|
+
# Returns nothing.
|
6
|
+
def self.process(file, trigger, parser)
|
7
|
+
new(file, trigger, parser).process
|
8
|
+
end
|
9
|
+
|
10
|
+
# Initialize a Processor instance.
|
11
|
+
#
|
12
|
+
# file - the file to be processed.
|
13
|
+
def initialize(file, trigger, parser)
|
14
|
+
@file = file
|
15
|
+
@trigger = trigger
|
16
|
+
@parser = parser
|
17
|
+
end
|
18
|
+
|
19
|
+
# Process the AST of the file.
|
20
|
+
#
|
21
|
+
# Returns nothing.
|
22
|
+
def process
|
23
|
+
process_node ast
|
24
|
+
rescue Parser::SyntaxError
|
25
|
+
end
|
26
|
+
|
27
|
+
# Recurse into an Parser::AST::Node, calling appropriate process functions
|
28
|
+
# for it and its children nodes.
|
29
|
+
#
|
30
|
+
# node - a Parser::AST::Node object.
|
31
|
+
#
|
32
|
+
# Returns nothing.
|
33
|
+
def process_node(node)
|
34
|
+
if node?(node)
|
35
|
+
process_send(node) if node.type == :send
|
36
|
+
node.children.each { |c| process_node c }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Process a :send Parser::AST::Node. Call any registered handler for the
|
41
|
+
# target/method being invoked.
|
42
|
+
#
|
43
|
+
# node - a Parser::AST::Node object.
|
44
|
+
#
|
45
|
+
# Returns nothing.
|
46
|
+
def process_send(node)
|
47
|
+
target = get_src node.children[0] if node.children[0]
|
48
|
+
target = target.slice(2..-1) if node.children[0] && target.start_with?('::')
|
49
|
+
method = node.children[1]
|
50
|
+
|
51
|
+
if @trigger.match? target, method
|
52
|
+
puts "#{@file}:#{node.loc.line} #{target}#{'.' if target}#{method}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Is an object a Parser::AST::Node.
|
57
|
+
#
|
58
|
+
# node - the object to test.
|
59
|
+
#
|
60
|
+
# Returns true/false.
|
61
|
+
def node?(node)
|
62
|
+
node.is_a? Parser::AST::Node
|
63
|
+
end
|
64
|
+
|
65
|
+
# Gets the source code of a given node.
|
66
|
+
#
|
67
|
+
# node - a Parser::AST::Node object.
|
68
|
+
#
|
69
|
+
# Returns a String.
|
70
|
+
def get_src(node)
|
71
|
+
range = node.loc.expression
|
72
|
+
|
73
|
+
# Line numbers start at 1
|
74
|
+
begin_line = range.begin.line - 1
|
75
|
+
end_line = range.end.line - 1
|
76
|
+
middle_lines = begin_line + 1 ... end_line - 1
|
77
|
+
|
78
|
+
# Column numbers start at 0
|
79
|
+
begin_column = range.begin.column
|
80
|
+
end_column = range.end.column
|
81
|
+
|
82
|
+
# Beginning/ending on same line
|
83
|
+
if begin_line == end_line
|
84
|
+
return src_lines[begin_line][begin_column...end_column]
|
85
|
+
end
|
86
|
+
|
87
|
+
lines = []
|
88
|
+
lines << src_lines[begin_line][begin_column..-1]
|
89
|
+
lines += src_lines[middle_lines]
|
90
|
+
lines << src_lines[end_line][0...end_line]
|
91
|
+
lines.join "\n"
|
92
|
+
end
|
93
|
+
|
94
|
+
# The AST of the source code.
|
95
|
+
#
|
96
|
+
# Returns a Parser::AST::Node object.
|
97
|
+
def ast
|
98
|
+
@ast ||= @parser.parse src
|
99
|
+
end
|
100
|
+
|
101
|
+
# The source code, broken up into lines.
|
102
|
+
#
|
103
|
+
# Returns an Array of Strings.
|
104
|
+
def src_lines
|
105
|
+
@src_lines = src.lines.to_a
|
106
|
+
end
|
107
|
+
|
108
|
+
# The source code.
|
109
|
+
#
|
110
|
+
# Returns a String.
|
111
|
+
def src
|
112
|
+
@src ||= File.read @file
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Scrutinize
|
4
|
+
class Trigger
|
5
|
+
ANY = Set.new(['SCRUTINIZE_ANY', true, nil])
|
6
|
+
NONE = Set.new(['SCRUTINIZE_NONE', false])
|
7
|
+
|
8
|
+
# Instantiate a new Trigger.
|
9
|
+
#
|
10
|
+
# Returns nothing.
|
11
|
+
def initialize
|
12
|
+
@targets = Set.new
|
13
|
+
@methods = Set.new
|
14
|
+
@target_methods = Set.new
|
15
|
+
@any_target_methods = Set.new
|
16
|
+
@any_method_targets = Set.new
|
17
|
+
@any_method_any_target = false
|
18
|
+
end
|
19
|
+
|
20
|
+
# Add targets/methods to the trigger.#
|
21
|
+
#
|
22
|
+
# criteria - A hash of targets/methods
|
23
|
+
# :targets - An Array of target names to trigger on. Setting to
|
24
|
+
# `true` means all targets match. Setting to nil
|
25
|
+
# means that only calls without a target match.
|
26
|
+
# :methods - An Array of method names to trigger on. Setting to
|
27
|
+
# `true` means all methods match.
|
28
|
+
#
|
29
|
+
# Returns nothing.
|
30
|
+
def add(criteria = {})
|
31
|
+
# Stop now if we're searching for everything.
|
32
|
+
return if @any_method_any_target
|
33
|
+
|
34
|
+
# Extract targets/methods from criteria
|
35
|
+
targets = Set.new
|
36
|
+
targets += Array(criteria['targets']) if criteria.key?('targets')
|
37
|
+
targets += Array(criteria['target']) if criteria.key?('target')
|
38
|
+
targets += [nil] if targets.empty? # Can't do Array(nil)
|
39
|
+
|
40
|
+
methods = Set.new
|
41
|
+
methods += Array(criteria['methods']) if criteria.key?('methods')
|
42
|
+
methods += Array(criteria['method']) if criteria.key?('method')
|
43
|
+
methods += [nil] if methods.empty? # Can't do Array(nil)
|
44
|
+
|
45
|
+
any_method = !(ANY & methods).empty?
|
46
|
+
any_target = !(ANY & targets).empty?
|
47
|
+
|
48
|
+
# Stop now if we're searching for everything.
|
49
|
+
if any_target && any_method
|
50
|
+
return @any_method_any_target = true
|
51
|
+
end
|
52
|
+
|
53
|
+
# Don't clean up methods if we're looking for all methods.
|
54
|
+
if !any_method
|
55
|
+
methods.map! &:to_sym
|
56
|
+
methods -= @any_target_methods
|
57
|
+
end
|
58
|
+
|
59
|
+
# Stop now if we're looking for any method.
|
60
|
+
if any_target
|
61
|
+
return @any_target_methods += methods
|
62
|
+
end
|
63
|
+
|
64
|
+
# Clean up targets, preserving no target case.
|
65
|
+
if !(targets & NONE).empty?
|
66
|
+
targets -= NONE
|
67
|
+
targets.map! &:to_sym
|
68
|
+
targets.add nil
|
69
|
+
else
|
70
|
+
targets.map! &:to_str
|
71
|
+
end
|
72
|
+
targets -= @any_method_targets
|
73
|
+
|
74
|
+
# Stop now if we're looking for any target.
|
75
|
+
if any_method
|
76
|
+
return @any_method_targets += targets
|
77
|
+
end
|
78
|
+
|
79
|
+
# Track all the methods/targets we've seen for faster checks.
|
80
|
+
@methods += methods
|
81
|
+
@targets += targets
|
82
|
+
|
83
|
+
# Track each target/method combo.
|
84
|
+
targets.each do |target|
|
85
|
+
methods.each do |method|
|
86
|
+
@target_methods.add [target, method]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Checks if a given target/method match the configuration.
|
92
|
+
#
|
93
|
+
# target - A String target name.
|
94
|
+
# method - A Symbol method name.
|
95
|
+
#
|
96
|
+
# Returns boolean.
|
97
|
+
def match?(target, method)
|
98
|
+
@any_method_any_target ||
|
99
|
+
@any_method_targets.include?(target) ||
|
100
|
+
@any_target_methods.include?(method) ||
|
101
|
+
(
|
102
|
+
@targets.include?(target) &&
|
103
|
+
@methods.include?(method) &&
|
104
|
+
@target_methods.include?([target, method])
|
105
|
+
)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/scrutinize.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'scrutinize/config'
|
2
|
+
require 'scrutinize/processor'
|
3
|
+
|
4
|
+
module Scrutinize
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def scan(opts)
|
8
|
+
config = Config.new opts
|
9
|
+
config.files.each do |file|
|
10
|
+
Processor.process(file, config.trigger, config.ruby_parser)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/scrutinize.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
3
|
+
require 'scrutinize/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "scrutinize"
|
7
|
+
spec.version = Scrutinize::VERSION
|
8
|
+
spec.authors = ["Ben Toews"]
|
9
|
+
spec.email = ["mastahyeti@gmail.com"]
|
10
|
+
spec.summary = %q{Ruby method call finder}
|
11
|
+
|
12
|
+
spec.files = `git ls-files -z`.split("\x0")
|
13
|
+
spec.executables = ["scrutinize"]
|
14
|
+
spec.require_paths = ["lib"]
|
15
|
+
|
16
|
+
spec.add_dependency "parser", "~> 2.1.9"
|
17
|
+
|
18
|
+
spec.add_development_dependency "rspec"
|
19
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
20
|
+
spec.add_development_dependency "rake"
|
21
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'scrutinize/config'
|
2
|
+
|
3
|
+
describe Scrutinize::Config do
|
4
|
+
describe "with unspecified ruby_version" do
|
5
|
+
subject { Scrutinize::Config.new }
|
6
|
+
|
7
|
+
it "uses RUBY_VERSION" do
|
8
|
+
expected = \
|
9
|
+
case RUBY_VERSION
|
10
|
+
when /^1\.8\./
|
11
|
+
'ruby18'
|
12
|
+
when /^1\.9\./
|
13
|
+
'ruby19'
|
14
|
+
when /^2\.0\./
|
15
|
+
'ruby20'
|
16
|
+
when /^2\.1\./
|
17
|
+
'ruby21'
|
18
|
+
when /^2\.2\./
|
19
|
+
'ruby22'
|
20
|
+
end
|
21
|
+
|
22
|
+
expect(subject.ruby_version).to eq(expected)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can be set to other versions" do
|
26
|
+
subject.ruby_version = "1.8.7"
|
27
|
+
expect(subject.ruby_version).to eq('ruby18')
|
28
|
+
end
|
29
|
+
|
30
|
+
it "parses crazy versions" do
|
31
|
+
subject.ruby_version = "1.8.7.0.0alpha"
|
32
|
+
expect(subject.ruby_version).to eq('ruby18')
|
33
|
+
end
|
34
|
+
|
35
|
+
it "selects a parser accordingly" do
|
36
|
+
subject.ruby_version = "1.8.7"
|
37
|
+
expect(subject.ruby_parser.to_s).to eq("Parser::Ruby18")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "raises for bad ruby versions" do
|
41
|
+
expect { subject.ruby_version = "9.9.9" }.to raise_error(NotImplementedError)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "with specified trigger options" do
|
46
|
+
it "allows target/method at top level of options" do
|
47
|
+
c = Scrutinize::Config.new 'target' => 'File', 'method' => 'read'
|
48
|
+
|
49
|
+
expect(c.trigger.match?('File', :read)).to eq(true)
|
50
|
+
expect(c.trigger.match?('Foo', :read)).to eq(false)
|
51
|
+
expect(c.trigger.match?('File', :foo)).to eq(false)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "allows target/method under trigger key" do
|
55
|
+
c = Scrutinize::Config.new(
|
56
|
+
'trigger' => {
|
57
|
+
'target' => 'File',
|
58
|
+
'method' => 'read'
|
59
|
+
}
|
60
|
+
)
|
61
|
+
|
62
|
+
expect(c.trigger.match?('File', :read)).to eq(true)
|
63
|
+
expect(c.trigger.match?('Foo', :read)).to eq(false)
|
64
|
+
expect(c.trigger.match?('File', :foo)).to eq(false)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "allows target/method under triggers key" do
|
68
|
+
c = Scrutinize::Config.new(
|
69
|
+
'triggers' => [{
|
70
|
+
'target' => 'File',
|
71
|
+
'method' => 'read'
|
72
|
+
}]
|
73
|
+
)
|
74
|
+
|
75
|
+
expect(c.trigger.match?('File', :read)).to eq(true)
|
76
|
+
expect(c.trigger.match?('Foo', :read)).to eq(false)
|
77
|
+
expect(c.trigger.match?('File', :foo)).to eq(false)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'scrutinize/trigger'
|
2
|
+
|
3
|
+
describe Scrutinize::Trigger, "#match?" do
|
4
|
+
describe "targets matching any method" do
|
5
|
+
subject do
|
6
|
+
Scrutinize::Trigger.new.tap do |target|
|
7
|
+
target.add 'targets' => %w(File IO)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it "matches any method for the targets" do
|
12
|
+
expect(subject.match?('File', :write)).to eq(true)
|
13
|
+
expect(subject.match?('IO', :read)).to eq(true)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "doesn't match methods for other targets" do
|
17
|
+
expect(subject.match?('Foo', :bar)).to eq(false)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "methods matching any target" do
|
22
|
+
subject do
|
23
|
+
Scrutinize::Trigger.new.tap do |target|
|
24
|
+
target.add 'methods' => %w(read write)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "matches any targets for the methods" do
|
29
|
+
expect(subject.match?('Foo', :write)).to eq(true)
|
30
|
+
expect(subject.match?('Bar', :read)).to eq(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "matches nil targets for the method" do
|
34
|
+
expect(subject.match?(nil, :write)).to eq(true)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "doesn't match methods for other targets" do
|
38
|
+
expect(subject.match?('Foo', :bar)).to eq(false)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "any target matching any method" do
|
43
|
+
subject do
|
44
|
+
Scrutinize::Trigger.new.tap do |target|
|
45
|
+
target.add 'target' => nil, 'method' => nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "matches any method and any target" do
|
50
|
+
expect(subject.match?('Foo', :write)).to eq(true)
|
51
|
+
expect(subject.match?('Bar', :read)).to eq(true)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "specific methods and targets" do
|
56
|
+
subject do
|
57
|
+
Scrutinize::Trigger.new.tap do |target|
|
58
|
+
target.add 'target' => 'IO', 'methods' => %w(select read)
|
59
|
+
target.add 'target' => 'File', 'methods' => %w(read write)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it "matches specified methods/targets" do
|
64
|
+
expect(subject.match?('IO', :select)).to eq(true)
|
65
|
+
expect(subject.match?('IO', :read)).to eq(true)
|
66
|
+
expect(subject.match?('File', :read)).to eq(true)
|
67
|
+
expect(subject.match?('File', :write)).to eq(true)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "doesn't match other methods/targets" do
|
71
|
+
expect(subject.match?('File', :select)).to eq(false)
|
72
|
+
expect(subject.match?('IO', :write)).to eq(false)
|
73
|
+
expect(subject.match?('Foo', :bar)).to eq(false)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "none target with specific methods" do
|
78
|
+
subject do
|
79
|
+
Scrutinize::Trigger.new.tap do |target|
|
80
|
+
target.add 'target' => false, 'methods' => %w(read)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "matches specific methods with none target" do
|
85
|
+
expect(subject.match?(nil, :read)).to eq(true)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "doesn't match methods with a target" do
|
89
|
+
expect(subject.match?('IO', :read)).to eq(false)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "doesn't match other methods with none target" do
|
93
|
+
expect(subject.match?(nil, :foo)).to eq(false)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: scrutinize
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Toews
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: parser
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.1.9
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.1.9
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.6'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- mastahyeti@gmail.com
|
72
|
+
executables:
|
73
|
+
- scrutinize
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- Gemfile
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- bin/scrutinize
|
82
|
+
- lib/scrutinize.rb
|
83
|
+
- lib/scrutinize/config.rb
|
84
|
+
- lib/scrutinize/processor.rb
|
85
|
+
- lib/scrutinize/trigger.rb
|
86
|
+
- lib/scrutinize/version.rb
|
87
|
+
- scrutinize.gemspec
|
88
|
+
- spec/config_spec.rb
|
89
|
+
- spec/trigger_spec.rb
|
90
|
+
homepage:
|
91
|
+
licenses: []
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 2.2.2
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: Ruby method call finder
|
113
|
+
test_files: []
|