activecontext 0.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.
@@ -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: []