micon 0.1.16 → 0.1.17
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/micon/config.rb +2 -2
- data/lib/micon/core.rb +52 -52
- data/lib/micon/helper.rb +6 -6
- data/lib/micon/metadata.rb +11 -11
- data/lib/micon/module.rb +9 -9
- data/lib/micon/spec.rb +4 -4
- data/readme.md +168 -75
- data/spec/callbacks_spec.rb +14 -14
- data/spec/config_spec.rb +4 -4
- data/spec/constants_spec.rb +18 -18
- data/spec/custom_scope_spec.rb +9 -9
- data/spec/example_spec/lib/components/controller.rb +8 -0
- data/spec/example_spec/lib/components/logger.production.yml +1 -0
- data/spec/example_spec/lib/components/logger.rb +8 -0
- data/spec/example_spec/lib/components/logger.yml +1 -0
- data/spec/example_spec/lib/components/request.rb +2 -0
- data/spec/example_spec/lib/components/router.rb +12 -0
- data/spec/example_spec/lib/pages_controller.rb +11 -0
- data/spec/example_spec/lib/rack_adapter.rb +25 -0
- data/spec/example_spec/lib/request.rb +8 -0
- data/spec/example_spec.rb +171 -0
- data/spec/initialization_spec.rb +11 -11
- data/spec/managed_spec.rb +3 -3
- data/spec/miscellaneous_spec.rb +11 -11
- data/spec/nested_custom_scope_spec.rb +3 -3
- data/spec/static_scope_spec.rb +11 -11
- metadata +29 -31
- data/spec/overview_spec.rb +0 -67
data/readme.md
CHANGED
@@ -1,95 +1,188 @@
|
|
1
|
-
#
|
1
|
+
# Micon IoC assembles and manages Your Application
|
2
2
|
|
3
|
-
Micon is infrastructural component, invisible to user and it's main goal is to simplify development. It reduces complex monolithic application to set of simple low coupled components.
|
3
|
+
Micon is infrastructural component, invisible to user and it's main goal is to simplify development. It reduces complex monolithic application to set of simple low coupled components.
|
4
4
|
|
5
5
|
Concentrate on business logic and interfaces and Micon will provide automatic configuration, life cycle management and dependency resolving.
|
6
6
|
|
7
7
|
Technically it's [IoC][ioc] like framework with components, callbacks, scopes and bijections, inspired by Spring and JBoss Seam.
|
8
8
|
|
9
|
-
Is it usefull, is there any real-life application? - I'm using it as a heart of my [web framework][rad_core], this
|
9
|
+
Is it usefull, is there any real-life application? - I'm using it as a heart of my [web framework][rad_core], this sites http://robotigra.ru, http://ruby-lang.info for example powered with it.
|
10
10
|
|
11
11
|
## Usage
|
12
|
-
|
12
|
+
|
13
13
|
Let's suppose you are building the Ruby on Rails clone, there are lots of modules let's try to deal with them
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
15
|
+
``` ruby
|
16
|
+
require 'micon'
|
17
|
+
|
18
|
+
# Here's our Web Framework, let's call it Rad
|
19
|
+
|
20
|
+
# Let's define shortcut to access the IoC API (optional
|
21
|
+
# but handy step). I don't know how You would like to call it,
|
22
|
+
# so I leave this step to You.
|
23
|
+
class ::Object
|
24
|
+
def rad; MICON end
|
25
|
+
end
|
26
|
+
|
27
|
+
# let's define some components
|
28
|
+
# the :logger is one per application, it's a static component (like singleton)
|
29
|
+
class Logger
|
30
|
+
register_as :logger
|
31
|
+
attr_accessor :log_file_path
|
32
|
+
def info msg
|
33
|
+
puts "#{msg} (writen to #{log_file_path})" unless defined?(RSpec)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# To demostrate basics of working with compnents let's configure our :logger
|
38
|
+
# explicitly (in the next example, it will be configured automatically).
|
39
|
+
rad.logger.log_file_path = '/tmp/rad.log'
|
40
|
+
|
41
|
+
# The :router requires complex initialization, so we use
|
42
|
+
# another form of component registration.
|
43
|
+
class Router
|
44
|
+
def initialize routes; @routes = routes end
|
45
|
+
def decode request;
|
46
|
+
class_name, method = @routes[request.url]
|
47
|
+
return eval(class_name), method # returning actual class
|
48
|
+
end
|
49
|
+
end
|
50
|
+
rad.register :router do
|
51
|
+
Router.new '/index' => ['PagesController', :index]
|
52
|
+
end
|
53
|
+
|
54
|
+
# The :controller component should be created and destroyed dynamically,
|
55
|
+
# for each request, we specifying that component is dynamic
|
56
|
+
# by declaring it's :scope.
|
57
|
+
# And, we don't know beforehead what it actully will be, for different
|
58
|
+
# request there can be different controllers,
|
59
|
+
# so, here we just declaring it without any initialization block, it
|
60
|
+
# will be created at runtime later.
|
61
|
+
rad.register :controller, scope: :request
|
62
|
+
|
63
|
+
# Let's define some of our controllers, the PagesController, note - we
|
64
|
+
# don't register it as component.
|
65
|
+
class PagesController
|
66
|
+
# We need access to :logger and :request, let's inject them
|
67
|
+
inject logger: :logger, request: :request
|
68
|
+
|
69
|
+
def index
|
70
|
+
# Here we can use injected component
|
71
|
+
logger.info "Application: processing #{request}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Request is also dynamic, and it also can't be created beforehead.
|
76
|
+
# We also registering it without initialization, it will be
|
77
|
+
# created at runtime later.
|
78
|
+
class Request
|
79
|
+
attr_reader :url
|
80
|
+
def initialize url; @url = url end
|
81
|
+
def to_s; @url end
|
82
|
+
end
|
83
|
+
# Registering without initialization block.
|
84
|
+
rad.register :request, scope: :request
|
85
|
+
|
86
|
+
# We need to integrate our application with web server, for example with the Rack.
|
87
|
+
# When the server receive web request, it calls the :call method of our RackAdapter
|
88
|
+
class RackAdapter
|
89
|
+
# Injecting components
|
90
|
+
inject request: :request, controller: :controller
|
91
|
+
|
92
|
+
def call env
|
93
|
+
# We need to tell Micon that the :request scope is started, so it will know
|
94
|
+
# that some dynamic components should be created during this scope and
|
95
|
+
# destroyed at the end of it.
|
96
|
+
rad.activate :request, {} do
|
97
|
+
# Here we manually creating the Request component
|
98
|
+
self.request = Request.new '/index'
|
99
|
+
|
100
|
+
# The :router also can be injected via :inject,
|
101
|
+
# but we can also use another way to access components,
|
102
|
+
# every component also availiable as rad.<component_name>
|
103
|
+
controller_class, method = rad.router.decode request
|
104
|
+
|
105
|
+
# Let's create and call our controller
|
106
|
+
self.controller = controller_class.new
|
107
|
+
controller.send method
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Let's pretend that there's a Web Server and run our application,
|
113
|
+
# You should see something like this in the console:
|
114
|
+
# Application: processing /index
|
115
|
+
RackAdapter.new.call({})
|
116
|
+
```
|
117
|
+
|
118
|
+
The example above is a good way to demonstrate how the IoC works in general, but it will not show two **extremelly important** aspects of IoC: **auto-discovery** and **auto-configuration**.
|
119
|
+
In real-life scenario You probably will use it in a little different way, as will be shown below, and utilize these important features (there's a short article about why these features are important [You underestimate the power of IoC][article]).
|
120
|
+
|
121
|
+
I would like to repeat it one more time - **auto-discovery and auto-configuration is extremelly important features** of the IoC, don't ignore them.
|
122
|
+
|
123
|
+
Below are the same example but done with utilizing these features, this is how the Micon IoC is supposed be used in the real-life scenario. As You can see it's almost empty, because all the components are auto-discovered, auto-loaded and auto-configured. Components are located in the [spec/example_spec/lib](https://github.com/alexeypetrushin/micon/blob/master/spec/example_spec/lib) folder.
|
124
|
+
|
125
|
+
Please note that this time logger convigured automatically, with logger.yml configuration file.
|
126
|
+
|
127
|
+
``` ruby
|
128
|
+
require 'micon'
|
129
|
+
require 'class_loader'
|
130
|
+
|
131
|
+
# Here's our Web Framework, let's call it Rad
|
132
|
+
|
133
|
+
# Let's define shortcut to access the IoC API (optional
|
134
|
+
# but handy step). I don't know how You would like to call it,
|
135
|
+
# so I leave this step to You.
|
136
|
+
class ::Object
|
137
|
+
def rad; MICON end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Auto-discovering:
|
141
|
+
#
|
142
|
+
# All components (:logger, :router, :request, :controller) are
|
143
|
+
# defined in spec/example_spec/lib/components folder.
|
144
|
+
# All classes (PagesController, RackAdapter) are
|
145
|
+
# located in spec/example_spec/lib folder.
|
146
|
+
#
|
147
|
+
# Note that there's no any "require 'xxx'" clause, all components and
|
148
|
+
# classes are loaded and dependecies are resolved automatically.
|
149
|
+
|
150
|
+
# Auto-configuring
|
151
|
+
#
|
152
|
+
# Remember our manual configuration of "logger.log_file_path" from
|
153
|
+
# the previous example?
|
154
|
+
# This time it will be configured automatically, take a look at
|
155
|
+
# the spec/example_spec/lib/components/logger.yml file.
|
156
|
+
#
|
157
|
+
# Note, that there are also logger.production.yml, configs are smart
|
158
|
+
# and are merged in the following order:
|
159
|
+
# logger.yml <- logger.<env>.yml <- <runtime_path>/config/logger.yml
|
160
|
+
# (If you define :environment and :runtime_path variables).
|
161
|
+
|
162
|
+
# Let's pretend that there's a Web Server and run our application,
|
163
|
+
# You should see something like this in the console:
|
164
|
+
# Application: processing /index
|
165
|
+
RackAdapter.new.call({})
|
166
|
+
```
|
167
|
+
|
168
|
+
For the actual code please look at [spec/example_spec.rb](https://github.com/alexeypetrushin/micon/blob/master/spec/example_spec.rb)
|
73
169
|
|
74
170
|
## Note
|
75
171
|
|
76
172
|
Current wersion isn't thread-safe, instead it supported evented IO (EventMachine).
|
77
|
-
Actually I implemented first wersion as thread-safe, but because there's no actual multithreading in
|
78
|
-
|
79
|
-
|
80
|
-
|
173
|
+
Actually I implemented first wersion as thread-safe, but because there's no actual multithreading in Ruby, the only thing it does - adds complexity and performance losses, so I removed it.
|
174
|
+
But if you need it it can be easily done.
|
175
|
+
|
81
176
|
## Installation
|
82
177
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
there's no multithreading in ruby.
|
89
|
-
- refactor specs, they are messy a little.
|
90
|
-
- maybe it makes sense to add ability to add dependencies for components after component registration?
|
178
|
+
``` bash
|
179
|
+
gem install micon
|
180
|
+
```
|
181
|
+
|
182
|
+
## License
|
91
183
|
|
92
184
|
Copyright (c) Alexey Petrushin http://petrush.in, released under the MIT license.
|
93
185
|
|
94
186
|
[ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
|
95
|
-
[rad_core]: https://github.com/alexeypetrushin/rad_core
|
187
|
+
[rad_core]: https://github.com/alexeypetrushin/rad_core
|
188
|
+
[article]: http://ruby-lang.info/blog/you-underestimate-the-power-of-ioc-3fh
|
data/spec/callbacks_spec.rb
CHANGED
@@ -8,17 +8,17 @@ describe "Callbacks" do
|
|
8
8
|
describe "components callbacs" do
|
9
9
|
it "basic" do
|
10
10
|
micon.register(:the_object){"The Object"}
|
11
|
-
|
11
|
+
|
12
12
|
check = mock
|
13
13
|
check.should_receive(:before)
|
14
14
|
micon.before :the_object do
|
15
15
|
check.before
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
check.should_receive(:after1).ordered
|
19
19
|
check.should_receive(:after2).ordered
|
20
20
|
obj = nil
|
21
|
-
micon.after :the_object do |o|
|
21
|
+
micon.after :the_object do |o|
|
22
22
|
check.after1
|
23
23
|
obj = o
|
24
24
|
end
|
@@ -26,7 +26,7 @@ describe "Callbacks" do
|
|
26
26
|
check.after2
|
27
27
|
obj.object_id.should == o.object_id
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
micon[:the_object].should == obj
|
31
31
|
end
|
32
32
|
|
@@ -54,8 +54,8 @@ describe "Callbacks" do
|
|
54
54
|
micon.after_scope(:custom){|container| check.after2 container}
|
55
55
|
|
56
56
|
micon.activate(:custom, {}){check.run}
|
57
|
-
end
|
58
|
-
end
|
57
|
+
end
|
58
|
+
end
|
59
59
|
|
60
60
|
describe "miscellaneous" do
|
61
61
|
it "should fire callbacks after assigning component" do
|
@@ -67,32 +67,32 @@ describe "Callbacks" do
|
|
67
67
|
end
|
68
68
|
micon.the_object = 'the_object'
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
it "should raise error if callback defined after component already created" do
|
72
72
|
micon.register(:the_object){"the_object"}
|
73
73
|
micon[:the_object]
|
74
|
-
|
74
|
+
|
75
75
|
-> {micon.before(:the_object){}}.should raise_error(/already created/)
|
76
76
|
-> {micon.after(:the_object){}}.should raise_error(/already created/)
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
it "should raise error if callback defined after scope already started" do
|
80
80
|
micon.activate :custom, {} do
|
81
81
|
-> {micon.before_scope(:custom){}}.should raise_error(/already started/)
|
82
82
|
-> {micon.after_scope(:custom){}}.should raise_error(/already started/)
|
83
83
|
end
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
it ":after with bang: false should execute callback if component already started and also register it as :after callback" do
|
87
87
|
micon.register(:the_object){"the_object"}
|
88
88
|
micon[:the_object]
|
89
|
-
|
89
|
+
|
90
90
|
check = mock
|
91
|
-
check.should_receive(:first).twice
|
91
|
+
check.should_receive(:first).twice
|
92
92
|
micon.after(:the_object, bang: false){check.first}
|
93
|
-
|
93
|
+
|
94
94
|
micon.delete :the_object
|
95
95
|
micon[:the_object]
|
96
96
|
end
|
97
|
-
end
|
97
|
+
end
|
98
98
|
end
|
data/spec/config_spec.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe "Configuration" do
|
3
|
+
describe "Configuration" do
|
4
4
|
before{self.micon = Micon::Core.new}
|
5
5
|
|
6
6
|
it "should configure component if config provided" do
|
7
|
-
micon.register(:logger){::OpenStruct.new}
|
8
|
-
with_load_path "#{spec_dir}/basic/lib" do
|
7
|
+
micon.register(:logger){::OpenStruct.new}
|
8
|
+
with_load_path "#{spec_dir}/basic/lib" do
|
9
9
|
micon[:logger].level.should == :info
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
it "should merge in order: conf <- conf.mode <- runtime <- runtime.mode" do
|
14
14
|
micon.register(:object){::OpenStruct.new}
|
15
|
-
with_load_path "#{spec_dir}/order/lib" do
|
15
|
+
with_load_path "#{spec_dir}/order/lib" do
|
16
16
|
micon.runtime_path = "#{spec_dir}/order/app"
|
17
17
|
micon.mode = :production
|
18
18
|
micon[:object].tap do |o|
|
data/spec/constants_spec.rb
CHANGED
@@ -1,70 +1,70 @@
|
|
1
1
|
# require 'spec_helper'
|
2
|
-
#
|
2
|
+
#
|
3
3
|
# describe "Autoloading" do
|
4
4
|
# with_load_path "#{spec_dir}/get_constant_component/lib"
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# before do
|
7
7
|
# self.micon = Micon::Core.new
|
8
8
|
# end
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# after do
|
11
11
|
# remove_constants :TheRouter, :TheRad, :TheController, :SomeModule
|
12
12
|
# end
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# describe "get_constant_component" do
|
15
15
|
# it "should autoload components" do
|
16
16
|
# micon.get_constant_component(:TheController).should == "TheController"
|
17
17
|
# end
|
18
|
-
#
|
18
|
+
#
|
19
19
|
# it "should not raise error if component not defined" do
|
20
20
|
# micon.get_constant_component(:TheValue).should == nil
|
21
21
|
# micon.register(:TheValue, constant: true){"TheValue"}
|
22
22
|
# micon.get_constant_component(:TheValue).should == "TheValue"
|
23
23
|
# end
|
24
|
-
#
|
24
|
+
#
|
25
25
|
# it "should get constants only" do
|
26
26
|
# micon.register(:TheController){"TheController"}
|
27
27
|
# micon.get_constant_component(:TheController).should == nil
|
28
|
-
#
|
28
|
+
#
|
29
29
|
# micon.register(:TheController, constant: true){"TheController"}
|
30
30
|
# micon.get_constant_component(:TheController).should == "TheController"
|
31
31
|
# end
|
32
32
|
# end
|
33
|
-
#
|
33
|
+
#
|
34
34
|
# it 'validation' do
|
35
35
|
# -> {micon.register 'TheController', constant: true}.should raise_error(/symbol/)
|
36
36
|
# -> {micon.register 'TheController'.to_sym, constant: true, scope: :custom}.should raise_error(/scope/)
|
37
37
|
# end
|
38
|
-
#
|
38
|
+
#
|
39
39
|
# it "should use constants as components" do
|
40
40
|
# -> {::TheRouter}.should raise_error(/uninitialized constant/)
|
41
|
-
#
|
41
|
+
#
|
42
42
|
# micon.register :TheRouter, constant: true do
|
43
43
|
# "TheRouter"
|
44
|
-
# end
|
45
|
-
#
|
44
|
+
# end
|
45
|
+
#
|
46
46
|
# module ::TheRad
|
47
47
|
# TheRouter.should == 'TheRouter'
|
48
48
|
# end
|
49
49
|
# ::TheRouter.should == 'TheRouter'
|
50
50
|
# micon[:TheRouter].should == 'TheRouter'
|
51
51
|
# end
|
52
|
-
#
|
52
|
+
#
|
53
53
|
# it "should support nested constants" do
|
54
|
-
# module ::TheRad; end
|
54
|
+
# module ::TheRad; end
|
55
55
|
# -> {::TheRad::TheView}.should raise_error(/uninitialized constant/)
|
56
|
-
#
|
56
|
+
#
|
57
57
|
# micon.register 'TheRad::TheView'.to_sym, constant: true do
|
58
58
|
# 'TheRad::TheView'
|
59
|
-
# end
|
60
|
-
#
|
59
|
+
# end
|
60
|
+
#
|
61
61
|
# module ::SomeModule
|
62
62
|
# ::TheRad::TheView.should == 'TheRad::TheView'
|
63
63
|
# end
|
64
64
|
# ::TheRad::TheView.should == 'TheRad::TheView'
|
65
65
|
# micon['TheRad::TheView'.to_sym].should == 'TheRad::TheView'
|
66
66
|
# end
|
67
|
-
#
|
67
|
+
#
|
68
68
|
# it "should check if constant is already defined" do
|
69
69
|
# micon.register :TheRouter, constant: true do
|
70
70
|
# class ::TheRouter; end
|
data/spec/custom_scope_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe "Custom Scope" do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
it "activate" do
|
9
|
-
container = {}
|
9
|
+
container = {}
|
10
10
|
micon.should_not be_active(:custom)
|
11
11
|
micon.activate :custom, container
|
12
12
|
micon.should be_active(:custom)
|
@@ -15,7 +15,7 @@ describe "Custom Scope" do
|
|
15
15
|
|
16
16
|
micon.deactivate :custom
|
17
17
|
-> {micon.deactivate :custom}.should raise_error(/not active/)
|
18
|
-
|
18
|
+
|
19
19
|
micon.should_not be_active(:custom)
|
20
20
|
micon.activate :custom, container do
|
21
21
|
micon.should be_active(:custom)
|
@@ -31,20 +31,20 @@ describe "Custom Scope" do
|
|
31
31
|
it "get" do
|
32
32
|
micon.register(:value, scope: :custom){"The Object"}
|
33
33
|
container, the_object = {}, nil
|
34
|
-
|
34
|
+
|
35
35
|
micon.activate :custom, container do
|
36
36
|
micon[:value].should == "The Object"
|
37
37
|
the_object = micon[:value]
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
micon.activate :custom, {} do
|
41
41
|
micon[:value].object_id.should_not == the_object.object_id
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
micon.activate :custom, container do
|
45
45
|
micon[:value].object_id.should == the_object.object_id
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
container.size.should == 1
|
49
49
|
container[:value].should == the_object
|
50
50
|
end
|
@@ -52,17 +52,17 @@ describe "Custom Scope" do
|
|
52
52
|
it "set" do
|
53
53
|
micon.register(:value, scope: :custom){"The Object"}
|
54
54
|
container = {}
|
55
|
-
|
55
|
+
|
56
56
|
micon.activate :custom, container do
|
57
57
|
micon[:value].should == "The Object"
|
58
58
|
micon[:value] = "Another Object"
|
59
59
|
the_object = micon[:value]
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
micon.activate :custom, {} do
|
63
63
|
micon[:value].should == "The Object"
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
micon.activate :custom, container do
|
67
67
|
micon[:value].should == "Another Object"
|
68
68
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# The :controller component should be created and destroyed dynamically,
|
2
|
+
# for each request, we specifying that component is dynamic
|
3
|
+
# by declaring it's :scope.
|
4
|
+
# And, we don't know beforehead what it actully will be, for different
|
5
|
+
# request there can be different controllers,
|
6
|
+
# so, here we just declaring it without any initialization block, it
|
7
|
+
# will be created at runtime later.
|
8
|
+
rad.register :controller, scope: :request
|
@@ -0,0 +1 @@
|
|
1
|
+
log_file_path: /tmp/rad.production.log
|
@@ -0,0 +1 @@
|
|
1
|
+
log_file_path: /tmp/rad.log
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# The :router requires complex initialization, so we use
|
2
|
+
# another form of component registration.
|
3
|
+
class Router
|
4
|
+
def initialize routes; @routes = routes end
|
5
|
+
def decode request;
|
6
|
+
class_name, method = @routes[request.url]
|
7
|
+
return eval(class_name), method # returning actual class
|
8
|
+
end
|
9
|
+
end
|
10
|
+
rad.register :router do
|
11
|
+
Router.new '/index' => ['PagesController', :index]
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Let's define some of our controllers, the PagesController, note - we
|
2
|
+
# don't register it as component.
|
3
|
+
class PagesController
|
4
|
+
# We need access to :logger and :request, let's inject them
|
5
|
+
inject logger: :logger, request: :request
|
6
|
+
|
7
|
+
def index
|
8
|
+
# Here we can use injected component
|
9
|
+
logger.info "Application: processing #{request}"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# We need to integrate our application with web server, for example with the Rack.
|
2
|
+
# When the server receive web request, it calls the :call method of our RackAdapter
|
3
|
+
class RackAdapter
|
4
|
+
# Injecting components
|
5
|
+
inject request: :request, controller: :controller
|
6
|
+
|
7
|
+
def call env
|
8
|
+
# We need to tell Micon that the :request scope is started, so it will know
|
9
|
+
# that some dynamic components should be created during this scope and
|
10
|
+
# destroyed at the end of it.
|
11
|
+
rad.activate :request, {} do
|
12
|
+
# Here we manually creating the Request component
|
13
|
+
self.request = Request.new '/index'
|
14
|
+
|
15
|
+
# The :router also can be injected via :inject,
|
16
|
+
# but we can also use another way to access components,
|
17
|
+
# every component also availiable as rad.<component_name>
|
18
|
+
controller_class, method = rad.router.decode request
|
19
|
+
|
20
|
+
# Let's create and call our controller
|
21
|
+
self.controller = controller_class.new
|
22
|
+
controller.send method
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|