activecontext 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,26 @@
1
+ require "activecontext/container"
2
+
3
+ module ActiveContext
4
+ def biject(*args)
5
+ inject(*args)
6
+ outject(*args)
7
+ end
8
+
9
+ def inject(*names)
10
+ names.each do |name|
11
+ raise "invalid inject name #{name}" if methods.include?(name)
12
+ define_method name do
13
+ (value = Container.current[name]) && value.is_a?(Proc) ? value.call : value
14
+ end
15
+ end
16
+ end
17
+
18
+ def outject(*names)
19
+ names.each do |name|
20
+ raise "invalid outject name #{name}" if methods.include?(:"#{name}=")
21
+ define_method "#{name}=" do |*args|
22
+ Container.current[name] = args.first
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,62 @@
1
+ module ActiveContext
2
+ class Container
3
+ def initialize
4
+ @names = {}
5
+ end
6
+
7
+ def register(name, ctx={}, &block)
8
+ raise "invalid context name" if methods.include?(name)
9
+ instance_variable_set("@#{name}", ctx)
10
+
11
+ eigen = class << self; self; end
12
+ eigen.send(:define_method, name) do |*args, &block2|
13
+ raise "#{name} #{args.first} already exist" if @names.key?(args.first)
14
+ @names[args.first] = name
15
+
16
+ if args.length > 1
17
+ raise "pass either a block or value. not both." if block2
18
+ self[args.first] = args[1]
19
+ end
20
+
21
+ self[args.first] = block2 if block2
22
+ end
23
+ end
24
+
25
+ def []=(key, value)
26
+ if @names.key?(key)
27
+ self.context(@names[key])[key] = value
28
+ else
29
+ raise "unknown name #{key}"
30
+ end
31
+ end
32
+
33
+ def [](key)
34
+ if @names.key?(key)
35
+ self.context(@names[key])[key]
36
+ else
37
+ raise "unknown name #{key}"
38
+ end
39
+ end
40
+
41
+ def run(&block)
42
+ c = Thread.current[:contextualize]
43
+ raise "found existing container" if c && c != self
44
+
45
+ begin
46
+ Thread.current[:contextualize] = self
47
+ block.call
48
+ ensure
49
+ Thread.current[:contextualize] = nil
50
+ end unless c
51
+ end
52
+
53
+ def self.current
54
+ Thread.current[:contextualize]
55
+ end
56
+
57
+ def context(name)
58
+ instance_variable_get("@#{name}")
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,26 @@
1
+ require "activecontext/container"
2
+ require "rack/request"
3
+
4
+ module ActiveContext
5
+ class Rack
6
+ def initialize(app, &block)
7
+ @app = app
8
+ @block = block
9
+ end
10
+
11
+ def call(env)
12
+ req = ::Rack::Request.new(env)
13
+
14
+ container = Container.new
15
+
16
+ container.register :request, {}
17
+ container.register :session, req.session
18
+
19
+ container.instance_exec(req, &@block) if @block
20
+
21
+ container.run do
22
+ @app.call(env)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,178 @@
1
+ require "rspec"
2
+ require "activecontext"
3
+
4
+ describe ActiveContext do
5
+
6
+ class TestObject
7
+ end
8
+
9
+ def new_test_object
10
+ t = TestObject.new
11
+
12
+ def t.eigenclass
13
+ class << self; self; end
14
+ end
15
+
16
+ t
17
+ end
18
+
19
+ describe "inject" do
20
+ it "should create a method for the injected name" do
21
+ o = new_test_object
22
+ o.eigenclass.instance_eval do
23
+ extend ActiveContext
24
+ inject :somename
25
+ end
26
+ o.should respond_to(:somename)
27
+ end
28
+
29
+ it "should create multiple methods when passing multiple injected names" do
30
+ o = new_test_object
31
+ o.eigenclass.instance_eval do
32
+ extend ActiveContext
33
+ inject :somename, :othername
34
+ end
35
+ o.should respond_to(:somename)
36
+ o.should respond_to(:othername)
37
+ end
38
+
39
+ it "should fail if a method with the same name as injected already exist" do
40
+ o = new_test_object
41
+ lambda do
42
+ o.eigenclass.instance_eval do
43
+ extend ActiveContext
44
+ inject :to_s
45
+ end
46
+ end.should raise_error("invalid inject name to_s")
47
+ end
48
+
49
+ it "should return the value of the injected name" do
50
+ c = ActiveContext::Container.new
51
+ c.register :request, {}
52
+ c.request :somename, :joe
53
+
54
+ c.run do
55
+ o = new_test_object
56
+ o.eigenclass.instance_eval do
57
+ extend ActiveContext
58
+ inject :somename
59
+ end
60
+
61
+ o.somename.should be(:joe)
62
+ end
63
+ end
64
+
65
+ it "should return the value of the injected name" do
66
+ c = ActiveContext::Container.new
67
+ c.register :request, {}
68
+ c.request :somename do
69
+ :joe
70
+ end
71
+
72
+ c.run do
73
+ o = new_test_object
74
+ o.eigenclass.instance_eval do
75
+ extend ActiveContext
76
+ inject :somename
77
+ end
78
+
79
+ o.somename.should be(:joe)
80
+ end
81
+ end
82
+
83
+ it "should return nil if no value exist" do
84
+ c = ActiveContext::Container.new
85
+ c.register :request, {}
86
+ c.request :somename
87
+
88
+ c.run do
89
+ o = new_test_object
90
+ o.eigenclass.instance_eval do
91
+ extend ActiveContext
92
+ inject :somename
93
+ end
94
+
95
+ o.somename.should be_nil
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ describe "outject" do
102
+ it "should create a method for the injected name" do
103
+ o = new_test_object
104
+ o.eigenclass.instance_eval do
105
+ extend ActiveContext
106
+ outject :somename
107
+ end
108
+ o.should respond_to(:"somename=")
109
+ end
110
+
111
+ it "should create multiple methods when passing multiple outjected names" do
112
+ o = new_test_object
113
+ o.eigenclass.instance_eval do
114
+ extend ActiveContext
115
+ outject :somename, :othername
116
+ end
117
+ o.should respond_to(:"somename=")
118
+ o.should respond_to(:"othername=")
119
+ end
120
+
121
+ it "should fail if a method with the same name as outjected already exist" do
122
+ o = new_test_object
123
+ lambda do
124
+ o.eigenclass.instance_eval do
125
+ extend ActiveContext
126
+ def dummy=(key, value)
127
+ end
128
+ outject :dummy
129
+ end
130
+ end.should raise_error("invalid outject name dummy")
131
+ end
132
+
133
+ it "should set the outjected value and read it back" do
134
+ c = ActiveContext::Container.new
135
+ ctx = {}
136
+ c.register :request, ctx
137
+ c.request :somename, :joe
138
+
139
+ c.run do
140
+ o = new_test_object
141
+ o.eigenclass.instance_eval do
142
+ extend ActiveContext
143
+ inject :somename
144
+ outject :somename
145
+ end
146
+
147
+ o.somename = :bob
148
+ o.somename.should be(:bob)
149
+ end
150
+
151
+ ctx.should eql({:somename => :bob})
152
+ end
153
+ end
154
+
155
+ describe "biject" do
156
+ it "should create a method pair for injected and outjected of the passed name" do
157
+ o = new_test_object
158
+ o.eigenclass.instance_eval do
159
+ extend ActiveContext
160
+ biject :somename
161
+ end
162
+ o.should respond_to(:somename)
163
+ o.should respond_to(:"somename=")
164
+ end
165
+
166
+ it "should create multiple method pairs for injected an outjected of the passed names" do
167
+ o = new_test_object
168
+ o.eigenclass.instance_eval do
169
+ extend ActiveContext
170
+ biject :somename, :othername
171
+ end
172
+ o.should respond_to(:somename)
173
+ o.should respond_to(:"somename=")
174
+ o.should respond_to(:othername)
175
+ o.should respond_to(:"othername=")
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,136 @@
1
+ require "rspec"
2
+ require "activecontext/container"
3
+
4
+ describe ActiveContext::Container do
5
+
6
+ it "should not contain any known names" do
7
+ ActiveContext::Container.new.instance_variable_get("@names").should be_empty
8
+ end
9
+
10
+ it "should fail if an unknown name is accessed" do
11
+ c = ActiveContext::Container.new
12
+ lambda do
13
+ c[:key]
14
+ end.should raise_error("unknown name key")
15
+ end
16
+
17
+ it "should fail when setting an unknown name" do
18
+ c = ActiveContext::Container.new
19
+ lambda do
20
+ c[:key] = 1
21
+ end.should raise_error("unknown name key")
22
+ end
23
+
24
+ it "should set current container, run block and clean up container" do
25
+ c = ActiveContext::Container.new
26
+ c.run do
27
+ ActiveContext::Container.current.should be(c)
28
+ end
29
+ ActiveContext::Container.current.should be_nil
30
+ end
31
+
32
+ it "should support nesting of the same container" do
33
+ c = ActiveContext::Container.new
34
+ c.run do
35
+ c.run do
36
+ ActiveContext::Container.current.should be(c)
37
+ end
38
+ ActiveContext::Container.current.should be(c)
39
+ end
40
+ ActiveContext::Container.current.should be_nil
41
+ end
42
+
43
+ it "should fail when different container exist" do
44
+ c = ActiveContext::Container.new
45
+ c.run do
46
+ c2 = ActiveContext::Container.new
47
+ lambda do
48
+ c2.run
49
+ end.should raise_error("found existing container")
50
+ end
51
+ end
52
+
53
+ describe "registering a context" do
54
+ it "should create an instance variable with same name as context" do
55
+ c = ActiveContext::Container.new
56
+ ctx = {}
57
+ c.register :request, ctx
58
+ c.context("request").should eq(ctx)
59
+ end
60
+
61
+ it "should create a method with same name as context to declare names in this context" do
62
+ c = ActiveContext::Container.new
63
+ c.register :request, {}
64
+ c.methods(:request).should_not be_nil
65
+ end
66
+
67
+ it "should fail when a method with same name already exist" do
68
+ c = ActiveContext::Container.new
69
+ lambda do
70
+ c.register :register, {}
71
+ end.should raise_error("invalid context name")
72
+ end
73
+
74
+ describe "registering a name" do
75
+ it "should map the name to a context" do
76
+ c = ActiveContext::Container.new
77
+ c.register :request, {}
78
+ c.request :somename
79
+ c.instance_variable_get("@names").should eq({:somename => :request})
80
+ end
81
+
82
+ it "should fail if name already exist" do
83
+ c = ActiveContext::Container.new
84
+ c.register :request, {}
85
+ c.request :somename
86
+ lambda do
87
+ c.request :somename
88
+ end.should raise_error("request somename already exist")
89
+ end
90
+
91
+ it "should take a initial value as second argument" do
92
+ c = ActiveContext::Container.new
93
+ c.register :request, {}
94
+ c.request :somename, :joe
95
+ c.context("request")[:somename].should be(:joe)
96
+ end
97
+
98
+ it "should take a initial value factory as block" do
99
+ c = ActiveContext::Container.new
100
+ c.register :request, {}
101
+ factory = -> { :joe }
102
+ c.request :somename, &factory
103
+ c.context("request")[:somename].should be(factory)
104
+ end
105
+
106
+ it "should fail when passing a initial value argument and a block at the same time" do
107
+ c = ActiveContext::Container.new
108
+ c.register :request, {}
109
+ factory = -> { :joe }
110
+ lambda do
111
+ c.request :somename, :bob, &factory
112
+ end.should raise_error("pass either a block or value. not both.")
113
+ end
114
+ end
115
+
116
+ it "should set a value" do
117
+ c = ActiveContext::Container.new
118
+ c.register :request, {}
119
+ c.request :somename
120
+ c[:somename] = :joe
121
+ c[:somename].should be(:joe)
122
+ end
123
+
124
+ it "should get the initial value" do
125
+ c = ActiveContext::Container.new
126
+ c.register :request, {}
127
+ c.request :somename, :joe
128
+ c.request :othername do
129
+ :bob
130
+ end
131
+ c[:somename].should be(:joe)
132
+ c[:othername].call.should be(:bob)
133
+ end
134
+ end
135
+
136
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activecontext
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - jan zimmek
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70264750979080 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70264750979080
25
+ description: ''
26
+ email:
27
+ - jan.zimmek@web.de
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - lib/activecontext/container.rb
33
+ - lib/activecontext/rack.rb
34
+ - lib/activecontext.rb
35
+ - spec/activecontext_spec.rb
36
+ - spec/container_spec.rb
37
+ homepage: http://www.github.com/jzimmek/activecontext
38
+ licenses: []
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: 1.9.2
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 1.8.10
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: ''
61
+ test_files: []