Class: ASpec
- Inherits:
-
Object
- Object
- ASpec
- Defined in:
- lib/aspeclib.rb
Overview
ASpec is a simple library that utilizes aspect oriented programming and meta programming to enable stubing, method call counting, Liskov Substition Principle testing and more
Constant Summary collapse
- @@class_substitutions =
{}
Instance Attribute Summary collapse
-
#expected_method_call_arguments ⇒ Object
readonly
Returns the value of attribute expected_method_call_arguments.
-
#expected_method_call_counts ⇒ Object
readonly
Returns the value of attribute expected_method_call_counts.
-
#method_call_arguments ⇒ Object
readonly
Returns the value of attribute method_call_arguments.
-
#method_call_counts ⇒ Object
readonly
Returns the value of attribute method_call_counts.
-
#return_values ⇒ Object
readonly
Returns the value of attribute return_values.
Class Method Summary collapse
-
.class_substition(original_class) ⇒ Object
Get the name of the class that should be replacing the original class in LSP testing.
-
.define_new_method(replaced_class) ⇒ Object
Replaces the constructor of the given class with the one from the LSP class subsititutions list.
- .new ⇒ Object
-
.remove_new_method_from_class(class_name) ⇒ Object
Removes the arbitrary new constructor from the given class.
Instance Method Summary collapse
-
#count_method_calls(type, method, expected_count) ⇒ Object
Defines the expected count of method calls for the method in the type.
-
#execute ⇒ Object
Executes the given block If there are LSP substitutes defined, executes the block for each of them.
-
#expect_method_arguments(type, method, expected_arguments) ⇒ Object
Defines the expected method arguments for each of the method calls expected_arguments is a list of lists of arguments, e.g.
-
#initialize ⇒ ASpec
constructor
A new instance of ASpec.
-
#lsp(replaced_class, replacing_classes) ⇒ Object
Test Liskov Substition Principle Replaces the replaced_class with each of the replacing_classes during execution.
-
#raise_exception(type, method) ⇒ Object
Raises exception when the method of the type is called.
-
#return_value ⇒ Object
The first returned value from the execution.
-
#stub(type, method, &block) ⇒ Object
Replaces the method of the type with the given block.
Constructor Details
#initialize ⇒ ASpec
Returns a new instance of ASpec.
14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/aspeclib.rb', line 14 def initialize @replaced_class = '' @replacing_classes = [nil] @method_stubs = {} @aspects = [] @return_values = [] @method_call_counts = {} @expected_method_call_counts = {} @method_call_arguments = {} @expected_method_call_arguments = {} end |
Instance Attribute Details
#expected_method_call_arguments ⇒ Object (readonly)
Returns the value of attribute expected_method_call_arguments.
8 9 10 |
# File 'lib/aspeclib.rb', line 8 def expected_method_call_arguments @expected_method_call_arguments end |
#expected_method_call_counts ⇒ Object (readonly)
Returns the value of attribute expected_method_call_counts.
8 9 10 |
# File 'lib/aspeclib.rb', line 8 def expected_method_call_counts @expected_method_call_counts end |
#method_call_arguments ⇒ Object (readonly)
Returns the value of attribute method_call_arguments.
8 9 10 |
# File 'lib/aspeclib.rb', line 8 def method_call_arguments @method_call_arguments end |
#method_call_counts ⇒ Object (readonly)
Returns the value of attribute method_call_counts.
8 9 10 |
# File 'lib/aspeclib.rb', line 8 def method_call_counts @method_call_counts end |
#return_values ⇒ Object (readonly)
Returns the value of attribute return_values.
8 9 10 |
# File 'lib/aspeclib.rb', line 8 def return_values @return_values end |
Class Method Details
.class_substition(original_class) ⇒ Object
Get the name of the class that should be replacing the original class in LSP testing
27 28 29 |
# File 'lib/aspeclib.rb', line 27 def self.class_substition(original_class) return @@class_substitutions[original_class] end |
.define_new_method(replaced_class) ⇒ Object
Replaces the constructor of the given class with the one from the LSP class subsititutions list
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/aspeclib.rb', line 102 def self.define_new_method(replaced_class) def (eval(replaced_class)).new obj = nil if ASpec.class_substition(self.to_s).nil? the_ancestor = '' self.ancestors.each do |ancestor| unless ASpec.class_substition(ancestor.to_s).nil? the_ancestor = ancestor.to_s break end end ASpec.remove_new_method_from_class(the_ancestor) obj = self.new ASpec.define_new_method(the_ancestor) else ASpec.remove_new_method_from_class(self.to_s) obj = eval(ASpec.class_substition(self.to_s)).new ASpec.define_new_method(self.to_s) end obj end end |
.new ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/aspeclib.rb', line 103 def (eval(replaced_class)).new obj = nil if ASpec.class_substition(self.to_s).nil? the_ancestor = '' self.ancestors.each do |ancestor| unless ASpec.class_substition(ancestor.to_s).nil? the_ancestor = ancestor.to_s break end end ASpec.remove_new_method_from_class(the_ancestor) obj = self.new ASpec.define_new_method(the_ancestor) else ASpec.remove_new_method_from_class(self.to_s) obj = eval(ASpec.class_substition(self.to_s)).new ASpec.define_new_method(self.to_s) end obj end |
.remove_new_method_from_class(class_name) ⇒ Object
Removes the arbitrary new constructor from the given class
126 127 128 129 130 |
# File 'lib/aspeclib.rb', line 126 def self.remove_new_method_from_class(class_name) class <<(eval(class_name)) remove_method :new end end |
Instance Method Details
#count_method_calls(type, method, expected_count) ⇒ Object
Defines the expected count of method calls for the method in the type
73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/aspeclib.rb', line 73 def count_method_calls(type, method, expected_count) type, method, expected_count = type.to_s, method.to_s, expected_count.to_i (@expected_method_call_counts[type] ||= {})[method] = expected_count (@method_call_counts[type] ||= {})[method] = 0 aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args| @method_call_counts[object.class.to_s][join_point.method_name.to_s] += 1 end @aspects << aspect self end |
#execute ⇒ Object
Executes the given block If there are LSP substitutes defined, executes the block for each of them
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/aspeclib.rb', line 134 def execute @replacing_classes.each do |replacing_class| unless replacing_class.nil? @@class_substitutions[@replaced_class] = replacing_class ASpec.define_new_method(@replaced_class) end @return_values << yield ASpec.remove_new_method_from_class(@replaced_class) unless replacing_class.nil? end @aspects.each do |aspect| aspect.unadvise end @aspects.clear self end |
#expect_method_arguments(type, method, expected_arguments) ⇒ Object
Defines the expected method arguments for each of the method calls expected_arguments is a list of lists of arguments, e.g. [[call1_arg1, call1_arg2], [call2_arg1, call2_arg2]]
88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/aspeclib.rb', line 88 def expect_method_arguments(type, method, expected_arguments) type, method = type.to_s, method.to_s (@expected_method_call_arguments[type] ||= {})[method] = expected_arguments (@method_call_arguments[type] ||= {})[method] = [] aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args| (@method_call_arguments[object.class.to_s][join_point.method_name.to_s] ||= []) << args end @aspects << aspect self end |
#lsp(replaced_class, replacing_classes) ⇒ Object
Test Liskov Substition Principle Replaces the replaced_class with each of the replacing_classes during execution
33 34 35 36 37 38 39 40 41 |
# File 'lib/aspeclib.rb', line 33 def lsp(replaced_class, replacing_classes) @replaced_class = replaced_class.to_s @replacing_classes += if replacing_classes.class == Array replacing_classes.map {|item| item.to_s} else [replacing_classes.to_s] end self end |
#raise_exception(type, method) ⇒ Object
Raises exception when the method of the type is called
62 63 64 65 66 67 68 69 70 |
# File 'lib/aspeclib.rb', line 62 def raise_exception(type, method) type, method = type.to_s, method.to_s aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args| raise "ASpec doesn't like this at all." end @aspects << aspect self end |
#return_value ⇒ Object
The first returned value from the execution
156 157 158 |
# File 'lib/aspeclib.rb', line 156 def return_value @return_values.first end |
#stub(type, method, &block) ⇒ Object
Replaces the method of the type with the given block
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/aspeclib.rb', line 44 def stub(type, method, &block) type, method = type.to_s, method.to_s @method_stubs[[type, method]] = block aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args| key = [object.class.to_s, join_point.method_name.to_s] if @method_stubs.has_key? key @method_stubs[key].call else jp.proceed end end @aspects << aspect self end |