micon 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- module Micon
5
- class Metadata
6
- attr_accessor :registry, :initializers, :before, :after
7
-
8
- def initialize registry, sync
9
- @registry, @sync = registry, sync
10
- @before, @after, @before_scope, @after_scope, @initializers = {}, {}, {}, {}, {}
11
- end
12
-
13
- def clear
14
- @sync.synchronize do
15
- @registry.clear
16
- @initializers.clear
17
- @before.clear
18
- @after.clear
19
- @before_scope.clear
20
- @after_scope.clear
21
- end
22
- end
23
-
24
- def delete key
25
- @sync.synchronize do
26
- @registry.delete key
27
- @initializers.delete key
28
- @before.delete key
29
- @after.delete key
30
- @before_scope.delete key
31
- @after_scope.delete key
32
- end
33
- end
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
- def call_before key
70
- if callbacks = @before[key]
71
- callbacks.each{|c| c.call}
72
- end
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
- def call_after key, object
76
- if callbacks = @after[key]
77
- callbacks.each{|c| c.call(object)}
78
- end
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
- # Scope callbacks
84
- #
85
- def register_before_scope key, &block
86
- @sync.synchronize do
87
- raise "you should provide block!" unless block
88
- (@before_scope[key] ||= []) << block
89
- end
90
- end
91
-
92
- def register_after_scope key, &block
93
- @sync.synchronize do
94
- raise "you should provide block!" unless block
95
- (@after_scope[key] ||= []) << block
96
- end
97
- end
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
- def with_scope_callbacks key, container, &block
112
- call_before_scope key, container
113
- result = block.call
114
- call_after_scope key, container
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
@@ -1,9 +1,11 @@
1
- class Module
2
- # inject :attribute => :session
1
+ Module.class_eval do
2
+ #
3
+ # inject attribute: :session
4
+ #
3
5
  def inject attributes
4
- Micon.raise_without_self "Invalid argument!" unless attributes.is_a? Hash
6
+ ::MICON.raise_without_self "Invalid argument!" unless attributes.is_a? Hash
5
7
  attributes.each do |name, specificator|
6
- Micon.raise_without_self "Attribute name should be a Symbol!" unless name.is_a? Symbol
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
- ::Micon[#{specificator}]
20
+ ::MICON[#{specificator}]
19
21
  end
20
22
 
21
23
  def #{name}= value
22
- ::Micon[#{specificator}] = value
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
@@ -0,0 +1,8 @@
1
+ Micon::Core.include Micon::Helper
2
+
3
+ micon = Micon::Core.new
4
+ micon.initialize!
5
+
6
+ def rad
7
+ ::MICON
8
+ end
@@ -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
@@ -1,17 +1,31 @@
1
- require 'monitor'
2
-
3
- module Micon
4
- def self.raise_without_self message
5
- raise RuntimeError, message, caller.select{|path| path !~ /\/lib\/micon\//}
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
- unless {}.respond_to? :symbolize_keys
10
- class Hash
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 your application
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, :scope => :request
42
+ register_as :request, scope: :request
43
43
  end
44
44
 
45
45
  class Application
46
46
  # injecting components into attributes
47
- inject :request => :request, :logger => :logger
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) 2009 Alexey Petrushin [http://bos-tec.com](http://bos-tec.com), released under the MIT license.
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
@@ -1,38 +1,42 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Callbacks" do
4
- before :each do
5
- Micon.clear
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
- Micon.register(:the_object){"The Object"}
10
+ micon.register(:the_object){"The Object"}
12
11
 
13
12
  check = mock
14
- check.should_receive(:done)
15
- Micon.before :the_object do
16
- check.done
13
+ check.should_receive(:before)
14
+ micon.before :the_object do
15
+ check.before
17
16
  end
18
17
 
19
- Micon.after :the_object do |o|
20
- o << " updated"
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
- Micon.after :the_object do |o|
23
- o << " even more updated"
25
+ micon.after :the_object do |o|
26
+ check.after2
27
+ obj.object_id.should == o.object_id
24
28
  end
25
-
26
- Micon[:the_object].should == "The Object updated even more updated"
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
- Micon.register(:the_object){"The Object"}
34
+ micon.register(:the_object){"The Object"}
31
35
  check = nil
32
- Micon.after :the_object do
33
- check = Micon[:the_object]
36
+ micon.after :the_object do
37
+ check = micon[:the_object]
34
38
  end
35
- Micon[:the_object]
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
- Micon.before_scope(:custom){|container| check.before container}
49
- Micon.after_scope(:custom){|container| check.after container}
50
- Micon.after_scope(:custom){|container| check.after2 container}
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
- Micon.activate(:custom, {}){check.run}
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