specifier 0.1.0 → 0.2.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 +4 -4
- data/README.md +22 -7
- data/lib/specifier.rb +12 -4
- data/lib/specifier/cli.rb +12 -0
- data/lib/specifier/colorizer.rb +26 -0
- data/lib/specifier/config.rb +13 -0
- data/lib/specifier/context.rb +58 -15
- data/lib/specifier/definition.rb +28 -0
- data/lib/specifier/example.rb +17 -10
- data/lib/specifier/expectation.rb +8 -0
- data/lib/specifier/formatter.rb +15 -0
- data/lib/specifier/formatter/base.rb +26 -8
- data/lib/specifier/formatter/documentation.rb +54 -0
- data/lib/specifier/formatter/progress.rb +24 -8
- data/lib/specifier/logger.rb +12 -0
- data/lib/specifier/memoizer.rb +17 -4
- data/lib/specifier/runner.rb +10 -0
- data/lib/specifier/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fcc4798a1f25e09eca4bafa1fcd12d394252cf41
|
4
|
+
data.tar.gz: 760454e29ac6570d2656d668373d526b3db51bfa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 944625dab26f7964579a42490722e1a1c02729172211feb3f5fbe6388925e99084faff054046b0a89848eb5b91f0e13fd5eee7f80713c871b9112b8e7b2e617e
|
7
|
+
data.tar.gz: 4d0810069845ecc67a544461c6518f06cff5d33ef86db94fa4359ee3c0d703d75374a5af33ac9b263c83fda2aca4f91659e376c24835392ba149603c13418a47
|
data/README.md
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
# Specifier
|
2
2
|
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
```bash
|
6
|
+
gem install specifier
|
7
|
+
```
|
8
|
+
|
3
9
|
## Example
|
4
10
|
|
5
11
|
```ruby
|
6
12
|
class Echo
|
7
|
-
def
|
13
|
+
def say(message)
|
8
14
|
message
|
9
15
|
end
|
10
16
|
end
|
@@ -12,13 +18,11 @@ end
|
|
12
18
|
|
13
19
|
```ruby
|
14
20
|
Specifier.specify Echo do
|
15
|
-
|
16
|
-
it 'says "Hello" if you say "Hello"' do
|
17
|
-
expect(Echo.say('Hello')).to equal('Hello')
|
18
|
-
end
|
21
|
+
let(:echo) { Echo.new }
|
19
22
|
|
20
|
-
|
21
|
-
|
23
|
+
describe '#say' do
|
24
|
+
it 'says "Hello" if you say "Hello"' do
|
25
|
+
expect(echo.say('Hello')).to equal('Hello')
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
@@ -29,3 +33,14 @@ end
|
|
29
33
|
```bash
|
30
34
|
bundle exec specifier ./specs
|
31
35
|
```
|
36
|
+
|
37
|
+
## Status
|
38
|
+
|
39
|
+
[](https://travis-ci.org/ksylvest/specifier)
|
40
|
+
[](https://gemnasium.com/ksylvest/specifier)
|
41
|
+
[](https://coveralls.io/r/ksylvest/specifier)
|
42
|
+
[](https://codeclimate.com/github/ksylvest/specifier)
|
43
|
+
|
44
|
+
## Copyright
|
45
|
+
|
46
|
+
Copyright (c) 2016 - 2017 Kevin Sylvestre. See LICENSE for details.
|
data/lib/specifier.rb
CHANGED
@@ -3,21 +3,29 @@ require 'slop'
|
|
3
3
|
|
4
4
|
require 'specifier/version'
|
5
5
|
require 'specifier/cli'
|
6
|
+
require 'specifier/colorizer'
|
6
7
|
require 'specifier/config'
|
7
8
|
require 'specifier/logger'
|
8
9
|
require 'specifier/runner'
|
9
10
|
require 'specifier/context'
|
11
|
+
require 'specifier/definition'
|
10
12
|
require 'specifier/example'
|
11
13
|
require 'specifier/expectation'
|
12
|
-
require 'specifier/memoizer'
|
13
14
|
require 'specifier/matcher'
|
15
|
+
require 'specifier/memoizer'
|
14
16
|
require 'specifier/formatter'
|
15
17
|
|
16
18
|
module Specifier
|
19
|
+
def self.contexts
|
20
|
+
@contexts ||= []
|
21
|
+
end
|
17
22
|
|
18
23
|
def self.specify(scope, &block)
|
19
|
-
|
20
|
-
|
24
|
+
contexts << Context.setup(scope, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.run
|
28
|
+
contexts.each(&:run)
|
21
29
|
end
|
22
30
|
|
23
31
|
def self.config
|
@@ -29,7 +37,7 @@ module Specifier
|
|
29
37
|
end
|
30
38
|
|
31
39
|
def self.formatter
|
32
|
-
@formatter ||= Formatter::
|
40
|
+
@formatter ||= Formatter.formatters[config.formatter || Specifier::Formatter::DEFAULT].new(logger)
|
33
41
|
end
|
34
42
|
|
35
43
|
end
|
data/lib/specifier/cli.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
module Specifier
|
2
|
+
|
3
|
+
# Used when interacting with the suite from the command line interface (CLI).
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# cli = Specifier::CLI.new
|
8
|
+
# cli.parse
|
9
|
+
#
|
2
10
|
class CLI
|
3
11
|
BANNER = 'usage: specifier [options] [./specs]'.freeze
|
4
12
|
|
@@ -13,6 +21,8 @@ module Specifier
|
|
13
21
|
options.on '-v', '--version', 'version' do
|
14
22
|
return version
|
15
23
|
end
|
24
|
+
|
25
|
+
options.string '-f', '--formatter', 'formatter', default: Specifier::Formatter::DEFAULT
|
16
26
|
end
|
17
27
|
|
18
28
|
run(config)
|
@@ -29,6 +39,8 @@ module Specifier
|
|
29
39
|
end
|
30
40
|
|
31
41
|
def run(options)
|
42
|
+
Specifier.config.formatter = options[:formatter]
|
43
|
+
|
32
44
|
paths = Set.new
|
33
45
|
options.arguments.each do |argument|
|
34
46
|
Find.find(argument) do |path|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Specifier
|
2
|
+
|
3
|
+
# Used to colorize messages for console output.
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# Specifier::Colorizer.muted("...")
|
8
|
+
# Specifier::Colorizer.passed("...")
|
9
|
+
# Specifier::Colorizer.failed("...")
|
10
|
+
#
|
11
|
+
module Colorizer
|
12
|
+
|
13
|
+
def self.muted(message)
|
14
|
+
"\e[37m#{message}\e[0m"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.failed(message)
|
18
|
+
"\e[31m#{message}\e[0m"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.passed(message)
|
22
|
+
"\e[32m#{message}\e[0m"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/specifier/config.rb
CHANGED
data/lib/specifier/context.rb
CHANGED
@@ -1,29 +1,72 @@
|
|
1
|
-
require 'byebug'
|
2
|
-
|
3
1
|
module Specifier
|
2
|
+
|
3
|
+
# Defines a context that can be deeply nested (evaluates from oldest to newest in ancestry).
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# let "..." do
|
8
|
+
# # ...
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# it "..." do
|
12
|
+
# # ...
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# describe "..." do
|
16
|
+
# end
|
17
|
+
#
|
4
18
|
class Context
|
5
19
|
attr_accessor :parent
|
20
|
+
attr_accessor :children
|
21
|
+
attr_accessor :description
|
6
22
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
|
23
|
+
def self.setup(description, parent = nil, &block)
|
24
|
+
context = Context.new(description, &block)
|
25
|
+
context.parent = parent
|
26
|
+
parent.children << context if parent
|
27
|
+
context.instance_eval(&block)
|
28
|
+
context
|
11
29
|
end
|
12
30
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
31
|
+
def initialize(description, &block)
|
32
|
+
@description = description
|
33
|
+
@block = block
|
34
|
+
@children = []
|
35
|
+
@examples = []
|
36
|
+
@definitions = []
|
17
37
|
end
|
18
38
|
|
19
|
-
def
|
20
|
-
|
39
|
+
def describe(description, &block)
|
40
|
+
self.class.setup(description, self, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def let(name, &block)
|
44
|
+
definition = Definition.new(name, &block)
|
45
|
+
@definitions << definition
|
46
|
+
definition
|
47
|
+
end
|
48
|
+
|
49
|
+
def it(description, &block)
|
50
|
+
example = Example.new(description, &block)
|
51
|
+
@examples << example
|
52
|
+
example
|
21
53
|
end
|
22
54
|
|
23
55
|
def run
|
24
|
-
|
25
|
-
|
26
|
-
|
56
|
+
Specifier.formatter.context(self) do
|
57
|
+
@examples.each do |example|
|
58
|
+
setup(example)
|
59
|
+
result = example.run
|
60
|
+
Specifier.formatter.record(example, result)
|
61
|
+
end
|
62
|
+
@children.each(&:run)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def setup(example)
|
67
|
+
parent&.setup(example)
|
68
|
+
@definitions.each do |definition|
|
69
|
+
definition.define(example)
|
27
70
|
end
|
28
71
|
end
|
29
72
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Specifier
|
2
|
+
|
3
|
+
# Configures a definition (used for let statements).
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# definition = Specifier::Definition.new("...") do
|
8
|
+
# # ...
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# definition.define(object)
|
12
|
+
#
|
13
|
+
class Definition
|
14
|
+
|
15
|
+
def initialize(name, &block)
|
16
|
+
@name = name
|
17
|
+
@memoizer = Memoizer.new(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def define(object)
|
21
|
+
memoizer = @memoizer
|
22
|
+
object.define_singleton_method(@name) do
|
23
|
+
memoizer.evaluate
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
data/lib/specifier/example.rb
CHANGED
@@ -1,17 +1,24 @@
|
|
1
1
|
module Specifier
|
2
|
+
|
3
|
+
# Configures an example (used for it statements).
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# example = Specifier::Example.new("...") do
|
8
|
+
# expect(value).to equal(value)
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# example.run
|
12
|
+
#
|
2
13
|
class Example
|
3
14
|
Result = Struct.new(:status, :message)
|
4
15
|
|
5
|
-
|
6
|
-
@_descriptor = descriptor
|
7
|
-
@_block = block
|
8
|
-
end
|
16
|
+
attr_accessor :description
|
9
17
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# end
|
18
|
+
def initialize(description, &block)
|
19
|
+
@description = description
|
20
|
+
@block = block
|
21
|
+
end
|
15
22
|
|
16
23
|
def expect(value)
|
17
24
|
Expectation.new(value)
|
@@ -22,7 +29,7 @@ module Specifier
|
|
22
29
|
end
|
23
30
|
|
24
31
|
def run
|
25
|
-
instance_eval(&@
|
32
|
+
instance_eval(&@block)
|
26
33
|
return Result.new(:pass)
|
27
34
|
rescue Specifier::Expectation::Miss => miss
|
28
35
|
return Result.new(:fail, miss.message)
|
@@ -1,4 +1,12 @@
|
|
1
1
|
module Specifier
|
2
|
+
|
3
|
+
# Configures an expectation (used for expect statements).
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# expectation = Specifier::Expectation.new("today")
|
8
|
+
# expectation.to(matcher) # 'raises 'Miss'
|
9
|
+
#
|
2
10
|
class Expectation
|
3
11
|
class Miss < StandardError
|
4
12
|
def initialize(message)
|
data/lib/specifier/formatter.rb
CHANGED
@@ -1,2 +1,17 @@
|
|
1
|
+
module Specifier
|
2
|
+
module Formatter
|
3
|
+
def self.formatters
|
4
|
+
@formatters ||= {}
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
1
9
|
require 'specifier/formatter/base'
|
10
|
+
require 'specifier/formatter/documentation'
|
2
11
|
require 'specifier/formatter/progress'
|
12
|
+
|
13
|
+
module Specifier
|
14
|
+
module Formatter
|
15
|
+
DEFAULT = Progress::NAME
|
16
|
+
end
|
17
|
+
end
|
@@ -1,5 +1,14 @@
|
|
1
1
|
module Specifier
|
2
2
|
module Formatter
|
3
|
+
|
4
|
+
# A base defintion for formatting the specifier results.
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# formatter = Specifier::Formatter::Base.new
|
9
|
+
# formatter.record(example, result)
|
10
|
+
# formatter.summarize
|
11
|
+
#
|
3
12
|
class Base
|
4
13
|
Recording = Struct.new(:example, :result) do
|
5
14
|
def status
|
@@ -18,12 +27,25 @@ module Specifier
|
|
18
27
|
def initialize(logger)
|
19
28
|
@logger = logger
|
20
29
|
@recordings = []
|
30
|
+
@contexts = []
|
21
31
|
end
|
22
32
|
|
23
33
|
def record(example, result)
|
24
34
|
@recordings << Recording.new(example, result)
|
25
35
|
end
|
26
36
|
|
37
|
+
def context(context)
|
38
|
+
@contexts << context
|
39
|
+
yield
|
40
|
+
end
|
41
|
+
|
42
|
+
def summarize
|
43
|
+
@logger.log
|
44
|
+
@logger.log(summary)
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
27
49
|
def passed
|
28
50
|
@recordings.select(&:pass?)
|
29
51
|
end
|
@@ -32,18 +54,14 @@ module Specifier
|
|
32
54
|
@recordings.select(&:fail?)
|
33
55
|
end
|
34
56
|
|
35
|
-
def summarize
|
36
|
-
@logger.log
|
37
|
-
@logger.log(summary)
|
38
|
-
end
|
39
|
-
|
40
57
|
def summary
|
41
58
|
<<~SUMMARY
|
42
|
-
Total: #{@recordings.count}
|
43
|
-
Passed: #{passed.count}
|
44
|
-
Failed: #{failed.count}
|
59
|
+
Total: #{Colorizer.muted(@recordings.count)}
|
60
|
+
Passed: #{Colorizer.passed(passed.count)}
|
61
|
+
Failed: #{Colorizer.failed(failed.count)}
|
45
62
|
SUMMARY
|
46
63
|
end
|
47
64
|
end
|
65
|
+
|
48
66
|
end
|
49
67
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Specifier
|
2
|
+
module Formatter
|
3
|
+
|
4
|
+
# A custom defintion for formatting the specifier results.
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# formatter = Specifier::Formatter::Documentation.new
|
9
|
+
# formatter.context(context) do
|
10
|
+
# formatter.record(example, result)
|
11
|
+
# end
|
12
|
+
# formatter.summarize
|
13
|
+
#
|
14
|
+
class Documentation < Base
|
15
|
+
INDENTATION = ' '.freeze
|
16
|
+
NAME = 'documentation'.freeze
|
17
|
+
|
18
|
+
Formatter.formatters[NAME] = self
|
19
|
+
|
20
|
+
def initialize(logger)
|
21
|
+
super
|
22
|
+
@indentation = 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def record(example, result)
|
26
|
+
super
|
27
|
+
|
28
|
+
message =
|
29
|
+
case result.status
|
30
|
+
when :pass then Colorizer.passed(indent(example.description))
|
31
|
+
when :fail then Colorizer.failed(indent(example.description))
|
32
|
+
end
|
33
|
+
|
34
|
+
@logger.log(message)
|
35
|
+
end
|
36
|
+
|
37
|
+
def context(context)
|
38
|
+
@logger.log(indent(context.description))
|
39
|
+
|
40
|
+
@indentation = @indentation.next
|
41
|
+
super
|
42
|
+
@indentation = @indentation.pred
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def indent(message)
|
48
|
+
INDENTATION * @indentation + String(message)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -1,20 +1,36 @@
|
|
1
1
|
module Specifier
|
2
2
|
module Formatter
|
3
|
+
|
4
|
+
# A custom defintion for formatting the specifier results.
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# formatter = Specifier::Formatter::Progress.new
|
9
|
+
# formatter.context(context) do
|
10
|
+
# formatter.record(example, result)
|
11
|
+
# end
|
12
|
+
# formatter.summarize
|
13
|
+
#
|
3
14
|
class Progress < Base
|
15
|
+
NAME = 'progress'.freeze
|
16
|
+
PASS = '+'.freeze
|
17
|
+
FAIL = '-'.freeze
|
18
|
+
|
19
|
+
Formatter.formatters[NAME] = self
|
20
|
+
|
4
21
|
def record(example, result)
|
5
22
|
super
|
6
|
-
@logger << symbol(result)
|
7
|
-
end
|
8
23
|
|
9
|
-
|
24
|
+
message =
|
25
|
+
case result.status
|
26
|
+
when :pass then Specifier::Colorizer.passed(PASS)
|
27
|
+
when :fail then Specifier::Colorizer.failed(FAIL)
|
28
|
+
end
|
10
29
|
|
11
|
-
|
12
|
-
case result.status
|
13
|
-
when :pass then '+'
|
14
|
-
when :fail then '-'
|
15
|
-
end
|
30
|
+
@logger << message
|
16
31
|
end
|
17
32
|
|
18
33
|
end
|
34
|
+
|
19
35
|
end
|
20
36
|
end
|
data/lib/specifier/logger.rb
CHANGED
@@ -7,6 +7,18 @@ module Specifier
|
|
7
7
|
# Specifier.logger.log("...")
|
8
8
|
#
|
9
9
|
class Logger
|
10
|
+
module Color
|
11
|
+
BLACK = 0
|
12
|
+
RED = 1
|
13
|
+
GREEN = 2
|
14
|
+
YELLOW = 3
|
15
|
+
end
|
16
|
+
|
17
|
+
module Formatting
|
18
|
+
DEFAULT = 0
|
19
|
+
BOLD = 1
|
20
|
+
ITALIC = 3
|
21
|
+
end
|
10
22
|
|
11
23
|
def initialize(stream = STDOUT)
|
12
24
|
@stream = stream
|
data/lib/specifier/memoizer.rb
CHANGED
@@ -1,11 +1,24 @@
|
|
1
1
|
module Specifier
|
2
|
+
|
3
|
+
# It remembers things (used for within let statements).
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# memoizer = Specifier::Memoizer.new do
|
8
|
+
# # ...
|
9
|
+
# end
|
10
|
+
# memoizer.evaluate
|
11
|
+
#
|
2
12
|
class Memoizer
|
3
|
-
|
4
|
-
|
13
|
+
|
14
|
+
def initialize(&block)
|
15
|
+
@block = block
|
5
16
|
end
|
6
17
|
|
7
|
-
def
|
8
|
-
@
|
18
|
+
def evaluate
|
19
|
+
return @result if defined?(@result)
|
20
|
+
@result = @block.call
|
9
21
|
end
|
22
|
+
|
10
23
|
end
|
11
24
|
end
|
data/lib/specifier/runner.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
module Specifier
|
2
|
+
|
3
|
+
# Handles load and execution of specs.
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# runner = Specifier::Runner.new(paths: "./spec")
|
8
|
+
# runner.run
|
9
|
+
#
|
2
10
|
class Runner
|
3
11
|
def initialize(paths:)
|
4
12
|
@paths = paths
|
@@ -8,6 +16,8 @@ module Specifier
|
|
8
16
|
@paths.each do |path|
|
9
17
|
load path
|
10
18
|
end
|
19
|
+
|
20
|
+
Specifier.run
|
11
21
|
Specifier.formatter.summarize
|
12
22
|
end
|
13
23
|
end
|
data/lib/specifier/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: specifier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Sylvestre
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: slop
|
@@ -108,12 +108,15 @@ files:
|
|
108
108
|
- bin/specifier
|
109
109
|
- lib/specifier.rb
|
110
110
|
- lib/specifier/cli.rb
|
111
|
+
- lib/specifier/colorizer.rb
|
111
112
|
- lib/specifier/config.rb
|
112
113
|
- lib/specifier/context.rb
|
114
|
+
- lib/specifier/definition.rb
|
113
115
|
- lib/specifier/example.rb
|
114
116
|
- lib/specifier/expectation.rb
|
115
117
|
- lib/specifier/formatter.rb
|
116
118
|
- lib/specifier/formatter/base.rb
|
119
|
+
- lib/specifier/formatter/documentation.rb
|
117
120
|
- lib/specifier/formatter/progress.rb
|
118
121
|
- lib/specifier/logger.rb
|
119
122
|
- lib/specifier/matcher.rb
|