quickdraw 0.0.5 → 0.1.0
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 +5 -5
- data/.rubocop.yml +18 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +6 -1
- data/Gemfile.lock +49 -0
- data/LICENSE.txt +17 -18
- data/README.md +100 -29
- data/config/quickdraw.rb +16 -0
- data/exe/qt +12 -0
- data/lib/quickdraw/cluster.rb +27 -0
- data/lib/quickdraw/configuration.rb +13 -0
- data/lib/quickdraw/context.rb +138 -0
- data/lib/quickdraw/expectation.rb +62 -0
- data/lib/quickdraw/map.rb +30 -0
- data/lib/quickdraw/matchers/boolean.rb +11 -0
- data/lib/quickdraw/matchers/case_equality.rb +9 -0
- data/lib/quickdraw/matchers/change.rb +33 -0
- data/lib/quickdraw/matchers/equality.rb +39 -0
- data/lib/quickdraw/matchers/include.rb +15 -0
- data/lib/quickdraw/matchers/predicate.rb +14 -0
- data/lib/quickdraw/matchers/respond_to.rb +15 -0
- data/lib/quickdraw/matchers/to_be_a.rb +18 -0
- data/lib/quickdraw/matchers/to_have_attributes.rb +13 -0
- data/lib/quickdraw/matchers/to_raise.rb +26 -0
- data/lib/quickdraw/matchers/to_receive.rb +30 -0
- data/lib/quickdraw/matchers.rb +13 -0
- data/lib/quickdraw/pipe.rb +27 -0
- data/lib/quickdraw/queue.rb +32 -0
- data/lib/quickdraw/registry.rb +57 -0
- data/lib/quickdraw/run.rb +53 -0
- data/lib/quickdraw/runner.rb +48 -0
- data/lib/quickdraw/timer.rb +30 -0
- data/lib/quickdraw/version.rb +3 -1
- data/lib/quickdraw/worker.rb +28 -0
- data/lib/quickdraw.rb +29 -22
- metadata +51 -123
- data/.gitignore +0 -17
- data/Rakefile +0 -1
- data/bin/quickdraw +0 -25
- data/lib/quickdraw/cli.rb +0 -251
- data/lib/quickdraw/shopify_connector.rb +0 -105
- data/lib/quickdraw/shopify_connector_pool.rb +0 -54
- data/quickdraw.gemspec +0 -29
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quickdraw::Matchers::Change
|
4
|
+
def to_change(from: Quickdraw::Null, to: Quickdraw::Null, by: Quickdraw::Null, &object)
|
5
|
+
original = object.call
|
6
|
+
|
7
|
+
if Quickdraw::Null != from
|
8
|
+
assert from === original do
|
9
|
+
"expected `#{original.inspect}` to be `#{from.inspect}`"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
block.call
|
14
|
+
|
15
|
+
new = object.call
|
16
|
+
|
17
|
+
if new == original
|
18
|
+
failure! "expected `#{original.inspect}` to change"
|
19
|
+
end
|
20
|
+
|
21
|
+
if Quickdraw::Null != to
|
22
|
+
assert to === new do
|
23
|
+
"expected `#{new.inspect}` to be `#{to.inspect}`"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if Quickdraw::Null != by
|
28
|
+
assert by === (new - original) do
|
29
|
+
"expected `#{new.inspect}` to change by `#{by.inspect}`"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quickdraw::Matchers::Equality
|
4
|
+
def ==(other)
|
5
|
+
assert value == other do
|
6
|
+
"expected `#{value.inspect}` to == `#{other.inspect}`"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def !=(other)
|
11
|
+
assert value != other do
|
12
|
+
"expected `#{value.inspect}` to != `#{other.inspect}`"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_eql?(other)
|
17
|
+
assert value.eql?(other) do
|
18
|
+
"expected `#{value.inspect}` to eql? `#{other.inspect}`"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def not_to_eql?(other)
|
23
|
+
refute value.eql?(other) do
|
24
|
+
"expected `#{value.inspect}` not to eql? `#{other.inspect}`"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_equal?(other)
|
29
|
+
assert value.equal?(other) do
|
30
|
+
"expected `#{value.inspect}` to equal? `#{other.inspect}`"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def not_to_equal?(other)
|
35
|
+
refute value.equal?(other) do
|
36
|
+
"expected `#{value.inspect}` not to equal? `#{other.inspect}`"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quickdraw::Matchers::Include
|
4
|
+
def to_include(other)
|
5
|
+
assert value.include?(other) do
|
6
|
+
"expected `#{value.inspect}` to include? `#{other.inspect}`"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def not_to_include(other)
|
11
|
+
refute value.include?(other) do
|
12
|
+
"expected `#{value.inspect}` to not include? `#{other.inspect}`"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quickdraw::Matchers::Predicate
|
4
|
+
def to_be(predicate)
|
5
|
+
assert(value.send(predicate)) { "expected `#{value.inspect}` to be `#{predicate.inspect}`" }
|
6
|
+
end
|
7
|
+
|
8
|
+
def not_to_be(predicate)
|
9
|
+
refute(value.send(predicate)) { "expected `#{value.inspect}` to not be `#{predicate.inspect}`" }
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method :to_have, :to_be
|
13
|
+
alias_method :not_to_have, :not_to_be
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quickdraw::Matchers::RespondTo
|
4
|
+
def to_respond_to(method)
|
5
|
+
assert value.respond_to?(method) do
|
6
|
+
"expected `#{value.inspect}` to respond to `#{method.inspect}`"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def not_to_respond_to(method)
|
11
|
+
refute value.respond_to?(method) do
|
12
|
+
"expected `#{value.inspect}` to not respond to `#{method.inspect}`"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quickdraw::Matchers::ToBeA
|
4
|
+
def to_be_a(type)
|
5
|
+
assert type === value do
|
6
|
+
"expected `#{value.inspect}` to have the type `#{type.inspect}`"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def not_to_be_a(type)
|
11
|
+
refute type === value do
|
12
|
+
"expected `#{value.inspect}` to not have the type `#{type.inspect}`"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :to_be_an, :to_be_a
|
17
|
+
alias_method :not_to_be_an, :not_to_be_a
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quickdraw::Matchers::ToHaveAttributes
|
4
|
+
def to_have_attributes(**attributes)
|
5
|
+
attributes.each do |k, v|
|
6
|
+
assert v === value.send(k) do
|
7
|
+
"expected `#{value.inspect}` to have the attribute `#{k.inspect}` equal to `#{v.inspect}`"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
rescue NoMethodError => e
|
11
|
+
failure! { "expected `#{value.inspect}` to respond to `#{e.name}`" }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quickdraw::Matchers::ToRaise
|
4
|
+
def to_raise(error = ::Exception)
|
5
|
+
expectation_block = block
|
6
|
+
|
7
|
+
begin
|
8
|
+
expectation_block.call
|
9
|
+
rescue error => e
|
10
|
+
success!
|
11
|
+
yield(e) if block_given?
|
12
|
+
return
|
13
|
+
rescue ::Exception => e
|
14
|
+
return failure! { "expected `#{error.inspect}` to be raised but `#{e.class.inspect}` was raised" }
|
15
|
+
end
|
16
|
+
|
17
|
+
failure! { "expected #{error} to be raised but wasn't" }
|
18
|
+
end
|
19
|
+
|
20
|
+
def not_to_raise
|
21
|
+
block.call
|
22
|
+
success!
|
23
|
+
rescue ::Exception => e
|
24
|
+
failure! { "expected the block not to raise, but it raised `#{e.class}`" }
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quickdraw::Matchers::ToReceive
|
4
|
+
def to_receive(method_name, &expectation_block)
|
5
|
+
__raise__ ::ArgumentError, "You can't use the `to_receive` matcher with a block expectation." if @block
|
6
|
+
|
7
|
+
interceptor = ::Module.new
|
8
|
+
|
9
|
+
# Define local variables so they're available from the block
|
10
|
+
expectation = self
|
11
|
+
context = @context
|
12
|
+
|
13
|
+
interceptor.define_method(method_name) do |*args, **kwargs, &block|
|
14
|
+
expectation.success!
|
15
|
+
super_block = -> (*a, &b) { (a.length > 0) || b ? super(*a, &b) : super(*args, **kwargs, &block) }
|
16
|
+
original_super = context.instance_variable_get(:@super)
|
17
|
+
begin
|
18
|
+
context.instance_variable_set(:@super, super_block)
|
19
|
+
result = expectation_block&.call(*args, **kwargs, &block)
|
20
|
+
ensure
|
21
|
+
context.instance_variable_set(:@super, original_super)
|
22
|
+
end
|
23
|
+
|
24
|
+
interceptor.define_method(method_name) { |*a, **k, &b| super(*a, **k, &b) }
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
value.singleton_class.prepend(interceptor)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Quickdraw::Matchers
|
2
|
+
autoload :Boolean, "quickdraw/matchers/boolean"
|
3
|
+
autoload :CaseEquality, "quickdraw/matchers/case_equality"
|
4
|
+
autoload :Change, "quickdraw/matchers/change"
|
5
|
+
autoload :Equality, "quickdraw/matchers/equality"
|
6
|
+
autoload :Include, "quickdraw/matchers/include"
|
7
|
+
autoload :Predicate, "quickdraw/matchers/predicate"
|
8
|
+
autoload :RespondTo, "quickdraw/matchers/respond_to"
|
9
|
+
autoload :ToBeA, "quickdraw/matchers/to_be_a"
|
10
|
+
autoload :ToHaveAttributes, "quickdraw/matchers/to_have_attributes"
|
11
|
+
autoload :ToRaise, "quickdraw/matchers/to_raise"
|
12
|
+
autoload :ToReceive, "quickdraw/matchers/to_receive"
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Quickdraw::Pipe
|
4
|
+
def initialize
|
5
|
+
@reader, @writer = IO.pipe
|
6
|
+
end
|
7
|
+
|
8
|
+
def reader
|
9
|
+
@writer.close
|
10
|
+
@reader
|
11
|
+
end
|
12
|
+
|
13
|
+
def writer
|
14
|
+
@reader.close
|
15
|
+
@writer
|
16
|
+
end
|
17
|
+
|
18
|
+
def with_writer
|
19
|
+
@reader.close
|
20
|
+
yield(@writer).tap { @writer.close }
|
21
|
+
end
|
22
|
+
|
23
|
+
def with_reader
|
24
|
+
@writer.close
|
25
|
+
yield(@reader).tap { @reader.close }
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Quickdraw::Queue
|
4
|
+
def initialize
|
5
|
+
@array = []
|
6
|
+
@mutex = Mutex.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def <<(item)
|
10
|
+
@mutex.synchronize { @array << item }
|
11
|
+
end
|
12
|
+
|
13
|
+
def drain
|
14
|
+
yield(shift) until empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def pop
|
18
|
+
@mutex.synchronize { @array.pop }
|
19
|
+
end
|
20
|
+
|
21
|
+
def shift
|
22
|
+
@mutex.synchronize { @array.shift }
|
23
|
+
end
|
24
|
+
|
25
|
+
def empty?
|
26
|
+
@array.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def size
|
30
|
+
@array.size
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
# frozen_string_literal: true
|
5
|
+
|
6
|
+
class Quickdraw::Registry
|
7
|
+
def initialize
|
8
|
+
@registered_matchers = Quickdraw::Map.new
|
9
|
+
@type_matchers = Quickdraw::Map.new
|
10
|
+
@shapes = Quickdraw::Map.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# Register a new matcher for the given types.
|
14
|
+
def register(matcher, *types)
|
15
|
+
@registered_matchers[matcher] = types
|
16
|
+
|
17
|
+
# We need to clear this cache because the output of `slowly_find_matchers_for` might have changed.
|
18
|
+
@type_matchers.clear
|
19
|
+
end
|
20
|
+
|
21
|
+
# Given a value, find or build an expectation class that includes all the matchers for the value.
|
22
|
+
def expectation_for(value, matchers: nil)
|
23
|
+
if matchers
|
24
|
+
shape_for(
|
25
|
+
matchers + matchers_for(value)
|
26
|
+
)
|
27
|
+
else
|
28
|
+
shape_for(
|
29
|
+
matchers_for(value)
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# A "shape" is a specialised Expectation class that includes the given matchers. It's cached against the list of matchers.
|
37
|
+
def shape_for(matchers)
|
38
|
+
@shapes[matchers] ||= Class.new(Quickdraw::Expectation) do
|
39
|
+
matchers.each { |m| include m }
|
40
|
+
freeze
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Given a value, find all the matchers that match it. This is cached against the class of the value.
|
45
|
+
def matchers_for(value)
|
46
|
+
@type_matchers[value.class] ||= slowly_find_matchers_for(value)
|
47
|
+
end
|
48
|
+
|
49
|
+
# If the above has a cache miss, we'll need to find the correct matchers slowly and then cache them.
|
50
|
+
def slowly_find_matchers_for(value)
|
51
|
+
[].tap do |matchers|
|
52
|
+
@registered_matchers.each do |matcher, types|
|
53
|
+
matchers << matcher if types.any? { |t| t === value }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Quickdraw::Run
|
4
|
+
def initialize(number_of_processes:, number_of_threads: 1, test_files:)
|
5
|
+
@number_of_processes = number_of_processes
|
6
|
+
@number_of_threads = number_of_threads
|
7
|
+
@test_files = test_files.shuffle
|
8
|
+
|
9
|
+
@cluster = Quickdraw::Cluster.new
|
10
|
+
@batches = Array.new(@number_of_processes) { Quickdraw::Queue.new }
|
11
|
+
|
12
|
+
@test_files.each_with_index do |file, index|
|
13
|
+
@batches[index % @number_of_processes] << file
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
report_time do
|
19
|
+
fork_processes
|
20
|
+
@results = @cluster.wait
|
21
|
+
puts_results
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def report_time(&)
|
26
|
+
total_time = Quickdraw::Timer.time(&)
|
27
|
+
puts "Total time: #{total_time}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def fork_processes
|
31
|
+
# Enable YJIT right before forking
|
32
|
+
RubyVM::YJIT.enable
|
33
|
+
|
34
|
+
@batches.each_with_index do |batch, index|
|
35
|
+
@cluster.fork do |writer|
|
36
|
+
results = @number_of_threads.times.map do
|
37
|
+
Thread.new { Quickdraw::Runner.call(batch) }
|
38
|
+
end.map(&:value)
|
39
|
+
|
40
|
+
results.each_with_index do |result, thread|
|
41
|
+
writer.write("\n")
|
42
|
+
writer.write("Process[#{index + 1}], Thread[#{thread + 1}]: #{result.successes.count} assertions passed in #{result.duration}. #{Quickdraw::SUCCESS_EMOJI.sample}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def puts_results
|
49
|
+
puts
|
50
|
+
puts
|
51
|
+
puts "Collated results: \n#{@results.join("\n")}"
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Quickdraw::Runner
|
4
|
+
def self.call(queue)
|
5
|
+
tests = []
|
6
|
+
|
7
|
+
queue.drain do |f|
|
8
|
+
tests << [f, Class.new(Quickdraw::Context) do
|
9
|
+
class_eval(
|
10
|
+
File.read(f), f, 1
|
11
|
+
)
|
12
|
+
end]
|
13
|
+
end
|
14
|
+
|
15
|
+
new(tests).tap(&:call)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(tests = nil)
|
19
|
+
@tests = tests
|
20
|
+
|
21
|
+
@successes = []
|
22
|
+
@failures = []
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :successes, :failures, :duration
|
26
|
+
|
27
|
+
def call
|
28
|
+
@duration = Quickdraw::Timer.time do
|
29
|
+
@tests.each { |(f, t)| t.run(self, [f]) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def success!(name)
|
34
|
+
@successes << [name]
|
35
|
+
|
36
|
+
Kernel.print "🟢 "
|
37
|
+
# ::Kernel.print "\e[32m⚬\e[0m"
|
38
|
+
end
|
39
|
+
|
40
|
+
def failure!(path, &message)
|
41
|
+
location = caller_locations.drop_while { |l| !l.path.include?(".test.rb") }
|
42
|
+
|
43
|
+
@failures << [message, location, path]
|
44
|
+
|
45
|
+
Kernel.print "🔴 "
|
46
|
+
# ::Kernel.print "\e[31m⚬\e[0m"
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Quickdraw::Timer
|
4
|
+
class Duration
|
5
|
+
def initialize(duration)
|
6
|
+
@duration = duration
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
if @duration < 1_000
|
11
|
+
"#{@duration}ns"
|
12
|
+
elsif @duration < 1_000_000
|
13
|
+
"#{@duration / 1_000}μs"
|
14
|
+
elsif @duration < 1_000_000_000
|
15
|
+
"#{@duration / 1_000_000}ms"
|
16
|
+
elsif @duration < 60_000_000_000
|
17
|
+
"#{@duration / 1_000_000_000}s"
|
18
|
+
else
|
19
|
+
"#{(@duration / 60_000_000_000)}m"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.time
|
25
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
|
26
|
+
yield
|
27
|
+
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
|
28
|
+
Duration.new(finish - start)
|
29
|
+
end
|
30
|
+
end
|
data/lib/quickdraw/version.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Quickdraw::Worker
|
4
|
+
def self.fork
|
5
|
+
pipe = Quickdraw::Pipe.new
|
6
|
+
|
7
|
+
pid = Process.fork do
|
8
|
+
pipe.with_writer do |writer|
|
9
|
+
yield(writer)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
new(pid:, pipe:)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(pid:, pipe:)
|
17
|
+
@pid = pid
|
18
|
+
@pipe = pipe
|
19
|
+
end
|
20
|
+
|
21
|
+
def wait
|
22
|
+
Process.wait(@pid)
|
23
|
+
|
24
|
+
@pipe.with_reader do |reader|
|
25
|
+
reader.read
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/quickdraw.rb
CHANGED
@@ -1,33 +1,40 @@
|
|
1
|
-
|
2
|
-
require 'pathname'
|
3
|
-
require 'filepath'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
3
|
module Quickdraw
|
4
|
+
autoload :Cluster, "quickdraw/cluster"
|
5
|
+
autoload :Configuration, "quickdraw/configuration"
|
6
|
+
autoload :Context, "quickdraw/context"
|
7
|
+
autoload :Expectation, "quickdraw/expectation"
|
8
|
+
autoload :Matchers, "quickdraw/matchers"
|
9
|
+
autoload :Pipe, "quickdraw/pipe"
|
10
|
+
autoload :Registry, "quickdraw/registry"
|
11
|
+
autoload :Run, "quickdraw/run"
|
12
|
+
autoload :Runner, "quickdraw/runner"
|
13
|
+
autoload :Timer, "quickdraw/timer"
|
14
|
+
autoload :Worker, "quickdraw/worker"
|
15
|
+
autoload :Queue, "quickdraw/queue"
|
16
|
+
autoload :Map, "quickdraw/map"
|
6
17
|
|
7
|
-
|
8
|
-
TIMER_RESET = 5 * 60 + 5
|
9
|
-
PERMIT_LOWER_LIMIT = 10
|
18
|
+
SUCCESS_EMOJI = %w[💃 🕺 🎉 🎊 💪 👏 🙌 ✨ 🥳 🎈 🌈 🎯 🏆]
|
10
19
|
|
11
|
-
|
12
|
-
|
13
|
-
config = YAML.load(File.read('config.yml'))
|
14
|
-
config
|
15
|
-
else
|
16
|
-
puts "config.yml does not exist!"
|
17
|
-
{}
|
18
|
-
end
|
19
|
-
end
|
20
|
+
Null = Object.new.freeze
|
21
|
+
Config = Configuration.new
|
20
22
|
|
21
|
-
|
22
|
-
FilePath.getwd
|
23
|
-
end
|
23
|
+
module Error; end
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
class TestFailure < RuntimeError
|
26
|
+
include Error
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
class ArgumentError < ::ArgumentError
|
30
|
+
include Error
|
31
31
|
end
|
32
32
|
|
33
|
+
def self.configure(&block)
|
34
|
+
if block.arity == 0
|
35
|
+
Config.instance_eval(&block)
|
36
|
+
else
|
37
|
+
yield Config
|
38
|
+
end
|
39
|
+
end
|
33
40
|
end
|