spectus 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +14 -0
  4. data/.travis.yml +6 -0
  5. data/.yardopts +1 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE.md +22 -0
  8. data/README.md +239 -0
  9. data/Rakefile +18 -0
  10. data/VERSION.semver +1 -0
  11. data/lib/spectus.rb +6 -0
  12. data/lib/spectus/dsl.rb +14 -0
  13. data/lib/spectus/expectation_target.rb +27 -0
  14. data/lib/spectus/matcher.rb +35 -0
  15. data/lib/spectus/matcher/capture_stderr.rb +31 -0
  16. data/lib/spectus/matcher/capture_stdout.rb +31 -0
  17. data/lib/spectus/matcher/eql.rb +21 -0
  18. data/lib/spectus/matcher/equal.rb +21 -0
  19. data/lib/spectus/matcher/match.rb +21 -0
  20. data/lib/spectus/matcher/raise_exception.rb +27 -0
  21. data/lib/spectus/reporter.rb +45 -0
  22. data/lib/spectus/version.rb +9 -0
  23. data/spectus.gemspec +20 -0
  24. data/test/helper_test.rb +4 -0
  25. data/test/spectus/helper_test.rb +1 -0
  26. data/test/spectus/matcher/built_in/helper_test.rb +1 -0
  27. data/test/spectus/matcher/built_in/test_capture_stderr.rb +21 -0
  28. data/test/spectus/matcher/built_in/test_capture_stdout.rb +21 -0
  29. data/test/spectus/matcher/built_in/test_eql.rb +21 -0
  30. data/test/spectus/matcher/built_in/test_equal.rb +21 -0
  31. data/test/spectus/matcher/built_in/test_match.rb +21 -0
  32. data/test/spectus/matcher/built_in/test_raise_exception.rb +21 -0
  33. data/test/spectus/matcher/custom/be_prime/helper_test.rb +13 -0
  34. data/test/spectus/matcher/custom/be_prime/test_be_prime.rb +21 -0
  35. data/test/spectus/matcher/custom/be_the_answer/helper_test.rb +11 -0
  36. data/test/spectus/matcher/custom/be_the_answer/test_be_the_answer.rb +21 -0
  37. data/test/spectus/matcher/custom/helper_test.rb +1 -0
  38. data/test/spectus/matcher/custom/start_with/helper_test.rb +15 -0
  39. data/test/spectus/matcher/custom/start_with/test_start_with.rb +21 -0
  40. data/test/spectus/matcher/helper_test.rb +1 -0
  41. data/test/spectus/test_dsl.rb +9 -0
  42. data/test/spectus/test_expectation_target.rb +17 -0
  43. data/test/spectus/test_matcher.rb +34 -0
  44. data/test/spectus/test_reporter.rb +97 -0
  45. data/test/spectus/test_version.rb +11 -0
  46. data/test/support.rb +3 -0
  47. data/test/support/coverage.rb +3 -0
  48. data/test/support/env.rb +4 -0
  49. data/test/support/presenter.rb +23 -0
  50. metadata +175 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 96fa46cd60fb62f1704a8dbf1dbe3b5519b1981f
4
+ data.tar.gz: 5ade56a1a4865de27fe71781c3fd21853d94dd8a
5
+ SHA512:
6
+ metadata.gz: 2ba1d3381e9c4f408e6f188c204582b11752119c8ee5fbca13e306ecfe93142cb4d7531bf2711ce768d9c38801b75228506de0a4e18edd8e4462531ecee2699f
7
+ data.tar.gz: db138bad384985792d3c480403a7881596a7334feca59618dd9146a265f1d4725fcd43bf20c331bb9a49be59b5276f82c149534147b10339d26f667d129146fa
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ script: 'bundle exec rake test:coverage'
3
+ rvm:
4
+ - 2.0.0
5
+ - 2.1.3
6
+ - ruby-head
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ - README.md
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Cyril Wack
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.
data/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # Spectus
2
+
3
+ [![Build Status](https://travis-ci.org/cyril/spectus.rb.svg?branch=master)](https://travis-ci.org/cyril/spectus.rb)
4
+ [![Coverage Status](http://img.shields.io/coveralls/cyril/spectus.rb.svg?branch=master)](https://coveralls.io/r/cyril/spectus.rb)
5
+ [![Code Climate](http://img.shields.io/codeclimate/github/cyril/spectus.rb.svg)](https://codeclimate.com/github/cyril/spectus.rb)
6
+ [![Dependency Status](https://gemnasium.com/cyril/spectus.rb.svg)](https://gemnasium.com/cyril/spectus.rb)
7
+ [![Gem Version](http://img.shields.io/gem/v/spectus.svg)](https://rubygems.org/gems/spectus)
8
+ [![Inline docs](http://inch-ci.org/github/cyril/spectus.rb.svg)](http://inch-ci.org/github/cyril/spectus.rb)
9
+ [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)](http://rubydoc.info/gems/spectus/frames)
10
+ [![License](http://img.shields.io/:license-MIT-38c800.svg)](http://cyril.mit-license.org/)
11
+
12
+ > An expectation library with some built-in matchers for Ruby.
13
+
14
+ ## Contact
15
+
16
+ * Home page: https://github.com/cyril/spectus.rb
17
+ * Bugs/issues: https://github.com/cyril/spectus.rb/issues
18
+ * Support: https://stackoverflow.com/questions/tagged/spectus-ruby
19
+
20
+ ## Rubies
21
+
22
+ __Spectus__ is supported by Ruby (MRI) 2+.
23
+
24
+ ## Installation
25
+
26
+ Add this line to your application's Gemfile:
27
+
28
+ ```ruby
29
+ gem 'spectus'
30
+ ```
31
+
32
+ And then execute:
33
+
34
+ ```shell
35
+ $ bundle
36
+ ```
37
+
38
+ Or install it yourself as:
39
+
40
+ ```shell
41
+ $ gem install spectus
42
+ ```
43
+
44
+ ## Why would I want this library?
45
+
46
+ * It's ~200 lines of fast and KISS code.
47
+ * Atomic state transitions, immutable objects, thread-safe.
48
+ * A generic, consistent DSL for assertions.
49
+
50
+ ## Usage
51
+
52
+ ```ruby
53
+ class Duck
54
+ def walks
55
+ "Klop klop!"
56
+ end
57
+
58
+ def swims
59
+ "Swoosh..."
60
+ end
61
+
62
+ def quacks
63
+ puts "Quaaaaaack!"
64
+ end
65
+ end
66
+
67
+ @bird = Duck.new
68
+ ```
69
+
70
+ > When I see a #<Duck:0x007f96b285d6d0> that ...
71
+
72
+ ```ruby
73
+ require 'spectus'
74
+ extend Spectus::DSL
75
+
76
+ expectation_1 = expect { @bird.walks }.to eql: "Klop klop!"
77
+ expectation_2 = expect { @bird.swims }.to eql: "Swoosh..."
78
+ expectation_3 = expect { @bird.quacks }.to capture_stdout: "Quaaaaaack!\n"
79
+ expectation_4 = expect { @bird.speaks }.to raise_exception: NoMethodError
80
+
81
+ case (expectation_1.pass? &&
82
+ expectation_2.pass? &&
83
+ expectation_3.pass? &&
84
+ expectation_4.pass?)
85
+ when true then puts "I call that #{@bird} a duck."
86
+ else warn 'WAT?'
87
+ end
88
+ ```
89
+
90
+ > I call that #<Duck:0x007f96b285d6d0> a duck.
91
+
92
+ ## Built-in matchers
93
+
94
+ ### Standard error
95
+
96
+ ```ruby
97
+ expect { warn 'foo' }.to capture_stderr: "foo\n"
98
+ ```
99
+
100
+ ### Standard output
101
+
102
+ ```ruby
103
+ expect { puts 'foo' }.to capture_stdout: "foo\n"
104
+ ```
105
+
106
+ ### Equivalence
107
+
108
+ ```ruby
109
+ expect { 'foo' }.to eql: 'foo'
110
+ ```
111
+
112
+ ### Identity
113
+
114
+ ```ruby
115
+ expect { :foo }.to equal: :foo
116
+ ```
117
+
118
+ ### Regular expressions
119
+
120
+ ```ruby
121
+ expect { 'foo' }.to({match: /^foo$/})
122
+ ```
123
+
124
+ ### Expecting errors
125
+
126
+ ```ruby
127
+ expect { Foo }.to raise_exception: NameError
128
+ ```
129
+
130
+ ## Custom matchers
131
+
132
+ Custom matchers can also be defined for expressing expectations.
133
+
134
+ ### Be prime
135
+
136
+ The following expression...
137
+
138
+ ```ruby
139
+ require 'prime'
140
+ expect { Prime.prime? 42 }.to equal: false
141
+ ```
142
+
143
+ ...could be refactored into:
144
+
145
+ ```ruby
146
+ expect { 42 }.not_to :be_prime
147
+ ```
148
+
149
+ It can be done with this custom matcher:
150
+
151
+ ```ruby
152
+ require 'prime'
153
+
154
+ module Spectus
155
+ module Matcher
156
+ class BePrime
157
+ def matches?
158
+ Prime.prime? yield
159
+ end
160
+ end
161
+ end
162
+ end
163
+ ```
164
+
165
+ ### Be the answer
166
+
167
+ The following expression...
168
+
169
+ ```ruby
170
+ expect { 42 }.to equal: 42
171
+ ```
172
+
173
+ ...could be refactored into:
174
+
175
+ ```ruby
176
+ expect { 42 }.to :be_the_answer
177
+ ```
178
+
179
+ It can be done with this custom matcher:
180
+
181
+ ```ruby
182
+ module Spectus
183
+ module Matcher
184
+ class BeTheAnswer
185
+ def matches?
186
+ 42.equal? yield
187
+ end
188
+ end
189
+ end
190
+ end
191
+ ```
192
+
193
+ ### Start with
194
+
195
+ The following expression...
196
+
197
+ ```ruby
198
+ expect { 'foobar' }.to match: /^foo/
199
+ ```
200
+
201
+ ...could be refactored into:
202
+
203
+ ```ruby
204
+ expect { 'foobar' }.to start_with: 'foo'
205
+ ```
206
+
207
+ It can be done with this custom matcher:
208
+
209
+ ```ruby
210
+ module Spectus
211
+ module Matcher
212
+ class StartWith
213
+ def initialize expected
214
+ @expected = expected
215
+ end
216
+
217
+ def matches?
218
+ !Regexp.new("^#{@expected}").match(yield).nil?
219
+ end
220
+ end
221
+ end
222
+ end
223
+ ```
224
+
225
+ ## Contributing
226
+
227
+ 1. [Fork it](https://github.com/cyril/spectus.rb/fork)
228
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
229
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
230
+ 4. Push to the branch (`git push origin my-new-feature`)
231
+ 5. Create a new Pull Request
232
+
233
+ ## Versioning
234
+
235
+ __Spectus__ follows [Semantic Versioning 2.0](http://semver.org/)
236
+
237
+ ## Copyright
238
+
239
+ &copy; [Cyril Wack](https://plus.google.com/+CyrilWack?rel=author)
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.pattern = File.join 'test', '**', 'test_*.rb'
6
+ t.verbose = true
7
+ t.warning = true
8
+ end
9
+
10
+ namespace :test do
11
+ task :coverage do
12
+ ENV['COVERAGE'] = 'true'
13
+ Rake::Task['test'].invoke
14
+ end
15
+ end
16
+
17
+ task(:doc_stats) { ruby '-S yard stats' }
18
+ task default: [:test, :doc_stats]
data/VERSION.semver ADDED
@@ -0,0 +1 @@
1
+ 1.0.0.pre
data/lib/spectus.rb ADDED
@@ -0,0 +1,6 @@
1
+ require_relative File.join 'spectus', 'dsl'
2
+ require_relative File.join 'spectus', 'version'
3
+
4
+ # Namespace for the Spectus library.
5
+ module Spectus
6
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'expectation_target'
2
+
3
+ module Spectus
4
+
5
+ # Expectation's domain-specific language.
6
+ module DSL
7
+
8
+ # Expectations are built with this method which takes a value, called the
9
+ # actual.
10
+ def expect &input
11
+ ExpectationTarget.new(&input)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'matcher'
2
+
3
+ module Spectus
4
+
5
+ # Wraps the target of an expectation.
6
+ #
7
+ # @example
8
+ # expect { do_something } # => ExpectationTarget wrapping the block
9
+ class ExpectationTarget
10
+ # @api private
11
+ def initialize &actual
12
+ @actual = actual
13
+
14
+ freeze
15
+ end
16
+
17
+ # To evaluate to a positive assertion.
18
+ def to definition
19
+ Matcher.eval false, definition, &@actual
20
+ end
21
+
22
+ # To evaluate to a negative assertion.
23
+ def not_to definition
24
+ Matcher.eval true, definition, &@actual
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'reporter'
2
+
3
+ module Spectus
4
+
5
+ # This module provides matchers to define expectations.
6
+ module Matcher
7
+
8
+ # Evaluate the expectation, and report the result.
9
+ def self.eval negated, definition, &actual
10
+ params = Array(definition).flatten(1)
11
+ name = params.first
12
+ expected_args = params[1..-1]
13
+ matcher = Matcher.get(name).new(*expected_args)
14
+
15
+ Reporter.new negated, name, *expected_args, begin
16
+ negated ^ matcher.matches?(&actual)
17
+ rescue => e
18
+ e
19
+ end
20
+ end
21
+
22
+ # Get the class of a matcher from its symbol.
23
+ #
24
+ # @example
25
+ #
26
+ # Matcher.get(:eql) # => Eql
27
+ def self.get name
28
+ const_get name.to_s.split('_').map {|w| w.capitalize }.join.to_sym
29
+ end
30
+ end
31
+ end
32
+
33
+ Dir[File.join File.dirname(__FILE__), 'matcher', '*.rb'].each do |filename|
34
+ require_relative filename
35
+ end
@@ -0,0 +1,31 @@
1
+ require 'stringio'
2
+
3
+ module Spectus
4
+ module Matcher
5
+
6
+ # @api private
7
+ # Provides the implementation for `capture_stderr`.
8
+ class CaptureStderr
9
+
10
+ # @api private
11
+ def initialize expected
12
+ @expected = expected
13
+
14
+ freeze
15
+ end
16
+
17
+ # @return [Boolean] Comparison between actual and expected values.
18
+ def matches?
19
+ begin
20
+ orig_std = $stderr
21
+ $stderr = StringIO.new
22
+
23
+ yield
24
+ $stderr.string.eql? @expected
25
+ ensure
26
+ $stderr = orig_std
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end