qspec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in qspec.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 tomykaira
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,69 @@
1
+ # Qspec
2
+
3
+ Qspec makes rspec test fast. Q is for **queue** and **quick**.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'qspec'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install qspec
18
+
19
+ ## Additional Installation
20
+
21
+ You can use `spork` to cut the overhead of Qspec startup.
22
+ **Use 1.0**. Old `spork` does not detect Qspec.
23
+
24
+ ```ruby
25
+ gem 'spork', '~> 1.0rc'
26
+ ```
27
+
28
+ If you are on rails, remember to add `spork-rails` too.
29
+
30
+ By default, qspec uses file based inter-process communication.
31
+ This is poorly implemented and becomes a burden.
32
+
33
+ We recommend to use `redis`.
34
+
35
+ - Setting up redis-server with default port
36
+ - Add `redis` gem to your Gemfile
37
+ - Specify `redis` for IPC method in `.qspec.yml`
38
+
39
+ ## Usage
40
+
41
+ Installing this gem adds `qspec` and `qspec-helper` commands.
42
+
43
+ ### Setup
44
+
45
+ ```sh
46
+ $ bundle exec qspec-helper init
47
+ # edit .qspec.yml
48
+ ```
49
+
50
+ ### Run spec
51
+
52
+ ```sh
53
+ bundle exec qspec spec/
54
+ ```
55
+
56
+ ### Run with spork
57
+
58
+ ```sh
59
+ bundle exec qspec-helper spork
60
+ bundle exec qspec spec/
61
+ ```
62
+
63
+ ## Contributing
64
+
65
+ 1. Fork it
66
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
67
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
68
+ 4. Push to the branch (`git push origin my-new-feature`)
69
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'qspec'
4
+ status = Qspec::CommandLine.new(ARGV).run($stderr, $stdout).to_i
5
+ exit status
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'qspec'
4
+ Qspec::Helper.new(ARGV).serve
@@ -0,0 +1,19 @@
1
+ require 'rspec/core'
2
+ require 'qspec/version'
3
+ require 'qspec/ipc'
4
+ require 'qspec/manager'
5
+ require 'qspec/spork_helper'
6
+ require 'qspec/command_line'
7
+ require 'qspec/formatters/redis_formatter'
8
+ require 'qspec/config'
9
+ require 'qspec/helper'
10
+
11
+ module Qspec
12
+ DIRECTORY = File.expand_path('tmp/qspec')
13
+
14
+ FileUtils.mkdir_p(DIRECTORY) unless FileTest.exists?(DIRECTORY)
15
+
16
+ def self.path(filename)
17
+ File.join(DIRECTORY, filename)
18
+ end
19
+ end
@@ -0,0 +1,54 @@
1
+ require 'rspec/core/command_line'
2
+
3
+ module Qspec
4
+ class CommandLine < ::RSpec::Core::CommandLine
5
+ include Manager # defines start_worker
6
+ include SporkHelper
7
+ attr_reader :output, :ipc, :config, :id
8
+
9
+ def initialize(options)
10
+ @config = Config.new()
11
+ @ipc = IPC.from_config(@config['ipc'])
12
+ @id = ENV['qspec_id']
13
+
14
+ super(options)
15
+ end
16
+
17
+ def run(err, out)
18
+ @configuration.error_stream = err
19
+ @output = @configuration.output_stream ||= out
20
+ @options.configure(@configuration)
21
+
22
+ if @id
23
+ process
24
+ else
25
+ start_worker
26
+ end
27
+ end
28
+
29
+ def process
30
+ success = true
31
+ while f = ipc.lpop("to_run_#{id}")
32
+ @configuration.add_formatter(Qspec::Formatters::RedisFormatterFactory.build(id, f))
33
+ begin
34
+ load File.expand_path(f)
35
+ @configuration.reporter.report(@world.example_count, @configuration.randomize? ? @configuration.seed : nil) do |reporter|
36
+ begin
37
+ GC.disable if @config['no_gc']
38
+ @configuration.run_hook(:before, :suite)
39
+ success &&= @world.example_groups.ordered.all? {|g| g.run(reporter)}
40
+ ensure
41
+ @configuration.run_hook(:after, :suite)
42
+ GC.enable if @config['no_gc']
43
+ GC.start if @config['no_gc']
44
+ end
45
+ end
46
+ ensure
47
+ @world.example_groups.clear
48
+ @configuration.reset # formatter, reporter
49
+ end
50
+ end
51
+ success ? 0 : @configuration.failure_exit_code
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,40 @@
1
+ require 'yaml'
2
+
3
+ module Qspec
4
+ class Config
5
+ DEFAULT_PATH = '.qspec.yml'
6
+
7
+ def initialize(path = DEFAULT_PATH)
8
+ @path = path
9
+ if File.exists?(path)
10
+ @config = YAML.load_file(path)
11
+ else
12
+ STDERR.puts "You do not have #{path}. Initialize with `qspec-helper init`"
13
+ exit 1
14
+ end
15
+ end
16
+
17
+ def [](key)
18
+ @config[key]
19
+ end
20
+
21
+ def self.create_template(path = DEFAULT_PATH)
22
+ if File.exists?(path)
23
+ STDERR.puts "You already have a template file #{path}. Remove it if you want to reset."
24
+ exit 1
25
+ end
26
+ File.open(path, 'w') do |f|
27
+ f.write <<TMPL
28
+ # DO NOT check this file into VCS (e.g. git).
29
+ # Parallelization setting differs between machines.
30
+ no_gc: false
31
+ ipc: file # 'file' or 'redis', if 'redis', gem and server are required
32
+ sort_by: time # 'time' or 'size', if 'time', store execution time and use it next time
33
+ workers: 4 # half of cpu - number of cpu
34
+ spork_port: 9240 # specified port..port+N-1 are used
35
+ TMPL
36
+ end
37
+ puts "Config file created in #{path}. Check it before run `qspec spec`."
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ require 'rspec/core/formatters/base_formatter'
2
+
3
+ module Qspec
4
+ module Formatters
5
+ module RedisFormatterFactory
6
+ def self.build(id, file)
7
+ Class.new(RSpec::Core::Formatters::BaseFormatter) do
8
+ @@id = id
9
+ @@file = file
10
+ include RedisFormatterFactory
11
+ end
12
+ end
13
+
14
+ def initialize(output)
15
+ @ipc = IPC.default
16
+ super
17
+ end
18
+
19
+ def dump_failures
20
+ failed_examples.each do |example|
21
+ ex = example.execution_result[:exception]
22
+ data = {
23
+ description: example.full_description,
24
+ exception: format_exception(example, ex),
25
+ backtrace: format_backtrace(ex.backtrace, example)
26
+ }
27
+ @ipc.rpush("failure_#{@@id}", Marshal.dump(data))
28
+ end
29
+ end
30
+
31
+ def dump_summary(duration, example_count, failure_count, pending_count)
32
+ data = [@@file, duration, example_count, failure_count, pending_count]
33
+ @ipc.rpush("stat_#{@@id}", Marshal.dump(data))
34
+ end
35
+
36
+ def format_exception(example, ex)
37
+ exception_class_name = ex.class.to_s
38
+ output = StringIO.new
39
+ output.puts "* #{example.full_description}"
40
+ output.puts "\tFailure/Error: #{read_failed_line(ex, example)}"
41
+ output.puts "\t#{exception_class_name}:" unless exception_class_name =~ /RSpec/
42
+ ex.message.to_s.split("\n").each { |line| output.puts "\t #{line}" } if ex.message
43
+ output.string
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ module Qspec
2
+ class Helper
3
+ include SporkHelper
4
+
5
+ def initialize(argv)
6
+ @argv = argv
7
+ end
8
+
9
+ def serve
10
+ case @argv.last
11
+ when 'init'
12
+ puts "Creating template"
13
+ Config.create_template
14
+ when 'spork'
15
+ @config = Config.new
16
+ puts "Start #{@config['workers']} sporks"
17
+ start_spork_workers(@config['workers'])
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ module Qspec
2
+ # abstract
3
+ class IPC
4
+ def self.from_config(name)
5
+ @@default =
6
+ case name
7
+ when 'redis'
8
+ require 'qspec/ipc/redis'
9
+ IPC::Redis.new
10
+ when 'file', nil
11
+ require 'qspec/ipc/file'
12
+ IPC::File.new
13
+ else
14
+ raise "Unknown IPC method #{name}"
15
+ end
16
+ end
17
+
18
+ def self.default
19
+ @@default || (raise 'Default IPC module not set')
20
+ end
21
+
22
+ def del(key)
23
+ end
24
+
25
+ def lpop(key)
26
+ end
27
+
28
+ def rpush(key, value)
29
+ end
30
+
31
+ def llen(key)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,62 @@
1
+ require 'fileutils'
2
+
3
+ module Qspec
4
+ class IPC
5
+ class File < IPC
6
+ DIRECTORY = 'tmp/qspec'
7
+
8
+ def initialize
9
+ FileUtils.mkdir_p(DIRECTORY) unless FileTest.exists?(DIRECTORY)
10
+ end
11
+
12
+ def del(key)
13
+ ::File.unlink(Qspec.path(key)) rescue nil
14
+ end
15
+
16
+ def lpop(key)
17
+ open(key, :rw) do |f|
18
+ list = safe_load(f)
19
+ f.truncate(0)
20
+ f.rewind
21
+ data = list.shift
22
+ f.write(Marshal.dump(list))
23
+ data
24
+ end
25
+ end
26
+
27
+ def rpush(key, value)
28
+ open(key, :rw) do |f|
29
+ list = safe_load(f)
30
+ f.truncate(0)
31
+ f.rewind
32
+ list.push(value)
33
+ f.write(Marshal.dump(list))
34
+ end
35
+ end
36
+
37
+ def llen(key)
38
+ open(key, :r) do |f|
39
+ safe_load(f).length
40
+ end
41
+ end
42
+
43
+ private
44
+ def open(key, type)
45
+ mode, lock = case type
46
+ when :rw then [::File::RDWR|::File::CREAT|::File::BINARY, ::File::LOCK_EX]
47
+ when :r then [::File::RDONLY|::File::CREAT|::File::BINARY, ::File::LOCK_SH]
48
+ end
49
+ ::File.open(Qspec.path(key), mode) do |f|
50
+ f.flock(lock)
51
+ f.set_encoding('ASCII-8BIT')
52
+ yield(f)
53
+ end
54
+ end
55
+
56
+ def safe_load(f)
57
+ data = f.read
58
+ data.strip == '' ? [] : Marshal.load(data)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,16 @@
1
+ require 'redis'
2
+ module Qspec
3
+ class IPC
4
+ class Redis < IPC
5
+ def initialize
6
+ @redis = ::Redis.new
7
+ end
8
+
9
+ [:del, :lpop, :rpush, :llen].each do |method|
10
+ define_method(method) do |*args|
11
+ @redis.send(method, *args)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,131 @@
1
+ require 'rspec/core/formatters/helpers'
2
+
3
+ module Qspec
4
+ module Manager
5
+ TIME_LOG_NAME = 'elapsed_time'
6
+ DEFAULT_ELAPSED_TIME = 3.0
7
+ attr_reader :output
8
+ attr_reader :id
9
+
10
+ def start_worker
11
+ @id = rand(10000)
12
+ output.puts "ID: #{id}"
13
+ register_files(id)
14
+ if runnning_ports
15
+ puts "Connecting to spork: #{runnning_ports.inspect}"
16
+ runnning_ports.each do |port|
17
+ fork do
18
+ connect_spork(port, id, @configuration.error_stream, output)
19
+ end
20
+ end
21
+ else
22
+ puts "Forking #{@config['workers']} workers"
23
+ command = "qspec #{@options.drb_argv.join " "}"
24
+ @config['workers'].times do |i|
25
+ env = {
26
+ "qspec_id" => id.to_s,
27
+ "TEST_ENV_NUMBER" => i == 0 ? '' : (i + 1).to_s }
28
+ spawn(env,
29
+ command,
30
+ out: '/dev/null')
31
+ end
32
+ end
33
+
34
+ @stats = []
35
+ thread = start_progress_thread(id)
36
+ success = Process.waitall.all? { |pid, status| status.exitstatus == 0 }
37
+ thread.exit
38
+
39
+ pop_stat(id)
40
+
41
+ output.puts "Failures: " if ipc.llen("failure_#{id}") > 0
42
+
43
+ each_object("failure_#{id}") do |failure|
44
+ dump_failure(failure)
45
+ end
46
+
47
+ log_elapsed_times
48
+ dump_summary
49
+ exit(success ? 0 : 1)
50
+ ensure
51
+ if ipc
52
+ ipc.del("to_run_#{id}")
53
+ ipc.del("stat_#{id}")
54
+ ipc.del("failure_#{id}")
55
+ end
56
+ end
57
+
58
+ private
59
+ def start_progress_thread(id)
60
+ Thread.new do
61
+ loop do
62
+ pop_stat(id)
63
+ sleep 1
64
+ end
65
+ end
66
+ end
67
+
68
+ def pop_stat(id)
69
+ each_object("stat_#{id}") do |obj|
70
+ @stats << obj
71
+ output.print "!!! " if obj[3] > 0
72
+ output.puts obj.inspect
73
+ end
74
+ end
75
+
76
+ def each_object(key)
77
+ while data = ipc.lpop(key)
78
+ yield(Marshal.load(data))
79
+ end
80
+ end
81
+
82
+ def dump_summary
83
+ sum = @stats.each_with_object({ example: 0, failure: 0, pending: 0 }) do |stat, sum|
84
+ sum[:example] += stat[2]
85
+ sum[:failure] += stat[3]
86
+ sum[:pending] += stat[4]
87
+ end
88
+ output.puts "\n#{sum[:example]} examples, #{sum[:failure]} failures, #{sum[:pending]} pendings"
89
+ end
90
+
91
+ def dump_failure(failure)
92
+ puts ""
93
+ puts failure[:exception]
94
+ failure[:backtrace].each do |line|
95
+ output.puts "\t#{line}"
96
+ end
97
+ end
98
+
99
+ def log_elapsed_times
100
+ File.open(Qspec.path(TIME_LOG_NAME), 'w') do |f|
101
+ @stats.each do |stat|
102
+ f.puts "#{File.expand_path(stat[0])}:#{stat[1].to_f}"
103
+ end
104
+ end
105
+ end
106
+
107
+ def register_files(id)
108
+ sorted_files_to_run.uniq.each do |f|
109
+ ipc.rpush "to_run_#{id}", f
110
+ end
111
+ end
112
+
113
+ def sorted_files_to_run
114
+ @sorted_files_to_run ||= if @config['sort_by'] == 'time' && File.exists?(Qspec.path(TIME_LOG_NAME))
115
+ sort_by_time(@configuration.files_to_run)
116
+ else
117
+ sort_by_size(@configuration.files_to_run)
118
+ end
119
+ end
120
+
121
+ def sort_by_time(files)
122
+ log = Hash[File.readlines(Qspec.path(TIME_LOG_NAME)).map { |line| line.strip.split(":") }]
123
+ files.sort_by { |file| log[File.expand_path(file)].to_f || DEFAULT_ELAPSED_TIME }.reverse
124
+ end
125
+
126
+ # large to small
127
+ def sort_by_size(files)
128
+ files.sort_by { |file| -File.stat(file).size }
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,65 @@
1
+ # spork is optional
2
+ begin
3
+ require 'drb/drb'
4
+ require 'spork/test_framework/qspec'
5
+ rescue LoadError
6
+ end
7
+
8
+ require 'rspec/core/drb_options'
9
+
10
+ module Qspec
11
+ module SporkHelper
12
+ def start_spork_workers(count)
13
+ Signal.trap(:INT){
14
+ puts "Stop spork processes"
15
+ remove_port_file
16
+ exit(0)
17
+ }
18
+
19
+ default_port = (@config['spork_port'] || ::Spork::TestFramework::Qspec::DEFAULT_PORT).to_i
20
+ ports = []
21
+ count.times do |i|
22
+ port = default_port+i
23
+ spawn({ "TEST_ENV_NUMBER" => i == 0 ? '' : (i + 1).to_s },
24
+ "spork qspec --port #{port}")
25
+ ports << port
26
+ end
27
+ create_port_file(ports)
28
+ Process.waitall.all? { |pid, status| status.exitstatus == 0 } ? 0 : 1
29
+ end
30
+
31
+ def connect_spork(port, id, err, out)
32
+ begin
33
+ DRb.start_service("druby://localhost:0")
34
+ rescue SocketError, Errno::EADDRNOTAVAIL
35
+ DRb.start_service("druby://:0")
36
+ end
37
+ spec_server = DRbObject.new_with_uri("druby://127.0.0.1:#{port||PORT}")
38
+ exit spec_server.run(@options.drb_argv + [id], err, out).to_i
39
+ end
40
+
41
+ def create_port_file(ports)
42
+ File.open(port_file, 'w') do |f|
43
+ f.puts ports.join("\n")
44
+ end
45
+ end
46
+
47
+ def runnning_ports
48
+ @runnning_ports ||= begin
49
+ ports = File.readlines(port_file).map { |line| line.strip.to_i }
50
+ ports.empty? ? nil : ports
51
+ rescue Errno::ENOENT
52
+ nil
53
+ end
54
+ end
55
+
56
+ def remove_port_file
57
+ File.unlink(port_file)
58
+ end
59
+
60
+ private
61
+ def port_file
62
+ @port_file ||= Qspec.path('spork_ports')
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module Qspec
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,11 @@
1
+ require 'spork'
2
+ class Spork::TestFramework::Qspec < Spork::TestFramework
3
+ DEFAULT_PORT = 9240
4
+ HELPER_FILE = File.join(Dir.pwd, "spec/spec_helper.rb")
5
+
6
+ def run_tests(argv, stderr, stdout)
7
+ require 'qspec'
8
+ ENV['qspec_id'] = argv.pop.to_s
9
+ ::Qspec::CommandLine.new(argv).run(stderr, stdout)
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'qspec/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "qspec"
8
+ gem.version = Qspec::VERSION
9
+ gem.authors = ["tomykaira"]
10
+ gem.email = ["tomykaira@gmail.com"]
11
+ gem.description = %q{QSpec inserts spec files to a queue. Workers process that queue one by one.}
12
+ gem.summary = %q{QSpec is extension of RSpec. Q is for queue, and quick.}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.post_install_message = "Run qspec-helper init to create your config file"
21
+
22
+ gem.add_dependency 'rspec-core', '~>2.13.1'
23
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qspec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - tomykaira
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec-core
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.13.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.13.1
30
+ description: QSpec inserts spec files to a queue. Workers process that queue one
31
+ by one.
32
+ email:
33
+ - tomykaira@gmail.com
34
+ executables:
35
+ - qspec
36
+ - qspec-helper
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - .gitignore
41
+ - Gemfile
42
+ - LICENSE.txt
43
+ - README.md
44
+ - Rakefile
45
+ - bin/qspec
46
+ - bin/qspec-helper
47
+ - lib/qspec.rb
48
+ - lib/qspec/command_line.rb
49
+ - lib/qspec/config.rb
50
+ - lib/qspec/formatters/redis_formatter.rb
51
+ - lib/qspec/helper.rb
52
+ - lib/qspec/ipc.rb
53
+ - lib/qspec/ipc/file.rb
54
+ - lib/qspec/ipc/redis.rb
55
+ - lib/qspec/manager.rb
56
+ - lib/qspec/spork_helper.rb
57
+ - lib/qspec/version.rb
58
+ - lib/spork/test_framework/qspec.rb
59
+ - qspec.gemspec
60
+ homepage: ''
61
+ licenses: []
62
+ post_install_message: Run qspec-helper init to create your config file
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ segments:
73
+ - 0
74
+ hash: -177445891
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ segments:
82
+ - 0
83
+ hash: -177445891
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 1.8.23
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: QSpec is extension of RSpec. Q is for queue, and quick.
90
+ test_files: []