micon 0.1.17 → 0.1.18

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/lib/micon/module.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  Module.class_eval do
2
- #
2
+ #
3
3
  # inject attribute: :session
4
- #
4
+ #
5
5
  def inject attributes
6
6
  ::MICON.raise_without_self "Invalid argument!" unless attributes.is_a? Hash
7
7
  attributes.each do |name, specificator|
8
- ::MICON.raise_without_self "Attribute name should be a Symbol!" unless name.is_a? Symbol
9
-
8
+ ::MICON.raise_without_self "Attribute name should be a Symbol!" unless name.is_a? Symbol
9
+
10
10
  if [Class, Module].include? specificator.class
11
11
  specificator = specificator.name
12
12
  elsif specificator.is_a? Symbol
@@ -28,24 +28,24 @@ def #{name}?
28
28
  ::MICON.include? #{specificator}
29
29
  end
30
30
  RUBY
31
-
31
+
32
32
  self.class_eval script, __FILE__, __LINE__
33
33
  end
34
- end
35
-
36
-
37
- #
34
+ end
35
+
36
+
37
+ #
38
38
  # Hook to use Constants as Components
39
- #
39
+ #
40
40
  # if defined? ::ClassLoader
41
41
  # text = <<-TEXT
42
42
  # It seems that ClassLoader already defined, but it supposed to be activated after the Micon, otherwise it can cause performance loss!
43
- # Micon.const_missing extension should be included before than ClassLoader.const_missing otherwise the Micon.const_missing will be
43
+ # Micon.const_missing extension should be included before than ClassLoader.const_missing otherwise the Micon.const_missing will be
44
44
  # called (and will ping file system) for every loaded class!
45
45
  # TEXT
46
46
  # warn text
47
47
  # end
48
- #
48
+ #
49
49
  # alias_method :const_missing_without_micon, :const_missing
50
50
  # protected :const_missing_without_micon
51
51
  # def const_missing const
data/lib/micon/spec.rb CHANGED
@@ -3,15 +3,15 @@ require 'rspec_ext'
3
3
  rspec do
4
4
  def self.with_micon options = {}
5
5
  scope = options[:before] || :all
6
-
6
+
7
7
  old, tmp = nil
8
-
9
- before scope do
8
+
9
+ before scope do
10
10
  old = MICON
11
11
  tmp = old.clone
12
12
  tmp.initialize!
13
13
  end
14
-
14
+
15
15
  after scope do
16
16
  tmp.deinitialize!
17
17
  old.initialize!
data/lib/micon/support.rb CHANGED
@@ -5,7 +5,7 @@ class Micon::Core
5
5
  end
6
6
  end
7
7
 
8
- class Hash
8
+ class Hash
9
9
  unless method_defined? :symbolize_keys
10
10
  def symbolize_keys
11
11
  r = {}
data/readme.md CHANGED
@@ -1,6 +1,6 @@
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
 
@@ -9,23 +9,20 @@ Technically it's [IoC][ioc] like framework with components, callbacks, scopes an
9
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
15
  ``` ruby
16
+ # Let's suppose that we want to build the Rails clone,
17
+ # there will be lot's of components - logger, controllers, router, ...
18
+
16
19
  require 'micon'
17
20
 
18
- # Here's our Web Framework, let's call it Rad
21
+ # Handy shortcut to access the IoC API (this is optional and You can omit it).
22
+ def micon; MICON end
19
23
 
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)
24
+ # Let's define some components.
25
+ # The :logger is one per application, it's a static component (like singleton).
29
26
  class Logger
30
27
  register_as :logger
31
28
  attr_accessor :log_file_path
@@ -36,29 +33,29 @@ end
36
33
 
37
34
  # To demostrate basics of working with compnents let's configure our :logger
38
35
  # explicitly (in the next example, it will be configured automatically).
39
- rad.logger.log_file_path = '/tmp/rad.log'
36
+ micon.logger.log_file_path = '/tmp/web_framework.log'
40
37
 
41
- # The :router requires complex initialization, so we use
38
+ # The :router requires complex initialization, so we use
42
39
  # another form of component registration.
43
40
  class Router
44
41
  def initialize routes; @routes = routes end
45
- def decode request;
46
- class_name, method = @routes[request.url]
42
+ def decode request;
43
+ class_name, method = @routes[request.url]
47
44
  return eval(class_name), method # returning actual class
48
45
  end
49
46
  end
50
- rad.register :router do
47
+ micon.register :router do
51
48
  Router.new '/index' => ['PagesController', :index]
52
49
  end
53
50
 
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,
51
+ # The :controller component should be created and destroyed dynamically,
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,
59
56
  # so, here we just declaring it without any initialization block, it
60
57
  # will be created at runtime later.
61
- rad.register :controller, scope: :request
58
+ micon.register :controller, scope: :request
62
59
 
63
60
  # Let's define some of our controllers, the PagesController, note - we
64
61
  # don't register it as component.
@@ -68,7 +65,7 @@ class PagesController
68
65
 
69
66
  def index
70
67
  # Here we can use injected component
71
- logger.info "Application: processing #{request}"
68
+ logger.info "Application: processing #{request}"
72
69
  end
73
70
  end
74
71
 
@@ -76,38 +73,38 @@ end
76
73
  # We also registering it without initialization, it will be
77
74
  # created at runtime later.
78
75
  class Request
79
- attr_reader :url
80
- def initialize url; @url = url end
76
+ attr_reader :url
77
+ def initialize url; @url = url end
81
78
  def to_s; @url end
82
79
  end
83
80
  # Registering without initialization block.
84
- rad.register :request, scope: :request
81
+ micon.register :request, scope: :request
85
82
 
86
83
  # We need to integrate our application with web server, for example with the Rack.
87
84
  # When the server receive web request, it calls the :call method of our RackAdapter
88
85
  class RackAdapter
89
86
  # Injecting components
90
87
  inject request: :request, controller: :controller
91
-
88
+
92
89
  def call env
93
90
  # 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
91
+ # that some dynamic components should be created during this scope and
95
92
  # destroyed at the end of it.
96
- rad.activate :request, {} do
93
+ micon.activate :request, {} do
97
94
  # Here we manually creating the Request component
98
95
  self.request = Request.new '/index'
99
-
96
+
100
97
  # The :router also can be injected via :inject,
101
98
  # 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
-
99
+ # every component also availiable as micon.<component_name>
100
+ controller_class, method = micon.router.decode request
101
+
105
102
  # Let's create and call our controller
106
103
  self.controller = controller_class.new
107
104
  controller.send method
108
105
  end
109
106
  end
110
- end
107
+ end
111
108
 
112
109
  # Let's pretend that there's a Web Server and run our application,
113
110
  # You should see something like this in the console:
@@ -120,69 +117,78 @@ In real-life scenario You probably will use it in a little different way, as wil
120
117
 
121
118
  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
119
 
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.
120
+ 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.
124
121
 
125
- Please note that this time logger convigured automatically, with logger.yml configuration file.
122
+ Note also, that this time logger convigured automatically, with the logger.yml configuration file.
126
123
 
127
124
  ``` ruby
125
+ # Please examine the 'web_framework1.rb' example before proceeding with this one.
126
+
127
+ # Let's suppose that we want to build the Rails clone,
128
+ # there will be lot's of components - logger, controllers, router, ...
129
+
130
+ # In this example we also need another tool that automatically find & load classes.
128
131
  require 'micon'
129
132
  require 'class_loader'
130
133
 
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
134
+ # Handy shortcut to access the IoC API (this is optional and You can omit it).
135
+ def micon; MICON end
139
136
 
140
137
  # Auto-discovering:
141
- #
142
- # All components (:logger, :router, :request, :controller) are
143
- # defined in spec/example_spec/lib/components folder.
138
+ #
139
+ # All components (:logger, :router, :request, :controller) are defined in
140
+ # the web_framework2/lib/components folder.
144
141
  # 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.
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
149
153
 
150
154
  # Auto-configuring
151
- #
152
- # Remember our manual configuration of "logger.log_file_path" from
155
+ #
156
+ # Remember our manual configuration of "logger.log_file_path" from
153
157
  # the previous example?
154
158
  # 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
+ # 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:
159
163
  # logger.yml <- logger.<env>.yml <- <runtime_path>/config/logger.yml
160
164
  # (If you define :environment and :runtime_path variables).
161
-
165
+
162
166
  # Let's pretend that there's a Web Server and run our application,
163
167
  # You should see something like this in the console:
164
168
  # Application: processing /index
165
169
  RackAdapter.new.call({})
166
170
  ```
167
-
168
- For the actual code please look at [spec/example_spec.rb](https://github.com/alexeypetrushin/micon/blob/master/spec/example_spec.rb)
171
+
172
+ For the actual code please look at [examples](https://github.com/alexeypetrushin/micon/blob/master/examples)
173
+
174
+ If You are interested in more samples, please look at the [actual components][rad_core_components] used in the Rad Core Framework.
169
175
 
170
176
  ## Note
171
177
 
172
- Current wersion isn't thread-safe, instead it supported evented IO (EventMachine).
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
-
178
+ 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.
179
+ But if you really need it for some reason - it can be easily done.
180
+
176
181
  ## Installation
177
182
 
178
183
  ``` bash
179
184
  gem install micon
180
185
  ```
181
-
186
+
182
187
  ## License
183
188
 
184
189
  Copyright (c) Alexey Petrushin http://petrush.in, released under the MIT license.
185
190
 
186
191
  [ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
187
192
  [rad_core]: https://github.com/alexeypetrushin/rad_core
193
+ [rad_core_components]: https://github.com/alexeypetrushin/rad_core/tree/master/lib/components
188
194
  [article]: http://ruby-lang.info/blog/you-underestimate-the-power-of-ioc-3fh
@@ -4,21 +4,21 @@ describe "Callbacks" do
4
4
  before do
5
5
  self.micon = Micon::Core.new
6
6
  end
7
-
7
+
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,10 +26,10 @@ 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
+
33
33
  it "should be able reference to the component itself inside of after filter (cycle reference)" do
34
34
  micon.register(:the_object){"The Object"}
35
35
  check = nil
@@ -40,7 +40,7 @@ describe "Callbacks" do
40
40
  check.should == "The Object"
41
41
  end
42
42
  end
43
-
43
+
44
44
  describe "custom scope callbacks" do
45
45
  it "scope :before and :after callbacks" do
46
46
  check = mock
@@ -54,9 +54,9 @@ 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
59
-
57
+ end
58
+ end
59
+
60
60
  describe "miscellaneous" do
61
61
  it "should fire callbacks after assigning component" do
62
62
  micon.register(:the_object)
@@ -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
@@ -2,17 +2,17 @@ require 'spec_helper'
2
2
 
3
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|