contextr 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +2 -0
- data/COPYING.txt +340 -0
- data/History.txt +11 -0
- data/LICENSE.txt +58 -0
- data/Manifest.txt +8 -8
- data/README.txt +15 -2
- data/examples/README +9 -0
- data/lib/contextr/class_methods.rb +23 -4
- data/lib/contextr/core_ext/module.rb +48 -9
- data/lib/contextr/core_ext/object.rb +68 -1
- data/lib/contextr/event_machine.rb +1 -1
- data/lib/contextr/layer.rb +5 -3
- data/lib/contextr/modules/mutex_code.rb +1 -1
- data/lib/contextr/modules/unique_id.rb +1 -1
- data/lib/contextr/public_api.rb +17 -15
- data/lib/contextr/version.rb +1 -1
- data/lib/ext/active_support_subset.rb +86 -4
- data/lib/ext/dynamic.rb +2 -1
- data/spec/contextr_spec.rb +211 -6
- data/spec/spec_helper.rb +1 -0
- data/test/test_class_side.rb +225 -0
- data/test/test_contextr.rb +19 -11
- data/test/test_dynamics.rb +207 -0
- data/test/test_helper.rb +55 -0
- data/test/test_introduction.rb +311 -0
- data/test/test_layer_state.rb +178 -0
- data/test/test_ordering.rb +146 -0
- metadata +39 -12
- metadata.gz.sig +0 -0
- data/License.txt +0 -20
- data/examples/general.rb +0 -152
- data/examples/ordering.rb +0 -29
- data/website/index.html +0 -116
- data/website/index.txt +0 -61
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -138
- data/website/template.rhtml +0 -48
@@ -0,0 +1,178 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/test_helper.rb"
|
2
|
+
|
3
|
+
test_class(:TestLayerState)
|
4
|
+
|
5
|
+
# One of the most frequent examples for the use of aspect oriented programming
|
6
|
+
# is caching. You have a method, that takes some time to compute a result,
|
7
|
+
# but the result is always the same, if the parameters are the same. Such
|
8
|
+
# methods are often called functions. The have no side effects and do not depend
|
9
|
+
# on inner state.
|
10
|
+
#
|
11
|
+
# Perhaps you would like to attach caching to such functions. But only under
|
12
|
+
# certain circumstances. If your application lacks time, it is a good idea to
|
13
|
+
# activate result caching. If it lacks memory, it is a bad one.
|
14
|
+
#
|
15
|
+
# This perfectly sounds like a problem, that can be solved using
|
16
|
+
# context-oriented programming.
|
17
|
+
#
|
18
|
+
# But for caching, we need a place to store the computed results. One could
|
19
|
+
# store them in the instance that computes them, but this would be strange,
|
20
|
+
# because, the code residing in it does not make direct use of this state.
|
21
|
+
# Perhaps we are using variables, that other methods use for their own
|
22
|
+
# purpose and this would result in strange results. We could use cryptic
|
23
|
+
# instance variable names, but all this is just a workaround.
|
24
|
+
#
|
25
|
+
# What we want is to attach the state to the code, that uses it. This is the
|
26
|
+
# main idea of object-oriented design anyway. So ContextR gives you the
|
27
|
+
# opportunity to save state inside your method modules. Code and state stay
|
28
|
+
# side by side. This state will reside there even after deactivating the
|
29
|
+
# layer, so you can reuse it. Perfect for our caching approach.
|
30
|
+
|
31
|
+
|
32
|
+
# Fibonacci numbers
|
33
|
+
# =================
|
34
|
+
|
35
|
+
# We will use the good old Fibonacci numbers to demonstrate our approach. First
|
36
|
+
# the simple recursive computation, that becomes really slow for larger numbers.
|
37
|
+
# I know that there is a non-recursive algorithm, working faster, but this
|
38
|
+
# would not make such a good example. So just assume, that the following
|
39
|
+
# code is the fastest, you could possibly get.
|
40
|
+
|
41
|
+
module Fibonacci
|
42
|
+
module ClassMethods
|
43
|
+
def compute(fixnum)
|
44
|
+
if fixnum == 1 or fixnum == 0
|
45
|
+
fixnum
|
46
|
+
elsif fixnum < 0
|
47
|
+
raise ArgumentError, "Fibonacci not defined for negative numbers"
|
48
|
+
else
|
49
|
+
compute(fixnum - 1) + compute(fixnum - 2)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
self.extend(ClassMethods)
|
54
|
+
end
|
55
|
+
|
56
|
+
example do
|
57
|
+
result_of(Fibonacci.compute(1)) == 1
|
58
|
+
result_of(Fibonacci.compute(2)) == 1
|
59
|
+
result_of(Fibonacci.compute(3)) == 2
|
60
|
+
end
|
61
|
+
|
62
|
+
# Just to make sure, that it is slow, I will try to compute Fib(100)
|
63
|
+
|
64
|
+
require 'timeout'
|
65
|
+
example do
|
66
|
+
timeout_raised = false
|
67
|
+
begin
|
68
|
+
Timeout::timeout(0.05) do
|
69
|
+
Fibonacci.compute(100)
|
70
|
+
end
|
71
|
+
|
72
|
+
rescue Timeout::Error
|
73
|
+
timeout_raised = true
|
74
|
+
end
|
75
|
+
|
76
|
+
result_of(timeout_raised) == true
|
77
|
+
end
|
78
|
+
|
79
|
+
# Okay, the 0.01 seconds are really impatient, but I know, that caching will
|
80
|
+
# come to rescue and makes it happen.
|
81
|
+
#
|
82
|
+
# Let's define a simple caching method. If I already know the result, return
|
83
|
+
# it, if not, let the base implementation compute it and save the it into
|
84
|
+
# our variable.
|
85
|
+
|
86
|
+
module Fibonacci
|
87
|
+
module ClassMethods
|
88
|
+
module CacheMethods
|
89
|
+
def cache
|
90
|
+
@cache ||= {}
|
91
|
+
end
|
92
|
+
|
93
|
+
def compute(fixnum)
|
94
|
+
cache[fixnum] ||= yield(:next, fixnum)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
extend ClassMethods::CacheMethods => :cache
|
100
|
+
end
|
101
|
+
|
102
|
+
# If you are not familiar with the above syntax, to define context dependent
|
103
|
+
# behaviour, have a look at test_class_side.rb.
|
104
|
+
#
|
105
|
+
# Now let's compute Fib(100) again. Of course with caching enabled
|
106
|
+
|
107
|
+
example do
|
108
|
+
timeout_raised = false
|
109
|
+
begin
|
110
|
+
Timeout::timeout(0.05) do
|
111
|
+
ContextR::with_layer :cache do
|
112
|
+
result_of(Fibonacci.compute(100)) == 354_224_848_179_261_915_075
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
rescue Timeout::Error
|
117
|
+
timeout_raised = true
|
118
|
+
end
|
119
|
+
|
120
|
+
# This time the time out was not triggered
|
121
|
+
result_of(timeout_raised) == false
|
122
|
+
end
|
123
|
+
|
124
|
+
# It is that simple to add state to your method modules. And just to make sure,
|
125
|
+
# that I did not cheat, I will add a simple case, were instance variables and
|
126
|
+
# layer specific variables _would_ conflict, but in fact don't.
|
127
|
+
|
128
|
+
class LayerStateExample
|
129
|
+
attr_accessor :state
|
130
|
+
module StateMethods
|
131
|
+
attr_accessor :state
|
132
|
+
end
|
133
|
+
|
134
|
+
include StateMethods => :test_layer_state
|
135
|
+
end
|
136
|
+
|
137
|
+
# When StateMethods would be included normally, its attr_accessor would simply
|
138
|
+
# be the same as in the class. But this does not happen, when using layers.
|
139
|
+
#
|
140
|
+
# Let's do a little warm up and make sure, everything works as expected.
|
141
|
+
|
142
|
+
$layer_state_example = LayerStateExample.new
|
143
|
+
|
144
|
+
example do
|
145
|
+
$layer_state_example.state = true
|
146
|
+
result_of($layer_state_example.state) == true
|
147
|
+
$layer_state_example.state = false
|
148
|
+
result_of($layer_state_example.state) == false
|
149
|
+
|
150
|
+
ContextR::with_layer :test_layer_state do
|
151
|
+
$layer_state_example.state = true
|
152
|
+
result_of($layer_state_example.state) == true
|
153
|
+
$layer_state_example.state = false
|
154
|
+
result_of($layer_state_example.state) == false
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Until now, I did not prove anything. Let's try it.
|
159
|
+
|
160
|
+
example do
|
161
|
+
# Set the state
|
162
|
+
$layer_state_example.state = true
|
163
|
+
ContextR::with_layer :test_layer_state do
|
164
|
+
$layer_state_example.state = false
|
165
|
+
end
|
166
|
+
|
167
|
+
# And make sure, that they differ
|
168
|
+
result_of($layer_state_example.state) == true
|
169
|
+
|
170
|
+
ContextR::with_layer :test_layer_state do
|
171
|
+
result_of($layer_state_example.state) == false
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# The last example was very theoretical and looks strange when seen isolated.
|
176
|
+
# Its main purpose is to show, that layer specific methods and base methods
|
177
|
+
# do not share their state, and that the layer specific state remains, also
|
178
|
+
# after layer deactivation. Don't take too serious.
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/test_helper.rb"
|
2
|
+
|
3
|
+
test_class(:TestOrdering)
|
4
|
+
|
5
|
+
# This document tries to demonstrate the invocation order within
|
6
|
+
# context-specific method calls. There are two cases where this is relevant:
|
7
|
+
# 1. There is more than one layer active, that extends the method.
|
8
|
+
# 2. There is more than one module in a single layer that extends the method.
|
9
|
+
#
|
10
|
+
# Unfortunately I could not find any relevant example that clearly demonstrates
|
11
|
+
# this behaviour. Therefore I will use foo bar code. But I think it is still
|
12
|
+
# easy to get the message.
|
13
|
+
|
14
|
+
# 1. Multiple active layers
|
15
|
+
# =========================
|
16
|
+
|
17
|
+
class OrderingTest
|
18
|
+
def test_method
|
19
|
+
"base_method"
|
20
|
+
end
|
21
|
+
|
22
|
+
module FooMethods
|
23
|
+
def test_method
|
24
|
+
"foo_before #{yield(:next)} foo_after"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
module BarMethods
|
28
|
+
def test_method
|
29
|
+
"bar_before #{yield(:next)} bar_after"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
include FooMethods => :foo
|
34
|
+
include BarMethods => :bar
|
35
|
+
end
|
36
|
+
|
37
|
+
# When multiple layers extend a single method, the order of activation
|
38
|
+
# determines the order of execution.
|
39
|
+
|
40
|
+
example do
|
41
|
+
instance = OrderingTest.new
|
42
|
+
result_of(instance.test_method) == "base_method"
|
43
|
+
|
44
|
+
ContextR::with_layer :foo do
|
45
|
+
result_of(instance.test_method) == "foo_before base_method foo_after"
|
46
|
+
end
|
47
|
+
ContextR::with_layer :bar do
|
48
|
+
result_of(instance.test_method) == "bar_before base_method bar_after"
|
49
|
+
end
|
50
|
+
|
51
|
+
ContextR::with_layer :bar, :foo do
|
52
|
+
result_of(instance.test_method) ==
|
53
|
+
"bar_before foo_before base_method foo_after bar_after"
|
54
|
+
end
|
55
|
+
|
56
|
+
ContextR::with_layer :bar do
|
57
|
+
ContextR::with_layer :foo do
|
58
|
+
result_of(instance.test_method) ==
|
59
|
+
"bar_before foo_before base_method foo_after bar_after"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
ContextR::with_layer :foo, :bar do
|
64
|
+
result_of(instance.test_method) ==
|
65
|
+
"foo_before bar_before base_method bar_after foo_after"
|
66
|
+
end
|
67
|
+
|
68
|
+
ContextR::with_layer :foo do
|
69
|
+
ContextR::with_layer :bar do
|
70
|
+
result_of(instance.test_method) ==
|
71
|
+
"foo_before bar_before base_method bar_after foo_after"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# As you can see, the innermost layer activation provides the innermost method
|
77
|
+
# definition. It is not important, whether the layers were activated at once
|
78
|
+
# or one after the other.
|
79
|
+
#
|
80
|
+
# Activating and already active layer may update the execution order. The outer
|
81
|
+
# activation is hidden, but is restored again after leaving the block.
|
82
|
+
|
83
|
+
example do
|
84
|
+
instance = OrderingTest.new
|
85
|
+
|
86
|
+
ContextR::with_layer :bar, :foo do
|
87
|
+
result_of(instance.test_method) ==
|
88
|
+
"bar_before foo_before base_method foo_after bar_after"
|
89
|
+
|
90
|
+
ContextR::with_layer :bar do
|
91
|
+
result_of(instance.test_method) ==
|
92
|
+
"foo_before bar_before base_method bar_after foo_after"
|
93
|
+
end
|
94
|
+
|
95
|
+
result_of(instance.test_method) ==
|
96
|
+
"bar_before foo_before base_method foo_after bar_after"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Multiple modules per layer and class
|
102
|
+
# ====================================
|
103
|
+
|
104
|
+
# It is also possible to have more than one module define the context-dependent
|
105
|
+
# behaviour of a class. In this case it may also happen, that multiple modules
|
106
|
+
# extend the same method definition.
|
107
|
+
#
|
108
|
+
# In this case we can reuse or already defined class and modules. This time
|
109
|
+
# we include them into the same layer and see what happens.
|
110
|
+
|
111
|
+
class OrderingTest
|
112
|
+
include FooMethods => :foo_bar
|
113
|
+
include BarMethods => :foo_bar
|
114
|
+
end
|
115
|
+
|
116
|
+
example do
|
117
|
+
instance = OrderingTest.new
|
118
|
+
result_of(instance.test_method) == "base_method"
|
119
|
+
|
120
|
+
ContextR::with_layer :foo_bar do
|
121
|
+
result_of(instance.test_method) ==
|
122
|
+
"bar_before foo_before base_method foo_after bar_after"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# This time the last inclusion defines the outermost method. This can be again
|
127
|
+
# changed. After repeating an inclusion the ordering is updated.
|
128
|
+
|
129
|
+
example do
|
130
|
+
class OrderingTest
|
131
|
+
include FooMethods => :foo_bar
|
132
|
+
end
|
133
|
+
|
134
|
+
instance = OrderingTest.new
|
135
|
+
result_of(instance.test_method) == "base_method"
|
136
|
+
|
137
|
+
ContextR::with_layer :foo_bar do
|
138
|
+
result_of(instance.test_method) ==
|
139
|
+
"foo_before bar_before base_method bar_after foo_after"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# These should be all case where ordering matters. If you are aware of the
|
144
|
+
# two basic rules, everything should work as expected. In an ideal world the
|
145
|
+
# the execution order would not be important. But hey, this is not the ideal
|
146
|
+
# world, so you better know.
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: contextr
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
7
|
-
date: 2007-09-
|
6
|
+
version: 0.1.1
|
7
|
+
date: 2007-09-16 00:00:00 +02:00
|
8
8
|
summary: The goal is to equip Ruby with an API to allow context-oriented programming.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -25,17 +25,39 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
25
25
|
platform: ruby
|
26
26
|
signing_key:
|
27
27
|
cert_chain:
|
28
|
+
- |
|
29
|
+
-----BEGIN CERTIFICATE-----
|
30
|
+
MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMQ0wCwYDVQQDDARydWJ5
|
31
|
+
MR0wGwYKCZImiZPyLGQBGRYNc2NobWlkdHdpc3NlcjESMBAGCgmSJomT8ixkARkW
|
32
|
+
AmRlMB4XDTA3MDkxNjEwMzkyN1oXDTA4MDkxNTEwMzkyN1owQjENMAsGA1UEAwwE
|
33
|
+
cnVieTEdMBsGCgmSJomT8ixkARkWDXNjaG1pZHR3aXNzZXIxEjAQBgoJkiaJk/Is
|
34
|
+
ZAEZFgJkZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOzbl83o33wh
|
35
|
+
veLMQ2JyEstgOulisHRBFpfbF9LbdavuS/EdoOUeEPkziWL/ZI0jvUo0MGmQ/8Of
|
36
|
+
F9DJbvNbhDdg0bK7BMe4R/I3Wpu49mX+7pOsdlC44nzJkVG1DQ67qWp6jx1zvDRc
|
37
|
+
iCoXaQKnROtsx6bCavVvm4P7XLrAQvs7l+1Ke5KLkXRtJ9xJWtAyBLRFoM4e6DeT
|
38
|
+
Py0DsixF9Zb5Nrb7UvK0CN8m6dulsKXNRDVQLHkFa5Zg/BEb0RI93LPmeBt8KGIE
|
39
|
+
eYVjk+6z+py03D18xd9KsUhOB/0lC0a5vWSZIKfZnxf1uYY9TTZVqTGGUMFi1sD4
|
40
|
+
k2TYBqQVsS8CAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
|
41
|
+
BBYEFAeq4388e2PUlF/YeemzaY8neefWMA0GCSqGSIb3DQEBBQUAA4IBAQAArQQo
|
42
|
+
3teQbCcYmZFTrdOzujMca6F4JVzTp+yTnOsp1/5hiBEUMc3GreCVAPh2tU9+IpuB
|
43
|
+
Lif+s5nLfYdI+JrpCHDzm+ecJEJ7u7gxidzUwEBPYpVuU32ALge7fuWWhQfi29JY
|
44
|
+
QwNZgIkGe34z3a2+r2GLBns/GY7t0Lomv6U2SvwLreLc8g7thr2hZfgEJidvcrJR
|
45
|
+
Q6amsFqY06NalH+I175Bp4y9rR7IArgNDS3I5Cly5/heVKK2SRm5Z+IACmKMxIXh
|
46
|
+
hzBK8YDsrjUvPNIJn9yl0LeEsZ5VhupI2OXr6Cqa/tVMJq0oiTsLfel3Tsb9Ph83
|
47
|
+
y3O9DT3o4BiyPe77
|
48
|
+
-----END CERTIFICATE-----
|
49
|
+
|
28
50
|
post_install_message:
|
29
51
|
authors:
|
30
52
|
- Gregor Schmidt
|
31
53
|
files:
|
54
|
+
- COPYING.txt
|
32
55
|
- History.txt
|
33
|
-
-
|
56
|
+
- LICENSE.txt
|
34
57
|
- Manifest.txt
|
35
58
|
- README.txt
|
36
59
|
- Rakefile
|
37
|
-
- examples/
|
38
|
-
- examples/ordering.rb
|
60
|
+
- examples/README
|
39
61
|
- lib/contextr.rb
|
40
62
|
- lib/contextr/class_methods.rb
|
41
63
|
- lib/contextr/core_ext.rb
|
@@ -54,25 +76,30 @@ files:
|
|
54
76
|
- spec/contextr_spec.rb
|
55
77
|
- spec/spec.opts
|
56
78
|
- spec/spec_helper.rb
|
79
|
+
- test/test_class_side.rb
|
57
80
|
- test/test_contextr.rb
|
81
|
+
- test/test_dynamics.rb
|
58
82
|
- test/test_helper.rb
|
59
|
-
-
|
60
|
-
-
|
61
|
-
-
|
62
|
-
- website/stylesheets/screen.css
|
63
|
-
- website/template.rhtml
|
83
|
+
- test/test_introduction.rb
|
84
|
+
- test/test_layer_state.rb
|
85
|
+
- test/test_ordering.rb
|
64
86
|
test_files:
|
87
|
+
- test/test_class_side.rb
|
65
88
|
- test/test_contextr.rb
|
89
|
+
- test/test_dynamics.rb
|
66
90
|
- test/test_helper.rb
|
91
|
+
- test/test_introduction.rb
|
92
|
+
- test/test_layer_state.rb
|
93
|
+
- test/test_ordering.rb
|
67
94
|
rdoc_options:
|
68
95
|
- --main
|
69
96
|
- README.txt
|
70
97
|
extra_rdoc_files:
|
98
|
+
- COPYING.txt
|
71
99
|
- History.txt
|
72
|
-
-
|
100
|
+
- LICENSE.txt
|
73
101
|
- Manifest.txt
|
74
102
|
- README.txt
|
75
|
-
- website/index.txt
|
76
103
|
executables: []
|
77
104
|
|
78
105
|
extensions: []
|
metadata.gz.sig
ADDED
Binary file
|
data/License.txt
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
Copyright (c) 2007 FIXME full name
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/examples/general.rb
DELETED
@@ -1,152 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + "/../lib/contextr.rb"
|
2
|
-
|
3
|
-
module Common
|
4
|
-
module AddressMethods
|
5
|
-
def to_s
|
6
|
-
[yield(:next), yield(:receiver).address].join("; ")
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class Student < Struct.new(:first_name, :last_name, :address, :university)
|
12
|
-
def to_s
|
13
|
-
[first_name, last_name].join(" ")
|
14
|
-
end
|
15
|
-
|
16
|
-
module EducationMethods
|
17
|
-
def to_s
|
18
|
-
[yield(:next), yield(:receiver).university].join("; ")
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
include Common
|
23
|
-
include EducationMethods => :education
|
24
|
-
include AddressMethods => :address
|
25
|
-
end
|
26
|
-
|
27
|
-
class University < Struct.new(:name, :address)
|
28
|
-
def to_s
|
29
|
-
name
|
30
|
-
end
|
31
|
-
|
32
|
-
include Common
|
33
|
-
include AddressMethods => :address
|
34
|
-
end
|
35
|
-
|
36
|
-
module Fibonacci
|
37
|
-
module ClassMethods
|
38
|
-
def compute(fixnum)
|
39
|
-
if fixnum == 1 or fixnum == 0
|
40
|
-
fixnum
|
41
|
-
elsif fixnum < 0
|
42
|
-
raise ArgumentError, "Fibonacci not defined for negative numbers"
|
43
|
-
else
|
44
|
-
compute(fixnum - 1) + compute(fixnum - 2)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
module LoggingMethods
|
49
|
-
def compute(fixnum)
|
50
|
-
print "."
|
51
|
-
yield(:next, fixnum)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
module CacheMethods
|
56
|
-
def cache
|
57
|
-
@cache ||={}
|
58
|
-
end
|
59
|
-
|
60
|
-
def compute(fixnum)
|
61
|
-
cache[fixnum] ||= yield(:next, fixnum)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
self.extend(ClassMethods)
|
67
|
-
include :class_side => true,
|
68
|
-
ClassMethods::CacheMethods => :cache,
|
69
|
-
ClassMethods::LoggingMethods => :logging
|
70
|
-
end
|
71
|
-
|
72
|
-
puts
|
73
|
-
puts "Example on Instance Side"
|
74
|
-
module Example
|
75
|
-
module ClassMethods
|
76
|
-
def show
|
77
|
-
me = Student.new("Gregor", "Schmidt", "Berlin")
|
78
|
-
hpi = University.new("HPI", "Potsdam")
|
79
|
-
me.university = hpi
|
80
|
-
print(me)
|
81
|
-
end
|
82
|
-
|
83
|
-
def print(me)
|
84
|
-
puts me
|
85
|
-
with_addresses do
|
86
|
-
puts me
|
87
|
-
end
|
88
|
-
with_education do
|
89
|
-
puts me
|
90
|
-
end
|
91
|
-
with_education do
|
92
|
-
with_addresses do
|
93
|
-
puts me
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def with_addresses
|
99
|
-
ContextR::with_layers :address do
|
100
|
-
yield
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def with_education
|
105
|
-
ContextR::with_layers :education do
|
106
|
-
yield
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
self.extend(ClassMethods)
|
111
|
-
end
|
112
|
-
Example.show
|
113
|
-
|
114
|
-
puts
|
115
|
-
puts "Example with changed instance methods after behaviour registration"
|
116
|
-
class Student
|
117
|
-
def to_s
|
118
|
-
[first_name, last_name].reverse.join(", ")
|
119
|
-
end
|
120
|
-
end
|
121
|
-
Example.show
|
122
|
-
|
123
|
-
puts
|
124
|
-
puts "Example with changed behaviour methods after their registration"
|
125
|
-
module Student::EducationMethods
|
126
|
-
def to_s
|
127
|
-
[yield(:next), yield(:receiver).university].join("\n - ")
|
128
|
-
end
|
129
|
-
end
|
130
|
-
Example.show
|
131
|
-
|
132
|
-
puts
|
133
|
-
puts "Example on Class Side"
|
134
|
-
class ExampleClassSide
|
135
|
-
module ClassMethods
|
136
|
-
def show(int = 3)
|
137
|
-
puts Fibonacci.compute(int)
|
138
|
-
ContextR::with_layers :cache do
|
139
|
-
puts Fibonacci.compute(int)
|
140
|
-
end
|
141
|
-
ContextR::with_layers :logging do
|
142
|
-
puts Fibonacci.compute(2 * int)
|
143
|
-
|
144
|
-
ContextR::with_layers :cache do
|
145
|
-
puts Fibonacci.compute(2 * int)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
self.extend(ClassMethods)
|
151
|
-
end
|
152
|
-
ExampleClassSide.show
|