Skip to content
Browse files

small upd & doc update

  • Loading branch information...
1 parent 40c75b2 commit 07dd93f418d47d1e784fc38b655fe72f86898b2e @alexeypetrushin committed Aug 16, 2011
View
3 .gitignore
@@ -1,4 +1,5 @@
*~
.DS_Store
.require_paths
-Thumbs.db
+Thumbs.db
+project_statistics.*
View
2 Rakefile
@@ -3,7 +3,7 @@ require 'rake_ext'
project(
name: "micon",
gem: true,
- summary: "Micon IoC assembles and manages Your Application",
+ summary: "Silent and invisible Killer of dependencies and configs",
author: "Alexey Petrushin",
homepage: "http://github.com/alexeypetrushin/micon"
View
0 examples/basics.rb
No changes.
View
1 examples/ultima1/config/config.yml
@@ -0,0 +1 @@
+url_root: /
View
3 examples/ultima1/lib/controller.rb
@@ -0,0 +1,3 @@
+class Controller
+ attr_accessor :request
+end
View
5 examples/ultima1/lib/pages_controller.rb
@@ -0,0 +1,5 @@
+class PagesController < Controller
+ def index
+ puts "PagesController: displaying the :index page."
+ end
+end
View
4 examples/ultima1/lib/request.rb
@@ -0,0 +1,4 @@
+class Request
+ attr_reader :url
+ def initialize url; @url = url end
+end
View
15 examples/ultima1/lib/router.rb
@@ -0,0 +1,15 @@
+class Router
+ attr_accessor :url_root
+
+ def initialize
+ @routes = {}
+ end
+
+ def add_route url, controller, method
+ @routes[url] = [controller, method]
+ end
+
+ def decode url
+ @routes[url] if url.include?(url_root)
+ end
+end
View
44 examples/ultima1/run.rb
@@ -0,0 +1,44 @@
+# setting load paths
+dir = File.dirname __FILE__
+$LOAD_PATH << "#{dir}/lib"
+
+
+# Assembling Ultima Framework
+module Ultima
+ class << self
+ attr_accessor :router, :config
+
+ def run url
+ request = Request.new url
+
+ controller_class, method = router.decode url
+
+ controller = controller_class.new
+ controller.request = request
+ controller.send method
+ end
+ end
+end
+
+require 'yaml'
+Ultima.config = YAML.load_file "#{dir}/config/config.yml"
+
+require 'router'
+router = Router.new
+router.url_root = Ultima.config['url_root']
+Ultima.router = router
+
+require 'request'
+require 'controller'
+
+
+# Assemblilng Application
+require 'pages_controller'
+
+Ultima.router.add_route '/index', PagesController, :index
+
+
+# Let's run it
+Ultima.run '/index'
+# You should see something like this in the console:
+# PagesController: displaying the :index page.
View
1 examples/ultima2/config/router.yml
@@ -0,0 +1 @@
+url_root: /
View
3 examples/ultima2/lib/components/request.rb
@@ -0,0 +1,3 @@
+# request can't be created automatically because it needs request url,
+# so here we just declaring it without initialization block.
+micon.register :request
View
16 examples/ultima2/lib/components/router.rb
@@ -0,0 +1,16 @@
+class Router
+ attr_accessor :url_root
+
+ def initialize
+ @routes = {}
+ end
+
+ def add_route url, controller, method
+ @routes[url] = [controller, method]
+ end
+
+ def decode url
+ @routes[url] if url.include?(url_root)
+ end
+end
+micon.register(:router){Router.new}
View
3 examples/ultima2/lib/controller.rb
@@ -0,0 +1,3 @@
+class Controller
+ attr_accessor :request
+end
View
5 examples/ultima2/lib/pages_controller.rb
@@ -0,0 +1,5 @@
+class PagesController < Controller
+ def index
+ puts "PagesController: displaying the :index page."
+ end
+end
View
4 examples/ultima2/lib/request.rb
@@ -0,0 +1,4 @@
+class Request
+ attr_reader :url
+ def initialize url; @url = url end
+end
View
48 examples/ultima2/run.rb
@@ -0,0 +1,48 @@
+# setting load paths (we also using automatic class loader)
+dir = File.dirname __FILE__
+$LOAD_PATH << "#{dir}/lib"
+
+require 'class_loader'
+autoload_path "#{dir}/lib"
+
+require 'micon'
+micon.runtime_path = dir
+
+
+# Assembling Ultima Framework
+# All components: router, request, controller will be automatically loaded & configured.
+class Ultima
+ inject router: :router
+
+ def run url
+ # we need to tell Micon about the :request scope, so the Request will be
+ # created & destroyed during this scope automatically.
+ micon.activate :request, {} do
+ request = Request.new url
+
+ controller_class, method = router.decode url
+
+ controller = controller_class.new
+ # no need to explicitly set request, it will be automatically injected
+ controller.send method
+ end
+ end
+end
+micon.register(:ultima){Ultima.new}
+
+# No need for 'requre', all classes will be discowered & laoded automatically
+
+# No need for config, Micon will automatically discower config/router.yml
+
+# No need for manual router configuring, router.yml config will be applied automatically
+
+
+# Assemblilng Application
+# Controller will be loaded automatically
+micon.router.add_route '/index', PagesController, :index
+
+
+# Let's run it
+micon.ultima.run '/index'
+# You should see something like this in the console:
+# PagesController: displaying the :index page.
View
4 lib/micon.rb
@@ -18,4 +18,6 @@ module Micon
# Initializing Micon
Micon::Core.send :include, Micon::Helper
micon = Micon::Core.new
-micon.initialize!
+micon.initialize!
+
+def micon; ::MICON end unless $dont_create_micon_shortcut
View
0 examples/web_framework1.rb → old/v1/examples/web_framework1.rb
File renamed without changes.
View
0 examples/web_framework2.rb → old/v1/examples/web_framework2.rb
File renamed without changes.
View
0 ...b_framework2/lib/components/controller.rb → ...b_framework2/lib/components/controller.rb
File renamed without changes.
View
0 ...ork2/lib/components/logger.production.yml → ...ork2/lib/components/logger.production.yml
File renamed without changes.
View
0 ...s/web_framework2/lib/components/logger.rb → ...s/web_framework2/lib/components/logger.rb
File renamed without changes.
View
0 .../web_framework2/lib/components/logger.yml → .../web_framework2/lib/components/logger.yml
File renamed without changes.
View
0 .../web_framework2/lib/components/request.rb → .../web_framework2/lib/components/request.rb
File renamed without changes.
View
0 ...s/web_framework2/lib/components/router.rb → ...s/web_framework2/lib/components/router.rb
File renamed without changes.
View
0 ...es/web_framework2/lib/pages_controller.rb → ...es/web_framework2/lib/pages_controller.rb
File renamed without changes.
View
0 examples/web_framework2/lib/rack_adapter.rb → ...amples/web_framework2/lib/rack_adapter.rb
File renamed without changes.
View
0 examples/web_framework2/lib/request.rb → ...v1/examples/web_framework2/lib/request.rb
File renamed without changes.
View
194 old/v1/readme.md
@@ -0,0 +1,194 @@
+# Micon IoC assembles and manages Your Application
+
+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.
+
+Concentrate on business logic and interfaces and Micon will provide automatic configuration, life cycle management and dependency resolving.
+
+Technically it's [IoC][ioc] like framework with components, callbacks, scopes and bijections, inspired by Spring and JBoss Seam.
+
+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.
+
+## Usage
+
+Let's suppose you are building the Ruby on Rails clone, there are lots of modules let's try to deal with them
+
+``` ruby
+# Let's suppose that we want to build the Rails clone,
+# there will be lot's of components - logger, controllers, router, ...
+
+require 'micon'
+
+# Handy shortcut to access the IoC API (this is optional and You can omit it).
+def micon; MICON end
+
+# Let's define some components.
+# The :logger is one per application, it's a static component (like singleton).
+class Logger
+ register_as :logger
+ attr_accessor :log_file_path
+ def info msg
+ puts "#{msg} (writen to #{log_file_path})"
+ end
+end
+
+# To demostrate basics of working with compnents let's configure our :logger
+# explicitly (in the next example, it will be configured automatically).
+micon.logger.log_file_path = '/tmp/web_framework.log'
+
+# The :router requires complex initialization, so we use
+# another form of component registration.
+class Router
+ def initialize routes; @routes = routes end
+ def decode request;
+ class_name, method = @routes[request.url]
+ return eval(class_name), method # returning actual class
+ end
+end
+micon.register :router do
+ Router.new '/index' => ['PagesController', :index]
+end
+
+# The :controller component should be created and destroyed dynamically,
+# for each request, we specifying that component is dynamic
+# by declaring it's :scope.
+# And, we don't know beforehead what it actully will be, for different
+# request there can be different controllers,
+# so, here we just declaring it without any initialization block, it
+# will be created at runtime later.
+micon.register :controller, scope: :request
+
+# Let's define some of our controllers, the PagesController, note - we
+# don't register it as component.
+class PagesController
+ # We need access to :logger and :request, let's inject them
+ inject logger: :logger, request: :request
+
+ def index
+ # Here we can use injected component
+ logger.info "Application: processing #{request}"
+ end
+end
+
+# Request is also dynamic, and it also can't be created beforehead.
+# We also registering it without initialization, it will be
+# created at runtime later.
+class Request
+ attr_reader :url
+ def initialize url; @url = url end
+ def to_s; @url end
+end
+# Registering without initialization block.
+micon.register :request, scope: :request
+
+# We need to integrate our application with web server, for example with the Rack.
+# When the server receive web request, it calls the :call method of our RackAdapter
+class RackAdapter
+ # Injecting components
+ inject request: :request, controller: :controller
+
+ def call env
+ # We need to tell Micon that the :request scope is started, so it will know
+ # that some dynamic components should be created during this scope and
+ # destroyed at the end of it.
+ micon.activate :request, {} do
+ # Here we manually creating the Request component
+ self.request = Request.new '/index'
+
+ # The :router also can be injected via :inject,
+ # but we can also use another way to access components,
+ # every component also availiable as micon.<component_name>
+ controller_class, method = micon.router.decode request
+
+ # Let's create and call our controller
+ self.controller = controller_class.new
+ controller.send method
+ end
+ end
+end
+
+# Let's pretend that there's a Web Server and run our application,
+# You should see something like this in the console:
+# Application: processing /index
+RackAdapter.new.call({})
+```
+
+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**.
+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]).
+
+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.
+
+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 [examples/web_framework2/lib/components](https://github.com/alexeypetrushin/micon/blob/master/examples/web_framework2/lib/components) folder.
+
+Note also, that this time logger convigured automatically, with the logger.yml configuration file.
+
+``` ruby
+# Please examine the 'web_framework1.rb' example before proceeding with this one.
+
+# Let's suppose that we want to build the Rails clone,
+# there will be lot's of components - logger, controllers, router, ...
+
+# In this example we also need another tool that automatically find & load classes.
+require 'micon'
+require 'class_loader'
+
+# Handy shortcut to access the IoC API (this is optional and You can omit it).
+def micon; MICON end
+
+# Auto-discovering:
+#
+# All components (:logger, :router, :request, :controller) are defined in
+# the web_framework2/lib/components folder.
+# All classes (PagesController, RackAdapter) are
+# located in web_framework2/lib folder.
+#
+# Note that there will be no any "require 'xxx'" clause, all components and
+# classes will be loaded and dependecies be resolved automatically.
+
+# Adding libraries to load path (in order to load components automatically).
+lib_dir = "#{File.dirname(__FILE__)}/web_framework2/lib"
+$LOAD_PATH << lib_dir
+
+# Adding libraries to autoload path (in order to load classes automatically).
+autoload_path lib_dir
+
+# Auto-configuring
+#
+# Remember our manual configuration of "logger.log_file_path" from
+# the previous example?
+# This time it will be configured automatically, take a look at
+# the web_framework2/lib/components/logger.yml file.
+#
+# Note, that there are also logger.production.yml, Micon is smart
+# and will merge configs in the following order:
+# logger.yml <- logger.<env>.yml <- <runtime_path>/config/logger.yml
+# (If you define :environment and :runtime_path variables).
+
+# Let's pretend that there's a Web Server and run our application,
+# You should see something like this in the console:
+# Application: processing /index
+RackAdapter.new.call({})
+```
+
+For the actual code please look at [examples](https://github.com/alexeypetrushin/micon/blob/master/examples).
+
+If You are interested in more samples, please look at the [actual components][rad_core_components] used in the Rad Core Framework.
+
+## Note
+
+Current wersion isn't thread-safe, and I did it intentially. Actually, the first version was implemented 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.
+But if you really need it for some reason - it can be easily done.
+
+## Installation
+
+``` bash
+gem install micon
+```
+
+## License
+
+Copyright (c) Alexey Petrushin http://petrush.in, released under the MIT license.
+
+[ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
+[rad_core]: https://github.com/alexeypetrushin/rad_core
+[rad_core_components]: https://github.com/alexeypetrushin/rad_core/tree/master/lib/components
+[article]: http://ruby-lang.info/blog/you-underestimate-the-power-of-ioc-3fh
View
256 readme.md
@@ -1,177 +1,154 @@
-# Micon IoC assembles and manages Your Application
+# Micon - silent and invisible Killer of dependencies and configs
-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.
+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:
-Concentrate on business logic and interfaces and Micon will provide automatic configuration, life cycle management and dependency resolving.
+- where the component's code is located
+- in what order should it be loaded
+- what configs does the component needs to be properly initialized
+- where those configs are stored
+- how to change configs in different environments
+- where are dependencies for component and how they should be initialized
+- how to replace some components with custom implementation
+- how to assembly parts of application for specs/tests
+- how to restore state after each spec/test (isolate it from each other)
+- how to control life-cycle of dynamically created components
+- connecting components to assemble an application
-Technically it's [IoC][ioc] like framework with components, callbacks, scopes and bijections, inspired by Spring and JBoss Seam.
+*By component I mean any parts of code logically grouped together.*
-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.
+Micon **solves all these tasks automatically**, and has the following **price** - You has to:
-## Usage
+- use the *register component_name, &initialization_block* method for component initialization
+- use the *inject component_name* to whire components toghether
+- place component definition to the lib/components folder
-Let's suppose you are building the Ruby on Rails clone, there are lots of modules let's try to deal with them
+That's all the price, not a big one, compared to the value, eh?
+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.
-``` ruby
-# Let's suppose that we want to build the Rails clone,
-# there will be lot's of components - logger, controllers, router, ...
+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.
+
+## Basic example
+``` ruby
require 'micon'
+# standard ruby logger
+require 'logger'
-# Handy shortcut to access the IoC API (this is optional and You can omit it).
-def micon; MICON end
+micon.register(:logger){Logger.new}
-# Let's define some components.
-# The :logger is one per application, it's a static component (like singleton).
-class Logger
- register_as :logger
- attr_accessor :log_file_path
- def info msg
- puts "#{msg} (writen to #{log_file_path})"
+class Application
+ inject logger: :logger
+
+ def run
+ logger.info 'running ...'
end
end
-# To demostrate basics of working with compnents let's configure our :logger
-# explicitly (in the next example, it will be configured automatically).
-micon.logger.log_file_path = '/tmp/web_framework.log'
-
-# The :router requires complex initialization, so we use
-# another form of component registration.
-class Router
- def initialize routes; @routes = routes end
- def decode request;
- class_name, method = @routes[request.url]
- return eval(class_name), method # returning actual class
- end
-end
-micon.register :router do
- Router.new '/index' => ['PagesController', :index]
-end
+Application.new.run # => running ...
+```
-# The :controller component should be created and destroyed dynamically,
-# for each request, we specifying that component is dynamic
-# by declaring it's :scope.
-# And, we don't know beforehead what it actully will be, for different
-# request there can be different controllers,
-# so, here we just declaring it without any initialization block, it
-# will be created at runtime later.
-micon.register :controller, scope: :request
-
-# Let's define some of our controllers, the PagesController, note - we
-# don't register it as component.
-class PagesController
- # We need access to :logger and :request, let's inject them
- inject logger: :logger, request: :request
-
- def index
- # Here we can use injected component
- logger.info "Application: processing #{request}"
- end
-end
+Code in examples/basics.rb
-# Request is also dynamic, and it also can't be created beforehead.
-# We also registering it without initialization, it will be
-# created at runtime later.
-class Request
- attr_reader :url
- def initialize url; @url = url end
- def to_s; @url end
-end
-# Registering without initialization block.
-micon.register :request, scope: :request
-
-# We need to integrate our application with web server, for example with the Rack.
-# When the server receive web request, it calls the :call method of our RackAdapter
-class RackAdapter
- # Injecting components
- inject request: :request, controller: :controller
-
- def call env
- # We need to tell Micon that the :request scope is started, so it will know
- # that some dynamic components should be created during this scope and
- # destroyed at the end of it.
- micon.activate :request, {} do
- # Here we manually creating the Request component
- self.request = Request.new '/index'
+## Advanced example: let's build the Ultima - an Ultimate Web Framework
+
+This example is more complicated and requires about 3-7 minutes.
+
+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.
+There will be two steps, at the first we'll build it as usual, and at the second refactor it using Micon.
- # The :router also can be injected via :inject,
- # but we can also use another way to access components,
- # every component also availiable as micon.<component_name>
- controller_class, method = micon.router.decode request
+There will be following components: router, request.
- # Let's create and call our controller
- self.controller = controller_class.new
+``` ruby
+# Assembling Ultima Framework
+module Ultima
+ class << self
+ attr_accessor :router, :config
+
+ def run url
+ request = Request.new url
+
+ controller_class, method = router.decode url
+
+ controller = controller_class.new
+ controller.request = request
controller.send method
end
end
end
-# Let's pretend that there's a Web Server and run our application,
+require 'yaml'
+Ultima.config = YAML.load_file "#{dir}/config/config.yml"
+
+require 'router'
+router = Router.new
+router.url_root = Ultima.config['url_root']
+Ultima.router = router
+
+require 'request'
+require 'controller'
+
+
+# Assemblilng Application
+require 'pages_controller'
+
+Ultima.router.add_route '/index', PagesController, :index
+
+
+# Let's run it
+Ultima.run '/index'
# You should see something like this in the console:
-# Application: processing /index
-RackAdapter.new.call({})
+# PagesController: displaying the :index page.
```
-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**.
-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]).
+Code in examples/ultima1/run.rb
+
+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.
+
+``` ruby
+# Assembling Ultima Framework
+# All components: router, request, controller will be automatically loaded & configured.
+class Ultima
+ inject router: :router
+
+ def run url
+ # we need to tell Micon about the :request scope, so the Request will be
+ # created & destroyed during this scope automatically.
+ micon.activate :request, {} do
+ request = Request.new url
+
+ controller_class, method = router.decode url
+
+ controller = controller_class.new
+ # no need to explicitly set request, it will be automatically injected
+ controller.send method
+ end
+ end
+end
+micon.register(:ultima){Ultima.new}
+
+# No need for 'requre', all classes will be discowered & laoded automatically
-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.
+# No need for config, Micon will automatically discower config/router.yml
-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 [examples/web_framework2/lib/components](https://github.com/alexeypetrushin/micon/blob/master/examples/web_framework2/lib/components) folder.
+# No need for manual router configuring, router.yml config will be applied automatically
-Note also, that this time logger convigured automatically, with the logger.yml configuration file.
-``` ruby
-# Please examine the 'web_framework1.rb' example before proceeding with this one.
+# Assemblilng Application
+# Controller will be loaded automatically
+micon.router.add_route '/index', PagesController, :index
-# Let's suppose that we want to build the Rails clone,
-# there will be lot's of components - logger, controllers, router, ...
-# In this example we also need another tool that automatically find & load classes.
-require 'micon'
-require 'class_loader'
-
-# Handy shortcut to access the IoC API (this is optional and You can omit it).
-def micon; MICON end
-
-# Auto-discovering:
-#
-# All components (:logger, :router, :request, :controller) are defined in
-# the web_framework2/lib/components folder.
-# All classes (PagesController, RackAdapter) are
-# located in web_framework2/lib folder.
-#
-# Note that there will be no any "require 'xxx'" clause, all components and
-# classes will be loaded and dependecies be resolved automatically.
-
-# Adding libraries to load path (in order to load components automatically).
-lib_dir = "#{File.dirname(__FILE__)}/web_framework2/lib"
-$LOAD_PATH << lib_dir
-
-# Adding libraries to autoload path (in order to load classes automatically).
-autoload_path lib_dir
-
-# Auto-configuring
-#
-# Remember our manual configuration of "logger.log_file_path" from
-# the previous example?
-# This time it will be configured automatically, take a look at
-# the web_framework2/lib/components/logger.yml file.
-#
-# Note, that there are also logger.production.yml, Micon is smart
-# and will merge configs in the following order:
-# logger.yml <- logger.<env>.yml <- <runtime_path>/config/logger.yml
-# (If you define :environment and :runtime_path variables).
-
-# Let's pretend that there's a Web Server and run our application,
+# Let's run it
+micon.ultima.run '/index'
# You should see something like this in the console:
-# Application: processing /index
-RackAdapter.new.call({})
+# PagesController: displaying the :index page.
```
-For the actual code please look at [examples](https://github.com/alexeypetrushin/micon/blob/master/examples).
+Code in examples/ultima2/run.rb
+
+## More samples
-If You are interested in more samples, please look at the [actual components][rad_core_components] used in the Rad Core Framework.
+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.
## Note
@@ -190,5 +167,4 @@ Copyright (c) Alexey Petrushin http://petrush.in, released under the MIT license
[ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
[rad_core]: https://github.com/alexeypetrushin/rad_core
-[rad_core_components]: https://github.com/alexeypetrushin/rad_core/tree/master/lib/components
-[article]: http://ruby-lang.info/blog/you-underestimate-the-power-of-ioc-3fh
+[rad_core_components]: https://github.com/alexeypetrushin/rad_core/tree/master/lib/components

0 comments on commit 07dd93f

Please sign in to comment.
Something went wrong with that request. Please try again.