aspectual 0.1.0 → 0.9.0

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.
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/aspectual'
4
+
5
+ class KwargsTestClass
6
+ extend Aspectual
7
+
8
+ attr_reader :methods_called
9
+
10
+ def initialize
11
+ # This is to ensure that all methods are properly called within the
12
+ # context of the current instance of this object.
13
+ @methods_called = []
14
+ end
15
+
16
+ def kwarg_aspect_method(**kwargs)
17
+ methods_called << "kwarg_aspect_method_kwargs_#{kwargs.to_a.join('_')}"
18
+ self
19
+ end
20
+
21
+ def kwarg_around_aspect_method(**kwargs)
22
+ methods_called << "before_block_kwarg_around_aspect_method_kwargs_#{kwargs.to_a.join('_')}"
23
+ yield
24
+ methods_called << "after_block_kwarg_around_aspect_method_kwargs_#{kwargs.to_a.join('_')}"
25
+ self
26
+ end
27
+
28
+ aspects before: :kwarg_aspect_method
29
+ def before_kwarg_test_method(**kwargs)
30
+ methods_called << "before_kwarg_test_method_kwargs_#{kwargs.to_a.join('_')}"
31
+ self
32
+ end
33
+
34
+ aspects around: :kwarg_around_aspect_method
35
+ def around_kwarg_test_method(**kwargs)
36
+ methods_called << "around_kwarg_test_method_kwargs_#{kwargs.to_a.join('_')}"
37
+ self
38
+ end
39
+
40
+ aspects after: :kwarg_aspect_method
41
+ def after_kwarg_test_method(**kwargs)
42
+ methods_called << "after_kwarg_test_method_kwargs_#{kwargs.to_a.join('_')}"
43
+ self
44
+ end
45
+ end
46
+
47
+ describe Aspectual do
48
+ describe 'methods with kwarg arguments' do
49
+ it 'can handle before aspects' do
50
+ test_instance = KwargsTestClass.new.before_kwarg_test_method(kwarg_1: :val_1, kwarg_2: :val_2)
51
+ expect(test_instance.methods_called).to eq(
52
+ %w[
53
+ kwarg_aspect_method_kwargs_kwarg_1_val_1_kwarg_2_val_2
54
+ before_kwarg_test_method_kwargs_kwarg_1_val_1_kwarg_2_val_2
55
+ ],
56
+ )
57
+ end
58
+
59
+ it 'can handle around aspects' do
60
+ test_instance = KwargsTestClass.new.around_kwarg_test_method(kwarg_1: :val_1, kwarg_2: :val_2)
61
+ expect(test_instance.methods_called).to eq(
62
+ %w[
63
+ before_block_kwarg_around_aspect_method_kwargs_kwarg_1_val_1_kwarg_2_val_2
64
+ around_kwarg_test_method_kwargs_kwarg_1_val_1_kwarg_2_val_2
65
+ after_block_kwarg_around_aspect_method_kwargs_kwarg_1_val_1_kwarg_2_val_2
66
+ ],
67
+ )
68
+ end
69
+
70
+ it 'can handle after aspects' do
71
+ test_instance = KwargsTestClass.new.after_kwarg_test_method(kwarg_1: :val_1, kwarg_2: :val_2)
72
+ expect(test_instance.methods_called).to eq(
73
+ %w[
74
+ after_kwarg_test_method_kwargs_kwarg_1_val_1_kwarg_2_val_2
75
+ kwarg_aspect_method_kwargs_kwarg_1_val_1_kwarg_2_val_2
76
+ ],
77
+ )
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/aspectual'
4
+
5
+ class NonWordEndingCharacterTestClass
6
+ extend Aspectual
7
+
8
+ attr_reader :methods_called
9
+
10
+ def initialize
11
+ # This is to ensure that all methods are properly called within the
12
+ # context of the current instance of this object.
13
+ @methods_called = []
14
+ end
15
+
16
+ def predicate_aspect_method?
17
+ methods_called << 'predicate_aspect_method?'
18
+ self
19
+ end
20
+
21
+ aspects before: :predicate_aspect_method?
22
+ def predicate_test_method
23
+ methods_called << 'predicate_test_method'
24
+ self
25
+ end
26
+
27
+ aspects before: :predicate_aspect_method?
28
+ def predicate_test_method?
29
+ methods_called << 'predicate_test_method?'
30
+ self
31
+ end
32
+
33
+ def bang_aspect_method!
34
+ methods_called << 'bang_aspect_method!'
35
+ self
36
+ end
37
+
38
+ aspects before: :bang_aspect_method!
39
+ def bang_test_method
40
+ methods_called << 'bang_test_method'
41
+ self
42
+ end
43
+
44
+ aspects before: :bang_aspect_method!
45
+ def bang_test_method!
46
+ methods_called << 'bang_test_method!'
47
+ self
48
+ end
49
+
50
+ def assign_aspect_method=
51
+ methods_called << 'assign_aspect_method='
52
+ end
53
+
54
+ aspects before: :assign_aspect_method=
55
+ def assign_test_method
56
+ methods_called << 'assign_test_method'
57
+ self
58
+ end
59
+
60
+ aspects before: :assign_aspect_method=
61
+ def assign_test_method=
62
+ methods_called << 'assign_test_method='
63
+ end
64
+ end
65
+
66
+ describe Aspectual do
67
+ describe 'methods ending in non-standard characters' do
68
+ describe 'predicate methods' do
69
+ it 'can handle predicate aspects' do
70
+ test_instance = NonWordEndingCharacterTestClass.new
71
+ test_instance.predicate_test_method
72
+ expect(test_instance.methods_called).to eq(%w[
73
+ predicate_aspect_method?
74
+ predicate_test_method
75
+ ])
76
+ end
77
+
78
+ it 'can handle predicate methods' do
79
+ test_instance = NonWordEndingCharacterTestClass.new
80
+ test_instance.predicate_test_method?
81
+ expect(test_instance.methods_called).to eq(%w[
82
+ predicate_aspect_method?
83
+ predicate_test_method?
84
+ ])
85
+ end
86
+ end
87
+
88
+ describe 'bang methods' do
89
+ it 'can handle bang aspects' do
90
+ test_instance = NonWordEndingCharacterTestClass.new
91
+ test_instance.bang_test_method
92
+ expect(test_instance.methods_called).to eq(%w[
93
+ bang_aspect_method!
94
+ bang_test_method
95
+ ])
96
+ end
97
+
98
+ it 'can handle bang methods' do
99
+ test_instance = NonWordEndingCharacterTestClass.new
100
+ test_instance.bang_test_method!
101
+ expect(test_instance.methods_called).to eq(%w[
102
+ bang_aspect_method!
103
+ bang_test_method!
104
+ ])
105
+ end
106
+ end
107
+
108
+ describe 'assign methods' do
109
+ it 'can handle assign aspects' do
110
+ test_instance = NonWordEndingCharacterTestClass.new
111
+ test_instance.assign_test_method
112
+ expect(test_instance.methods_called).to eq(%w[
113
+ assign_aspect_method=
114
+ assign_test_method
115
+ ])
116
+ end
117
+
118
+ it 'can handle assign methods' do
119
+ test_instance = NonWordEndingCharacterTestClass.new
120
+ test_instance.send(:assign_test_method=)
121
+ expect(test_instance.methods_called).to eq(%w[
122
+ assign_aspect_method=
123
+ assign_test_method=
124
+ ])
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/aspectual'
4
+
5
+ class PositionalArgsTestClass
6
+ extend Aspectual
7
+
8
+ attr_reader :methods_called
9
+
10
+ def initialize
11
+ # This is to ensure that all methods are properly called within the
12
+ # context of the current instance of this object.
13
+ @methods_called = []
14
+ end
15
+
16
+ def positional_aspect_method(*args)
17
+ methods_called << "positional_aspect_method_args_#{args.join('_')}"
18
+ self
19
+ end
20
+
21
+ def positional_around_aspect_method(*args)
22
+ methods_called << "before_block_positional_around_aspect_method_args_#{args.join('_')}"
23
+ yield
24
+ methods_called << "after_block_positional_around_aspect_method_args_#{args.join('_')}"
25
+ self
26
+ end
27
+
28
+ aspects before: :positional_aspect_method
29
+ def before_positional_test_method(*args)
30
+ methods_called << "before_positional_test_method_args_#{args.join('_')}"
31
+ self
32
+ end
33
+
34
+ aspects around: :positional_around_aspect_method
35
+ def around_positional_test_method(*args)
36
+ methods_called << "before_positional_test_method_args_#{args.join('_')}"
37
+ self
38
+ end
39
+
40
+ aspects after: :positional_aspect_method
41
+ def after_positional_test_method(*args)
42
+ methods_called << "after_positional_test_method_args_#{args.join('_')}"
43
+ self
44
+ end
45
+ end
46
+
47
+ describe Aspectual do
48
+ describe 'methods with positional arguments' do
49
+ it 'can handle before aspects' do
50
+ test_instance = PositionalArgsTestClass.new.before_positional_test_method('arg_1', 'arg_2')
51
+ expect(test_instance.methods_called).to eq(%w[
52
+ positional_aspect_method_args_arg_1_arg_2
53
+ before_positional_test_method_args_arg_1_arg_2
54
+ ])
55
+ end
56
+
57
+ it 'can handle around aspects' do
58
+ test_instance = PositionalArgsTestClass.new.around_positional_test_method('arg_1', 'arg_2')
59
+ expect(test_instance.methods_called).to eq(%w[
60
+ before_block_positional_around_aspect_method_args_arg_1_arg_2
61
+ before_positional_test_method_args_arg_1_arg_2
62
+ after_block_positional_around_aspect_method_args_arg_1_arg_2
63
+ ])
64
+ end
65
+
66
+ it 'can handle after aspects' do
67
+ test_instance = PositionalArgsTestClass.new.after_positional_test_method('arg_1', 'arg_2')
68
+ expect(test_instance.methods_called).to eq(%w[
69
+ after_positional_test_method_args_arg_1_arg_2
70
+ positional_aspect_method_args_arg_1_arg_2
71
+ ])
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/aspectual'
4
+
5
+ class ReturnValueTestClass
6
+ extend Aspectual
7
+
8
+ attr_reader :methods_called
9
+
10
+ def initialize
11
+ # This is to ensure that all methods are properly called within the
12
+ # context of the current instance of this object.
13
+ @methods_called = []
14
+ end
15
+
16
+ # These definitions could be looped over to make this class shorter, but the
17
+ # decision has been made to go for clarity over brevity.
18
+ def single_test_method
19
+ methods_called << 'single_test_method'
20
+ 'single_test_method'
21
+ end
22
+
23
+ def array_test_method_0
24
+ methods_called << 'array_test_method_0'
25
+ 'array_test_method_0'
26
+ end
27
+
28
+ def array_test_method_1
29
+ methods_called << 'array_test_method_1'
30
+ 'array_test_method_1'
31
+ end
32
+
33
+ def before_test_method_0
34
+ methods_called << 'before_test_method_0'
35
+ 'before_test_method_0'
36
+ end
37
+
38
+ def before_test_method_1
39
+ methods_called << 'before_test_method_1'
40
+ 'before_test_method_1'
41
+ end
42
+
43
+ def around_test_method_0
44
+ methods_called << 'before_block_around_aspect_method_0'
45
+ yield
46
+ methods_called << 'after_block_around_aspect_method_0'
47
+ end
48
+
49
+ def around_test_method_1
50
+ methods_called << 'before_block_around_aspect_method_1'
51
+ yield
52
+ methods_called << 'after_block_around_aspect_method_1'
53
+ end
54
+
55
+ def after_test_method_0
56
+ methods_called << 'after_test_method_0'
57
+ 'after_test_method_0'
58
+ end
59
+
60
+ def after_test_method_1
61
+ methods_called << 'after_test_method_1'
62
+ 'after_test_method_1'
63
+ end
64
+
65
+ aspects before: :single_test_method
66
+ def single_before_test_method
67
+ methods_called << 'single_before_test_method'
68
+ 'single_before_test_method'
69
+ end
70
+
71
+ aspects after: :single_test_method
72
+ def single_after_test_method
73
+ methods_called << 'single_after_test_method'
74
+ 'single_after_test_method'
75
+ end
76
+
77
+ aspects before: %i[array_test_method_0 array_test_method_1]
78
+ def array_before_test_method
79
+ methods_called << 'array_before_test_method'
80
+ 'array_before_test_method'
81
+ end
82
+
83
+ aspects before: :array_test_method_0
84
+ aspects before: :array_test_method_1
85
+ def multiple_before_test_method
86
+ methods_called << 'multiple_before_test_method'
87
+ 'multiple_before_test_method'
88
+ end
89
+
90
+ def specific_before_test_method
91
+ methods_called << 'specific_before_test_method'
92
+ 'specific_before_test_method'
93
+ end
94
+ aspects :specific_before_test_method, before: :single_test_method
95
+
96
+ aspects after: %i[array_test_method_0 array_test_method_1]
97
+ def array_after_test_method
98
+ methods_called << 'array_after_test_method'
99
+ 'array_after_test_method'
100
+ end
101
+
102
+ aspects after: :array_test_method_0
103
+ aspects after: :array_test_method_1
104
+ def multiple_after_test_method
105
+ methods_called << 'multiple_after_test_method'
106
+ 'multiple_after_test_method'
107
+ end
108
+
109
+ def specific_after_test_method
110
+ methods_called << 'specific_after_test_method'
111
+ 'specific_after_test_method'
112
+ end
113
+ aspects :specific_after_test_method, after: :single_test_method
114
+
115
+ aspects(
116
+ before: %i[before_test_method_0 before_test_method_1],
117
+ around: %i[around_test_method_0 around_test_method_1],
118
+ after: %i[after_test_method_0 after_test_method_1],
119
+ )
120
+ def before_and_after_aspects_test_method
121
+ methods_called << 'before_and_after_aspects_test_method'
122
+ 'before_and_after_aspects_test_method'
123
+ end
124
+ end
125
+
126
+ describe Aspectual do
127
+ describe 'before aspects do not change return value' do
128
+ it 'calls before aspect methods before the called method' do
129
+ test_instance = ReturnValueTestClass.new
130
+ result = test_instance.single_before_test_method
131
+ expect(result).to eq('single_before_test_method')
132
+ end
133
+
134
+ it 'can be defined for a specific method' do
135
+ test_instance = ReturnValueTestClass.new
136
+ result = test_instance.specific_before_test_method
137
+ expect(result).to eq('specific_before_test_method')
138
+ end
139
+
140
+ it 'allows multiple aspects to be declared' do
141
+ test_instance = ReturnValueTestClass.new
142
+ result = test_instance.array_before_test_method
143
+ expect(result).to eq('array_before_test_method')
144
+ end
145
+
146
+ it 'allows multiple aspects to be declared in separate calls' do
147
+ test_instance = ReturnValueTestClass.new
148
+ result = test_instance.multiple_before_test_method
149
+ expect(result).to eq('multiple_before_test_method')
150
+ end
151
+ end
152
+
153
+ describe 'after aspects do change return value' do
154
+ it 'calls before aspect methods before the called method' do
155
+ test_instance = ReturnValueTestClass.new
156
+ result = test_instance.single_after_test_method
157
+ expect(result).to eq('single_test_method')
158
+ end
159
+
160
+ it 'can be defined for a specific method' do
161
+ test_instance = ReturnValueTestClass.new
162
+ result = test_instance.specific_after_test_method
163
+ expect(result).to eq('single_test_method')
164
+ end
165
+
166
+ it 'allows multiple aspects to be declared' do
167
+ test_instance = ReturnValueTestClass.new
168
+ result = test_instance.array_after_test_method
169
+ expect(result).to eq('array_test_method_1')
170
+ end
171
+
172
+ it 'allows multiple aspects to be declared in separate calls' do
173
+ test_instance = ReturnValueTestClass.new
174
+ result = test_instance.multiple_after_test_method
175
+ expect(result).to eq('array_test_method_1')
176
+ end
177
+ end
178
+
179
+ describe 'mixed aspects' do
180
+ it 'calls all the aspect declarations in the correct order' do
181
+ test_instance = ReturnValueTestClass.new
182
+ result = test_instance.before_and_after_aspects_test_method
183
+ expect(result).to eq('after_test_method_1')
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/aspectual'
4
+
5
+ class ScopingTestClass
6
+ extend Aspectual
7
+
8
+ attr_reader :methods_called
9
+
10
+ def initialize
11
+ # This is to ensure that all methods are properly called within the
12
+ # context of the current instance of this object.
13
+ @methods_called = []
14
+ end
15
+
16
+ def public_aspect_method
17
+ methods_called << 'public_aspect_method'
18
+ self
19
+ end
20
+
21
+ aspects before: %i[
22
+ public_aspect_method
23
+ protected_aspect_method
24
+ private_aspect_method
25
+ ]
26
+
27
+ def public_method
28
+ methods_called << 'public_method'
29
+ self
30
+ end
31
+
32
+ aspects before: :protected_aspect_method
33
+ def test_protected_aspect_method
34
+ methods_called << 'protected_test_method'
35
+ self
36
+ end
37
+
38
+ aspects before: :private_aspect_method
39
+ def test_private_aspect_method
40
+ methods_called << 'private_test_method'
41
+ self
42
+ end
43
+
44
+ protected
45
+
46
+ def protected_aspect_method
47
+ methods_called << 'protected_aspect_method'
48
+ self
49
+ end
50
+
51
+ aspects before: %i[
52
+ public_aspect_method
53
+ protected_aspect_method
54
+ private_aspect_method
55
+ ]
56
+
57
+ def protected_method
58
+ methods_called << 'protected_method'
59
+ self
60
+ end
61
+
62
+ private
63
+
64
+ def private_aspect_method
65
+ methods_called << 'private_aspect_method'
66
+ self
67
+ end
68
+
69
+ aspects before: %i[
70
+ public_aspect_method
71
+ protected_aspect_method
72
+ private_aspect_method
73
+ ]
74
+
75
+ def private_method
76
+ methods_called << 'private_method'
77
+ self
78
+ end
79
+ end
80
+
81
+ describe Aspectual do
82
+ describe 'public methods' do
83
+ it 'can have varying accessibility aspects' do
84
+ test_instance = ScopingTestClass.new.public_method
85
+ expect(test_instance.methods_called).to eq(%w[
86
+ public_aspect_method
87
+ protected_aspect_method
88
+ private_aspect_method
89
+ public_method
90
+ ])
91
+ end
92
+
93
+ it 'stays public' do
94
+ test_instance = ScopingTestClass.new
95
+ expect(test_instance.public_methods).to include(:public_method)
96
+ end
97
+ end
98
+
99
+ describe 'protected methods' do
100
+ it 'can have varying accessibility aspects' do
101
+ test_instance = ScopingTestClass.new.send(:protected_method)
102
+ expect(test_instance.methods_called).to eq(%w[
103
+ public_aspect_method
104
+ protected_aspect_method
105
+ private_aspect_method
106
+ protected_method
107
+ ])
108
+ end
109
+
110
+ it 'stays protected' do
111
+ test_instance = ScopingTestClass.new
112
+ expect(test_instance.protected_methods).to include(:protected_method)
113
+ end
114
+ end
115
+
116
+ describe 'private methods' do
117
+ it 'can have varying accessibility aspects' do
118
+ test_instance = ScopingTestClass.new.send(:private_method)
119
+ expect(test_instance.methods_called).to eq(%w[
120
+ public_aspect_method
121
+ protected_aspect_method
122
+ private_aspect_method
123
+ private_method
124
+ ])
125
+ end
126
+
127
+ it 'stays private' do
128
+ test_instance = ScopingTestClass.new
129
+ expect(test_instance.private_methods).to include(:private_method)
130
+ end
131
+ end
132
+ end