object_mock 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.
Files changed (4) hide show
  1. data/README.rdoc +97 -0
  2. data/lib/object_mock.rb +114 -0
  3. data/object_mock.gemspec +16 -0
  4. metadata +63 -0
data/README.rdoc ADDED
@@ -0,0 +1,97 @@
1
+ = Introduction
2
+
3
+ A group of methods added to Object class to enable simple mocking
4
+ of instance or class methods.
5
+ This mocking can be done temporarily within the scope of a block.
6
+ Alternatively it can be done indefinitely until explicitly undone.
7
+
8
+ = Object#mock
9
+
10
+ method for mocking or adding methods for a single object
11
+ (or class methods if the object is a class instance)
12
+ methods: a comma separated key value pairs
13
+ where the key is the name of the instance method to be mocked
14
+ and the value is the new definition in the form of a proc or lambda
15
+ or simply the required return for the mocked method
16
+ An optional block can passed so that the mocking is applied
17
+ only within the scope of the block
18
+
19
+ example usage:
20
+
21
+ d = Duck.new; p d.quack; p d.swim; p d.eat("fish")
22
+ # => "quack!" "swimming!" "yummy fish!!"
23
+ d.mock(:quack => "Haaahaa", :swim => "Tshhhhhhh") do
24
+ p d.quack; p d.swim
25
+ end
26
+ # => "Haaahaa" "Tshhhhhhh"
27
+ d.mock(:eat => lambda {|food| "No #{food}. Not hungry!!}) do
28
+ p d.eat("fish")
29
+ end
30
+ # => "No fish. Not hungry!!"
31
+ d.hi
32
+ # => NoMethodError: undefined method `hi'
33
+ d.mock(:hi => "Hi boss!!")
34
+ d.hi
35
+ # => "Hi boss!!"
36
+ p Duck.all; # => "quackwaaack waaack quaaaack!"
37
+ Duck.mock(:all => "Yeeeeeeeehaaaaaah")
38
+ p Duck.all
39
+ # => "Yeeeeeeeehaaaaaah"
40
+ Duck.unmock # => [:all]
41
+ p Duck.all; # => "quackwaaack waaack quaaaack!"
42
+
43
+ = Object#unmock
44
+
45
+ method for unmocking methods mocked by mock method
46
+ methods: a comma separated list of names of instance methods to be unmocked
47
+ when no methods are passed all mocked instance methods will be unmocked
48
+ returns: array of the names of methods unmocked
49
+
50
+ example usage:
51
+
52
+ d = Duck.new;
53
+ p d.quack; p d.swim # => "quack!" "swimming!"
54
+ d.mock(:quack => "Haaahaa", :swim => "Tshhhhhhh")
55
+ p d.quack; p d.swim # => "Haaahaa" "Tshhhhhhh"
56
+ d.unmock(:quack, :swim)
57
+ p d.quack; p d.swim # => "quack!" "swimming!"
58
+
59
+ = Object#class_mock
60
+
61
+ The same as mock methods but applies mocking for all instances of the class
62
+ This method can be either called on the class object or on any instance of the class
63
+
64
+ example usage:
65
+
66
+ p Duck.new.quack # => "quack!"
67
+ Duck.class_mock(:quack => "Haaahaa") do
68
+ p Duck.new.quack # => "Haaahaa"
69
+ end
70
+ p Duck.new.quack # => "quack!"
71
+
72
+ d = Duck.new
73
+ p d.swim # => "swimming!"
74
+ d.class_mock(:swim => "Tshhhhhhh") do
75
+ p Duck.new.swim; p d.swim # => "Tshhhhhhh" "Tshhhhhhh"
76
+ end
77
+ p Duck.new.swim # => "swimming!"
78
+
79
+ = Object#class_unmock
80
+
81
+ method for unmocking methods mocked using class_mock
82
+ This method can be either called on the class object or on any instance of the class
83
+ methods: a comma separated list of names of instance methods to be unmocked
84
+ when no methods are passed all mocked instance methods will be unmocked
85
+ returns: array of the names of methods unmocked
86
+
87
+ example:
88
+
89
+ d = Duck.new
90
+ p d.swim # => "swimming!"
91
+ d.class_mock(:swim => "Buckbuckbuck") do
92
+ p Duck.new.swim; p d.swim # => "Buckbuckbuck" "Buckbuckbuck"
93
+ Duck.class_unmock(:swim)
94
+ p Duck.new.swim; p d.swim # => "swimming!" "swimming!"
95
+
96
+
97
+
@@ -0,0 +1,114 @@
1
+ # A group of methods added to Object class to enable simple mocking
2
+ # of instance or class methods.
3
+ # This mocking can be done temporarily within the scope of a block.
4
+ # Alternatively it can be done indefinitely until explicitly undone.
5
+
6
+ class Object
7
+
8
+ # method for mocking or adding methods for a single object
9
+ # (or class methods if the object is a class instance)
10
+ # methods: a comma separated key value pairs
11
+ # where the key is the name of the instance method to be mocked
12
+ # and the value is the new definition in the form of a proc or lambda
13
+ # or simply the required return for the mocked method
14
+ # An optional block can passed so that the mocking is applied
15
+ # only within the scope of the block
16
+ def mock(methods)
17
+ do_mock(methods)
18
+ if block_given?
19
+ yield
20
+ unmock(*methods.keys)
21
+ end
22
+ end
23
+
24
+ # method for unmocking methods mocked by mock method
25
+ # methods: a comma separated list of names of instance methods to be unmocked
26
+ # when no methods are passed all mocked instance methods will be unmocked
27
+ # returns: array of the names of methods unmocked
28
+ def unmock(*methods)
29
+ do_unmock(methods)
30
+ end
31
+
32
+ # The same as mock methods but applies mocking for all instances of the class
33
+ # This method can be either called on the class object or on any instance of the class
34
+ def class_mock(methods, &block)
35
+ return self.class.class_mock(methods, &block) if !self.is_a?(Module)
36
+ do_mock(methods, :instance, lambda {|m| instance_methods.collect{|n| n.to_sym}.include?(m.to_sym)}, self)
37
+
38
+ if block
39
+ block.call
40
+ class_unmock(*methods.keys)
41
+ end
42
+
43
+ end
44
+
45
+ # method for unmocking methods mocked using class_mock
46
+ # This method can be either called on the class object or on any instance of the class
47
+ # methods: a comma separated list of names of instance methods to be unmocked
48
+ # when no methods are passed all mocked instance methods will be unmocked
49
+ # returns: array of the names of methods unmocked
50
+ def class_unmock(*methods)
51
+ return self.class.class_unmock(*methods) if !self.is_a?(Module)
52
+ do_unmock(methods, :instance, self)
53
+ end
54
+
55
+ private
56
+
57
+ def do_mock(methods, type = :singleton,
58
+ exists = lambda {|m| singleton_methods.collect{|n| n.to_sym}.include?(m.to_sym)},
59
+ object = (class << self; self; end))
60
+ backup_name = "@#{type.to_s}_backup"
61
+
62
+ backup = instance_variable_get(backup_name) || {}
63
+
64
+ methods.each do |name, result|
65
+ backup[name] = backup[name] || []
66
+
67
+ if exists.call(name)
68
+ original = "#{name}_#{backup[name].length}"
69
+ object.class_eval { alias_method original, name }
70
+ elsif
71
+ original = nil
72
+ end
73
+
74
+ backup[name] << original
75
+ t = result.respond_to?(:to_proc) ? result.to_proc : proc { result }
76
+ object.class_eval { define_method(name, t) }
77
+ end
78
+
79
+ instance_variable_set(backup_name, backup)
80
+ end
81
+
82
+ def do_unmock(methods, type = :singleton, object = (class << self; self; end))
83
+ unmocked = []
84
+ backup_name = "@#{type.to_s}_backup"
85
+ backup = instance_variable_get(backup_name)
86
+
87
+ if backup
88
+ methods = backup.keys if methods.empty?
89
+
90
+ methods.each do |name|
91
+ stack = backup[name]
92
+ if stack
93
+ if stack.last
94
+ object.class_eval do
95
+ alias_method name, stack.last
96
+ remove_method(stack.pop)
97
+ end
98
+ else
99
+ stack.pop
100
+ object.class_eval { remove_method(name) }
101
+ end
102
+ unmocked << name
103
+ backup.delete(name) if stack.empty?
104
+ end
105
+ end
106
+
107
+ instance_eval { remove_instance_variable(backup_name) } if backup.empty?
108
+ end
109
+
110
+ return unmocked
111
+ end
112
+
113
+ end
114
+
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "object_mock"
3
+ s.version = "0.1"
4
+ s.date = "2010-04-19"
5
+ s.summary = "A simple, flexible and reversible mocking solution"
6
+ s.email = "mohammed.shalaby@espace.com.eg"
7
+ s.homepage = "http://github.com/mshalaby/object_mock"
8
+ s.description = "A group of methods added to Object class to enable simple mocking of instance or class methods. This mocking can be done temporarily within the scope of a block. Alternatively it can be done indefinitely until explicitly undone."
9
+ s.has_rdoc = true
10
+ s.authors = ["Mohammed Shalaby"]
11
+ s.files = [
12
+ "object_mock.gemspec",
13
+ "README.rdoc",
14
+ "lib/object_mock.rb"
15
+ ]
16
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: object_mock
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Mohammed Shalaby
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-04-19 00:00:00 +02:00
17
+ default_executable:
18
+ dependencies: []
19
+
20
+ description: A group of methods added to Object class to enable simple mocking of instance or class methods. This mocking can be done temporarily within the scope of a block. Alternatively it can be done indefinitely until explicitly undone.
21
+ email: mohammed.shalaby@espace.com.eg
22
+ executables: []
23
+
24
+ extensions: []
25
+
26
+ extra_rdoc_files: []
27
+
28
+ files:
29
+ - object_mock.gemspec
30
+ - README.rdoc
31
+ - lib/object_mock.rb
32
+ has_rdoc: true
33
+ homepage: http://github.com/mshalaby/object_mock
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ requirements: []
56
+
57
+ rubyforge_project:
58
+ rubygems_version: 1.3.6
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: A simple, flexible and reversible mocking solution
62
+ test_files: []
63
+