Class: SyntaxFinder
- Inherits:
-
Object
- Object
- SyntaxFinder
- Defined in:
- lib/syntax_finder.rb,
lib/syntax_finder/version.rb
Constant Summary collapse
- VERSION =
'0.1.0'- @@finders =
[self]
- @@result =
Hash.new(0)
- @@result_notes =
Hash.new{|h, k| h[k] = []}
- @@opt =
{}
Class Method Summary collapse
- .aggregate_results ⇒ Object
- .cleanup_parallel ⇒ Object
- .inc(key) ⇒ Object
- .inherited(klass) ⇒ Object
- .kick(finder, file) ⇒ Object
- .last_finder ⇒ Object
- .note(key, note) ⇒ Object
- .parse_opt(finder, argv) ⇒ Object
- .print_result ⇒ Object
- .run(finder, argv = ARGV) ⇒ Object
- .setup_parallel(finder, pn) ⇒ Object
Instance Method Summary collapse
-
#inc(key) ⇒ Object
any object can be a key.
-
#initialize(file) ⇒ SyntaxFinder
constructor
A new instance of SyntaxFinder.
-
#look(node) ⇒ Object
Please write your pattern here to investigate the node.
-
#nline(node) ⇒ Object
node line (1st line of node lines).
-
#nlines(node) ⇒ Object
node lines.
-
#nloc(node) ⇒ Object
node location information.
- #note(key, note) ⇒ Object
-
#start_traverse ⇒ Object
Execution management.
- #success?(r) ⇒ Boolean
-
#traverse(node) ⇒ Object
If you need to pass some context while traversing, redefine this method with context like ‘def traverse node, context = nil`.
- #traverse_rest(node) ⇒ Object
Constructor Details
#initialize(file) ⇒ SyntaxFinder
6 7 8 |
# File 'lib/syntax_finder.rb', line 6 def initialize file @file = file end |
Class Method Details
.aggregate_results ⇒ Object
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/syntax_finder.rb', line 212 def self.aggregate_results if @@result_notes.size > 0 results = @@result.sort_by{|k, v| -v}.map{|k, v| if !(note = @@result_notes[k]).empty? [k, v, note] else [k, v] end } else results = @@result.sort_by{|k, v| -v} end results.partition{|key,| Symbol === key && key.length > 1 && /^[A-Z_]+$/ =~ key } end |
.cleanup_parallel ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/syntax_finder.rb', line 169 def self.cleanup_parallel return unless taskq = @@opt[:taskq] trap(:INT){ trap(:INT, 'DEFAULT') } taskq.close @@opt[:parallel].times do |i| results, notes = @@opt[:resq].pop @@result.merge!(results){|k, a, b| a + b} @@result_notes.merge!(notes) end end |
.inc(key) ⇒ Object
72 73 74 |
# File 'lib/syntax_finder.rb', line 72 def self.inc key @@result[key] += 1 end |
.inherited(klass) ⇒ Object
102 103 104 |
# File 'lib/syntax_finder.rb', line 102 def self.inherited klass @@finders << klass end |
.kick(finder, file) ⇒ Object
208 209 210 |
# File 'lib/syntax_finder.rb', line 208 def self.kick finder, file finder.new(file).start_traverse end |
.last_finder ⇒ Object
106 107 108 |
# File 'lib/syntax_finder.rb', line 106 def self.last_finder @@finders.last end |
.note(key, note) ⇒ Object
76 77 78 |
# File 'lib/syntax_finder.rb', line 76 def self.note key, note @@result_notes[key] << note end |
.parse_opt(finder, argv) ⇒ Object
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/syntax_finder.rb', line 183 def self.parse_opt finder, argv o = OptionParser.new o.on '-v', '--verbose', 'VERBOSE mode' do $VERBOSE = true end o.on '-d', '--debug' do $DEBUG = true end o.on '-q', '--quiet' do @@opt[:quiet] = true end o.on '-j', '--jobs[=N]', 'Parallel mode' do require 'etc' pn = @@opt[:parallel] = _1&.to_i || Etc.nprocessors setup_parallel finder, pn end o.parse! argv pp options: @@opt if $DEBUG end |
.print_result ⇒ Object
230 231 232 233 |
# File 'lib/syntax_finder.rb', line 230 def self.print_result system_results, user_results = aggregate_results pp [system_results, user_results] end |
.run(finder, argv = ARGV) ⇒ Object
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/syntax_finder.rb', line 235 def self.run finder, argv = ARGV @already_run = true parse_opt finder, argv files = argv.empty? ? ARGF : argv files.each do |f| f = f.scrub.strip next unless FileTest.file?(f) inc :FILES if q = @@opt[:taskq] q << f else kick finder, f end end rescue Interrupt STDERR.puts "-- Interrupted" exit ensure cleanup_parallel finder.print_result if finder end |
.setup_parallel(finder, pn) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/syntax_finder.rb', line 114 def self.setup_parallel finder, pn taskq = @@opt[:taskq] = Queue.new resq = @@opt[:resq] = Queue.new term_cmd = '-- terminate' @@opt[:threads] = pn.times.map{ Thread.new _1 do |ti| task_r, task_w = IO.pipe res_r, res_w = IO.pipe pid = fork do trap(:INT, 'IGNORE') loop do file = task_r.gets.chomp case file when term_cmd @@result_notes.default_proc = nil last_result = [@@result, @@result_notes] break else kick finder, file last_result = nil end rescue Interrupt STDERR.puts "Worker is interrupted (pid: #{Process.pid})" @@result_notes.default_proc = nil last_result = [@@result, @@result_notes] exit ensure res_w.puts Marshal.dump(last_result).dump end end result = nil while true file = taskq.pop task_w.puts file || term_cmd result = Marshal.load(res_r.gets.chomp.undump) # wait for the result if result resq << result break end end ensure p [Thread.current, $!] if $DEBUG Process.kill :KILL, pid Process.waitpid pid end } end |
Instance Method Details
#inc(key) ⇒ Object
any object can be a key. if key is [A-Z_]+, it’s system key. it’s returns true if the key is already exists.
62 63 64 65 66 |
# File 'lib/syntax_finder.rb', line 62 def inc key has_key = @@result.has_key? key @@result[key] += 1 has_key end |
#look(node) ⇒ Object
Please write your pattern here to investigate the node. This method is called for each node.
14 15 16 |
# File 'lib/syntax_finder.rb', line 14 def look node # override here end |
#nline(node) ⇒ Object
node line (1st line of node lines)
39 40 41 |
# File 'lib/syntax_finder.rb', line 39 def nline node node.slice_lines.lines.first.chomp end |
#nlines(node) ⇒ Object
node lines
44 45 46 |
# File 'lib/syntax_finder.rb', line 44 def nlines node node.slice_lines end |
#nloc(node) ⇒ Object
node location information
34 35 36 |
# File 'lib/syntax_finder.rb', line 34 def nloc node "#{@file}:#{node.location.start_line}" end |
#note(key, note) ⇒ Object
68 69 70 |
# File 'lib/syntax_finder.rb', line 68 def note key, note @@result_notes[key] << note end |
#start_traverse ⇒ Object
Execution management
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/syntax_finder.rb', line 82 def start_traverse puts "Start #{@file}" if $DEBUG @root = Prism.parse_file(@file) if success?(@root) traverse @ast = @root.value else # pp [@file, @root.errors] # inc :FAILED, @file inc :FAILED_PARSE end rescue Interrupt exit rescue Exception => e pp [e, @file, e.backtrace] if $DEBUG inc [:FAILED, e.class] end |
#success?(r) ⇒ Boolean
48 49 50 51 52 53 54 55 56 57 |
# File 'lib/syntax_finder.rb', line 48 def success? r return true if r.success? if r.errors.size == 1 && r.errors.first.type == :script_not_found true else false end end |
#traverse(node) ⇒ Object
If you need to pass some context while traversing, redefine this method with context like ‘def traverse node, context = nil`.
20 21 22 23 |
# File 'lib/syntax_finder.rb', line 20 def traverse node look node traverse_rest node end |
#traverse_rest(node) ⇒ Object
25 26 27 28 29 |
# File 'lib/syntax_finder.rb', line 25 def traverse_rest node node.child_nodes.compact.each do |child| traverse child end end |