peck 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.
data/COPYING ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c)
2
+ 2007 - 2008 Christian Neukirchen <purl.org/net/chneukirchen>
3
+ 2011 - 2012 Eloy Durán <eloy.de.enige@gmail.com>
4
+ 2012 Manfred Stienstra, Fingertips <manfred@fngtps.com>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
7
+ this software and associated documentation files (the "Software"), to deal in
8
+ the Software without restriction, including without limitation the rights to
9
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10
+ the Software, and to permit persons to whom the Software is furnished to do so,
11
+ subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # Peck
2
+
3
+ Peck is a concurrent spec framework.
4
+
5
+ [![Build Status](https://secure.travis-ci.org/Fingertips/Peck.png?branch=master)](http://travis-ci.org/Fingertips/Peck)
6
+
7
+ ## Getting Started
8
+
9
+ You can install Peck as a gem.
10
+
11
+ $ gem install peck
12
+
13
+ Write a little test.
14
+
15
+ require 'peck/flavors/vanilla'
16
+
17
+ describe MicroMachine do
18
+ it "drives really fast" do
19
+ MicroMachine.should.drives(:fast)
20
+ end
21
+ end
22
+
23
+ And enjoy the output.
24
+
25
+ ruby -rubygems spec/micro_machine_spec.rb -e ''
26
+ .
27
+ 1 spec, 0 failures, finished in 0.0 seconds.
28
+
29
+ ## Why another framework/test library/spec language?
30
+
31
+ I guess that's something you will have to find out for yourself. For us a spec
32
+ framework needs two things: a good way to describe intention of the specs and
33
+ flexibility to work with the different types of project we work on.
34
+
35
+ We really like Bacon and test/spec but we've found that they're to limiting
36
+ in some of our projects. Bacon doesn't work really well with Rails and
37
+ test/spec needs test/unit, which will be gone in Ruby 1.9.
38
+
39
+ In some projects we find that we have an enormous amount of little specs which
40
+ beg to be run concurrently.
41
+
42
+ Peck tries to be what we, and maybe you, need it to be. Within reason of
43
+ course.
44
+
45
+ ### Peck can be concurrent
46
+
47
+ Peck has two run modes: serial and concurrent. Right now that's a global
48
+ setting for the whole suite.
49
+
50
+ Peck.concurrency = 9
51
+
52
+ Some projects don't allow concurrency because either the code or the test
53
+ suite aren't thread safe. We've also found that some suites actually run
54
+ slower in threads.
55
+
56
+ ### Peck can host your own spec syntax
57
+
58
+ When implementing your own spec syntax you only have to add expectations
59
+ to a little accessor when they run and raise Peck::Error when something
60
+ fails.
61
+
62
+ describe "Fish" do
63
+ it "breathes with water" do
64
+ # If you don't like .should, you can write your own assertion
65
+ # DSL
66
+ expects {
67
+ Fish.breathes == water
68
+ }
69
+ end
70
+ end
71
+
72
+ With a bit of work you could make Peck run your Rspec tests.
73
+
74
+ ### Peck has a pluggable notification system
75
+
76
+ You can write your own notifiers and register them with Peck's delegate
77
+ system.
78
+
79
+ class Remotifier < Peck::Notifiers::Base
80
+ def finished
81
+ HTTP.post("https://ci.lan/runs?ran=#{Peck.counter.ran}" +
82
+ "&failures=#{Peck.counter.failed}")
83
+ end
84
+ end
85
+ Remotifier.use
86
+
87
+ ### Peck is extensible
88
+
89
+ Expect opening up Peck classes you can also extend during runtime with the
90
+ `once` callback. This callback is ran when a new context (describe) is
91
+ created.
92
+
93
+ Peck::Context.once do |context|
94
+ context.class_eval do
95
+ attr_accessor :controller_class
96
+
97
+ before do
98
+ @controller = controller_class.new
99
+ end
100
+ emd
101
+ end
102
+
103
+ ## Documentation
104
+
105
+ Peck is still very much in flux and will probably change a lot in the coming
106
+ months. Currently we support a small number of assertions:
107
+
108
+ * should, should.not, and should.be
109
+ * should.equal
110
+ * should.raise([exception]) { }
111
+ * should.change([expression]) { }
112
+ * should.satisfy { |object| }
113
+
114
+ If you want to learn more you're probably best of reading the code
115
+ documentation.
116
+
117
+ ## Copying
118
+
119
+ Peck inherits a lot of ideas, concepts and even some implementation from both
120
+ Bacon and MacBacon. Both of these projects have been released under the terms
121
+ of an MIT-style license.
122
+
123
+ Copyright (C) 2007 - 2012 Christian Neukirchen http://purl.org/net/chneukirchen
124
+ Copyright (C) 2011 - 2012 Eloy Durán eloy.de.enige@gmail.com
125
+ Copyright (C) 2012 Manfred Stienstra, Fingertips <manfred@fngtps.com>
126
+
127
+ Peck is freely distributable under the terms of an MIT-style license. See COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -0,0 +1,106 @@
1
+ class Peck
2
+ class Context
3
+ attr_reader :specification
4
+
5
+ def initialize(specification)
6
+ @specification = specification
7
+ end
8
+
9
+ def describe(*args, &block)
10
+ self.class.describe(*args, &block)
11
+ end
12
+
13
+ class << self
14
+ FILENAME_WITHOUT_LINE_RE = /^(.+?):\d+/
15
+
16
+ attr_reader :description, :block, :specs, :source_file
17
+ attr_accessor :timeout
18
+
19
+ def init(before, after, *description, &block)
20
+ # Find the first file in the backtrace which is not this file
21
+ source_file = caller.find { |line| line[0,__FILE__.size] != __FILE__ }
22
+ if source_file
23
+ source_file = source_file.match(FILENAME_WITHOUT_LINE_RE)[1]
24
+ source_file = File.expand_path(source_file)
25
+ else
26
+ log("Unable to determine the file in which the context is defined.")
27
+ end
28
+
29
+ context = Class.new(self) do
30
+ @before = before.dup
31
+ @after = after.dup
32
+ @source_file = source_file
33
+ @description = description
34
+ @block = block
35
+ @specs = []
36
+ end
37
+
38
+ if @setup
39
+ @setup.each { |b| b.call(context) }
40
+ end
41
+
42
+ Peck.contexts << context
43
+ context.class_eval(&block)
44
+ context
45
+ end
46
+
47
+ def label
48
+ Peck.join_description(description)
49
+ end
50
+
51
+ def describe(*description, &block)
52
+ if Peck.context_selector.match(Peck.join_description(*description))
53
+ init(@before, @after, *description, &block)
54
+ end
55
+ end
56
+
57
+ # Is only ran once for every context when it's initialized. Great place
58
+ # to hook in test suite specific functionality.
59
+ #
60
+ # Peck::Context.once { |context| context.before { @name = 'Mary' } }
61
+ def once(&block)
62
+ @setup ||= []
63
+ @setup << block
64
+ end
65
+
66
+ def before(*args, &block)
67
+ add_callback(@before, *args, &block)
68
+ end
69
+ alias setup before
70
+
71
+ def after(*args, &block)
72
+ add_callback(@after, *args, &block)
73
+ end
74
+ alias teardown after
75
+
76
+ private
77
+
78
+ def add_callback(chain, *args, &block)
79
+ args.each do |method|
80
+ Peck.log("Adding method `#{method}' to callback chain")
81
+ chain << Proc.new { send(method) }
82
+ end
83
+ if block_given?
84
+ chain << block
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ PECK_PART_RE = /Peck/
91
+ def self.join_description(description)
92
+ description.map do |part|
93
+ part = part.to_s
94
+ part = nil if part =~ PECK_PART_RE
95
+ part
96
+ end.compact.join(' ')
97
+ end
98
+ end
99
+
100
+ module Kernel
101
+ private
102
+
103
+ def describe(*description, &block)
104
+ Peck::Context.init([], [], *description, &block)
105
+ end
106
+ end
@@ -0,0 +1,48 @@
1
+ class Peck
2
+ class << self
3
+ attr_accessor :counter
4
+ end
5
+
6
+ class Counter
7
+ def self.instance
8
+ @instance ||= new
9
+ end
10
+
11
+ attr_accessor :ran, :passed, :failed, :pending, :missing, :events
12
+
13
+ def initialize
14
+ @ran = @passed = @failed = 0
15
+ @pending = []
16
+ @missing = []
17
+ @events = []
18
+ $stdout.sync = true
19
+ end
20
+
21
+ def finished_specification(spec)
22
+ @ran += 1
23
+ if spec.passed?
24
+ @passed += 1
25
+ elsif spec.failed?
26
+ @failed += 1
27
+ end
28
+ end
29
+
30
+ def received_pending(label)
31
+ @pending << label
32
+ end
33
+
34
+ def received_missing(spec)
35
+ @missing << spec
36
+ end
37
+
38
+ def received_exception(spec, exception)
39
+ @events << exception
40
+ end
41
+ end
42
+
43
+ self.counter = Counter.instance
44
+
45
+ if respond_to?(:delegates)
46
+ self.delegates << self.counter
47
+ end
48
+ end
data/lib/peck/debug.rb ADDED
@@ -0,0 +1,14 @@
1
+ class Peck
2
+ def self.logger
3
+ @logger ||= begin
4
+ require 'logger'
5
+ logger = Logger.new($stdout)
6
+ logger.formatter = Logger::Formatter.new
7
+ logger
8
+ end
9
+ end
10
+
11
+ def self.log(message)
12
+ logger.debug(message)
13
+ end
14
+ end
@@ -0,0 +1,44 @@
1
+ require 'set'
2
+
3
+ class Peck
4
+ class Delegates < Set
5
+ def self.instance
6
+ @instance ||= new
7
+ end
8
+
9
+ MESSAGES = %w(
10
+ started
11
+ finished
12
+ started_specification
13
+ finished_specification
14
+ received_missing
15
+ received_exception
16
+ ).freeze
17
+
18
+ def supported_messages
19
+ MESSAGES
20
+ end
21
+
22
+ def method_missing(method, *args, &block)
23
+ method = method.to_s
24
+ if supported_messages.include?(method)
25
+ each do |delegate|
26
+ if delegate.respond_to?(method)
27
+ delegate.send(method, *args, &block)
28
+ end
29
+ end
30
+ else
31
+ super
32
+ end
33
+ end
34
+ end
35
+
36
+ class << self
37
+ # This can be used by a `client' to receive status updates.
38
+ #
39
+ # Peck.delegates << Notifier.new
40
+ attr_reader :delegates
41
+ end
42
+
43
+ @delegates = Peck::Delegates.instance
44
+ end
data/lib/peck/error.rb ADDED
@@ -0,0 +1,14 @@
1
+ class Peck
2
+ class Error < RuntimeError
3
+ attr_accessor :type
4
+
5
+ def initialize(type, message)
6
+ @type = type.to_s
7
+ super message
8
+ end
9
+
10
+ def count_as?(type)
11
+ @type == type.to_s
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,115 @@
1
+ require 'peck/error'
2
+
3
+ class Peck
4
+ class Should
5
+ # Kills ==, ===, =~, eql?, equal?, frozen?, instance_of?, is_a?,
6
+ # kind_of?, nil?, respond_to?, tainted?
7
+ KILL_METHODS_RE = /\?|^\W+$/
8
+ instance_methods.each do |name|
9
+ undef_method(name) if name =~ KILL_METHODS_RE
10
+ end
11
+
12
+ def initialize(this)
13
+ @this = this
14
+ @negated = false
15
+ Thread.current['peck-spec'].expectations << self
16
+ end
17
+
18
+ def not
19
+ @negated = !@negated
20
+ self
21
+ end
22
+
23
+ def be(*args, &block)
24
+ if args.empty?
25
+ self
26
+ else
27
+ block = args.shift unless block_given?
28
+ satisfy(*args, &block)
29
+ end
30
+ end
31
+
32
+ def satisfy(*args, &block)
33
+ if args.size == 1 && String === args.first
34
+ description = args.shift
35
+ else
36
+ description = ""
37
+ end
38
+
39
+ result = yield(@this, *args)
40
+ unless @negated ^ result
41
+ Kernel.raise Peck::Error.new(:failed, description)
42
+ end
43
+ result
44
+ end
45
+
46
+ def change(expression, change=nil)
47
+ if @negated
48
+ description = "#{expression} changed"
49
+ description << " by #{actual}" if change
50
+ else
51
+ description = "#{expression} didn't change"
52
+ description << " by #{change}" if change
53
+ end
54
+
55
+ satisfy(description) do |x|
56
+ difference = change || 1
57
+ binding = x.send(:binding)
58
+
59
+ before = eval(expression, binding)
60
+ result = @this.call
61
+ after = eval(expression, binding)
62
+
63
+ after == before + difference
64
+ end
65
+ end
66
+
67
+ def raise(exception_class=nil)
68
+ exception = nil
69
+ begin
70
+ @this.call
71
+ rescue Exception => e
72
+ exception = e
73
+ end
74
+
75
+ description = if exception_class
76
+ if @negated
77
+ "expected `#{exception_class}' to not be raised"
78
+ else
79
+ "expected `#{exception_class}' to be raised, but got a `#{exception.class}'"
80
+ end
81
+ else
82
+ if @negated
83
+ "expected nothing to be raised, but got `#{exception.inspect}'"
84
+ else
85
+ "expected an exception, but nothing was raised"
86
+ end
87
+ end
88
+
89
+ satisfy(description) do
90
+ if exception_class
91
+ exception.kind_of?(exception_class)
92
+ else
93
+ !exception.nil?
94
+ end
95
+ end
96
+ end
97
+
98
+ PREDICATE_METHOD_RE = /\w[^?]\z/
99
+ def method_missing(name, *args, &block)
100
+ name = "#{name}?" if name.to_s =~ PREDICATE_METHOD_RE
101
+
102
+ desc = @negated ? "not " : ""
103
+ desc << @this.inspect << "." << name.to_s
104
+ desc << "(" << args.map{|x|x.inspect}.join(", ") << ") failed"
105
+
106
+ satisfy(desc) { |x| x.__send__(name, *args, &block) }
107
+ end
108
+ end
109
+ end
110
+
111
+ class Object
112
+ def should(*args, &block)
113
+ Peck::Should.new(self).be(*args, &block)
114
+ end
115
+ end
@@ -0,0 +1,8 @@
1
+ require 'peck'
2
+ require 'peck/delegates'
3
+ require 'peck/counter'
4
+ require 'peck/context'
5
+ require 'peck/specification'
6
+ require 'peck/expectations'
7
+
8
+ Peck.run_at_exit
@@ -0,0 +1,10 @@
1
+ require 'peck'
2
+ require 'peck/delegates'
3
+ require 'peck/counter'
4
+ require 'peck/context'
5
+ require 'peck/specification'
6
+ require 'peck/expectations'
7
+ require 'peck/notifiers/default'
8
+
9
+ Peck::Notifiers::Default.use
10
+ Peck.run_at_exit
@@ -0,0 +1,39 @@
1
+ class Peck
2
+ class Notifiers
3
+ class Base
4
+ # When a file starts with this path, it's in the Peck library
5
+ PECK_PATH = File.expand_path('../../../../', __FILE__)
6
+
7
+ # Matches: `block (2 levels) in <top (required)>'
8
+ ANONYMOUS_BLOCK_RE = /`block/
9
+
10
+ def self.use
11
+ @instance ||= begin
12
+ notifier = new
13
+ notifier.install_at_exit
14
+ Peck.delegates << notifier
15
+ notifier
16
+ end
17
+ end
18
+
19
+ protected
20
+
21
+ def pluralize(count, stem)
22
+ count == 1 ? stem : "#{stem}s"
23
+ end
24
+
25
+ def clean_backtrace(backtrace)
26
+ stripped = []
27
+ backtrace.each do |line|
28
+ if line.start_with?(PECK_PATH) || line.start_with?("<")
29
+ elsif line =~ ANONYMOUS_BLOCK_RE
30
+ stripped << line.split(':')[0,2].join(':')
31
+ else
32
+ stripped << line
33
+ end
34
+ end
35
+ stripped.empty? ? backtrace : stripped
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,68 @@
1
+ require 'peck/notifiers/base'
2
+
3
+ class Peck
4
+ class Notifiers
5
+ class Default < Peck::Notifiers::Base
6
+ def initialize
7
+ @started_at = @finished_at = Time.now
8
+ end
9
+
10
+ def started
11
+ @started_at = Time.now
12
+ end
13
+
14
+ def finished
15
+ @finished_at = Time.now
16
+ end
17
+
18
+ def finished_specification(spec)
19
+ if spec.passed?
20
+ $stdout.write('.')
21
+ elsif spec.failed?
22
+ $stdout.write('f')
23
+ end
24
+ end
25
+
26
+ def write_exeception(number, event)
27
+ puts " #{number}) #{event.spec.label}\n\n"
28
+ backtrace = clean_backtrace(event.exception.backtrace)
29
+ puts " #{event.exception.message}\n\n\t#{backtrace.join("\n\t")}\n\n"
30
+ end
31
+
32
+ def write_event(number, event)
33
+ case event.exception
34
+ when Exception
35
+ write_exeception(number, event)
36
+ else
37
+ raise ArgumentError, "Don't know how to display event `#{event.expectation.class.name}'"
38
+ end
39
+ end
40
+
41
+ def write_events
42
+ Peck.all_events.each_with_index do |event, index|
43
+ number = index + 1
44
+ write_event(number, event)
45
+ end
46
+ end
47
+
48
+ def runtime_in_seconds
49
+ runtime = @finished_at - @started_at
50
+ (runtime * 100).round / 100.0
51
+ end
52
+
53
+ def write_stats
54
+ puts "#{Peck.counter.ran} #{pluralize(Peck.counter.ran, 'spec')}, #{Peck.counter.failed} #{pluralize(Peck.counter.failed, 'failure')}, finished in #{runtime_in_seconds} seconds."
55
+ end
56
+
57
+ def write
58
+ puts if Peck.counter.ran > 0
59
+ write_events
60
+ write_stats
61
+ end
62
+
63
+ def install_at_exit
64
+ at_exit { write }
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,85 @@
1
+ class Peck
2
+ class Context
3
+ def self.it(description, &block)
4
+ return unless Peck.spec_selector.match(label)
5
+ specification = Specification.new(self, @before, @after, description, &block)
6
+ @specs << specification
7
+ specification
8
+ end
9
+
10
+ def self.pending(description)
11
+ return unless Peck.spec_selector.match(label)
12
+ delegates.received_pending(description)
13
+ end
14
+ end
15
+
16
+ class Event
17
+ attr_accessor :exception, :spec
18
+
19
+ def initialize(exception, spec)
20
+ @exception = exception
21
+ @spec = spec
22
+ end
23
+ end
24
+
25
+ class Specification
26
+ attr_reader :description, :context
27
+ attr_reader :expectations, :events
28
+
29
+ def initialize(context, before, after, description, &block)
30
+ @context = context.new(self)
31
+ @before = before.dup
32
+ @after = after.dup
33
+ @description = description
34
+ @block = block
35
+
36
+ @expectations = []
37
+ @events = []
38
+ end
39
+
40
+ def label
41
+ "#{@context.class.label} #{@description}"
42
+ end
43
+
44
+ def synchronized(&block)
45
+ if semaphore = Thread.current['peck-semaphore']
46
+ semaphore.synchronize(&block)
47
+ else
48
+ block.call
49
+ end
50
+ end
51
+
52
+ def run
53
+ if @block
54
+ @before.each { |cb| @context.instance_eval(&cb) }
55
+ begin
56
+ synchronized do
57
+ Thread.current['peck-spec'] = self
58
+ @context.instance_eval(&@block)
59
+ Thread.current['peck-spec'] = nil
60
+ end
61
+ Peck.delegates.received_missing(self) if empty?
62
+ ensure
63
+ @after.each { |cb| @context.instance_eval(&cb) }
64
+ end
65
+ else
66
+ Peck.delegates.received_missing(self)
67
+ end
68
+ rescue Object => e
69
+ Peck.delegates.received_exception(self, e)
70
+ @events << Event.new(e, self)
71
+ end
72
+
73
+ def empty?
74
+ @expectations.empty?
75
+ end
76
+
77
+ def failed?
78
+ !@events.empty?
79
+ end
80
+
81
+ def passed?
82
+ !failed? && !empty?
83
+ end
84
+ end
85
+ end
data/lib/peck.rb ADDED
@@ -0,0 +1,124 @@
1
+ class Peck
2
+ VERSION = "0.1.0"
3
+
4
+ class << self
5
+ # Returns all the defined contexts.
6
+ attr_reader :contexts
7
+
8
+ # Used to select which contexts should be run. The match method will be
9
+ # called on these with the label of the context as argument. You can use
10
+ # a regular expression or a custom class to match what needs to be run.
11
+ #
12
+ # module ContextMatcher
13
+ # def self.match(label)
14
+ # label =~ /^Birds/
15
+ # end
16
+ # end
17
+ # Peck.context_selector = ContextMatcher
18
+ attr_accessor :context_selector
19
+
20
+ # Used to select which specs should be run. See Peck.select_context
21
+ # for more information.
22
+ attr_accessor :spec_selector
23
+
24
+ # Sets the level of concurrency.
25
+ attr_accessor :concurrency
26
+ end
27
+
28
+ # A no-op unless you require 'peck/debug'
29
+ def self.log(message)
30
+ end
31
+
32
+ # Returns true if the suite should run concurrent.
33
+ def self.concurrent?
34
+ concurrency && concurrency > 1
35
+ end
36
+
37
+ def self.reset!
38
+ @contexts = []
39
+ end
40
+
41
+ @context_selector = //
42
+ @spec_selector = //
43
+
44
+ reset!
45
+
46
+ def self.all_specs
47
+ contexts.inject([]) do |all, context|
48
+ all.concat(context.specs)
49
+ end
50
+ end
51
+
52
+ def self.all_events
53
+ contexts.inject([]) do |all, context|
54
+ context.specs.inject(all) do |events, spec|
55
+ events.concat(spec.events)
56
+ end
57
+ end
58
+ end
59
+
60
+ def self.run
61
+ delegates.started
62
+ concurrent? ? run_concurrent : run_serial
63
+ delegates.finished
64
+ end
65
+
66
+ def self.run_at_exit
67
+ at_exit do
68
+ run
69
+ exit Peck.counter.failed
70
+ end
71
+ end
72
+
73
+ def self.run_serial
74
+ Peck.log("Running specs in serial")
75
+ Thread.current['peck-semaphore'] = Mutex.new
76
+ contexts.each do |context|
77
+ context.specs.each do |specification|
78
+ delegates.started_specification(specification)
79
+ specification.run
80
+ delegates.finished_specification(specification)
81
+ end
82
+ end
83
+ rescue Exception => e
84
+ log("An error bubbled up from the context, this should never happen and is possibly a bug.")
85
+ raise e
86
+ end
87
+
88
+ def self.run_concurrent
89
+ Peck.log("Running specs concurrently")
90
+ current_spec = -1
91
+ specs = all_specs
92
+ threaded do |nr|
93
+ Thread.current['peck-semaphore'] = Mutex.new
94
+ loop do
95
+ spec_index = Thread.exclusive { current_spec += 1 }
96
+ if specification = specs[spec_index]
97
+ delegates.started_specification(specification)
98
+ specification.run
99
+ delegates.finished_specification(specification)
100
+ else
101
+ break
102
+ end
103
+ end
104
+ end
105
+
106
+ delegates.finished
107
+ end
108
+
109
+ def self.threaded
110
+ threads = []
111
+ Peck.concurrency.times do |nr|
112
+ threads[nr] = Thread.new do
113
+ yield nr
114
+ end
115
+ end
116
+
117
+ threads.compact.each do |thread|
118
+ begin
119
+ thread.join
120
+ rescue Interrupt
121
+ end
122
+ end
123
+ end
124
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: peck
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Manfred Stienstra
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-26 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! ' Concurrent spec framework.
15
+
16
+ '
17
+ email: manfred@fngtps.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files:
21
+ - COPYING
22
+ files:
23
+ - lib/peck/context.rb
24
+ - lib/peck/counter.rb
25
+ - lib/peck/debug.rb
26
+ - lib/peck/delegates.rb
27
+ - lib/peck/error.rb
28
+ - lib/peck/expectations.rb
29
+ - lib/peck/flavors/quiet.rb
30
+ - lib/peck/flavors/vanilla.rb
31
+ - lib/peck/notifiers/base.rb
32
+ - lib/peck/notifiers/default.rb
33
+ - lib/peck/specification.rb
34
+ - lib/peck.rb
35
+ - COPYING
36
+ - README.md
37
+ homepage:
38
+ licenses: []
39
+ post_install_message:
40
+ rdoc_options:
41
+ - --charset=utf-8
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 1.8.11
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: Peck is a concurrent spec framework which inherits a lot from the fabulous
62
+ Bacon and MacBacon. We call it a framework because it was designed to be used in
63
+ parts and is easily extended.
64
+ test_files: []