lib/smart_todo/cli.rb in smart_todo-1.6.0 vs lib/smart_todo/cli.rb in smart_todo-1.7.0

- old
+ new

@@ -1,35 +1,40 @@ # frozen_string_literal: true require "optionparser" +require "etc" module SmartTodo # This class is the entrypoint of the SmartTodo library and is responsible # to retrieve the command line options as well as iterating over each files/directories # to run the +CommentParser+ on. class CLI - def initialize + def initialize(dispatcher = nil) @options = {} @errors = [] + @dispatcher = dispatcher end # @param args [Array<String>] def run(args = ARGV) paths = define_options.parse!(args) validate_options! paths << "." if paths.empty? + comment_parser = CommentParser.new paths.each do |path| - normalize_path(path).each do |file| - parse_file(file) + normalize_path(path).each do |filepath| + comment_parser.parse_file(filepath) $stdout.print(".") $stdout.flush end end + process_dispatches(process_todos(comment_parser.todos)) + if @errors.empty? 0 else $stderr.puts "There were errors while checking for TODOs:\n" @@ -77,27 +82,56 @@ else Dir["#{path}/**/*.rb"] end end - # @param file [String] a path to a file - def parse_file(file) - Parser::CommentParser.new(File.read(file, encoding: "UTF-8")).parse.each do |todo_node| + def process_todos(todos) + events = Events.new + dispatches = [] + + todos.each do |todo| event_message = nil - event_met = todo_node.metadata.events.find do |event| - event_message = Events.public_send(event.method_name, *event.arguments) + event_met = todo.events.find do |event| + event_message = events.public_send(event.method_name, *event.arguments) rescue => e - message = "Error while parsing #{file} on event `#{event.method_name}` with arguments #{event.arguments}: " \ + message = "Error while parsing #{todo.filepath} on event `#{event.method_name}` " \ + "with arguments #{event.arguments.map(&:inspect)}: " \ "#{e.message}" @errors << message nil end - @errors.concat(todo_node.metadata.errors) - - dispatcher.new(event_message, todo_node, file, @options).dispatch if event_met + @errors.concat(todo.errors) + dispatches << [event_message, todo] if event_met end + + dispatches + end + + def process_dispatches(dispatches) + queue = Queue.new + dispatches.each { |dispatch| queue << dispatch } + + thread_count = Etc.nprocessors + thread_count.times { queue << nil } + + threads = + thread_count.times.map do + Thread.new do + Thread.current.abort_on_exception = true + + loop do + dispatch = queue.pop + break if dispatch.nil? + + (event_message, todo) = dispatch + dispatcher.new(event_message, todo, todo.filepath, @options).dispatch + end + end + end + + threads.each(&:join) end end end