Class: Recheck::Runner
- Inherits:
-
Object
- Object
- Recheck::Runner
- Defined in:
- lib/recheck/runner.rb
Constant Summary collapse
- PASSTHROUGH_EXCEPTIONS =
[ # ours HookDidNotYield, HookYieldedTwice, UnexpectedHookYield, # Ruby's NoMemoryError, SignalException, SystemExit ]
Instance Method Summary collapse
-
#cant_run(reporters:, checker:, queries:, checks:, type:) ⇒ Object
only for calling from inside run().
-
#initialize(checkers: [], reporters: []) ⇒ Runner
constructor
A new instance of Runner.
-
#reduce(hook:, kwargs: {}, reporters: [], &blk) ⇒ Object
compose reporter hooks so they each see the block fire once at ‘yield’.
-
#run ⇒ Object
n queries * n check methods * n records = O(1) right?.
Constructor Details
#initialize(checkers: [], reporters: []) ⇒ Runner
Returns a new instance of Runner.
46 47 48 49 50 51 |
# File 'lib/recheck/runner.rb', line 46 def initialize(checkers: [], reporters: []) # maintain order and we want to check/report in user-provided order; Set lacks .reverse @checkers = checkers.uniq @reporters = reporters.uniq @yields = Yields.new end |
Instance Method Details
#cant_run(reporters:, checker:, queries:, checks:, type:) ⇒ Object
only for calling from inside run()
69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/recheck/runner.rb', line 69 def cant_run reporters:, checker:, queries:, checks:, type: checker_counts = CountStats.new checker_counts.increment type @total_counts << checker_counts error = Error.new(checker:, query: nil, check: nil, record: nil, type:, exception: nil) reduce(reporters:, hook: :around_checker, kwargs: {checker:, queries:, checks:}) do reporters.each { _1.halt(checker:, query: nil, check: nil, error:) } checker_counts end end |
#reduce(hook:, kwargs: {}, reporters: [], &blk) ⇒ Object
compose reporter hooks so they each see the block fire once at ‘yield’
54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/recheck/runner.rb', line 54 def reduce(hook:, kwargs: {}, reporters: [], &blk) reporters.reverse.reduce(blk) do |proc, reporter| @yields.expect(hook:, reporter:) -> { result = nil reporter.public_send(hook, **kwargs) { @yields.ran(hook:, reporter:) result = proc.call.freeze } result } end.call end |
#run ⇒ Object
n queries * n check methods * n records = O(1) right?
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 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 168 |
# File 'lib/recheck/runner.rb', line 82 def run @total_counts = CountStats.new # All happy families are alike; each unhappy family is unhappy in its own way. pass = Pass.new # for want of a monad... reduce(reporters: @reporters, hook: :around_run, kwargs: {checkers: @checkers}) do # for each checker... @checkers.each do |checker| checker_counts = CountStats.new if !checker.class.respond_to?(:query_methods) cant_run(reporters: @reporters, checker:, type: :no_query_methods, queries: nil, checks: nil) next end if (queries = checker.class.query_methods).empty? cant_run(reporters: @reporters, checker:, type: :no_queries, queries:, checks: nil) next end if !checker.class.respond_to?(:check_methods) cant_run(reporters: @reporters, checker:, type: :no_check_methods, queries:, checks: nil) next end if (checks = checker.class.check_methods).empty? cant_run(reporters: @reporters, checker:, type: :no_checks, queries:, checks:) next end reduce(reporters: @reporters, hook: :around_checker, kwargs: {checker:, queries:, checks:}) do # for each query_... queries.each do |query| reduce(reporters: @reporters, hook: :around_query, kwargs: {checker:, query:, checks:}) do checker_counts.increment :queries # for each record... # TODO: must handle if the query method yields (find_each) OR returns (current) (checker.public_send(query) || []).each do |record| # for each check_method... checks.each do |check| raw_result = nil reduce(reporters: @reporters, hook: :around_check, kwargs: {checker:, query:, check:, record:}) do raw_result = checker.public_send(check, record) result = raw_result ? pass : Error.new(checker:, query:, check:, record:, type: :fail, exception: nil) checker_counts.increment(result.type) break if checker_counts.reached_blanket_failure? result rescue *PASSTHROUGH_EXCEPTIONS raise rescue => e Error.new(checker:, query:, check:, record:, type: :exception, exception: e) end end @yields.raise_unless_all_reporters_yielded(hook: :around_check) # if the first 20 error out, halt the check method, it's probably buggy if checker_counts.reached_blanket_failure? checker_counts.increment :blanket error = Error.new(checker:, query:, check: nil, record: nil, type: :blanket, exception: nil) @reporters.each { _1.halt(checker:, query:, check: nil, error:) } break end end nil # yield nothing around_query end @yields.raise_unless_all_reporters_yielded(hook: :around_query) rescue *PASSTHROUGH_EXCEPTIONS raise rescue => e # puts "outer rescue: #{e.inspect}" @reporters.each do |check_reporter| result = Error.new(checker:, query:, check: nil, record: nil, type: :exception, exception: e) check_reporter.around_check(checker:, query: query, check: nil, record: nil) { result } end end checker_counts end @yields.raise_unless_all_reporters_yielded(hook: :around_checker) @total_counts << checker_counts end @total_counts end @yields.raise_unless_all_reporters_yielded(hook: :around_run) @total_counts end |