contextr 0.1.1 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- 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.tar.gz.sig
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
&�3��Q��<��o;\ؿ}0�`Y�G��(��%���z$9P�#��xj���O�N0*�kKK@\!�P�J3�ŵQ�S�$�Ds�K�f�/@� ��o0f��Sz�)ٓ/?f#�&bD��186� o�M�GU�Ha��;��uq�{�:�f)���D�W�ŭ��"5ǹ7֦�m��X9s쬽��X�&�m�
|
2
|
+
=����ȄJN�r��'���"kU{�v�nS̹��=��s#{>��㴯/<u�h�jQBN8(G ,z8
|
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -11,6 +11,7 @@ lib/contextr/core_ext.rb
|
|
11
11
|
lib/contextr/core_ext/module.rb
|
12
12
|
lib/contextr/core_ext/object.rb
|
13
13
|
lib/contextr/event_machine.rb
|
14
|
+
lib/contextr/inner_class.rb
|
14
15
|
lib/contextr/layer.rb
|
15
16
|
lib/contextr/modules/mutex_code.rb
|
16
17
|
lib/contextr/modules/unique_id.rb
|
@@ -23,10 +24,24 @@ setup.rb
|
|
23
24
|
spec/contextr_spec.rb
|
24
25
|
spec/spec.opts
|
25
26
|
spec/spec_helper.rb
|
27
|
+
test/lib/example_test.rb
|
28
|
+
test/lib/literate_markaby_test.rb
|
29
|
+
test/lib/literate_maruku_test.rb
|
30
|
+
test/test_class_side.mkd
|
26
31
|
test/test_class_side.rb
|
27
32
|
test/test_contextr.rb
|
33
|
+
test/test_dynamic_scope.mkd
|
34
|
+
test/test_dynamic_scope.rb
|
35
|
+
test/test_dynamics.mkd
|
28
36
|
test/test_dynamics.rb
|
37
|
+
test/test_hello_world.mkd
|
38
|
+
test/test_hello_world.rb
|
29
39
|
test/test_helper.rb
|
40
|
+
test/test_introduction.mkd
|
30
41
|
test/test_introduction.rb
|
42
|
+
test/test_layer_state.mkd
|
31
43
|
test/test_layer_state.rb
|
44
|
+
test/test_meta_api.mkd
|
45
|
+
test/test_meta_api.rb
|
46
|
+
test/test_ordering.mkd
|
32
47
|
test/test_ordering.rb
|
data/Rakefile
CHANGED
@@ -107,8 +107,8 @@ task :website => [:website_generate, :website_upload, :publish_docs]
|
|
107
107
|
desc 'Release the website and new gem version'
|
108
108
|
task :deploy => [:check_version, :website, :release] do
|
109
109
|
puts "Remember to create SVN tag:"
|
110
|
-
puts "svn copy svn+ssh
|
111
|
-
"svn+ssh
|
110
|
+
puts "svn copy svn+ssh://rubyforge.org/var/svn/#{PATH}/trunk " +
|
111
|
+
"svn+ssh://rubyforge.org/var/svn/#{PATH}/tags/contextr-#{VERS} "
|
112
112
|
puts "Suggested comment:"
|
113
113
|
puts "Tagging release #{CHANGES}"
|
114
114
|
end
|
data/lib/contextr.rb
CHANGED
@@ -11,7 +11,8 @@ end
|
|
11
11
|
|
12
12
|
# the basic library code
|
13
13
|
%w{public_api class_methods layer
|
14
|
-
event_machine core_ext version
|
14
|
+
event_machine core_ext version
|
15
|
+
inner_class}.each { | file |
|
15
16
|
require File.dirname(__FILE__) + "/contextr/#{file}" }
|
16
17
|
|
17
18
|
unless Dynamic.variables.include?( :layers )
|
@@ -2,17 +2,17 @@ module ContextR # :nodoc:
|
|
2
2
|
module ClassMethods # :nodoc:
|
3
3
|
include MutexCode
|
4
4
|
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
else
|
9
|
-
super
|
5
|
+
def stored_core_methods
|
6
|
+
@stored_core_methods ||= Hash.new do |hash, key|
|
7
|
+
hash[key] = Hash.new
|
10
8
|
end
|
11
9
|
end
|
12
10
|
|
13
|
-
def
|
14
|
-
@
|
15
|
-
hash[key] = Hash.new
|
11
|
+
def stored_module_definitions
|
12
|
+
@stored_module_definitions ||= Hash.new do |hash, key|
|
13
|
+
hash[key] = Hash.new do |hash, key|
|
14
|
+
hash[key] = Module.new
|
15
|
+
end
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -25,24 +25,22 @@ module ContextR # :nodoc:
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def layers_as_classes
|
28
|
-
|
29
|
-
l.scan(/(.+)Layer/).first.first.underscore.to_sym
|
30
|
-
}
|
28
|
+
@layers.values
|
31
29
|
end
|
32
30
|
|
33
31
|
def symbol_by_layer(lay)
|
34
|
-
|
32
|
+
@layers.index(lay)
|
35
33
|
end
|
36
34
|
|
37
35
|
def layer_by_symbol(sym)
|
38
|
-
|
36
|
+
@layers[sym] ||= ContextR::Layer.new
|
39
37
|
end
|
40
38
|
|
41
39
|
def call_methods_stack(stack, receiver, method_name, arguments, block)
|
42
40
|
if stack.size == 1
|
43
41
|
stack.pop.call(*arguments, &block)
|
44
42
|
else
|
45
|
-
stack.pop.
|
43
|
+
stack.pop.__send__(method_name, *arguments) do | action, *rest_args |
|
46
44
|
case action
|
47
45
|
when :receiver
|
48
46
|
receiver
|
@@ -62,7 +60,9 @@ module ContextR # :nodoc:
|
|
62
60
|
method_name, arguments, block)
|
63
61
|
proxies = []
|
64
62
|
active_layers_as_classes.each do |layer|
|
65
|
-
proxies += layer.context_proxies(
|
63
|
+
proxies += layer.context_proxies(receiver,
|
64
|
+
contextified_class,
|
65
|
+
method_name)
|
66
66
|
end.compact
|
67
67
|
|
68
68
|
proxies << core_proxy(receiver, contextified_class, method_name)
|
@@ -104,6 +104,10 @@ module ContextR # :nodoc:
|
|
104
104
|
def meta_method?(method_name)
|
105
105
|
method_name.to_s =~ /method_added(_with(out)?_contextr_listener)?/
|
106
106
|
end
|
107
|
+
|
108
|
+
def self.extended(base)
|
109
|
+
base.instance_variable_set(:@layers, {})
|
110
|
+
end
|
107
111
|
end
|
108
112
|
self.extend(ClassMethods)
|
109
113
|
end
|
@@ -1,41 +1,16 @@
|
|
1
|
-
#--
|
2
|
-
# The aliasing of these methods is done in a class_eval block to avoid code
|
3
|
-
# documentation by RDoc.
|
4
|
-
#++
|
5
|
-
Module.class_eval do
|
6
|
-
alias_method :include_without_layers, :include
|
7
|
-
end
|
8
|
-
|
9
1
|
class Module
|
10
|
-
|
11
|
-
def include_with_layers(associations) # :nodoc:
|
12
|
-
associations.each do | modul, layer |
|
13
|
-
ContextR::layer_by_symbol(layer).add_method_collection(self, modul)
|
14
|
-
end
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
# call-seq:
|
19
|
-
# include(module, ...) => self
|
20
|
-
# include(module => layer_qualifier, ...) => self
|
21
|
-
#
|
22
|
-
# Invokes <code>Module.append_features</code> on each parameter in turn.
|
2
|
+
# Adds context-dependent behaviour to instances.
|
23
3
|
#
|
24
|
-
# If called with a hash, adds the module to the given layer. The behaviour
|
25
|
-
# is associated with the class side of the object.
|
26
|
-
#
|
27
|
-
# module Mod
|
28
|
-
# def name
|
29
|
-
# "Hello from #{yield(:next)}.\n"
|
30
|
-
# end
|
31
|
-
# end
|
32
|
-
#
|
33
4
|
# class Klass
|
34
5
|
# def name
|
35
6
|
# "Klass"
|
36
7
|
# end
|
37
8
|
#
|
38
|
-
#
|
9
|
+
# in_layer :hello do
|
10
|
+
# def name
|
11
|
+
# "Hello from #{super}.\n"
|
12
|
+
# end
|
13
|
+
# end
|
39
14
|
# end
|
40
15
|
#
|
41
16
|
# k = Klass.new
|
@@ -45,13 +20,17 @@ class Module
|
|
45
20
|
# end
|
46
21
|
# k.name #=> "Klass.\n"
|
47
22
|
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
23
|
+
# Note: in_layer automatically generates the inner module
|
24
|
+
# and attaches it to the given layer. It is guaranteed, that the inner module
|
25
|
+
# used for method definitons will always be the same for any layer x class
|
26
|
+
# combination.
|
27
|
+
def in_layer(layer_symbol, &block)
|
28
|
+
extension = ContextR::stored_module_definitions[layer_symbol][self]
|
29
|
+
|
30
|
+
extension.module_eval(&block) if block_given?
|
53
31
|
|
54
|
-
|
55
|
-
|
56
|
-
|
32
|
+
ContextR::layer_by_symbol(layer_symbol).add_method_collection(self,
|
33
|
+
extension)
|
34
|
+
extension
|
35
|
+
end
|
57
36
|
end
|
@@ -1,71 +1,4 @@
|
|
1
|
-
|
2
|
-
# The aliasing of these methods is done in a class_eval block to avoid code
|
3
|
-
# documentation by RDoc.
|
4
|
-
#++
|
5
|
-
Object.class_eval do
|
6
|
-
alias_method :extend_without_layers, :extend
|
7
|
-
end
|
8
|
-
|
9
|
-
class Object
|
10
|
-
def extend_with_layers(associations) # :nodoc:
|
11
|
-
klass = class << self; self; end
|
12
|
-
associations.each do | modul, layer |
|
13
|
-
ContextR::layer_by_symbol(layer).add_method_collection(klass, modul)
|
14
|
-
end
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
# call-seq:
|
19
|
-
# obj.extend(module, ...) => obj
|
20
|
-
# obj.extend(module => layer_qualifier, ...) => obj
|
21
|
-
#
|
22
|
-
# Adds to _obj_ the instance methods from each module given as a
|
23
|
-
# parameter.
|
24
|
-
#
|
25
|
-
# module Mod
|
26
|
-
# def hello
|
27
|
-
# "Hello from Mod.\n"
|
28
|
-
# end
|
29
|
-
# end
|
30
|
-
#
|
31
|
-
# class Klass
|
32
|
-
# def hello
|
33
|
-
# "Hello from Klass.\n"
|
34
|
-
# end
|
35
|
-
# end
|
36
|
-
#
|
37
|
-
# k = Klass.new
|
38
|
-
# k.hello #=> "Hello from Klass.\n"
|
39
|
-
# k.extend(Mod) #=> #<Klass:0x401b3bc8>
|
40
|
-
# k.hello #=> "Hello from Mod.\n"
|
41
|
-
#
|
42
|
-
# If called with a hash, adds the module to the given layer. The behaviour
|
43
|
-
# is associated with the class side of the object.
|
44
|
-
#
|
45
|
-
# module Mod
|
46
|
-
# def name
|
47
|
-
# "Hello from #{yield(:next)}.\n"
|
48
|
-
# end
|
49
|
-
# end
|
50
|
-
#
|
51
|
-
# class Klass
|
52
|
-
# def name
|
53
|
-
# "Klass"
|
54
|
-
# end
|
55
|
-
# end
|
56
|
-
#
|
57
|
-
# k = Klass.new
|
58
|
-
# k.extend(Mod => :hello) #=> #<Klass:0x401b3bc8>
|
59
|
-
# k.name #=> "Klass.\n"
|
60
|
-
# ContextR::with_layer :hello do
|
61
|
-
# k.name #=> "Hello from Klass.\n"
|
62
|
-
# end
|
63
|
-
# k.name #=> "Klass.\n"
|
64
|
-
def extend(*args)
|
65
|
-
args.first.is_a?(Module) ? extend_without_layers(*args) :
|
66
|
-
extend_with_layers(*args)
|
67
|
-
end
|
68
|
-
|
1
|
+
class Object #:nodoc:
|
69
2
|
def behavioural_class #:nodoc:
|
70
3
|
if self.kind_of?(Module)
|
71
4
|
class << self; self; end
|
@@ -4,7 +4,7 @@ module ContextR
|
|
4
4
|
include UniqueId
|
5
5
|
|
6
6
|
def listeners
|
7
|
-
@listeners ||= {
|
7
|
+
@listeners ||= {:method_added => {}}
|
8
8
|
end
|
9
9
|
|
10
10
|
def register(listener, callback, options)
|
@@ -20,8 +20,8 @@ module ContextR
|
|
20
20
|
|
21
21
|
def on_method_added(modul, name)
|
22
22
|
version = self.new_unique_id
|
23
|
-
self.listeners[:method_added][modul].each do |
|
24
|
-
listener.send(
|
23
|
+
self.listeners[:method_added][modul].to_a.each do |listener, method|
|
24
|
+
listener.send(method, modul, name, version)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ContextR
|
2
|
+
class InnerClass # :nodoc:
|
3
|
+
#--
|
4
|
+
# Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
|
5
|
+
# All rights reserved.
|
6
|
+
|
7
|
+
# Permission is granted for use, copying, modification, distribution,
|
8
|
+
# and distribution of modified versions of this work as long as the
|
9
|
+
# above copyright notice is included.
|
10
|
+
#++
|
11
|
+
class << self
|
12
|
+
# Hide the method named +name+ in the BlankSlate class. Don't
|
13
|
+
# hide +instance_eval+ or any method beginning with "__".
|
14
|
+
def hide(name)
|
15
|
+
if instance_methods.include?(name.to_s) and
|
16
|
+
name !~ /^(__|instance_eval)/
|
17
|
+
@hidden_methods ||= {}
|
18
|
+
@hidden_methods[name.to_sym] = instance_method(name)
|
19
|
+
undef_method name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_hidden_method(name)
|
24
|
+
@hidden_methods ||= {}
|
25
|
+
@hidden_methods[name] || superclass.find_hidden_method(name)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Redefine a previously hidden method so that it may be called on a blank
|
29
|
+
# slate object.
|
30
|
+
def reveal(name)
|
31
|
+
bound_method = nil
|
32
|
+
unbound_method = find_hidden_method(name)
|
33
|
+
fail "Don't know how to reveal method '#{name}'" unless unbound_method
|
34
|
+
define_method(name) do |*args|
|
35
|
+
bound_method ||= unbound_method.bind(self)
|
36
|
+
bound_method.call(*args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
instance_methods.each { |m| hide(m) }
|
42
|
+
|
43
|
+
def method_missing(method_name, *rest_args)
|
44
|
+
yield(:next, *rest_args)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/contextr/layer.rb
CHANGED
@@ -1,88 +1,82 @@
|
|
1
1
|
module ContextR # :nodoc:
|
2
2
|
class Layer # :nodoc: all
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
3
|
+
def definitions
|
4
|
+
@definitions ||= {}
|
5
|
+
end
|
6
|
+
def proxies
|
7
|
+
@proxies ||= {}
|
8
|
+
end
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
def add_method_collection(contextified_class, methods_module)
|
11
|
+
definitions[contextified_class] ||= []
|
12
|
+
definitions[contextified_class].delete(methods_module)
|
13
|
+
definitions[contextified_class].push(methods_module)
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
register_callbacks(contextified_class, methods_module)
|
15
|
+
(methods_module.instance_methods &
|
16
|
+
contextified_class.instance_methods).each do | method_name |
|
17
|
+
replace_core_method(contextified_class, method_name, 0)
|
21
18
|
end
|
19
|
+
register_callbacks(contextified_class, methods_module)
|
20
|
+
end
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
else
|
29
|
-
[]
|
22
|
+
def methods_modules_containing_method(contextified_class, method_name)
|
23
|
+
if definitions.include?(contextified_class)
|
24
|
+
definitions[contextified_class].select do | methods_module |
|
25
|
+
methods_module.instance_methods.include?(method_name.to_s)
|
30
26
|
end
|
27
|
+
else
|
28
|
+
[]
|
31
29
|
end
|
30
|
+
end
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def context_proxy_for_module(methods_module)
|
41
|
-
proxies[methods_module] ||= begin
|
42
|
-
c = Class.new
|
43
|
-
c.class_eval(%Q{
|
44
|
-
include ObjectSpace._id2ref(#{methods_module.object_id})
|
45
|
-
}, __FILE__, __LINE__)
|
46
|
-
c.new
|
47
|
-
end
|
48
|
-
end
|
32
|
+
def context_proxies(receiver, contextified_class, method_name)
|
33
|
+
methods_modules_containing_method(contextified_class, method_name).
|
34
|
+
collect do | methods_module |
|
35
|
+
context_proxy_for_module(receiver, methods_module)
|
36
|
+
end.reverse
|
37
|
+
end
|
49
38
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
39
|
+
def context_proxy_for_module(receiver, methods_module)
|
40
|
+
proxies[methods_module] ||= begin
|
41
|
+
c = Class.new(ContextR::InnerClass)
|
42
|
+
c.class_eval(%Q{
|
43
|
+
include ObjectSpace._id2ref(#{methods_module.object_id})
|
44
|
+
}, __FILE__, __LINE__)
|
45
|
+
c.new
|
55
46
|
end
|
47
|
+
end
|
56
48
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
end.compact.each do | contextified_class |
|
63
|
-
replace_core_method(contextified_class, method_name, 0)
|
64
|
-
end
|
49
|
+
def on_class_method_added(contextified_class, method_name, version)
|
50
|
+
unless methods_modules_containing_method(contextified_class,
|
51
|
+
method_name).empty?
|
52
|
+
replace_core_method(contextified_class, method_name, version)
|
65
53
|
end
|
54
|
+
end
|
66
55
|
|
67
|
-
|
68
|
-
|
69
|
-
|
56
|
+
def on_wrapper_method_added(methods_module, method_name, version)
|
57
|
+
self.definitions.collect do | each_class, each_methods_modules |
|
58
|
+
if each_methods_modules.include?(methods_module)
|
59
|
+
each_class
|
60
|
+
end
|
61
|
+
end.compact.select do |contextified_class|
|
62
|
+
contextified_class.instance_methods.include?(method_name.to_s)
|
63
|
+
end.each do | contextified_class |
|
64
|
+
replace_core_method(contextified_class, method_name, 0)
|
70
65
|
end
|
66
|
+
end
|
71
67
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
ContextR::EventMachine.register(self, callback,
|
76
|
-
:on_event => :method_added,
|
77
|
-
:in_class => klass)
|
78
|
-
end
|
79
|
-
end
|
68
|
+
def replace_core_method(contextified_class, method_name, version)
|
69
|
+
ContextR::observe_core_method(contextified_class, method_name.to_sym,
|
70
|
+
version)
|
80
71
|
end
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
72
|
+
|
73
|
+
def register_callbacks(cclass, mmodule)
|
74
|
+
{:on_wrapper_method_added => mmodule,
|
75
|
+
:on_class_method_added => cclass }.each do | callback, klass |
|
76
|
+
ContextR::EventMachine.register(self, callback,
|
77
|
+
:on_event => :method_added,
|
78
|
+
:in_class => klass)
|
79
|
+
end
|
86
80
|
end
|
87
81
|
end
|
88
82
|
end
|