contextr 0.1.1 → 0.1.9
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 -2
- data/History.txt +8 -0
- data/Manifest.txt +15 -0
- data/Rakefile +2 -2
- data/lib/contextr.rb +2 -1
- data/lib/contextr/class_methods.rb +19 -15
- data/lib/contextr/core_ext/module.rb +18 -39
- data/lib/contextr/core_ext/object.rb +1 -68
- data/lib/contextr/event_machine.rb +3 -3
- data/lib/contextr/inner_class.rb +47 -0
- data/lib/contextr/layer.rb +62 -68
- data/lib/contextr/version.rb +1 -1
- data/lib/ext/dynamic.rb +2 -2
- data/spec/contextr_spec.rb +36 -30
- data/test/lib/example_test.rb +59 -0
- data/test/lib/literate_markaby_test.rb +97 -0
- data/test/lib/literate_maruku_test.rb +108 -0
- data/test/test_class_side.mkd +234 -0
- data/test/test_class_side.rb +1 -222
- data/test/test_contextr.rb +0 -12
- data/test/test_dynamic_scope.mkd +61 -0
- data/test/test_dynamic_scope.rb +4 -0
- data/test/test_dynamics.mkd +201 -0
- data/test/test_dynamics.rb +1 -204
- data/test/test_hello_world.mkd +70 -0
- data/test/test_hello_world.rb +4 -0
- data/test/test_helper.rb +4 -53
- data/test/test_introduction.mkd +325 -0
- data/test/test_introduction.rb +1 -308
- data/test/test_layer_state.mkd +170 -0
- data/test/test_layer_state.rb +1 -176
- data/test/test_meta_api.mkd +21 -0
- data/test/test_meta_api.rb +4 -0
- data/test/test_ordering.mkd +142 -0
- data/test/test_ordering.rb +1 -144
- metadata +65 -41
- metadata.gz.sig +0 -0
data/lib/contextr/version.rb
CHANGED
data/lib/ext/dynamic.rb
CHANGED
data/spec/contextr_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
2
|
|
3
3
|
module AddressMethods
|
4
4
|
def to_s
|
5
|
-
"#{
|
5
|
+
"#{super} (#{yield(:receiver).address})"
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
@@ -11,7 +11,9 @@ class University < Struct.new(:name, :address)
|
|
11
11
|
name
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
in_layer :address do
|
15
|
+
include AddressMethods
|
16
|
+
end
|
15
17
|
end
|
16
18
|
|
17
19
|
class Student < Struct.new(:name, :address, :education)
|
@@ -19,35 +21,35 @@ class Student < Struct.new(:name, :address, :education)
|
|
19
21
|
name
|
20
22
|
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
in_layer :address do
|
25
|
+
include AddressMethods
|
26
|
+
end
|
27
|
+
in_layer :education do
|
25
28
|
def to_s
|
26
|
-
"#{
|
29
|
+
"#{super}, #{yield(:receiver).education}"
|
27
30
|
end
|
28
31
|
end
|
29
|
-
|
30
|
-
include EducationMethods => :education
|
31
32
|
end
|
32
33
|
|
33
34
|
class Ordering
|
34
|
-
def
|
35
|
+
def inner_outer
|
35
36
|
"base"
|
36
37
|
end
|
37
38
|
|
38
39
|
module InnerMethods
|
39
|
-
def
|
40
|
-
"inner #{
|
40
|
+
def inner_outer
|
41
|
+
"inner #{super} inner"
|
41
42
|
end
|
42
43
|
end
|
43
|
-
include InnerMethods => :multiple_modules
|
44
|
-
|
45
44
|
module OuterMethods
|
46
|
-
def
|
47
|
-
"outer #{
|
45
|
+
def inner_outer
|
46
|
+
"outer #{super} outer"
|
48
47
|
end
|
49
48
|
end
|
50
|
-
|
49
|
+
in_layer :multiple_modules do
|
50
|
+
include InnerMethods
|
51
|
+
include OuterMethods
|
52
|
+
end
|
51
53
|
end
|
52
54
|
|
53
55
|
|
@@ -104,22 +106,26 @@ describe "A contextified object" do
|
|
104
106
|
|
105
107
|
it "should also activate multiple modules per layer" do
|
106
108
|
ContextR::with_layers :multiple_modules do
|
107
|
-
Ordering.new.
|
109
|
+
Ordering.new.inner_outer.should == "outer inner base inner outer"
|
108
110
|
end
|
109
111
|
end
|
110
112
|
|
111
113
|
it "should show new specific behaviour after changing module definitions" do
|
112
|
-
|
113
|
-
|
114
|
-
|
114
|
+
class Student
|
115
|
+
in_layer :education do
|
116
|
+
def to_s
|
117
|
+
"#{super} @ #{yield(:receiver).education}"
|
118
|
+
end
|
115
119
|
end
|
116
120
|
end
|
117
121
|
ContextR::with_layer :education do
|
118
122
|
@student.to_s.should == "Gregor Schmidt @ HPI"
|
119
123
|
end
|
120
|
-
|
121
|
-
|
122
|
-
|
124
|
+
class Student
|
125
|
+
in_layer :education do
|
126
|
+
def to_s
|
127
|
+
"#{super}, #{yield(:receiver).education}"
|
128
|
+
end
|
123
129
|
end
|
124
130
|
end
|
125
131
|
end
|
@@ -149,14 +155,13 @@ describe "A method modules defining context dependent behaviour" do
|
|
149
155
|
|
150
156
|
it "should have inner state" do
|
151
157
|
class Student
|
152
|
-
|
158
|
+
in_layer :log do
|
153
159
|
def to_s
|
154
160
|
@i ||= 0
|
155
161
|
@i += 1
|
156
|
-
"#{@i}: #{
|
162
|
+
"#{@i}: #{super}"
|
157
163
|
end
|
158
164
|
end
|
159
|
-
include LogMethods => :log
|
160
165
|
end
|
161
166
|
ContextR::with_layer :log do
|
162
167
|
@student.to_s.should == "1: Gregor Schmidt"
|
@@ -172,11 +177,11 @@ describe "A method modules defining context dependent behaviour" do
|
|
172
177
|
|
173
178
|
it "should not lose its state after redefinition of the module" do
|
174
179
|
class Student
|
175
|
-
|
180
|
+
in_layer :log do
|
176
181
|
def to_s
|
177
182
|
@i ||= 0
|
178
183
|
@i += 1
|
179
|
-
"(#{@i}) #{
|
184
|
+
"(#{@i}) #{super}"
|
180
185
|
end
|
181
186
|
end
|
182
187
|
end
|
@@ -210,7 +215,8 @@ describe "ContextR" do
|
|
210
215
|
end
|
211
216
|
|
212
217
|
it "should provide a method to query for all layers ever defined" do
|
213
|
-
|
214
|
-
|
218
|
+
[:address, :education, :log, :multiple_modules].each do |layer|
|
219
|
+
ContextR::layers.sort_by{ |s| s.to_s }.should include(layer)
|
220
|
+
end
|
215
221
|
end
|
216
222
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module ExampleTest
|
2
|
+
module ClassMethods
|
3
|
+
attr_accessor :latest_test_class
|
4
|
+
attr_accessor :latest_test_case
|
5
|
+
end
|
6
|
+
extend ClassMethods
|
7
|
+
|
8
|
+
module ObjectExtension
|
9
|
+
def test_class(name)
|
10
|
+
ExampleTest::latest_test_class = Class.new(Test::Unit::TestCase)
|
11
|
+
ExampleTest::latest_test_case = 0
|
12
|
+
Object.const_set(name, ExampleTest::latest_test_class)
|
13
|
+
end
|
14
|
+
|
15
|
+
def example(&block)
|
16
|
+
ExampleTest::latest_test_class.class_eval do
|
17
|
+
define_method("test_%03d" % (ExampleTest::latest_test_case += 1),
|
18
|
+
&block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module TestExtension
|
24
|
+
def assert_to_s(expected, actual)
|
25
|
+
assert_equal(expected, actual.to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
def result_of(object)
|
29
|
+
Result.new(object, self)
|
30
|
+
end
|
31
|
+
|
32
|
+
def output_of(object)
|
33
|
+
Output.new(object, self)
|
34
|
+
end
|
35
|
+
|
36
|
+
class Result
|
37
|
+
attr_accessor :object, :test_class
|
38
|
+
def initialize(object, test_class)
|
39
|
+
self.object = object
|
40
|
+
self.test_class = test_class
|
41
|
+
end
|
42
|
+
def ==(string)
|
43
|
+
test_class.assert_equal(string, object)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
class Output < Result
|
47
|
+
def ==(string)
|
48
|
+
test_class.assert_equal(string, object.to_s)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Test::Unit::TestCase
|
55
|
+
include ExampleTest::TestExtension
|
56
|
+
end
|
57
|
+
class Object
|
58
|
+
include ExampleTest::ObjectExtension
|
59
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'markaby'
|
2
|
+
if PLATFORM == "java"
|
3
|
+
class Markaby::Builder
|
4
|
+
def pre_block(block)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
else
|
8
|
+
require 'ruby2ruby'
|
9
|
+
end
|
10
|
+
|
11
|
+
module LiterateMarkabyTest
|
12
|
+
TARGET_DIR = File.dirname(__FILE__) + "/../../website/test/"
|
13
|
+
module ObjectExtension
|
14
|
+
def test(name, &block)
|
15
|
+
mab = Markaby::Builder.new
|
16
|
+
|
17
|
+
mab.test_class = Class.new(Test::Unit::TestCase)
|
18
|
+
mab.latest_test_case = 0
|
19
|
+
|
20
|
+
Object.const_set(name, mab.test_class)
|
21
|
+
mab.xhtml_strict do
|
22
|
+
head do
|
23
|
+
title { name }
|
24
|
+
end
|
25
|
+
body do
|
26
|
+
h1 { name }
|
27
|
+
div(&block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Dir.mkdir(TARGET_DIR) unless File.directory?(TARGET_DIR)
|
32
|
+
File.open(TARGET_DIR + name.to_s.underscore + ".html", "w") do |f|
|
33
|
+
f.puts mab.to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module MarkabyBuilderExtension
|
39
|
+
attr_accessor :test_class, :latest_test_case
|
40
|
+
def pre_block(block)
|
41
|
+
self.pre(block.to_ruby.gsub(/^proc \{\n(.*)\n\}$/m, '\1'))
|
42
|
+
end
|
43
|
+
|
44
|
+
def output(&block)
|
45
|
+
block.call
|
46
|
+
pre_block(block)
|
47
|
+
end
|
48
|
+
def example(&block)
|
49
|
+
name = "test_%03d" % (self.latest_test_case += 1)
|
50
|
+
test_class.class_eval do
|
51
|
+
define_method(name, &block)
|
52
|
+
end
|
53
|
+
pre_block(block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module TestExtension
|
58
|
+
def assert_to_s(expected, actual)
|
59
|
+
assert_equal(expected, actual.to_s)
|
60
|
+
end
|
61
|
+
|
62
|
+
def result_of(object)
|
63
|
+
Result.new(object, self)
|
64
|
+
end
|
65
|
+
|
66
|
+
def output_of(object)
|
67
|
+
Output.new(object, self)
|
68
|
+
end
|
69
|
+
|
70
|
+
class Result
|
71
|
+
attr_accessor :object, :test_class
|
72
|
+
def initialize(object, test_class)
|
73
|
+
self.object = object
|
74
|
+
self.test_class = test_class
|
75
|
+
end
|
76
|
+
def ==(string)
|
77
|
+
test_class.assert_equal(string, object)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
class Output < Result
|
81
|
+
def ==(string)
|
82
|
+
test_class.assert_equal(string, object.to_s)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
#class Test::Unit::TestCase
|
89
|
+
# include LiterateMarkabyTest::TestExtension
|
90
|
+
#end
|
91
|
+
class Object
|
92
|
+
include LiterateMarkabyTest::ObjectExtension
|
93
|
+
end
|
94
|
+
class Markaby::Builder
|
95
|
+
include LiterateMarkabyTest::MarkabyBuilderExtension
|
96
|
+
end
|
97
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
gem "literate_maruku"
|
2
|
+
require "literate_maruku"
|
3
|
+
require 'markaby'
|
4
|
+
require 'active_support'
|
5
|
+
|
6
|
+
class Fixnum
|
7
|
+
def ordinal
|
8
|
+
# teens
|
9
|
+
return 'th' if (10..19).include?(self % 100)
|
10
|
+
# others
|
11
|
+
case self % 10
|
12
|
+
when 1: return 'st'
|
13
|
+
when 2: return 'nd'
|
14
|
+
when 3: return 'rd'
|
15
|
+
else return 'th'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Time
|
21
|
+
def pretty
|
22
|
+
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module LiterateMarukuTest
|
27
|
+
BASE_DIR = File.dirname(__FILE__) + "/../"
|
28
|
+
TARGET_DIR = File.dirname(__FILE__) + "/../../website/test/"
|
29
|
+
|
30
|
+
def self.load(file)
|
31
|
+
content = LiterateMaruku.require(
|
32
|
+
BASE_DIR + "#{File.basename(file, '.rb')}.mkd",
|
33
|
+
:inline => true,
|
34
|
+
:attributes => {:execute => true})
|
35
|
+
|
36
|
+
download = "http://rubyforge.org/projects/contextr"
|
37
|
+
version = ContextR::VERSION::STRING
|
38
|
+
modified = Time.now
|
39
|
+
sub_title = File.basename(file, '.rb').gsub("test_", "").titleize
|
40
|
+
|
41
|
+
doc = Markaby::Builder.new.xhtml_strict do
|
42
|
+
head do
|
43
|
+
title "ContextR - #{sub_title} - Documentation"
|
44
|
+
link :href => "../stylesheets/screen.css", :rel=>'stylesheet',
|
45
|
+
:type=>'text/css', :media => "screen"
|
46
|
+
script :src => "../javascripts/rounded_corners_lite.inc.js",
|
47
|
+
:type =>"text/javascript"
|
48
|
+
script %Q{
|
49
|
+
window.onload = function() {
|
50
|
+
settings = {
|
51
|
+
tl: { radius: 10 },
|
52
|
+
tr: { radius: 10 },
|
53
|
+
bl: { radius: 10 },
|
54
|
+
br: { radius: 10 },
|
55
|
+
antiAlias: true,
|
56
|
+
autoPad: true,
|
57
|
+
validTags: ["div"]
|
58
|
+
}
|
59
|
+
var versionBox = new curvyCorners(settings,
|
60
|
+
document.getElementById("version"));
|
61
|
+
versionBox.applyCornersToAll();
|
62
|
+
}
|
63
|
+
}, :type => "text/javascript"
|
64
|
+
end
|
65
|
+
body do
|
66
|
+
div.main! do
|
67
|
+
h1 sub_title
|
68
|
+
div.version! :class => "clickable",
|
69
|
+
:onclick => "document.location='#{download}'; return false" do
|
70
|
+
p "Get Version"
|
71
|
+
a version, :href => download, :class => "numbers"
|
72
|
+
end
|
73
|
+
h1 do
|
74
|
+
self << "→ ‘"
|
75
|
+
a "contextr", :href => "http://contextr.rubyforge.org/"
|
76
|
+
self << "’"
|
77
|
+
end
|
78
|
+
|
79
|
+
ul.navi! do
|
80
|
+
Dir[File.dirname(file) + "/test_*.mkd"].each do |mkd_file_name|
|
81
|
+
li do
|
82
|
+
name = File.basename(mkd_file_name, ".mkd").gsub("test_", "")
|
83
|
+
a name.titleize, :href => name + ".html"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
self << content
|
89
|
+
p.coda do
|
90
|
+
text modified.pretty
|
91
|
+
br
|
92
|
+
text "Theme extended from "
|
93
|
+
a "Paul Battley", :href => "http://rb2js.rubyforge.org/"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
File.open(TARGET_DIR +
|
99
|
+
"#{File.basename(file, '.rb').gsub("test_", "")}.html", "w") do |f|
|
100
|
+
f.puts(%q{<!DOCTYPE html
|
101
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
102
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">})
|
103
|
+
doc.to_s.each do |chunk|
|
104
|
+
f.puts(chunk)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
**TODO: Update to use new in\_layer API**
|
2
|
+
|
3
|
+
In Ruby there are multiple ways of defining behaviour on the class side. That
|
4
|
+
are messages that are send to the class, not to the instance. Class side
|
5
|
+
behaviour is often useful for functional methods, i.e. methods that do not
|
6
|
+
rely on inner state and have no side effects. Mathematical functions have
|
7
|
+
these characteristics - that is where the name probably comes from.
|
8
|
+
|
9
|
+
**Note**: Java programmers may know these methods as static. It is similar but
|
10
|
+
not exactly the same.
|
11
|
+
|
12
|
+
|
13
|
+
Using `def self.method_name`
|
14
|
+
-----------------------------
|
15
|
+
|
16
|
+
The simpliest way of defining class side behaviour is prepending self. to the
|
17
|
+
method definition. This way, the method is attached to the surrounding class
|
18
|
+
and not instance. A simple example:
|
19
|
+
|
20
|
+
class SimpleMath
|
21
|
+
def self.pi
|
22
|
+
3.14159265
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
example do
|
27
|
+
result_of(SimpleMath.pi) == 3.14159265
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
Using `class << self`
|
32
|
+
---------------------
|
33
|
+
|
34
|
+
When you are having lots of class side methods as well as instance side ones,
|
35
|
+
it can be difficult to spot the little self. in front of the method name.
|
36
|
+
Probably you like to group them more explicitly. You could use Ruby's
|
37
|
+
eigenclass principle for that. It will look like the following:
|
38
|
+
|
39
|
+
class SimpleMath
|
40
|
+
class << self
|
41
|
+
def e
|
42
|
+
2.71828183
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
example do
|
48
|
+
result_of(SimpleMath.e) == 2.71828183
|
49
|
+
end
|
50
|
+
|
51
|
+
**Note**: Eigenclasses are also known as *singleton class* or *meta class*.
|
52
|
+
I prefer eigenclass, because it not used with different meanings in other
|
53
|
+
contexts, which eases talking about it with experts in different languages.
|
54
|
+
|
55
|
+
Using a module
|
56
|
+
--------------
|
57
|
+
|
58
|
+
For even more encapsulation you could also use modules and extend the class
|
59
|
+
definition with them. I am using extend here on purpose. Module's include
|
60
|
+
method adds the behaviour to the instance side, extend to the class side.
|
61
|
+
Or to rephrase it: Module's include method adds the behaviour to instances,
|
62
|
+
extend to the class itself.
|
63
|
+
|
64
|
+
class SimpleMath
|
65
|
+
module ClassMethods
|
66
|
+
def golden_ratio
|
67
|
+
1.6180339887
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
extend ClassMethods
|
72
|
+
end
|
73
|
+
|
74
|
+
example do
|
75
|
+
result_of(SimpleMath.golden_ratio) == 1.6180339887
|
76
|
+
end
|
77
|
+
|
78
|
+
The last method is e.g. used in the web framework Ruby on Rails. Often
|
79
|
+
a variation of it is used to define class and instance side behaviour for
|
80
|
+
mixin modules
|
81
|
+
|
82
|
+
module MathMixin
|
83
|
+
def counter
|
84
|
+
@counter ||= 0
|
85
|
+
@counter += 1
|
86
|
+
end
|
87
|
+
|
88
|
+
module ClassMethods
|
89
|
+
def sqrt(x)
|
90
|
+
x ** 0.5
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.included(base)
|
95
|
+
base.extend ClassMethods
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class SimpleMath
|
100
|
+
include MathMixin
|
101
|
+
end
|
102
|
+
|
103
|
+
example do
|
104
|
+
result_of(SimpleMath.sqrt(4)) == 2
|
105
|
+
|
106
|
+
my_simple_math = SimpleMath.new
|
107
|
+
result_of(my_simple_math.counter) == 1
|
108
|
+
result_of(my_simple_math.counter) == 2
|
109
|
+
end
|
110
|
+
|
111
|
+
This is regarded as the most elegant way of defining class and instance
|
112
|
+
methods for a mixin module. And the basic functionality is the same as in the
|
113
|
+
previous example.
|
114
|
+
|
115
|
+
After we now know how to define class side behaviour, everybody is curious
|
116
|
+
to know how to extend this behaviour using context-oriented programming and
|
117
|
+
ContextR.
|
118
|
+
|
119
|
+
Additionial, context-dependent behaviour is defined in `in_layer` blocks.
|
120
|
+
These are then attached to the layer, in which the behaviour should reside.
|
121
|
+
For examples on the instance side have a look at the bottom of
|
122
|
+
`test_introduction`.
|
123
|
+
|
124
|
+
Let's look how we can achieve the same on the class side for each of the
|
125
|
+
different methods of defining class side behaviour.
|
126
|
+
|
127
|
+
|
128
|
+
Using `def self.method_name`
|
129
|
+
----------------------------
|
130
|
+
|
131
|
+
**TODO: Allow def self.method\_name to add class side behaviour**
|
132
|
+
|
133
|
+
Okay, we won't get rid of the modules, used to encapsulate the
|
134
|
+
context-dependent behaviour, so the extension is a bit noisier, than the
|
135
|
+
basic notation.
|
136
|
+
|
137
|
+
class SimpleMath
|
138
|
+
class << self
|
139
|
+
in_layer :access_control do
|
140
|
+
def pi
|
141
|
+
"You are not allowed to access this method"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
But we can use the same principles, like we did for the instance side. Simply
|
148
|
+
use a hash to tell extend, that the module should only be used in a certain
|
149
|
+
layer.
|
150
|
+
|
151
|
+
example do
|
152
|
+
result_of(SimpleMath.pi) == 3.14159265
|
153
|
+
|
154
|
+
ContextR::with_layer :access_control do
|
155
|
+
result_of(SimpleMath.pi) == "You are not allowed to access this method"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
Using `class << self`
|
161
|
+
---------------------
|
162
|
+
|
163
|
+
When your using the eigenclass, you are able to use to good old in\_layer to
|
164
|
+
manage the extension.
|
165
|
+
|
166
|
+
class SimpleMath
|
167
|
+
class << self
|
168
|
+
in_layer :english do
|
169
|
+
def e
|
170
|
+
"Euler's constant"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class << self
|
176
|
+
in_layer :german do
|
177
|
+
def e
|
178
|
+
"Eulersche Zahl"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
example do
|
185
|
+
result_of(SimpleMath.e) == 2.71828183
|
186
|
+
|
187
|
+
ContextR::with_layer :german do
|
188
|
+
result_of(SimpleMath.e) == "Eulersche Zahl"
|
189
|
+
end
|
190
|
+
ContextR::with_layer :english do
|
191
|
+
result_of(SimpleMath.e) == "Euler's constant"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
Using a module
|
197
|
+
--------------
|
198
|
+
|
199
|
+
Hey, this is what we did all the time, so it is only natural to have the same
|
200
|
+
syntax to extend a class using in module for context-dependent behaviour. But
|
201
|
+
for the sake of completeness, I will attach another example.
|
202
|
+
|
203
|
+
class SimpleMath
|
204
|
+
class << self
|
205
|
+
in_layer :exact_computation do
|
206
|
+
def golden_ratio
|
207
|
+
sleep(0.01) # In real life this would take a bit longer,
|
208
|
+
# but I don't have the time.
|
209
|
+
1.6180339887_4989484820_4586834365_6381177203_0917980576
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
example do
|
216
|
+
result_of(SimpleMath.golden_ratio) == 1.6180339887
|
217
|
+
|
218
|
+
ContextR::with_layer :exact_computation do
|
219
|
+
result_of(SimpleMath.golden_ratio) ==
|
220
|
+
1.6180339887_4989484820_4586834365_6381177203_0917980576
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
Conclusion
|
226
|
+
----------
|
227
|
+
|
228
|
+
In general, there are two options to define context-dependent class side
|
229
|
+
behaviour. Use in\_layer in the eigenclass or use extend anywhere else. Both
|
230
|
+
options result in the same behaviour, just like the different options in
|
231
|
+
plain ruby look different, but have the same effect.
|
232
|
+
|
233
|
+
The programmer is free to use, whatever suites best. This is still Ruby.
|
234
|
+
|