micon 0.1.6 → 0.1.7
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 +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
|