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 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
@@ -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
@@ -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
@@ -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: []