contextr 0.1.9 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/History.txt +8 -0
- data/Manifest.txt +12 -17
- data/README.txt +0 -1
- data/examples/employer.rb +229 -0
- data/examples/node.rb +213 -0
- data/lib/contextr/class_methods.rb +14 -6
- data/lib/contextr/core_ext/module.rb +3 -2
- data/lib/contextr/event_machine.rb +12 -12
- data/lib/contextr/inner_class.rb +7 -3
- data/lib/contextr/layer.rb +17 -7
- data/lib/contextr/public_api.rb +44 -3
- data/lib/contextr/version.rb +3 -3
- data/lib/ext/active_support_subset.rb +0 -45
- data/spec/contextr_spec.rb +97 -7
- data/test/{test_class_side.mkd → class_side.mkd} +6 -13
- data/test/{test_dynamic_scope.mkd → dynamic_scope.mkd} +2 -2
- data/test/{test_dynamics.mkd → dynamics.mkd} +3 -3
- data/test/{test_hello_world.mkd → hello_world.mkd} +1 -1
- data/test/{test_introduction.mkd → introduction.mkd} +4 -4
- data/test/{test_layer_state.mkd → layer_state.mkd} +2 -2
- data/test/lib/example_test.rb +2 -2
- data/test/lib/literate_maruku_test.rb +11 -9
- data/test/{test_meta_api.mkd → meta_api.mkd} +1 -1
- data/test/method_missing.mkd +40 -0
- data/test/{test_ordering.mkd → ordering.mkd} +8 -8
- data/test/restrictions.mkd +177 -0
- data/test/test_contextr.rb +7 -0
- data/test/test_plain.rb +92 -0
- metadata +17 -29
- metadata.gz.sig +0 -0
- data/test/lib/literate_markaby_test.rb +0 -97
- data/test/test_class_side.rb +0 -4
- data/test/test_dynamic_scope.rb +0 -4
- data/test/test_dynamics.rb +0 -4
- data/test/test_hello_world.rb +0 -4
- data/test/test_introduction.rb +0 -4
- data/test/test_layer_state.rb +0 -3
- data/test/test_meta_api.rb +0 -4
- data/test/test_ordering.rb +0 -3
@@ -9,9 +9,9 @@ module ContextR # :nodoc:
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def stored_module_definitions
|
12
|
-
@stored_module_definitions ||= Hash.new do |
|
13
|
-
|
14
|
-
|
12
|
+
@stored_module_definitions ||= Hash.new do |layer_hash, layer|
|
13
|
+
layer_hash[layer] = Hash.new do |extended_modules_hash, x_module|
|
14
|
+
extended_modules_hash[x_module] = Module.new
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -40,17 +40,25 @@ module ContextR # :nodoc:
|
|
40
40
|
if stack.size == 1
|
41
41
|
stack.pop.call(*arguments, &block)
|
42
42
|
else
|
43
|
-
stack.pop.__send__(method_name, *arguments) do |
|
43
|
+
stack.pop.__send__(method_name, *arguments) do |action, *rest_args|
|
44
44
|
case action
|
45
45
|
when :receiver
|
46
46
|
receiver
|
47
47
|
when :block
|
48
|
+
block
|
49
|
+
when :block!
|
48
50
|
block.call(*rest_args)
|
51
|
+
when :block=
|
52
|
+
block = rest_args.first
|
53
|
+
when :block_given?
|
54
|
+
!block.nil?
|
49
55
|
when :next
|
56
|
+
rest_args.shift unless method_name == :method_missing
|
50
57
|
call_methods_stack(stack, receiver, method_name, rest_args, block)
|
51
58
|
else
|
52
|
-
raise ArgumentError
|
53
|
-
|
59
|
+
raise ArgumentError, "Use only :receiver, :block, :block_given?, " +
|
60
|
+
":block!, :block=, or :next " +
|
61
|
+
"as first argument."
|
54
62
|
end
|
55
63
|
end
|
56
64
|
end
|
@@ -27,10 +27,11 @@ class Module
|
|
27
27
|
def in_layer(layer_symbol, &block)
|
28
28
|
extension = ContextR::stored_module_definitions[layer_symbol][self]
|
29
29
|
|
30
|
-
extension.module_eval(&block) if block_given?
|
30
|
+
return_value = extension.module_eval(&block) if block_given?
|
31
31
|
|
32
32
|
ContextR::layer_by_symbol(layer_symbol).add_method_collection(self,
|
33
33
|
extension)
|
34
|
-
|
34
|
+
|
35
|
+
block_given? ? return_value : extension
|
35
36
|
end
|
36
37
|
end
|
@@ -52,20 +52,20 @@ module ContextR
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def observe_method_added(modul)
|
55
|
-
modul.
|
56
|
-
def self.method_added_with_contextr_listener(name)
|
57
|
-
ContextR::EventMachine::on_method_added(self, name)
|
58
|
-
method_added_without_contextr_listener(name)
|
59
|
-
end
|
60
|
-
unless self.methods.include? "method_added"
|
61
|
-
def self.method_added(name); end
|
62
|
-
end
|
63
|
-
class << self
|
64
|
-
alias_method_chain(:method_added, :contextr_listener)
|
65
|
-
end
|
66
|
-
}, __FILE__, __LINE__)
|
55
|
+
modul.extend(ContextRListener)
|
67
56
|
end
|
68
57
|
end
|
69
58
|
self.extend(ClassMethods)
|
59
|
+
|
60
|
+
module ContextRListener
|
61
|
+
def method_added(name)
|
62
|
+
ContextR::EventMachine::on_method_added(self, name)
|
63
|
+
super
|
64
|
+
end
|
65
|
+
def include(modul)
|
66
|
+
modul.instance_method.each { |m| method_added(m) }
|
67
|
+
super
|
68
|
+
end
|
69
|
+
end
|
70
70
|
end
|
71
71
|
end
|
data/lib/contextr/inner_class.rb
CHANGED
@@ -13,7 +13,7 @@ module ContextR
|
|
13
13
|
# hide +instance_eval+ or any method beginning with "__".
|
14
14
|
def hide(name)
|
15
15
|
if instance_methods.include?(name.to_s) and
|
16
|
-
name !~ /^(__|
|
16
|
+
name !~ /^(__|extend)/
|
17
17
|
@hidden_methods ||= {}
|
18
18
|
@hidden_methods[name.to_sym] = instance_method(name)
|
19
19
|
undef_method name
|
@@ -40,8 +40,12 @@ module ContextR
|
|
40
40
|
|
41
41
|
instance_methods.each { |m| hide(m) }
|
42
42
|
|
43
|
-
def method_missing(
|
44
|
-
|
43
|
+
def method_missing(*rest_args)
|
44
|
+
if block_given?
|
45
|
+
yield(:next, *rest_args)
|
46
|
+
else
|
47
|
+
super
|
48
|
+
end
|
45
49
|
end
|
46
50
|
end
|
47
51
|
end
|
data/lib/contextr/layer.rb
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
module ContextR # :nodoc:
|
2
|
-
class Layer
|
2
|
+
class Layer
|
3
|
+
def activated
|
4
|
+
nil
|
5
|
+
end
|
6
|
+
def deactivated
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
def inspect
|
10
|
+
"ContextR::layer(:#{ContextR::symbol_by_layer(self)})"
|
11
|
+
end
|
12
|
+
alias_method :to_s, :inspect
|
13
|
+
|
14
|
+
# :nodoc: all
|
3
15
|
def definitions
|
4
16
|
@definitions ||= {}
|
5
17
|
end
|
@@ -38,11 +50,9 @@ module ContextR # :nodoc:
|
|
38
50
|
|
39
51
|
def context_proxy_for_module(receiver, methods_module)
|
40
52
|
proxies[methods_module] ||= begin
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
}, __FILE__, __LINE__)
|
45
|
-
c.new
|
53
|
+
p = ContextR::InnerClass.new.extend(methods_module)
|
54
|
+
class << p; hide(:extend); end
|
55
|
+
p
|
46
56
|
end
|
47
57
|
end
|
48
58
|
|
@@ -70,7 +80,7 @@ module ContextR # :nodoc:
|
|
70
80
|
version)
|
71
81
|
end
|
72
82
|
|
73
|
-
def
|
83
|
+
def register_callbacks(cclass, mmodule)
|
74
84
|
{:on_wrapper_method_added => mmodule,
|
75
85
|
:on_class_method_added => cclass }.each do | callback, klass |
|
76
86
|
ContextR::EventMachine.register(self, callback,
|
data/lib/contextr/public_api.rb
CHANGED
@@ -17,8 +17,14 @@ module ContextR
|
|
17
17
|
def with_layers(*layer_symbols, &block)
|
18
18
|
layers = layer_symbols.collect do |layer_symbol|
|
19
19
|
layer_by_symbol(layer_symbol)
|
20
|
-
end
|
21
|
-
|
20
|
+
end.reverse
|
21
|
+
layers_being_activated = layers - active_layers_as_classes
|
22
|
+
layers_being_activated.each { |l| l.activated }
|
23
|
+
|
24
|
+
return_value = layered_do(layers | active_layers_as_classes, block)
|
25
|
+
|
26
|
+
layers_being_activated.each { |l| l.deactivated }
|
27
|
+
return_value
|
22
28
|
end
|
23
29
|
alias with_layer with_layers
|
24
30
|
|
@@ -40,7 +46,13 @@ module ContextR
|
|
40
46
|
layers = layer_symbols.collect do |layer_symbol|
|
41
47
|
layer_by_symbol(layer_symbol)
|
42
48
|
end
|
43
|
-
|
49
|
+
layers_being_deactivated = layers & active_layers_as_classes
|
50
|
+
layers_being_deactivated.each { |l| l.deactivated }
|
51
|
+
|
52
|
+
return_value = layered_do(active_layers_as_classes - layers, block)
|
53
|
+
|
54
|
+
layers_being_deactivated.each { |l| l.activated }
|
55
|
+
return_value
|
44
56
|
end
|
45
57
|
alias without_layer without_layers
|
46
58
|
|
@@ -54,6 +66,35 @@ module ContextR
|
|
54
66
|
layers_as_classes.collect { |layer| symbol_by_layer(layer) }
|
55
67
|
end
|
56
68
|
|
69
|
+
# returns the layer, defined by the given name. If passed a block, it will
|
70
|
+
# instance_eval it on the layer and return its value instead. The latter
|
71
|
+
# may be used to define the activated and deactived methods for a layer.
|
72
|
+
#
|
73
|
+
# ContextR::layer(:log) do
|
74
|
+
# def logger
|
75
|
+
# @logger ||= Logger.new
|
76
|
+
# end
|
77
|
+
# def activated
|
78
|
+
# logger.log("Logging active")
|
79
|
+
# end
|
80
|
+
# def deactivated
|
81
|
+
# logger.log("Logging inactive")
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# # will call activated before executing the block
|
86
|
+
# # and deactivated afterwards
|
87
|
+
# ContextR::with_layer(:log) do
|
88
|
+
# 1 + 1
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
def layer(name, &block)
|
92
|
+
if block_given?
|
93
|
+
layer_by_symbol(name).instance_eval(&block)
|
94
|
+
else
|
95
|
+
layer_by_symbol(name)
|
96
|
+
end
|
97
|
+
end
|
57
98
|
end
|
58
99
|
self.extend(PublicApi)
|
59
100
|
end
|
data/lib/contextr/version.rb
CHANGED
@@ -1,49 +1,4 @@
|
|
1
1
|
unless Object.const_defined? "ActiveSupport"
|
2
|
-
class Module
|
3
|
-
# Encapsulates the common pattern of:
|
4
|
-
#
|
5
|
-
# alias_method :foo_without_feature, :foo
|
6
|
-
# alias_method :foo, :foo_with_feature
|
7
|
-
#
|
8
|
-
# With this, you simply do:
|
9
|
-
#
|
10
|
-
# alias_method_chain :foo, :feature
|
11
|
-
#
|
12
|
-
# And both aliases are set up for you.
|
13
|
-
#
|
14
|
-
# Query and bang methods (foo?, foo!) keep the same punctuation:
|
15
|
-
#
|
16
|
-
# alias_method_chain :foo?, :feature
|
17
|
-
#
|
18
|
-
# is equivalent to
|
19
|
-
#
|
20
|
-
# alias_method :foo_without_feature?, :foo?
|
21
|
-
# alias_method :foo?, :foo_with_feature?
|
22
|
-
#
|
23
|
-
# so you can safely chain foo, foo?, and foo! with the same feature.
|
24
|
-
def alias_method_chain(target, feature)
|
25
|
-
# Strip out punctuation on predicates or bang methods since
|
26
|
-
# e.g. target?_without_feature is not a valid method name.
|
27
|
-
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
|
28
|
-
yield(aliased_target, punctuation) if block_given?
|
29
|
-
|
30
|
-
with_method = "#{aliased_target}_with_#{feature}#{punctuation}"
|
31
|
-
without_method = "#{aliased_target}_without_#{feature}#{punctuation}"
|
32
|
-
|
33
|
-
alias_method without_method, target
|
34
|
-
alias_method target, with_method
|
35
|
-
|
36
|
-
case
|
37
|
-
when public_method_defined?(without_method)
|
38
|
-
public target
|
39
|
-
when protected_method_defined?(without_method)
|
40
|
-
protected target
|
41
|
-
when private_method_defined?(without_method)
|
42
|
-
private target
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
2
|
# The Inflector transforms words from singular to plural, class names to
|
48
3
|
# table names, modularized class names to ones without, and class names to
|
49
4
|
# foreign keys. The default inflections for pluralization, singularization,
|
data/spec/contextr_spec.rb
CHANGED
@@ -52,6 +52,25 @@ class Ordering
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
class ExceptionExample
|
56
|
+
def secure
|
57
|
+
insecure
|
58
|
+
rescue RuntimeError
|
59
|
+
"caught in secure method"
|
60
|
+
end
|
61
|
+
|
62
|
+
def insecure
|
63
|
+
raise "insecure action failed"
|
64
|
+
end
|
65
|
+
|
66
|
+
in_layer :security do
|
67
|
+
def insecure
|
68
|
+
super
|
69
|
+
rescue RuntimeError
|
70
|
+
"caught in security layer"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
55
74
|
|
56
75
|
describe "A contextified object" do
|
57
76
|
before do
|
@@ -77,19 +96,19 @@ describe "A contextified object" do
|
|
77
96
|
end
|
78
97
|
|
79
98
|
it "should show specific behaviour down the whole stack for all layers" do
|
80
|
-
ContextR::with_layers :
|
99
|
+
ContextR::with_layers :address, :education do
|
81
100
|
@student.to_s.should == "Gregor Schmidt (Berlin), HPI (Potsdam)"
|
82
101
|
end
|
83
102
|
end
|
84
103
|
|
85
104
|
it "should take care of layer activation odering" do
|
86
|
-
ContextR::with_layers :
|
87
|
-
ContextR::with_layers :
|
105
|
+
ContextR::with_layers :address do
|
106
|
+
ContextR::with_layers :education do
|
88
107
|
@student.to_s.should == "Gregor Schmidt (Berlin), HPI (Potsdam)"
|
89
108
|
end
|
90
109
|
end
|
91
|
-
ContextR::with_layers :
|
92
|
-
ContextR::with_layers :
|
110
|
+
ContextR::with_layers :education do
|
111
|
+
ContextR::with_layers :address do
|
93
112
|
@student.to_s.should == "Gregor Schmidt, HPI (Potsdam) (Berlin)"
|
94
113
|
end
|
95
114
|
end
|
@@ -97,9 +116,9 @@ describe "A contextified object" do
|
|
97
116
|
|
98
117
|
it "should avoid double activation, but update ordering" do
|
99
118
|
ContextR::with_layers :education, :address do
|
100
|
-
ContextR::active_layers.should == [:
|
119
|
+
ContextR::active_layers.should == [:address, :education]
|
101
120
|
ContextR::with_layer :education do
|
102
|
-
ContextR::active_layers.should == [:
|
121
|
+
ContextR::active_layers.should == [:education, :address]
|
103
122
|
end
|
104
123
|
end
|
105
124
|
end
|
@@ -219,4 +238,75 @@ describe "ContextR" do
|
|
219
238
|
ContextR::layers.sort_by{ |s| s.to_s }.should include(layer)
|
220
239
|
end
|
221
240
|
end
|
241
|
+
|
242
|
+
it "should return a layer on #layer(:name)" do
|
243
|
+
ContextR::layer(:log).should == ContextR::layer_by_symbol(:log)
|
244
|
+
end
|
245
|
+
it "should execute the block given to #layer(:name)" do
|
246
|
+
lambda do
|
247
|
+
ContextR::layer(:log) do
|
248
|
+
def moo
|
249
|
+
"moo"
|
250
|
+
end
|
251
|
+
end.should == nil
|
252
|
+
end.should_not raise_error
|
253
|
+
|
254
|
+
ContextR::layer(:log).moo == "moo"
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should execute activated for all layers on activation" do
|
258
|
+
ContextR::layer(:log) do
|
259
|
+
def activated
|
260
|
+
raise "activated"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
lambda do
|
265
|
+
ContextR::with_layer(:log) { 1 + 1 }
|
266
|
+
end.should raise_error(RuntimeError, "activated")
|
267
|
+
|
268
|
+
ContextR::layer(:log) do
|
269
|
+
def activated
|
270
|
+
nil
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should execute deactivated for all layers on deactivation" do
|
276
|
+
ContextR::layer(:log) do
|
277
|
+
def deactivated
|
278
|
+
raise "deactivated"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
lambda do
|
283
|
+
ContextR::with_layer(:log) { 1 + 1 }
|
284
|
+
end.should raise_error(RuntimeError, "deactivated")
|
285
|
+
|
286
|
+
ContextR::layer(:log) do
|
287
|
+
def deactivated
|
288
|
+
nil
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
describe "ContextR" do
|
295
|
+
it "should propagate exceptions into outer layers first" do
|
296
|
+
|
297
|
+
instance = ExceptionExample.new
|
298
|
+
|
299
|
+
instance.secure.should == "caught in secure method"
|
300
|
+
|
301
|
+
ContextR::with_layer :security do
|
302
|
+
instance.secure.should == "caught in security layer"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
describe ContextR::Layer do
|
308
|
+
it "should give a nice, self-referencing output on inspect and to_s" do
|
309
|
+
eval(ContextR::layer(:log).inspect).should == ContextR::layer(:log)
|
310
|
+
eval(ContextR::layer(:log).to_s).should == ContextR::layer(:log)
|
311
|
+
end
|
222
312
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
**TODO: Update to use new in\_layer API**
|
2
|
-
|
3
1
|
In Ruby there are multiple ways of defining behaviour on the class side. That
|
4
2
|
are messages that are send to the class, not to the instance. Class side
|
5
3
|
behaviour is often useful for functional methods, i.e. methods that do not
|
@@ -128,8 +126,6 @@ different methods of defining class side behaviour.
|
|
128
126
|
Using `def self.method_name`
|
129
127
|
----------------------------
|
130
128
|
|
131
|
-
**TODO: Allow def self.method\_name to add class side behaviour**
|
132
|
-
|
133
129
|
Okay, we won't get rid of the modules, used to encapsulate the
|
134
130
|
context-dependent behaviour, so the extension is a bit noisier, than the
|
135
131
|
basic notation.
|
@@ -144,9 +140,8 @@ basic notation.
|
|
144
140
|
end
|
145
141
|
end
|
146
142
|
|
147
|
-
But we can use the same principles, like we did for the instance side
|
148
|
-
|
149
|
-
layer.
|
143
|
+
But we can use the same principles, like we did for the instance side - just in
|
144
|
+
side the singleton class.
|
150
145
|
|
151
146
|
example do
|
152
147
|
result_of(SimpleMath.pi) == 3.14159265
|
@@ -170,9 +165,7 @@ manage the extension.
|
|
170
165
|
"Euler's constant"
|
171
166
|
end
|
172
167
|
end
|
173
|
-
end
|
174
168
|
|
175
|
-
class << self
|
176
169
|
in_layer :german do
|
177
170
|
def e
|
178
171
|
"Eulersche Zahl"
|
@@ -196,12 +189,12 @@ manage the extension.
|
|
196
189
|
Using a module
|
197
190
|
--------------
|
198
191
|
|
199
|
-
|
200
|
-
|
201
|
-
|
192
|
+
It is only natural to have the same syntax to extend a class using in module
|
193
|
+
for context-dependent behaviour. But for the sake of completeness, I will
|
194
|
+
attach another example.
|
202
195
|
|
203
196
|
class SimpleMath
|
204
|
-
|
197
|
+
module ClassMethods
|
205
198
|
in_layer :exact_computation do
|
206
199
|
def golden_ratio
|
207
200
|
sleep(0.01) # In real life this would take a bit longer,
|