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.
@@ -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