aspeclib 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.
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: []