micon 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +5 -5
- data/lib/micon.rb +5 -1
- data/lib/micon/class.rb +2 -2
- data/lib/micon/core.rb +408 -0
- data/lib/micon/helper.rb +26 -0
- data/lib/micon/metadata.rb +120 -124
- data/lib/micon/module.rb +39 -8
- data/lib/micon/rad.rb +8 -0
- data/lib/micon/spec.rb +20 -0
- data/lib/micon/support.rb +23 -9
- data/readme.md +18 -4
- data/spec/callbacks_spec.rb +65 -22
- data/spec/constants_spec.rb +75 -0
- data/spec/constants_spec/get_constant_component/lib/components/TheController.rb +3 -0
- data/spec/custom_scope_spec.rb +33 -34
- data/spec/initialization_spec.rb +71 -0
- data/spec/managed_spec.rb +14 -14
- data/spec/micelaneous_spec.rb +33 -29
- data/spec/micelaneous_spec/autoload/lib/components/TheRad/TheView.rb +3 -0
- data/spec/micelaneous_spec/autoload/lib/components/TheRouter.rb +3 -0
- data/spec/micelaneous_spec/autoload/lib/components/some_value.rb +3 -0
- data/spec/nested_custom_scope_spec.rb +13 -14
- data/spec/overview_spec.rb +7 -3
- data/spec/spec_helper.rb +10 -3
- data/spec/static_scope_spec.rb +47 -22
- metadata +30 -41
- data/lib/micon/micon.rb +0 -250
data/lib/micon/metadata.rb
CHANGED
@@ -1,136 +1,132 @@
|
|
1
1
|
#
|
2
2
|
# This class intentially made using "wired and not clear code", to provide better performance.
|
3
3
|
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
#
|
37
|
-
# Registry
|
38
|
-
#
|
39
|
-
def [] key
|
40
|
-
@sync.synchronize{@registry[key]}
|
41
|
-
end
|
42
|
-
|
43
|
-
# def []= key, value
|
44
|
-
# @sync.synchronize{@registry[key] = value}
|
45
|
-
# end
|
46
|
-
|
47
|
-
def include? key
|
48
|
-
@sync.synchronize{@registry.include? key}
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
#
|
53
|
-
# Callbacks
|
54
|
-
#
|
55
|
-
def register_before key, &block
|
56
|
-
@sync.synchronize do
|
57
|
-
raise "you should provide block!" unless block
|
58
|
-
(@before[key] ||= []) << block
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def register_after key, &block
|
63
|
-
@sync.synchronize do
|
64
|
-
raise "you should provide block!" unless block
|
65
|
-
(@after[key] ||= []) << block
|
66
|
-
end
|
4
|
+
class Micon::Metadata
|
5
|
+
attr_accessor :registry, :initializers, :before, :after
|
6
|
+
|
7
|
+
def initialize registry
|
8
|
+
@registry = registry
|
9
|
+
@before, @after, @before_scope, @after_scope, @initializers = {}, {}, {}, {}, {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear
|
13
|
+
@registry.clear
|
14
|
+
@initializers.clear
|
15
|
+
@before.clear
|
16
|
+
@after.clear
|
17
|
+
@before_scope.clear
|
18
|
+
@after_scope.clear
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete key
|
22
|
+
@registry.delete key
|
23
|
+
@initializers.delete key
|
24
|
+
@before.delete key
|
25
|
+
@after.delete key
|
26
|
+
@before_scope.delete key
|
27
|
+
@after_scope.delete key
|
28
|
+
end
|
29
|
+
|
30
|
+
def clone
|
31
|
+
another = super
|
32
|
+
%w(@registry @before @after @before_scope @after_scope @initializers).each do |name|
|
33
|
+
value = instance_variable_get name
|
34
|
+
another.instance_variable_set name, value.clone
|
67
35
|
end
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
36
|
+
another
|
37
|
+
end
|
38
|
+
alias_method :deep_clone, :clone
|
39
|
+
|
40
|
+
|
41
|
+
#
|
42
|
+
# Registry
|
43
|
+
#
|
44
|
+
def [] key
|
45
|
+
@registry[key]
|
46
|
+
end
|
47
|
+
|
48
|
+
# def []= key, value
|
49
|
+
# @registry[key] = value
|
50
|
+
# end
|
51
|
+
|
52
|
+
def include? key
|
53
|
+
@registry.include? key
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
#
|
58
|
+
# Callbacks
|
59
|
+
#
|
60
|
+
def register_before key, &block
|
61
|
+
raise "you should provide block!" unless block
|
62
|
+
(@before[key] ||= []) << block
|
63
|
+
end
|
64
|
+
|
65
|
+
def register_after key, &block
|
66
|
+
raise "you should provide block!" unless block
|
67
|
+
(@after[key] ||= []) << block
|
68
|
+
end
|
69
|
+
|
70
|
+
def call_before key
|
71
|
+
if callbacks = @before[key]
|
72
|
+
callbacks.each{|c| c.call}
|
73
73
|
end
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
74
|
+
end
|
75
|
+
|
76
|
+
def call_after key, object
|
77
|
+
if callbacks = @after[key]
|
78
|
+
callbacks.each{|c| c.call(object)}
|
79
79
|
end
|
80
|
+
end
|
80
81
|
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
def call_before_scope key, container
|
100
|
-
if callbacks = @before_scope[key]
|
101
|
-
callbacks.each{|c| c.call container}
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def call_after_scope key, container
|
106
|
-
if callbacks = @after_scope[key]
|
107
|
-
callbacks.each{|c| c.call container}
|
108
|
-
end
|
83
|
+
#
|
84
|
+
# Scope callbacks
|
85
|
+
#
|
86
|
+
def register_before_scope key, &block
|
87
|
+
raise "you should provide block!" unless block
|
88
|
+
(@before_scope[key] ||= []) << block
|
89
|
+
end
|
90
|
+
|
91
|
+
def register_after_scope key, &block
|
92
|
+
raise "you should provide block!" unless block
|
93
|
+
(@after_scope[key] ||= []) << block
|
94
|
+
end
|
95
|
+
|
96
|
+
def call_before_scope key, container
|
97
|
+
if callbacks = @before_scope[key]
|
98
|
+
callbacks.each{|c| c.call container}
|
109
99
|
end
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
result
|
100
|
+
end
|
101
|
+
|
102
|
+
def call_after_scope key, container
|
103
|
+
if callbacks = @after_scope[key]
|
104
|
+
callbacks.each{|c| c.call container}
|
116
105
|
end
|
117
|
-
|
118
|
-
|
119
|
-
#
|
120
|
-
# Other
|
121
|
-
#
|
122
|
-
# def inspect
|
123
|
-
# "Registry: " + self.registry.keys.inspect
|
124
|
-
# end
|
125
|
-
|
126
|
-
# def deep_clone
|
127
|
-
# m = Metadata.new @sync
|
128
|
-
# m.registry = {}
|
129
|
-
# registry.each do |k, v|
|
130
|
-
# m.registry[k] = v
|
131
|
-
# end
|
132
|
-
# p m
|
133
|
-
# m
|
134
|
-
# end
|
135
106
|
end
|
107
|
+
|
108
|
+
def with_scope_callbacks key, container, &block
|
109
|
+
call_before_scope key, container
|
110
|
+
result = block.call
|
111
|
+
call_after_scope key, container
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
#
|
117
|
+
# Other
|
118
|
+
#
|
119
|
+
# def inspect
|
120
|
+
# "Registry: " + self.registry.keys.inspect
|
121
|
+
# end
|
122
|
+
|
123
|
+
# def deep_clone
|
124
|
+
# m = Metadata.new
|
125
|
+
# m.registry = {}
|
126
|
+
# registry.each do |k, v|
|
127
|
+
# m.registry[k] = v
|
128
|
+
# end
|
129
|
+
# p m
|
130
|
+
# m
|
131
|
+
# end
|
136
132
|
end
|
data/lib/micon/module.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
|
2
|
-
#
|
1
|
+
Module.class_eval do
|
2
|
+
#
|
3
|
+
# inject attribute: :session
|
4
|
+
#
|
3
5
|
def inject attributes
|
4
|
-
|
6
|
+
::MICON.raise_without_self "Invalid argument!" unless attributes.is_a? Hash
|
5
7
|
attributes.each do |name, specificator|
|
6
|
-
|
8
|
+
::MICON.raise_without_self "Attribute name should be a Symbol!" unless name.is_a? Symbol
|
7
9
|
|
8
10
|
if [Class, Module].include? specificator.class
|
9
11
|
specificator = specificator.name
|
@@ -13,15 +15,44 @@ class Module
|
|
13
15
|
specificator = "\"#{specificator}\""
|
14
16
|
end
|
15
17
|
|
16
|
-
script =
|
18
|
+
script = <<-RUBY
|
17
19
|
def #{name}
|
18
|
-
::
|
20
|
+
::MICON[#{specificator}]
|
19
21
|
end
|
20
22
|
|
21
23
|
def #{name}= value
|
22
|
-
::
|
23
|
-
end
|
24
|
+
::MICON[#{specificator}] = value
|
25
|
+
end
|
26
|
+
|
27
|
+
def #{name}?
|
28
|
+
::MICON.include? #{specificator}
|
29
|
+
end
|
30
|
+
RUBY
|
31
|
+
|
24
32
|
self.class_eval script, __FILE__, __LINE__
|
25
33
|
end
|
26
34
|
end
|
35
|
+
|
36
|
+
|
37
|
+
#
|
38
|
+
# Hook to use Constants as Components
|
39
|
+
#
|
40
|
+
# if defined? ::ClassLoader
|
41
|
+
# text = <<-TEXT
|
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
|
44
|
+
# called (and will ping file system) for every loaded class!
|
45
|
+
# TEXT
|
46
|
+
# warn text
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# alias_method :const_missing_without_micon, :const_missing
|
50
|
+
# protected :const_missing_without_micon
|
51
|
+
# def const_missing const
|
52
|
+
# if value = ::MICON.get_constant(self, const)
|
53
|
+
# value
|
54
|
+
# else
|
55
|
+
# const_missing_without_micon const
|
56
|
+
# end
|
57
|
+
# end
|
27
58
|
end
|
data/lib/micon/rad.rb
ADDED
data/lib/micon/spec.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rspec_ext'
|
2
|
+
|
3
|
+
rspec do
|
4
|
+
def self.with_micon options = {}
|
5
|
+
scope = options[:before] || :all
|
6
|
+
|
7
|
+
old, tmp = nil
|
8
|
+
|
9
|
+
before scope do
|
10
|
+
old = MICON
|
11
|
+
tmp = old.clone
|
12
|
+
tmp.initialize!
|
13
|
+
end
|
14
|
+
|
15
|
+
after scope do
|
16
|
+
tmp.deinitialize!
|
17
|
+
old.initialize!
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/micon/support.rb
CHANGED
@@ -1,17 +1,31 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
end
|
1
|
+
class Micon::Core
|
2
|
+
protected
|
3
|
+
def raise_without_self message
|
4
|
+
raise RuntimeError, message, caller.select{|path| path !~ /\/lib\/micon\//}
|
5
|
+
end
|
7
6
|
end
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
class Hash
|
9
|
+
unless method_defined? :symbolize_keys
|
11
10
|
def symbolize_keys
|
12
11
|
r = {}
|
13
12
|
each{|k, v| r[k.to_sym] = v}
|
14
13
|
r
|
15
14
|
end
|
16
15
|
end
|
17
|
-
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# class Module
|
19
|
+
# unless respond_to? :namespace_for
|
20
|
+
# # TODO3 cache it?
|
21
|
+
# def self.namespace_for class_name
|
22
|
+
# list = class_name.split("::")
|
23
|
+
# if list.size > 1
|
24
|
+
# list.pop
|
25
|
+
# return eval(list.join("::"), TOPLEVEL_BINDING, __FILE__, __LINE__)
|
26
|
+
# else
|
27
|
+
# return nil
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
# end
|
data/readme.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Assembles and manages pieces of
|
1
|
+
# Assembles and manages pieces of Your Application
|
2
2
|
|
3
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
|
|
@@ -39,12 +39,12 @@ Let's suppose you are building the Ruby on Rails clone, there are lots of module
|
|
39
39
|
|
40
40
|
# dynamic components, will be created and destroyed for every request
|
41
41
|
class Request
|
42
|
-
register_as :request, :
|
42
|
+
register_as :request, scope: :request
|
43
43
|
end
|
44
44
|
|
45
45
|
class Application
|
46
46
|
# injecting components into attributes
|
47
|
-
inject :
|
47
|
+
inject request: :request, logger: :logger
|
48
48
|
|
49
49
|
def do_business
|
50
50
|
# now we can use injected component
|
@@ -68,11 +68,25 @@ Let's suppose you are building the Ruby on Rails clone, there are lots of module
|
|
68
68
|
RackAdapter.new.call({})
|
69
69
|
|
70
70
|
For actual code go to spec/overview_spec.rb
|
71
|
+
|
72
|
+
## Note
|
73
|
+
|
74
|
+
Current wersion isn't thread-safe, instead it supported evented IO (EventMachine).
|
75
|
+
Actually I implemented first wersion as thread-safe, but because there's no actual multithreading in
|
76
|
+
Ruby, the only thing it does - adds complexity and performance losses, so I removed it.
|
77
|
+
But if you need it it can be done very easy.
|
71
78
|
|
72
79
|
## Installation
|
73
80
|
|
74
81
|
$ sudo gem install micon
|
82
|
+
|
83
|
+
## TODO
|
84
|
+
|
85
|
+
- remove threads and synchronization support, probably it will be never needed in any real situation, because
|
86
|
+
there's no multithreading in ruby.
|
87
|
+
- refactor specs, they are messy a little.
|
88
|
+
- maybe it makes sense to add ability to add dependencies for components after component registration?
|
75
89
|
|
76
|
-
Copyright (c)
|
90
|
+
Copyright (c) Alexey Petrushin [http://4ire.net](http://4ire.net), released under the MIT license.
|
77
91
|
|
78
92
|
[ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
|
data/spec/callbacks_spec.rb
CHANGED
@@ -1,38 +1,42 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Callbacks" do
|
4
|
-
before
|
5
|
-
Micon.
|
6
|
-
Micon.metadata.clear
|
4
|
+
before do
|
5
|
+
self.micon = Micon::Core.new
|
7
6
|
end
|
8
7
|
|
9
8
|
describe "components callbacs" do
|
10
9
|
it "basic" do
|
11
|
-
|
10
|
+
micon.register(:the_object){"The Object"}
|
12
11
|
|
13
12
|
check = mock
|
14
|
-
check.should_receive(:
|
15
|
-
|
16
|
-
check.
|
13
|
+
check.should_receive(:before)
|
14
|
+
micon.before :the_object do
|
15
|
+
check.before
|
17
16
|
end
|
18
17
|
|
19
|
-
|
20
|
-
|
18
|
+
check.should_receive(:after1).ordered
|
19
|
+
check.should_receive(:after2).ordered
|
20
|
+
obj = nil
|
21
|
+
micon.after :the_object do |o|
|
22
|
+
check.after1
|
23
|
+
obj = o
|
21
24
|
end
|
22
|
-
|
23
|
-
|
25
|
+
micon.after :the_object do |o|
|
26
|
+
check.after2
|
27
|
+
obj.object_id.should == o.object_id
|
24
28
|
end
|
25
|
-
|
26
|
-
|
29
|
+
|
30
|
+
micon[:the_object].should == obj
|
27
31
|
end
|
28
32
|
|
29
33
|
it "should be able reference to the component itself inside of after filter (cycle reference)" do
|
30
|
-
|
34
|
+
micon.register(:the_object){"The Object"}
|
31
35
|
check = nil
|
32
|
-
|
33
|
-
check =
|
36
|
+
micon.after :the_object do
|
37
|
+
check = micon[:the_object]
|
34
38
|
end
|
35
|
-
|
39
|
+
micon[:the_object]
|
36
40
|
check.should == "The Object"
|
37
41
|
end
|
38
42
|
end
|
@@ -45,11 +49,50 @@ describe "Callbacks" do
|
|
45
49
|
check.should_receive(:after).with({}).ordered
|
46
50
|
check.should_receive(:after2).with({}).ordered
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
micon.before_scope(:custom){|container| check.before container}
|
53
|
+
micon.after_scope(:custom){|container| check.after container}
|
54
|
+
micon.after_scope(:custom){|container| check.after2 container}
|
51
55
|
|
52
|
-
|
56
|
+
micon.activate(:custom, {}){check.run}
|
53
57
|
end
|
54
|
-
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "micelaneous" do
|
61
|
+
it "should fire callbacks after assigning component" do
|
62
|
+
micon.register(:the_object)
|
63
|
+
check = mock
|
64
|
+
check.should_receive(:done)
|
65
|
+
micon.after :the_object do
|
66
|
+
check.done
|
67
|
+
end
|
68
|
+
micon.the_object = 'the_object'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should raise error if callback defined after component already created" do
|
72
|
+
micon.register(:the_object){"the_object"}
|
73
|
+
micon[:the_object]
|
74
|
+
|
75
|
+
-> {micon.before(:the_object){}}.should raise_error(/already created/)
|
76
|
+
-> {micon.after(:the_object){}}.should raise_error(/already created/)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should raise error if callback defined after scope already started" do
|
80
|
+
micon.activate :custom, {} do
|
81
|
+
-> {micon.before_scope(:custom){}}.should raise_error(/already started/)
|
82
|
+
-> {micon.after_scope(:custom){}}.should raise_error(/already started/)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it ":after with bang: false should execute callback if component already started and also register it as :after callback" do
|
87
|
+
micon.register(:the_object){"the_object"}
|
88
|
+
micon[:the_object]
|
89
|
+
|
90
|
+
check = mock
|
91
|
+
check.should_receive(:first).twice
|
92
|
+
micon.after(:the_object, bang: false){check.first}
|
93
|
+
|
94
|
+
micon.delete :the_object
|
95
|
+
micon[:the_object]
|
96
|
+
end
|
97
|
+
end
|
55
98
|
end
|