ancient_mock 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b63a9acbabc8f04ce9f8be0f3168753764e4edb8
4
+ data.tar.gz: 32d9db7b5c7b99346865971b1516e820f56f59fc
5
+ SHA512:
6
+ metadata.gz: d0a7e334dab6b0d1c32ae934b37aee04327c9f2c671919d39924517101fcfb37bca9112b89001279ffdf33abf90e26adc1ec259d1984116e29bdf62e46667f3d
7
+ data.tar.gz: 7e3f796694b208d65b6bb2f9066cd64d964c68d88b0f3dd3ab7cab8f000d46b0776887bfa7603a799f08d7f970aceb07dab9873a14cdf2079dfef4ed9958ae75
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ancient_mock.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andy Lindeman
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.
@@ -0,0 +1,38 @@
1
+ # AncientMock
2
+
3
+ A simple mock object library that I build on stage at [Ancient City
4
+ Ruby](http://ancientcityruby.com).
5
+
6
+ **Do not use in production!** It was an academic exercise meant to teach
7
+ the basics of building a mock object library.
8
+
9
+ * Video from the talk (not yet posted)
10
+ * [Slides from the talk](https://docs.google.com/presentation/d/1laaQYHFyzcTJzlB9qMmEHyoHIB-S93p9B4L8SbbhoTw/edit#slide=id.p)
11
+
12
+ ## Installation
13
+
14
+ ```ruby
15
+ # Gemfile
16
+ gem 'ancient_mock'
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ warehouse = Object.new
23
+
24
+ # Stub
25
+ allow(warhouse).to receive(:full?).and_return(true)
26
+ warehouse.full? # => true
27
+
28
+ # Mock
29
+ item_id = 1234
30
+ expect(warehouse).to receive(:remove).with(item_id)
31
+ # warehouse.remove(1234) must be called
32
+ ```
33
+
34
+ ## Tests
35
+
36
+ ```ruby
37
+ bundle exec rake
38
+ ```
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.test_files = FileList['test/*_test.rb']
6
+ end
7
+
8
+ task :default => :test
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ancient_mock/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ancient_mock"
8
+ spec.version = AncientMock::VERSION
9
+ spec.authors = ["Andy Lindeman"]
10
+ spec.email = ["alindeman@gmail.com"]
11
+ spec.description = %q{A simple mock object library I built on stage at Ancient City Ruby. Do not use in production!}
12
+ spec.summary = %q{A simple mock object library I built on stage at Ancient City Ruby.}
13
+ spec.homepage = "https://github.com/alindeman/ancient_mock"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "minitest", "~> 4.7.0"
24
+ end
@@ -0,0 +1,137 @@
1
+ require_relative "ancient_mock/version"
2
+
3
+ module AncientMock
4
+ ExpectationNotSatisfied = Class.new(StandardError)
5
+
6
+ class StubTarget
7
+ def initialize(obj)
8
+ @obj = obj
9
+ end
10
+
11
+ def to(definition)
12
+ Stubber.for_object(@obj).stub(definition)
13
+ end
14
+ end
15
+
16
+ class ExpectationTarget < StubTarget
17
+ def to(definition)
18
+ super
19
+ AncientMock.expectations << definition
20
+ end
21
+ end
22
+
23
+ class Stubber
24
+ def self.stubbers
25
+ @stubbers ||= { }
26
+ end
27
+
28
+ def self.for_object(obj)
29
+ stubbers[obj.__id__] ||= Stubber.new(obj)
30
+ end
31
+
32
+ def self.reset
33
+ stubbers.each_value(&:reset)
34
+ stubbers.clear
35
+ end
36
+
37
+ def initialize(obj)
38
+ @obj = obj
39
+ @definitions = []
40
+ @preserved_methods = []
41
+ end
42
+
43
+ def stub(definition)
44
+ @definitions << definition
45
+
46
+ # preserve the method if already exists
47
+ if @obj.singleton_class.method_defined?(definition.message)
48
+ @preserved_methods <<
49
+ @obj.singleton_class.instance_method(definition.message)
50
+ end
51
+
52
+ definitions = @definitions
53
+ @obj.define_singleton_method(definition.message) do |*arguments|
54
+ definitions.
55
+ reverse.
56
+ find { |d| d.matches?(definition.message, *arguments) }.
57
+ call
58
+ end
59
+ end
60
+
61
+ def reset
62
+ @definitions.each do |definition|
63
+ @obj.singleton_class.class_eval do
64
+ remove_method(definition.message) if method_defined?(definition.message)
65
+ end
66
+ end
67
+
68
+ @preserved_methods.reverse.each do |method|
69
+ @obj.define_singleton_method(method.name, method)
70
+ end
71
+ end
72
+ end
73
+
74
+ class ExpectationDefinition
75
+ attr_reader :message, :return_value
76
+
77
+ def initialize(message)
78
+ @message = message
79
+ @invocation_count = 0
80
+ end
81
+
82
+ def and_return(return_value)
83
+ @return_value = return_value
84
+ self
85
+ end
86
+
87
+ def with(*arguments)
88
+ @arguments = arguments
89
+ self
90
+ end
91
+
92
+ def matches?(message, *arguments)
93
+ message == @message &&
94
+ (@arguments.nil? || arguments == @arguments)
95
+ end
96
+
97
+ def call
98
+ @invocation_count += 1
99
+ @return_value
100
+ end
101
+
102
+ def verify
103
+ if @invocation_count != 1
104
+ raise ExpectationNotSatisfied
105
+ end
106
+ end
107
+ end
108
+
109
+ module TestExtensions
110
+ def allow(obj)
111
+ StubTarget.new(obj)
112
+ end
113
+
114
+ def expect(obj)
115
+ ExpectationTarget.new(obj)
116
+ end
117
+
118
+ def receive(message)
119
+ ExpectationDefinition.new(message)
120
+ end
121
+ end
122
+
123
+ def self.reset
124
+ expectations.each(&:verify)
125
+ ensure
126
+ expectations.clear
127
+ Stubber.reset
128
+ end
129
+
130
+ def self.expectations
131
+ @expectations ||= []
132
+ end
133
+ end
134
+
135
+ class MiniTest::Unit::TestCase
136
+ include AncientMock::TestExtensions
137
+ end
@@ -0,0 +1,3 @@
1
+ module AncientMock
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,64 @@
1
+ require "minitest/spec"
2
+ require "minitest/autorun"
3
+ require_relative "../lib/ancient_mock"
4
+
5
+ describe AncientMock do
6
+ it "allows an object to receive a message, returning a value" do
7
+ warehouse = Object.new
8
+
9
+ allow(warehouse).to receive(:full?).and_return(true)
10
+
11
+ warehouse.full?.must_equal true
12
+ end
13
+
14
+ it "removes stubbed methods after tests finish" do
15
+ warehouse = Object.new
16
+
17
+ allow(warehouse).to receive(:full?).and_return(true)
18
+
19
+ AncientMock.reset
20
+
21
+ assert_raises(NoMethodError) { warehouse.full? }
22
+ end
23
+
24
+ it "preserves methods that originally existed" do
25
+ warehouse = Object.new
26
+ def warehouse.full?; false; end
27
+
28
+ allow(warehouse).to receive(:full?).and_return(true)
29
+
30
+ AncientMock.reset
31
+
32
+ warehouse.full?.must_equal false
33
+ end
34
+
35
+ it "expects that a message will be received" do
36
+ warehouse = Object.new
37
+
38
+ expect(warehouse).to receive(:empty)
39
+ # warehouse.empty not called!
40
+
41
+ assert_raises(AncientMock::ExpectationNotSatisfied) do
42
+ AncientMock.reset
43
+ end
44
+ end
45
+
46
+ it "does not raise an error if expectations are satisfied" do
47
+ warehouse = Object.new
48
+
49
+ expect(warehouse).to receive(:empty)
50
+ warehouse.empty
51
+
52
+ AncientMock.reset
53
+ end
54
+
55
+ it "allows objects to receive messages with arguments" do
56
+ warehouse = Object.new
57
+
58
+ allow(warehouse).to receive(:include?).with(1234).and_return(true)
59
+ allow(warehouse).to receive(:include?).with(9876).and_return(false)
60
+
61
+ warehouse.include?(1234).must_equal true
62
+ warehouse.include?(9876).must_equal false
63
+ end
64
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ancient_mock
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andy Lindeman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 4.7.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 4.7.0
55
+ description: A simple mock object library I built on stage at Ancient City Ruby. Do
56
+ not use in production!
57
+ email:
58
+ - alindeman@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - .gitignore
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - ancient_mock.gemspec
69
+ - lib/ancient_mock.rb
70
+ - lib/ancient_mock/version.rb
71
+ - test/ancient_mock_test.rb
72
+ homepage: https://github.com/alindeman/ancient_mock
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.0.2
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: A simple mock object library I built on stage at Ancient City Ruby.
96
+ test_files:
97
+ - test/ancient_mock_test.rb