expectation 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: []