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.
- checksums.yaml +7 -0
- data/lib/aspeclib.rb +159 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -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
|
data/lib/aspeclib.rb
ADDED
@@ -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: []
|