expectation 0.1.1
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/README.md +23 -0
- data/lib/expectation/version.rb +8 -0
- data/lib/expectation.rb +120 -0
- data/test/expect_test.rb +119 -0
- data/test/test_helper.rb +18 -0
- metadata +55 -0
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Expect
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
gem install expectations
|
6
|
+
|
7
|
+
## Getting started
|
8
|
+
|
9
|
+
This function expects a String argument starting with "http:", an Integer or Float argument, and a Hash
|
10
|
+
with a String entry at key `:foo`, and either an Array or nil at key `:bar`.
|
11
|
+
|
12
|
+
def function(a, b, options = {})
|
13
|
+
expect! a => /^http:/,
|
14
|
+
b => [Integer, Float],
|
15
|
+
options => {
|
16
|
+
:foo => String,
|
17
|
+
:bar => [ Array, nil ]
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
## License
|
22
|
+
|
23
|
+
The expectations gem is distributed under the terms of the Modified BSD License, see LICENSE.BSD for details.
|
@@ -0,0 +1,8 @@
|
|
1
|
+
#--
|
2
|
+
# Author:: radiospiel (mailto:eno@radiospiel.org)
|
3
|
+
# Copyright:: Copyright (c) 2011, 2012 radiospiel
|
4
|
+
# License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
|
5
|
+
module Expectation
|
6
|
+
# The expectation gem's version.
|
7
|
+
VERSION="0.1.1"
|
8
|
+
end
|
data/lib/expectation.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
#--
|
2
|
+
# Author:: radiospiel (mailto:eno@radiospiel.org)
|
3
|
+
# Copyright:: Copyright (c) 2011, 2012 radiospiel
|
4
|
+
# License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
|
5
|
+
#++
|
6
|
+
# The Expectation module implements methods to verify one or more values
|
7
|
+
# against set of expectations. This is a subset of
|
8
|
+
# design-by-contract programming (see http://en.wikipedia.org/wiki/Design_by_contract)
|
9
|
+
# features, and should speed you up during development phases.
|
10
|
+
#
|
11
|
+
# == Example
|
12
|
+
#
|
13
|
+
# This function expects a String argument starting with <tt>"http:"</tt>,
|
14
|
+
# an Integer or Float argument, and a Hash with a String entry at key
|
15
|
+
# <tt>:foo</tt>, and either an Array or +nil+ at key <tt>:bar</tt>.
|
16
|
+
#
|
17
|
+
# def function(a, b, options = {})
|
18
|
+
# expect! a => /^http:/,
|
19
|
+
# b => [Integer, Float],
|
20
|
+
# options => {
|
21
|
+
# :foo => String,
|
22
|
+
# :bar => [ Array, nil ]
|
23
|
+
# }
|
24
|
+
# end
|
25
|
+
|
26
|
+
module Expectation
|
27
|
+
# Verifies a number of expectations. Raises an ArgumentError if one
|
28
|
+
# or more expectations are not met.
|
29
|
+
#
|
30
|
+
# In contrast to Expectation#expect this method can not be
|
31
|
+
# disabled at runtime.
|
32
|
+
def expect!(*expectations, &block)
|
33
|
+
if block_given?
|
34
|
+
Expectation.verify! true, block
|
35
|
+
end
|
36
|
+
|
37
|
+
expectations.each do |expectation|
|
38
|
+
case expectation
|
39
|
+
when Hash
|
40
|
+
expectation.each do |value, e|
|
41
|
+
Expectation.verify! value, e
|
42
|
+
end
|
43
|
+
else
|
44
|
+
Expectation.verify! expectation, :truish
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Verifies a number of expectations. If one or more expectations are
|
50
|
+
# not met it raises an ArgumentError.
|
51
|
+
#
|
52
|
+
# This method can be enabled or disabled at runtime using
|
53
|
+
# Expectation.enable and Expectation.disable.
|
54
|
+
def expect(*expectations, &block)
|
55
|
+
expect!(*expectations, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
# A do nothing expect method. This is the standin for expect, when
|
59
|
+
# Expectation are disabled.
|
60
|
+
def expect_dummy!(*expectations, &block) #:nodoc:
|
61
|
+
end
|
62
|
+
|
63
|
+
# Does a value meet the expectation? Retruns +true+ or +false+.
|
64
|
+
def self.met?(value, expectation) #:nodoc:
|
65
|
+
case expectation
|
66
|
+
when :truish then !!value
|
67
|
+
when :fail then false
|
68
|
+
when Array then expectation.any? { |e| met?(value, e) }
|
69
|
+
when Proc then expectation.arity == 0 ? expectation.call : expectation.call(value)
|
70
|
+
when Regexp then value.is_a?(String) && expectation =~ value
|
71
|
+
else expectation === value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Verifies a value against an expectation. Builds and raises
|
76
|
+
# an ArgumentError exception if the expectation is not met.
|
77
|
+
def self.verify!(value, expectation)
|
78
|
+
failed_value, failed_expectation, message = value, expectation, nil
|
79
|
+
|
80
|
+
# Test expectation, collect failed_value, failed_expectation, failed_message
|
81
|
+
unless expectation.is_a?(Hash)
|
82
|
+
good = met?(value, expectation)
|
83
|
+
else
|
84
|
+
good = met?(value, Hash)
|
85
|
+
if good
|
86
|
+
good = expectation.all? do |key, expect|
|
87
|
+
next true if met?(value[key], expect)
|
88
|
+
|
89
|
+
failed_value, failed_expectation, message = value[key], expect, "at key #{key.inspect}"
|
90
|
+
false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# are we good?
|
96
|
+
return if good
|
97
|
+
|
98
|
+
# build exception with adjusted backtrace.
|
99
|
+
backtrace = caller[5 .. -1]
|
100
|
+
|
101
|
+
e = ArgumentError.new "#{failed_value.inspect} does not meet expectation #{failed_expectation.inspect}#{message && ", #{message}"}"
|
102
|
+
e.singleton_class.send(:define_method, :backtrace) do
|
103
|
+
backtrace
|
104
|
+
end
|
105
|
+
raise e
|
106
|
+
end
|
107
|
+
|
108
|
+
# Enable the Expectation#expect method.
|
109
|
+
def self.enable
|
110
|
+
alias_method :expect, :expect!
|
111
|
+
end
|
112
|
+
|
113
|
+
# Disable the Expectation#expect method.
|
114
|
+
def self.disable
|
115
|
+
alias_method :expect, :expect_dummy!
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
Expectation.enable
|
120
|
+
Object.send :include, Expectation
|
data/test/expect_test.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# Author:: radiospiel (mailto:eno@radiospiel.org)
|
2
|
+
# Copyright:: Copyright (c) 2011, 2012 radiospiel
|
3
|
+
# License:: Distributes under the terms of the Modified BSD License, see LICENSE.BSD for details.
|
4
|
+
require_relative 'test_helper'
|
5
|
+
|
6
|
+
class ExpectationTest < Test::Unit::TestCase
|
7
|
+
def assert_expectation!(*expectation, &block)
|
8
|
+
assert_nothing_raised do
|
9
|
+
expect! *expectation, &block
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def assert_failed_expectation!(*expectation, &block)
|
14
|
+
assert_raise(ArgumentError) {
|
15
|
+
expect! *expectation, &block
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def assert_expectation(*expectation, &block)
|
20
|
+
assert_nothing_raised do
|
21
|
+
expect *expectation, &block
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def assert_failed_expectation(*expectation, &block)
|
26
|
+
assert_raise(ArgumentError) {
|
27
|
+
expect *expectation, &block
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Verify that the exception's backtrace is properly adjusted,
|
32
|
+
# i.e. points to this file.
|
33
|
+
def test_expectations_backtrace
|
34
|
+
backtrace = nil
|
35
|
+
|
36
|
+
begin
|
37
|
+
expect! 1 => 0
|
38
|
+
rescue
|
39
|
+
backtrace = $!.backtrace
|
40
|
+
end
|
41
|
+
assert backtrace.first.include?("/expect_test.rb:")
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_int_expectations
|
45
|
+
assert_expectation! 1 => 1
|
46
|
+
assert_expectation! 1 => Fixnum
|
47
|
+
assert_expectation! 1 => Integer
|
48
|
+
assert_expectation! 1 => 0..2
|
49
|
+
assert_expectation! 1 => 0..1
|
50
|
+
assert_expectation! 1 => 1..10
|
51
|
+
assert_expectation! 1 => [0,1,2]
|
52
|
+
assert_expectation! 1 => lambda { |i| i.odd? }
|
53
|
+
|
54
|
+
assert_failed_expectation! 1 => 2
|
55
|
+
assert_failed_expectation! 1 => Float
|
56
|
+
assert_failed_expectation! 1 => 0...1
|
57
|
+
assert_failed_expectation! 1 => 3..5
|
58
|
+
assert_failed_expectation! 1 => [3,4,5]
|
59
|
+
assert_failed_expectation! 1 => lambda { |i| i.even? }
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_regexp_expectations
|
63
|
+
assert_expectation! " foo" => /foo/
|
64
|
+
assert_failed_expectation! " foo" => /^foo/
|
65
|
+
|
66
|
+
assert_expectation! "1" => /1/
|
67
|
+
assert_failed_expectation! "1" => /2/
|
68
|
+
|
69
|
+
assert_failed_expectation! 1 => /1/
|
70
|
+
assert_failed_expectation! 1 => /2/
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_multiple_expectations
|
74
|
+
assert_expectation! 1 => 1, :a => :a
|
75
|
+
assert_failed_expectation! 1 => 2, :a => :a
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_array_expectations
|
79
|
+
assert_expectation! 1, 1, 1, /1/
|
80
|
+
assert_expectation! 1, 1, "1" => /1/
|
81
|
+
|
82
|
+
assert_failed_expectation! 1, 1, "1" => /2/
|
83
|
+
assert_failed_expectation! 1, 1, 1 => /2/
|
84
|
+
assert_failed_expectation! 1, nil, "1" => /1/
|
85
|
+
assert_failed_expectation! 1, false, "1" => /1/
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_block_expectations
|
89
|
+
assert_expectation! do true end
|
90
|
+
assert_failed_expectation! do false end
|
91
|
+
assert_failed_expectation! do nil end
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_hash_expectations
|
95
|
+
assert_failed_expectation!({} => { :key => "Foo" })
|
96
|
+
assert_expectation!({ :key => "Foo" } => { :key => "Foo" })
|
97
|
+
|
98
|
+
assert_failed_expectation!({ :other_key => "Foo" } => { :key => "Foo" })
|
99
|
+
assert_failed_expectation!({ :key => "Bar" } => { :key => "Foo" })
|
100
|
+
|
101
|
+
assert_expectation!({ :key => "Foo" } => { :key => String })
|
102
|
+
assert_expectation!({ :key => "Foo" } => { :key => [Integer,String] })
|
103
|
+
assert_failed_expectation!({ :key => "Foo" } => { :key => [Integer,"Bar"] })
|
104
|
+
assert_expectation!({ :other_key => "Foo" } => { :key => [nil, "Foo"] })
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_enable_and_disable
|
108
|
+
assert_failed_expectation! "foo" => "bar"
|
109
|
+
assert_failed_expectation "foo" => "bar"
|
110
|
+
|
111
|
+
Expectation.disable
|
112
|
+
assert_failed_expectation! "foo" => "bar"
|
113
|
+
assert_expectation "foo" => "bar"
|
114
|
+
|
115
|
+
Expectation.enable
|
116
|
+
assert_failed_expectation! "foo" => "bar"
|
117
|
+
assert_failed_expectation "foo" => "bar"
|
118
|
+
end
|
119
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'simplecov'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'test/unit/ui/console/testrunner'
|
7
|
+
|
8
|
+
class Test::Unit::UI::Console::TestRunner
|
9
|
+
def guess_color_availability; true; end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'mocha'
|
13
|
+
|
14
|
+
SimpleCov.start do
|
15
|
+
add_filter "test/*.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
require "expectation"
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: expectation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- radiospiel
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-30 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Defensive programming with expectations
|
15
|
+
email: eno@radiospiel.org
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/expectation/version.rb
|
21
|
+
- lib/expectation.rb
|
22
|
+
- README.md
|
23
|
+
- test/expect_test.rb
|
24
|
+
- test/test_helper.rb
|
25
|
+
homepage: http://github.com/radiospiel/expectation
|
26
|
+
licenses: []
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ! '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
segments:
|
38
|
+
- 0
|
39
|
+
hash: 2234163165414067055
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
hash: 2234163165414067055
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.8.24
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: Defensive programming with expectations
|
55
|
+
test_files: []
|