aspeclib 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/aspeclib.rb +159 -0
  3. metadata +44 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 544a8f45bd275c53849a5ee29c76d5ab4a89fda2
4
+ data.tar.gz: 2db22fb4882de4704f4a1f99b78b5fcc7acc93ea
5
+ SHA512:
6
+ metadata.gz: a13f828e996c9a434975f351482f7a3ef10e4de3d97a6dcd3635a06cb7a4613b9ff27d374dbfd961ec3b86e48e5e65f8a1d23c1985b6c7beece76caab7a9e129
7
+ data.tar.gz: b63999a5b91adcd5c76741ffa502d372948401de2be83a8142ccc4102d10495ae0164fc458af4d308c9789cf434e115575fb2b2fcd81b1d8864b128a8ef9a0b7
@@ -0,0 +1,159 @@
1
+ require 'aquarium'
2
+
3
+ include Aquarium::Aspects
4
+
5
+ ## ASpec is a simple library that utilizes aspect oriented programming and meta programming
6
+ ## to enable stubing, method call counting, Liskov Substition Principle testing and more
7
+ class ASpec
8
+ attr_reader :return_values,
9
+ :method_call_counts, :expected_method_call_counts,
10
+ :method_call_arguments, :expected_method_call_arguments
11
+
12
+ @@class_substitutions = {}
13
+
14
+ def initialize
15
+ @replaced_class = ''
16
+ @replacing_classes = [nil]
17
+ @method_stubs = {}
18
+ @aspects = []
19
+ @return_values = []
20
+ @method_call_counts = {}
21
+ @expected_method_call_counts = {}
22
+ @method_call_arguments = {}
23
+ @expected_method_call_arguments = {}
24
+ end
25
+
26
+ ## Get the name of the class that should be replacing the original class in LSP testing
27
+ def self.class_substition(original_class)
28
+ return @@class_substitutions[original_class]
29
+ end
30
+
31
+ ## Test Liskov Substition Principle
32
+ ## Replaces the replaced_class with each of the replacing_classes during execution
33
+ def lsp(replaced_class, replacing_classes)
34
+ @replaced_class = replaced_class.to_s
35
+ @replacing_classes += if replacing_classes.class == Array
36
+ replacing_classes.map {|item| item.to_s}
37
+ else
38
+ [replacing_classes.to_s]
39
+ end
40
+ self
41
+ end
42
+
43
+ ## Replaces the method of the type with the given block
44
+ def stub(type, method, &block)
45
+ type, method = type.to_s, method.to_s
46
+ @method_stubs[[type, method]] = block
47
+
48
+ aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args|
49
+ key = [object.class.to_s, join_point.method_name.to_s]
50
+ if @method_stubs.has_key? key
51
+ @method_stubs[key].call
52
+ else
53
+ jp.proceed
54
+ end
55
+ end
56
+
57
+ @aspects << aspect
58
+ self
59
+ end
60
+
61
+ ## Raises exception when the method of the type is called
62
+ def raise_exception(type, method)
63
+ type, method = type.to_s, method.to_s
64
+ aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args|
65
+ raise "ASpec doesn't like this at all."
66
+ end
67
+
68
+ @aspects << aspect
69
+ self
70
+ end
71
+
72
+ ## Defines the expected count of method calls for the method in the type
73
+ def count_method_calls(type, method, expected_count)
74
+ type, method, expected_count = type.to_s, method.to_s, expected_count.to_i
75
+ (@expected_method_call_counts[type] ||= {})[method] = expected_count
76
+ (@method_call_counts[type] ||= {})[method] = 0
77
+
78
+ aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args|
79
+ @method_call_counts[object.class.to_s][join_point.method_name.to_s] += 1
80
+ end
81
+
82
+ @aspects << aspect
83
+ self
84
+ end
85
+
86
+ ## Defines the expected method arguments for each of the method calls
87
+ ## expected_arguments is a list of lists of arguments, e.g. [[call1_arg1, call1_arg2], [call2_arg1, call2_arg2]]
88
+ def expect_method_arguments(type, method, expected_arguments)
89
+ type, method = type.to_s, method.to_s
90
+ (@expected_method_call_arguments[type] ||= {})[method] = expected_arguments
91
+ (@method_call_arguments[type] ||= {})[method] = []
92
+
93
+ aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args|
94
+ (@method_call_arguments[object.class.to_s][join_point.method_name.to_s] ||= []) << args
95
+ end
96
+
97
+ @aspects << aspect
98
+ self
99
+ end
100
+
101
+ ## Replaces the constructor of the given class with the one from the LSP class subsititutions list
102
+ def self.define_new_method(replaced_class)
103
+ def (eval(replaced_class)).new
104
+ obj = nil
105
+ if ASpec.class_substition(self.to_s).nil?
106
+ the_ancestor = ''
107
+ self.ancestors.each do |ancestor|
108
+ unless ASpec.class_substition(ancestor.to_s).nil?
109
+ the_ancestor = ancestor.to_s
110
+ break
111
+ end
112
+ end
113
+ ASpec.remove_new_method_from_class(the_ancestor)
114
+ obj = self.new
115
+ ASpec.define_new_method(the_ancestor)
116
+ else
117
+ ASpec.remove_new_method_from_class(self.to_s)
118
+ obj = eval(ASpec.class_substition(self.to_s)).new
119
+ ASpec.define_new_method(self.to_s)
120
+ end
121
+ obj
122
+ end
123
+ end
124
+
125
+ ## Removes the arbitrary new constructor from the given class
126
+ def self.remove_new_method_from_class(class_name)
127
+ class <<(eval(class_name))
128
+ remove_method :new
129
+ end
130
+ end
131
+
132
+ ## Executes the given block
133
+ ## If there are LSP substitutes defined, executes the block for each of them
134
+ def execute
135
+ @replacing_classes.each do |replacing_class|
136
+
137
+ unless replacing_class.nil?
138
+ @@class_substitutions[@replaced_class] = replacing_class
139
+ ASpec.define_new_method(@replaced_class)
140
+ end
141
+
142
+ @return_values << yield
143
+
144
+ ASpec.remove_new_method_from_class(@replaced_class) unless replacing_class.nil?
145
+ end
146
+
147
+ @aspects.each do |aspect|
148
+ aspect.unadvise
149
+ end
150
+ @aspects.clear
151
+
152
+ self
153
+ end
154
+
155
+ ## The first returned value from the execution
156
+ def return_value
157
+ @return_values.first
158
+ end
159
+ end
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aspeclib
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Matus Tomlein
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A helper for unit testing that utilizes AOP and metaprogramming
14
+ email: matus.tomlein@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/aspeclib.rb
20
+ homepage: https://github.com/matus-tomlein/ASpec
21
+ licenses:
22
+ - MIT
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubyforge_project:
40
+ rubygems_version: 2.0.6
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: ASpec
44
+ test_files: []