motion-stump 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ # Specify your gem's dependencies in bubble-wrap.gemspec
4
+ gemspec
data/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ == 0.1.0
2
+
3
+ * motion-stump: initial release
data/License.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Francis Chong
2
+
3
+ Copyright (c) 2008 Jeremy McAnally
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,93 @@
1
+ # motion-stump
2
+
3
+ Stubbing and mocking for RubyMotion. Based on Jeremy McAnally's [stump](https://github.com/jm/stump) library.
4
+
5
+ ## Features
6
+
7
+ ### Stubbing right on the object
8
+
9
+ ```ruby
10
+ # Returns 'hey!'
11
+ MyClass.stub!(:thing, :return => "hey!")
12
+ # Returns nil
13
+ your_object.stub!(:hello)
14
+ ```
15
+
16
+ ### Pure stub objects
17
+ ```ruby
18
+ my_stub = stub(:thing, :return => "dude, a thing!")
19
+ my_stub.thing # => "dude, a thing!"
20
+ ```
21
+
22
+ ### Mocking right on the object
23
+
24
+ ```ruby
25
+ my_object = "things are fun"
26
+ my_object.mock!(:fancy, :return => "ooo fancy!")
27
+ my_object.fancy # => "ooo fancy!"
28
+ my_object.mock!(:tancy, :return => "ooo fancy!")
29
+
30
+ # if my_object.tancy is not called, it will fail the spec
31
+ ```
32
+
33
+ ### Pure mock objects
34
+ ```ruby
35
+ my_mock = mock(:hello, :return => "what fun is this?")
36
+ my_mock.hello # => "what fun is this?"
37
+ ```
38
+
39
+
40
+ ### Proxying objects
41
+
42
+ ```ruby
43
+ class Greeting
44
+ def bonjour
45
+ "Bonjour!"
46
+ end
47
+ end
48
+
49
+ greet_me = Greeting.new
50
+ greet_me.proxy!(:bonjour)
51
+ greet_me.bonjour # => "Bonjour!"
52
+
53
+ greet_you = Greeting.new
54
+ greet_you.proxy!(:bonjour)
55
+
56
+ # finish test...
57
+ # ! Unmet expectations: #<Greeting:0x371d24> expected bonjour
58
+ ```
59
+
60
+ ## Installation
61
+
62
+ ```ruby
63
+ gem install 'motion-stump'
64
+ ```
65
+
66
+ ### Usage
67
+
68
+ Add following lines in your motion Rakefile
69
+
70
+ ```ruby
71
+ $:.unshift("/Library/RubyMotion/lib")
72
+ require 'motion/project'
73
+ require 'rubygems'
74
+ require 'motion-stump'
75
+
76
+ Motion::Project::App.setup do |app|
77
+ app.name = 'motion-stump'
78
+ end
79
+ ```
80
+
81
+ ## License
82
+
83
+ (The MIT License)
84
+
85
+ Copyright © 2012 Francis Chong
86
+
87
+ Copyright © 2008 Jeremy McAnally
88
+
89
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
90
+
91
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
92
+
93
+ THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "bundler/gem_tasks"
3
+
4
+ $:.unshift("/Library/RubyMotion/lib")
5
+ require 'motion/project'
6
+ require 'bundler'
7
+ Bundler.require :default, :development
8
+
9
+ Motion::Project::App.setup do |app|
10
+ app.name = 'motion-stump'
11
+ end
12
+
13
+ desc "Build the gem"
14
+ task :gem do
15
+ sh "bundle exec gem build motion-stump.gemspec"
16
+ sh "mkdir -p pkg"
17
+ sh "mv *.gem pkg/"
18
+ end
@@ -0,0 +1,5 @@
1
+ class AppDelegate
2
+ def application(application, didFinishLaunchingWithOptions:launchOptions)
3
+ true
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ unless defined?(Motion::Project::Config)
2
+ raise "This file must be required within a RubyMotion project Rakefile."
3
+ end
4
+
5
+ ## Extend Motion config to include our spec helper
6
+ module Motion; module Project;
7
+ class Config
8
+ alias_method :spec_files_before_stump, :spec_files
9
+ def spec_files
10
+ core = Dir.chdir(motiondir + '/lib/motion') { (['spec.rb'] + Dir.glob(File.join('spec', 'helpers', '*.rb'))).map { |x| File.expand_path(x) } }
11
+ (core + [File.join(File.dirname(__FILE__), 'stump/stump_spec_helper.rb')] + spec_files_before_stump).uniq
12
+ end
13
+ end
14
+ end; end
15
+
16
+
17
+ ## Include stump in dev mode
18
+ Motion::Project::App.setup do |app|
19
+ app.development do
20
+ [
21
+ File.join(File.dirname(__FILE__), 'stump/version.rb'),
22
+ File.join(File.dirname(__FILE__), 'stump/metaid.rb'),
23
+ File.join(File.dirname(__FILE__), 'stump/stub.rb'),
24
+ File.join(File.dirname(__FILE__), 'stump/mocks.rb'),
25
+ File.join(File.dirname(__FILE__), 'stump/mock.rb'),
26
+ File.join(File.dirname(__FILE__), 'stump/proxy.rb')
27
+ ].reverse.each {|f| app.files.unshift(f) }
28
+ end
29
+ end
30
+
31
+ ## Include supports for define_method
32
+ require 'motion-define-method'
@@ -0,0 +1,17 @@
1
+ # thanks _why
2
+ # http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
3
+ class Object
4
+ # The hidden singleton lurks behind everyone
5
+ def metaclass; class << self; self; end; end
6
+ def meta_eval &blk; metaclass.instance_eval &blk; end
7
+
8
+ # Adds methods to a metaclass
9
+ def meta_def name, &blk
10
+ meta_eval { define_method name, &blk }
11
+ end
12
+
13
+ # Defines an instance method within a class
14
+ def class_def name, &blk
15
+ class_eval { define_method name, &blk }
16
+ end
17
+ end
data/lib/stump/mock.rb ADDED
@@ -0,0 +1,51 @@
1
+ class Object
2
+ # Create a mock method on an object. A mock object will place an expectation
3
+ # on behavior and cause a test failure if it's not fulfilled.
4
+ #
5
+ # ==== Examples
6
+ #
7
+ # my_string = "a wooden rabbit"
8
+ # my_string.mock!(:retreat!, :return => "run away! run away!")
9
+ # my_string.mock!(:question, :return => "what is the airspeed velocity of an unladen sparrow?")
10
+ #
11
+ # # test/your_test.rb
12
+ # my_string.retreat! # => "run away! run away!"
13
+ # # If we let the test case end at this point, it fails with:
14
+ # # Unmet expectation: #<Sparrow:1ee7> expected question
15
+ #
16
+ def mock!(method, options = {}, &block)
17
+ Stump::Mocks.add([self, method])
18
+
19
+ behavior = if block_given?
20
+ lambda do |*args|
21
+ raise ArgumentError if block.arity >= 0 && args.length != block.arity
22
+
23
+ Stump::Mocks.verify([self, method])
24
+ block.call(*args)
25
+ end
26
+ else
27
+ lambda do |*args|
28
+ Stump::Mocks.verify([self, method])
29
+ return options[:return]
30
+ end
31
+ end
32
+
33
+ meta_def method, &behavior
34
+ end
35
+ end
36
+
37
+ module Kernel
38
+ # Create a pure mock object rather than mocking specific methods on an object.
39
+ #
40
+ # ==== Examples
41
+ #
42
+ # my_mock = mock(:thing, :return => "whee!")
43
+ # my_mock.thing # => "whee"
44
+ #
45
+ def mock(method, options = {}, &block)
46
+ mock_object = Object.new
47
+ mock_object.mock!(method, options, &block)
48
+ mock_object
49
+ end
50
+ end
51
+
@@ -0,0 +1,27 @@
1
+ module Stump
2
+ # A class to track the mocks and proxies that have been satisfied
3
+ class Mocks
4
+ class <<self
5
+ def size
6
+ @mocks ? 0 : @mocks.size
7
+ end
8
+
9
+ def add(mock)
10
+ @mocks ||= []
11
+ @mocks << mock
12
+ end
13
+
14
+ def verify(mock)
15
+ @mocks.delete(mock)
16
+ end
17
+
18
+ def failures
19
+ @mocks
20
+ end
21
+
22
+ def clear!
23
+ @mocks = []
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,117 @@
1
+ class Object
2
+ # Creates a proxy method on an object. In this setup, it places an expectation on an object (like a mock)
3
+ # but still calls the original method. So if you want to make sure the method is called and still return
4
+ # its value, or simply want to invoke the side effects of a method and return a stubbed value, then you can
5
+ # do that.
6
+ #
7
+ # ==== Examples
8
+ #
9
+ # class Parrot
10
+ # def speak!
11
+ # puts @words
12
+ # end
13
+ #
14
+ # def say_this(words)
15
+ # @words = words
16
+ # "I shall say #{words}!"
17
+ # end
18
+ # end
19
+ #
20
+ # # => test/your_test.rb
21
+ # sqawky = Parrot.new
22
+ # sqawky.proxy!(:say_this)
23
+ # # Proxy method still calls original method...
24
+ # sqawky.say_this("hey") # => "I shall say hey!"
25
+ # sqawky.speak! # => "hey"
26
+ #
27
+ # sqawky.proxy!(:say_this, "herro!")
28
+ # # Even though we return a stubbed value...
29
+ # sqawky.say_this("these words") # => "herro!"
30
+ # # ...the side effects are still there.
31
+ # sqawky.speak! # => "these words"
32
+ #
33
+ # TODO: This implementation is still very rough. Needs refactoring and refining. Won't
34
+ # work on ActiveRecord attributes, for example.
35
+ #
36
+ def proxy!(method, options = {}, &block)
37
+ Stump::Mocks.add([self, method])
38
+
39
+ if respond_to?(method)
40
+ proxy_existing_method(method, options, &block)
41
+ else
42
+ proxy_missing_method(method, options, &block)
43
+ end
44
+ end
45
+
46
+ protected
47
+ def proxy_existing_method(method, options = {}, &block)
48
+ method_alias = "__old_#{method}".to_sym
49
+
50
+ meta_eval do
51
+ module_eval do
52
+ alias_method method_alias, method
53
+ end
54
+ end
55
+
56
+ check_arity = Proc.new do |args|
57
+ arity = method(method_alias.to_sym).arity
58
+ if ((arity >= 0) ?
59
+ (args.length != arity) :
60
+ (args.length < ~arity))
61
+ # Negative arity means some params are optional, so we check
62
+ # for the minimum required. Sadly, we can't tell what the
63
+ # maximum is.
64
+ raise ArgumentError
65
+ end
66
+ end
67
+
68
+ behavior = if options[:return]
69
+ lambda do |*args|
70
+ check_arity.call(args)
71
+
72
+ Stump::Mocks.verify([self, method])
73
+
74
+ if method(method_alias.to_sym).arity == 0
75
+ send(method_alias)
76
+ else
77
+ send(method_alias, *args)
78
+ end
79
+
80
+ return options[:return]
81
+ end
82
+ else
83
+ lambda do |*args|
84
+ check_arity.call(args)
85
+
86
+ Stump::Mocks.verify([self, method])
87
+
88
+ if method(method_alias.to_sym).arity == 0
89
+ return send(method_alias)
90
+ else
91
+ return send(method_alias, *args)
92
+ end
93
+ end
94
+ end
95
+
96
+ meta_def method, &behavior
97
+ end
98
+
99
+ def proxy_missing_method(method, options = {}, &block)
100
+ behavior = if options[:return]
101
+ lambda do |*args|
102
+ Stump::Mocks.verify([self, method])
103
+
104
+ method_missing(method, args)
105
+ return options[:return]
106
+ end
107
+ else
108
+ lambda do |*args|
109
+ Stump::Mocks.verify([self, method])
110
+
111
+ method_missing(method, args)
112
+ end
113
+ end
114
+
115
+ meta_def method, &behavior
116
+ end
117
+ end
data/lib/stump/stub.rb ADDED
@@ -0,0 +1,34 @@
1
+ class Object
2
+ # Create a stub method on an object. Simply returns a value for a method call on
3
+ # an object.
4
+ #
5
+ # ==== Examples
6
+ #
7
+ # my_string = "a wooden rabbit"
8
+ # my_string.stub!(:retreat!, :return => "run away! run away!")
9
+ #
10
+ # # test/your_test.rb
11
+ # my_string.retreat! # => "run away! run away!"
12
+ #
13
+ def stub!(method, options = {}, &block)
14
+ behavior = (block_given? ? block : proc { return options[:return] })
15
+
16
+ meta_def method, &behavior
17
+ end
18
+ end
19
+
20
+ module Kernel
21
+ # Create a pure stub object.
22
+ #
23
+ # ==== Examples
24
+ #
25
+ # stubbalicious = stub(:failure, "wat u say?")
26
+ # stubbalicious.failure # => "wat u say?"
27
+ #
28
+ def stub(method, options = {}, &block)
29
+ stub_object = Object.new
30
+ stub_object.stub!(method, options, &block)
31
+
32
+ stub_object
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ module Stump
2
+ module Baconize
3
+ module ContextExtensions
4
+ def self.included(base)
5
+ base.class_eval do
6
+ alias_method :it_without_mock_verification, :it
7
+ alias_method :it, :it_with_mock_verification
8
+ end
9
+ end
10
+
11
+ def verify_mocks
12
+ if !Stump::Mocks.failures.nil? && !Stump::Mocks.failures.empty?
13
+ fails = Stump::Mocks.failures.map {|object, method| "#{object.inspect} expected #{method}"}.join(", ")
14
+ should.flunk "Unmet expectations: #{fails}"
15
+ end
16
+ end
17
+
18
+ def it_with_mock_verification(description, &block)
19
+ @after << proc { verify_mocks }
20
+ it_without_mock_verification(description, &block)
21
+ ensure
22
+ Stump::Mocks.clear!
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ begin
29
+ Bacon::Context.class_eval { include Stump::Baconize::ContextExtensions }
30
+ rescue LoadError
31
+ puts 'Bacon is not available.'
32
+ end
@@ -0,0 +1,3 @@
1
+ module Stump
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path('../lib/stump/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ["Francis Chong"]
5
+ gem.email = ["francis@ignition.hk"]
6
+ gem.description = "Stubbing and mocking for RubyMotion"
7
+ gem.summary = "Stubbing and mocking for RubyMotion"
8
+ gem.homepage = "https://github.com/siuying/motion-stump"
9
+
10
+ gem.files = `git ls-files`.split($\)
11
+ gem.test_files = gem.files.grep(%r{^(test|spec|lib_spec|features)/})
12
+ gem.name = "motion-stump"
13
+ gem.require_paths = ["lib"]
14
+ gem.version = Stump::VERSION
15
+
16
+ gem.add_dependency 'motion-define-method', '~> 0.1.2'
17
+ gem.add_development_dependency 'motion-redgreen'
18
+ gem.add_development_dependency 'rake'
19
+ end
data/spec/main_spec.rb ADDED
@@ -0,0 +1,44 @@
1
+ describe "Application 'stump-test'" do
2
+ class Hello
3
+ end
4
+
5
+ it "stub on object" do
6
+ Hello.stub!(:thing, :return => "hey!")
7
+ Hello.should.not.be.nil
8
+ Hello.thing.should == "hey!"
9
+
10
+ my_obj = Object.new
11
+ my_obj.stub!(:hello)
12
+ my_obj.hello.should.be.nil
13
+ end
14
+
15
+ it "should create pure stub" do
16
+ my_stub = stub(:thing, :return => "dude, a thing!")
17
+ my_stub.thing.should == "dude, a thing!"
18
+ end
19
+
20
+ it "should mock object" do
21
+ my_object = "things are fun"
22
+ my_object.mock!(:fancy, :return => "ooo fancy!")
23
+ my_object.mock!(:tancy, :return => "ooo tancy!")
24
+ my_object.fancy.should == 'ooo fancy!'
25
+ end
26
+
27
+ # it "should create pure mock" do
28
+ # my_mock = mock(:hello, :return => "what fun is this?")
29
+ # my_mock.hello.should == "what fun is this?"
30
+ # end
31
+
32
+ # class Greeting
33
+ # def bonjour
34
+ # "Bonjour!"
35
+ # end
36
+ # end
37
+
38
+ # it "should use proxy objects" do
39
+ # greet_me = Greeting.new
40
+ # greet_me.proxy!(:bonjour)
41
+ # greet_me.bonjour # => "Bonjour!"
42
+ # end
43
+
44
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: motion-stump
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Francis Chong
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: motion-define-method
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.1.2
30
+ - !ruby/object:Gem::Dependency
31
+ name: motion-redgreen
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Stubbing and mocking for RubyMotion
63
+ email:
64
+ - francis@ignition.hk
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - History.txt
72
+ - License.txt
73
+ - README.md
74
+ - Rakefile
75
+ - app/app_delegate.rb
76
+ - lib/motion-stump.rb
77
+ - lib/stump/metaid.rb
78
+ - lib/stump/mock.rb
79
+ - lib/stump/mocks.rb
80
+ - lib/stump/proxy.rb
81
+ - lib/stump/stub.rb
82
+ - lib/stump/stump_spec_helper.rb
83
+ - lib/stump/version.rb
84
+ - motion-stump.gemspec
85
+ - spec/main_spec.rb
86
+ homepage: https://github.com/siuying/motion-stump
87
+ licenses: []
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ segments:
99
+ - 0
100
+ hash: 731758381242350488
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ segments:
108
+ - 0
109
+ hash: 731758381242350488
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 1.8.24
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: Stubbing and mocking for RubyMotion
116
+ test_files:
117
+ - spec/main_spec.rb