micon 0.1.19 → 0.1.20
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.rb +3 -1
- data/readme.md +116 -140
- metadata +3 -3
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rake_ext'
|
|
3
3
|
project(
|
4
4
|
name: "micon",
|
5
5
|
gem: true,
|
6
|
-
summary: "
|
6
|
+
summary: "Silent and invisible Killer of dependencies and configs",
|
7
7
|
|
8
8
|
author: "Alexey Petrushin",
|
9
9
|
homepage: "http://github.com/alexeypetrushin/micon"
|
data/lib/micon.rb
CHANGED
data/readme.md
CHANGED
@@ -1,177 +1,154 @@
|
|
1
|
-
# Micon
|
1
|
+
# Micon - silent and invisible Killer of dependencies and configs
|
2
2
|
|
3
|
-
Micon
|
3
|
+
Micon allows You easilly and transparently eliminate dependencies and configs in Your Application. Usually, when You are building complex system there are following tasks should be solved:
|
4
4
|
|
5
|
-
|
5
|
+
- where the component's code is located
|
6
|
+
- in what order should it be loaded
|
7
|
+
- what configs does the component needs to be properly initialized
|
8
|
+
- where those configs are stored
|
9
|
+
- how to change configs in different environments
|
10
|
+
- where are dependencies for component and how they should be initialized
|
11
|
+
- how to replace some components with custom implementation
|
12
|
+
- how to assembly parts of application for specs/tests
|
13
|
+
- how to restore state after each spec/test (isolate it from each other)
|
14
|
+
- how to control life-cycle of dynamically created components
|
15
|
+
- connecting components to assemble an application
|
6
16
|
|
7
|
-
|
17
|
+
*By component I mean any parts of code logically grouped together.*
|
8
18
|
|
9
|
-
|
19
|
+
Micon **solves all these tasks automatically**, and has the following **price** - You has to:
|
10
20
|
|
11
|
-
|
21
|
+
- use the *register component_name, &initialization_block* method for component initialization
|
22
|
+
- use the *inject component_name* to whire components toghether
|
23
|
+
- place component definition to the lib/components folder
|
12
24
|
|
13
|
-
|
25
|
+
That's all the price, not a big one, compared to the value, eh?
|
26
|
+
That all You need to know to use 95% of it, there are also 2-3 more specific methods, but they are needed very rarelly.
|
14
27
|
|
15
|
-
|
16
|
-
|
17
|
-
|
28
|
+
Techincally Micon is sort of Dependency Injector, but because of it's simplicity and invisibility it looks like an alien compared to it's complex and bloated IoC / DI cousins.
|
29
|
+
|
30
|
+
## Basic example
|
18
31
|
|
32
|
+
``` ruby
|
19
33
|
require 'micon'
|
34
|
+
# standard ruby logger
|
35
|
+
require 'logger'
|
20
36
|
|
21
|
-
|
22
|
-
def micon; MICON end
|
37
|
+
micon.register(:logger){Logger.new}
|
23
38
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def info msg
|
30
|
-
puts "#{msg} (writen to #{log_file_path})" unless defined?(RSpec)
|
39
|
+
class Application
|
40
|
+
inject logger: :logger
|
41
|
+
|
42
|
+
def run
|
43
|
+
logger.info 'running ...'
|
31
44
|
end
|
32
45
|
end
|
33
46
|
|
34
|
-
#
|
35
|
-
|
36
|
-
micon.logger.log_file_path = '/tmp/web_framework.log'
|
37
|
-
|
38
|
-
# The :router requires complex initialization, so we use
|
39
|
-
# another form of component registration.
|
40
|
-
class Router
|
41
|
-
def initialize routes; @routes = routes end
|
42
|
-
def decode request;
|
43
|
-
class_name, method = @routes[request.url]
|
44
|
-
return eval(class_name), method # returning actual class
|
45
|
-
end
|
46
|
-
end
|
47
|
-
micon.register :router do
|
48
|
-
Router.new '/index' => ['PagesController', :index]
|
49
|
-
end
|
47
|
+
Application.new.run # => running ...
|
48
|
+
```
|
50
49
|
|
51
|
-
|
52
|
-
# for each request, we specifying that component is dynamic
|
53
|
-
# by declaring it's :scope.
|
54
|
-
# And, we don't know beforehead what it actully will be, for different
|
55
|
-
# request there can be different controllers,
|
56
|
-
# so, here we just declaring it without any initialization block, it
|
57
|
-
# will be created at runtime later.
|
58
|
-
micon.register :controller, scope: :request
|
59
|
-
|
60
|
-
# Let's define some of our controllers, the PagesController, note - we
|
61
|
-
# don't register it as component.
|
62
|
-
class PagesController
|
63
|
-
# We need access to :logger and :request, let's inject them
|
64
|
-
inject logger: :logger, request: :request
|
65
|
-
|
66
|
-
def index
|
67
|
-
# Here we can use injected component
|
68
|
-
logger.info "Application: processing #{request}"
|
69
|
-
end
|
70
|
-
end
|
50
|
+
Code in examples/basics.rb
|
71
51
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
def to_s; @url end
|
79
|
-
end
|
80
|
-
# Registering without initialization block.
|
81
|
-
micon.register :request, scope: :request
|
82
|
-
|
83
|
-
# We need to integrate our application with web server, for example with the Rack.
|
84
|
-
# When the server receive web request, it calls the :call method of our RackAdapter
|
85
|
-
class RackAdapter
|
86
|
-
# Injecting components
|
87
|
-
inject request: :request, controller: :controller
|
88
|
-
|
89
|
-
def call env
|
90
|
-
# We need to tell Micon that the :request scope is started, so it will know
|
91
|
-
# that some dynamic components should be created during this scope and
|
92
|
-
# destroyed at the end of it.
|
93
|
-
micon.activate :request, {} do
|
94
|
-
# Here we manually creating the Request component
|
95
|
-
self.request = Request.new '/index'
|
52
|
+
## Advanced example: let's build the Ultima - an Ultimate Web Framework
|
53
|
+
|
54
|
+
This example is more complicated and requires about 3-7 minutes.
|
55
|
+
|
56
|
+
Let's pretend that we are building an Ultimate Framework, the RoR Killer. There will be lot's of modules and dependencies, let's see how Micon can eliminate them.
|
57
|
+
There will be two steps, at the first we'll build it as usual, and at the second refactor it using Micon.
|
96
58
|
|
97
|
-
|
98
|
-
# but we can also use another way to access components,
|
99
|
-
# every component also availiable as micon.<component_name>
|
100
|
-
controller_class, method = micon.router.decode request
|
59
|
+
There will be following components: router, request.
|
101
60
|
|
102
|
-
|
103
|
-
|
61
|
+
``` ruby
|
62
|
+
# Assembling Ultima Framework
|
63
|
+
module Ultima
|
64
|
+
class << self
|
65
|
+
attr_accessor :router, :config
|
66
|
+
|
67
|
+
def run url
|
68
|
+
request = Request.new url
|
69
|
+
|
70
|
+
controller_class, method = router.decode url
|
71
|
+
|
72
|
+
controller = controller_class.new
|
73
|
+
controller.request = request
|
104
74
|
controller.send method
|
105
75
|
end
|
106
76
|
end
|
107
77
|
end
|
108
78
|
|
109
|
-
|
79
|
+
require 'yaml'
|
80
|
+
Ultima.config = YAML.load_file "#{dir}/config/config.yml"
|
81
|
+
|
82
|
+
require 'router'
|
83
|
+
router = Router.new
|
84
|
+
router.url_root = Ultima.config['url_root']
|
85
|
+
Ultima.router = router
|
86
|
+
|
87
|
+
require 'request'
|
88
|
+
require 'controller'
|
89
|
+
|
90
|
+
|
91
|
+
# Assemblilng Application
|
92
|
+
require 'pages_controller'
|
93
|
+
|
94
|
+
Ultima.router.add_route '/index', PagesController, :index
|
95
|
+
|
96
|
+
|
97
|
+
# Let's run it
|
98
|
+
Ultima.run '/index'
|
110
99
|
# You should see something like this in the console:
|
111
|
-
#
|
112
|
-
RackAdapter.new.call({})
|
100
|
+
# PagesController: displaying the :index page.
|
113
101
|
```
|
114
102
|
|
115
|
-
|
116
|
-
|
103
|
+
Code in examples/ultima1/run.rb
|
104
|
+
|
105
|
+
Below are the same example but done with Micon. As You can see there's no any assembling or configuration code, because all the components are auto-discovered, auto-loaded and auto-configured.
|
106
|
+
|
107
|
+
``` ruby
|
108
|
+
# Assembling Ultima Framework
|
109
|
+
# All components: router, request, controller will be automatically loaded & configured.
|
110
|
+
class Ultima
|
111
|
+
inject router: :router
|
112
|
+
|
113
|
+
def run url
|
114
|
+
# we need to tell Micon about the :request scope, so the Request will be
|
115
|
+
# created & destroyed during this scope automatically.
|
116
|
+
micon.activate :request, {} do
|
117
|
+
request = Request.new url
|
118
|
+
|
119
|
+
controller_class, method = router.decode url
|
120
|
+
|
121
|
+
controller = controller_class.new
|
122
|
+
# no need to explicitly set request, it will be automatically injected
|
123
|
+
controller.send method
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
micon.register(:ultima){Ultima.new}
|
128
|
+
|
129
|
+
# No need for 'requre', all classes will be discowered & laoded automatically
|
117
130
|
|
118
|
-
|
131
|
+
# No need for config, Micon will automatically discower config/router.yml
|
119
132
|
|
120
|
-
|
133
|
+
# No need for manual router configuring, router.yml config will be applied automatically
|
121
134
|
|
122
|
-
Note also, that this time logger convigured automatically, with the logger.yml configuration file.
|
123
135
|
|
124
|
-
|
125
|
-
#
|
136
|
+
# Assemblilng Application
|
137
|
+
# Controller will be loaded automatically
|
138
|
+
micon.router.add_route '/index', PagesController, :index
|
126
139
|
|
127
|
-
# Let's suppose that we want to build the Rails clone,
|
128
|
-
# there will be lot's of components - logger, controllers, router, ...
|
129
140
|
|
130
|
-
#
|
131
|
-
|
132
|
-
require 'class_loader'
|
133
|
-
|
134
|
-
# Handy shortcut to access the IoC API (this is optional and You can omit it).
|
135
|
-
def micon; MICON end
|
136
|
-
|
137
|
-
# Auto-discovering:
|
138
|
-
#
|
139
|
-
# All components (:logger, :router, :request, :controller) are defined in
|
140
|
-
# the web_framework2/lib/components folder.
|
141
|
-
# All classes (PagesController, RackAdapter) are
|
142
|
-
# located in web_framework2/lib folder.
|
143
|
-
#
|
144
|
-
# Note that there will be no any "require 'xxx'" clause, all components and
|
145
|
-
# classes will be loaded and dependecies be resolved automatically.
|
146
|
-
|
147
|
-
# Adding libraries to load path (in order to load components automatically).
|
148
|
-
lib_dir = "#{File.dirname(__FILE__)}/web_framework2/lib"
|
149
|
-
$LOAD_PATH << lib_dir
|
150
|
-
|
151
|
-
# Adding libraries to autoload path (in order to load classes automatically).
|
152
|
-
autoload_path lib_dir
|
153
|
-
|
154
|
-
# Auto-configuring
|
155
|
-
#
|
156
|
-
# Remember our manual configuration of "logger.log_file_path" from
|
157
|
-
# the previous example?
|
158
|
-
# This time it will be configured automatically, take a look at
|
159
|
-
# the web_framework2/lib/components/logger.yml file.
|
160
|
-
#
|
161
|
-
# Note, that there are also logger.production.yml, Micon is smart
|
162
|
-
# and will merge configs in the following order:
|
163
|
-
# logger.yml <- logger.<env>.yml <- <runtime_path>/config/logger.yml
|
164
|
-
# (If you define :environment and :runtime_path variables).
|
165
|
-
|
166
|
-
# Let's pretend that there's a Web Server and run our application,
|
141
|
+
# Let's run it
|
142
|
+
micon.ultima.run '/index'
|
167
143
|
# You should see something like this in the console:
|
168
|
-
#
|
169
|
-
RackAdapter.new.call({})
|
144
|
+
# PagesController: displaying the :index page.
|
170
145
|
```
|
171
146
|
|
172
|
-
|
147
|
+
Code in examples/ultima2/run.rb
|
148
|
+
|
149
|
+
## More samples
|
173
150
|
|
174
|
-
If You are interested in more samples, please look at the [actual components][rad_core_components] used in the Rad Core Framework.
|
151
|
+
If You are interested in more samples, please take a look at the [actual components][rad_core_components] used in the Rad Core Web Framework.
|
175
152
|
|
176
153
|
## Note
|
177
154
|
|
@@ -190,5 +167,4 @@ Copyright (c) Alexey Petrushin http://petrush.in, released under the MIT license
|
|
190
167
|
|
191
168
|
[ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
|
192
169
|
[rad_core]: https://github.com/alexeypetrushin/rad_core
|
193
|
-
[rad_core_components]: https://github.com/alexeypetrushin/rad_core/tree/master/lib/components
|
194
|
-
[article]: http://ruby-lang.info/blog/you-underestimate-the-power-of-ioc-3fh
|
170
|
+
[rad_core_components]: https://github.com/alexeypetrushin/rad_core/tree/master/lib/components
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: micon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.20
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-08-
|
12
|
+
date: 2011-08-16 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email:
|
@@ -70,5 +70,5 @@ rubyforge_project:
|
|
70
70
|
rubygems_version: 1.8.6
|
71
71
|
signing_key:
|
72
72
|
specification_version: 3
|
73
|
-
summary:
|
73
|
+
summary: Silent and invisible Killer of dependencies and configs
|
74
74
|
test_files: []
|