micon 0.1.16 → 0.1.17
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.
- 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
|