contextr 0.1.0 → 0.1.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.
- 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
|