micon 0.1.7 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/micon.rb +3 -0
- data/lib/micon/config.rb +46 -0
- data/lib/micon/core.rb +65 -98
- data/readme.md +4 -1
- data/spec/config_spec.rb +25 -0
- data/spec/config_spec/basic/lib/components/logger.yml +1 -0
- data/spec/config_spec/order/app/config/object.production.yml +1 -0
- data/spec/config_spec/order/app/config/object.yml +2 -0
- data/spec/config_spec/order/lib/components/object.production.yml +3 -0
- data/spec/config_spec/order/lib/components/object.yml +3 -0
- data/spec/micelaneous_spec.rb +48 -23
- data/spec/static_scope_spec.rb +2 -4
- metadata +9 -2
data/Rakefile
CHANGED
data/lib/micon.rb
CHANGED
data/lib/micon/config.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
class Micon::Config
|
2
|
+
attr_reader :micon, :name
|
3
|
+
def initialize micon, name
|
4
|
+
@micon, @name = micon, name
|
5
|
+
end
|
6
|
+
|
7
|
+
def load
|
8
|
+
files = []
|
9
|
+
files.push *config_paths.collect{|path| find_file(path, $LOAD_PATH)}
|
10
|
+
files.push *runtime_config_paths.collect{|path| find_file(path, [micon.runtime_path])} if micon.runtime_path?
|
11
|
+
|
12
|
+
config = {}
|
13
|
+
files.compact.each do |f|
|
14
|
+
c = YAML.load_file(f)
|
15
|
+
next unless c
|
16
|
+
raise "component config must be a Hash (#{f})!" unless c.is_a? Hash
|
17
|
+
c.each{|k, v| config[:"#{k}="] = v}
|
18
|
+
end
|
19
|
+
|
20
|
+
config.empty? ? nil : config
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
def config_paths
|
25
|
+
fs_name = name.to_s.gsub(/::/, '/')
|
26
|
+
paths = ["/components/#{fs_name}.yml"]
|
27
|
+
paths << "/components/#{fs_name}.#{micon.mode}.yml" if micon.mode?
|
28
|
+
paths
|
29
|
+
end
|
30
|
+
|
31
|
+
def runtime_config_paths
|
32
|
+
fs_name = name.to_s.gsub(/::/, '/')
|
33
|
+
paths = ["/config/#{fs_name}.yml"]
|
34
|
+
if micon.mode?
|
35
|
+
paths << "/config/#{fs_name}.#{micon.mode}.yml"
|
36
|
+
paths << "/config/#{micon.mode}/#{fs_name}.yml"
|
37
|
+
end
|
38
|
+
paths
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_file path, directories
|
42
|
+
files = directories.collect{|dir| "#{dir}#{path}"}.select{|f| File.exist? f}
|
43
|
+
raise "multiple configs for :#{name} component" if files.size > 1
|
44
|
+
files.first
|
45
|
+
end
|
46
|
+
end
|
data/lib/micon/core.rb
CHANGED
@@ -107,66 +107,6 @@ class Micon::Core
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
-
# def get_constant_component key
|
111
|
-
# sname = @registry[key] || autoload_component_definition(key, false)
|
112
|
-
#
|
113
|
-
# case sname
|
114
|
-
# when nil
|
115
|
-
# nil
|
116
|
-
# when :instance
|
117
|
-
# must_be.never_called
|
118
|
-
# when :application
|
119
|
-
# return nil unless @constants.include? key
|
120
|
-
#
|
121
|
-
# o = @application[key]
|
122
|
-
# unless o
|
123
|
-
# return create_object(key, @application)
|
124
|
-
# else
|
125
|
-
# return o
|
126
|
-
# end
|
127
|
-
# else # custom
|
128
|
-
# must_be.never_called
|
129
|
-
# end
|
130
|
-
# end
|
131
|
-
#
|
132
|
-
# def get_constant namespace, const
|
133
|
-
# original_namespace = namespace
|
134
|
-
# namespace = nil if namespace == Object or namespace == Module
|
135
|
-
# target_namespace = namespace
|
136
|
-
#
|
137
|
-
# # Name hack (for anonymous classes)
|
138
|
-
# namespace = eval "#{name_hack(namespace)}" if namespace
|
139
|
-
#
|
140
|
-
# class_name = namespace ? "#{namespace.name}::#{const}" : const
|
141
|
-
#
|
142
|
-
# simple_also_tried = false
|
143
|
-
# begin
|
144
|
-
# simple_also_tried = (namespace == nil)
|
145
|
-
#
|
146
|
-
# if result = get_constant_component(class_name.to_sym)
|
147
|
-
# if @loaded_classes.include?(class_name)
|
148
|
-
# raise_without_self "something wrong is goin on, constant '#{const}' in '#{original_namespace}' namespace already has been defined!"
|
149
|
-
# end
|
150
|
-
#
|
151
|
-
# real_namespace = namespace ? namespace : Object
|
152
|
-
# if real_namespace.const_defined?(const)
|
153
|
-
# raise_without_self "component trying to redefine constant '#{const}' that already defined in '#{real_namespace}'!"
|
154
|
-
# end
|
155
|
-
#
|
156
|
-
# real_namespace.const_set const, result
|
157
|
-
#
|
158
|
-
# @loaded_classes[class_name] = [real_namespace, const]
|
159
|
-
#
|
160
|
-
# return result
|
161
|
-
# elsif namespace
|
162
|
-
# namespace = Module.namespace_for(namespace.name)
|
163
|
-
# class_name = namespace ? "#{namespace.name}::#{const}" : const
|
164
|
-
# end
|
165
|
-
# end until simple_also_tried
|
166
|
-
#
|
167
|
-
# return nil
|
168
|
-
# end
|
169
|
-
|
170
110
|
def []= key, value
|
171
111
|
raise "can't assign nill as :#{key} component!" unless value
|
172
112
|
|
@@ -296,6 +236,7 @@ class Micon::Core
|
|
296
236
|
# I intentially broke the Metadata incapsulation to provide better performance, don't refactor it.
|
297
237
|
@registry = {} # @loaded_classes, @constants = {}, {}
|
298
238
|
@metadata = Micon::Metadata.new(@registry)
|
239
|
+
@stack = {}
|
299
240
|
|
300
241
|
@application, @custom_scopes = {}, {}
|
301
242
|
|
@@ -319,59 +260,85 @@ class Micon::Core
|
|
319
260
|
# @loaded_classes.clear
|
320
261
|
end
|
321
262
|
|
263
|
+
#
|
264
|
+
# :mode, :runtime_path, used in component configuration
|
265
|
+
# - 'app/runtime'
|
266
|
+
# - :development, :test, :production
|
267
|
+
#
|
268
|
+
def runtime_path; @runtime_path || raise(":runtime_path not defined!") end
|
269
|
+
def runtime_path= runtime_path
|
270
|
+
runtime_path, force = runtime_path
|
271
|
+
raise "some components has been already initialized before You set :runtime_path!" unless empty? or force
|
272
|
+
@runtime_path = runtime_path
|
273
|
+
end
|
274
|
+
def runtime_path?; !!@runtime_path end
|
275
|
+
|
276
|
+
def mode; @mode || raise(":mode not defined!") end
|
277
|
+
def mode= mode
|
278
|
+
mode, force = mode
|
279
|
+
raise "some components has been already initialized before You set :mode!" unless empty? or force
|
280
|
+
@mode = mode
|
281
|
+
end
|
282
|
+
def mode?; !!@mode end
|
283
|
+
|
322
284
|
protected
|
323
285
|
def autoload_component_definition key, bang = true
|
324
286
|
begin
|
325
287
|
load "components/#{key.to_s.gsub(/::/, '/')}.rb"
|
326
288
|
rescue LoadError
|
327
|
-
end
|
289
|
+
end
|
328
290
|
sname = @registry[key]
|
329
291
|
raise_without_self "'#{key}' component not managed!" if bang and !sname
|
330
292
|
sname
|
331
293
|
end
|
332
294
|
|
333
295
|
def create_object key, container = nil
|
334
|
-
initializer, dependencies = @metadata.initializers[key]
|
296
|
+
initializer, dependencies, config = @metadata.initializers[key]
|
335
297
|
raise "no initializer for :#{key} component!" unless initializer
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
# app.after :environment do
|
360
|
-
# app[:conveyors]
|
361
|
-
# end
|
362
|
-
#
|
363
|
-
# app[:conveyors]
|
364
|
-
|
365
|
-
o = container[key]
|
298
|
+
|
299
|
+
raise "component :#{key} used before it's initialization is finished!" if @stack.include? key
|
300
|
+
begin
|
301
|
+
dependencies.each{|d| self[d]}
|
302
|
+
@metadata.call_before key
|
303
|
+
|
304
|
+
# we need to check container first, in complex cases (circullar dependency)
|
305
|
+
# the object already may be initialized.
|
306
|
+
# See "should allow to use circullar dependency in :after callback".
|
307
|
+
@stack[key] = true
|
308
|
+
o = (container && container[key]) || initializer.call
|
309
|
+
|
310
|
+
unless config == false
|
311
|
+
unless config
|
312
|
+
# loading and caching config
|
313
|
+
config = get_config key
|
314
|
+
config = false unless config # we use false to differentiate from nil
|
315
|
+
@metadata.initializers[key] = [initializer, dependencies, config]
|
316
|
+
|
317
|
+
apply_config o, config if config
|
318
|
+
else
|
319
|
+
apply_config o, config
|
320
|
+
end
|
366
321
|
end
|
367
|
-
|
368
|
-
|
322
|
+
|
323
|
+
container[key] = o if container
|
324
|
+
|
325
|
+
raise "initializer for component :#{key} returns nill!" unless o
|
326
|
+
ensure
|
327
|
+
@stack.delete key
|
369
328
|
end
|
370
|
-
|
371
|
-
|
329
|
+
|
372
330
|
@metadata.call_after key, o
|
373
|
-
o
|
374
|
-
end
|
331
|
+
o
|
332
|
+
end
|
333
|
+
|
334
|
+
def get_config key
|
335
|
+
::Micon::Config.new(self, key).load
|
336
|
+
end
|
337
|
+
|
338
|
+
def apply_config component, config
|
339
|
+
# config already have keys like "#{k}="
|
340
|
+
config.each{|k, v| component.send(k, v)}
|
341
|
+
end
|
375
342
|
|
376
343
|
def name_hack namespace
|
377
344
|
if namespace
|
data/readme.md
CHANGED
@@ -6,6 +6,8 @@ Concentrate on business logic and interfaces and Micon will provide automatic co
|
|
6
6
|
|
7
7
|
Technically it's [IoC][ioc] like framework with components, callbacks, scopes and bijections, inspired by Spring and JBoss Seam.
|
8
8
|
|
9
|
+
Is it usefull, is there any real-life application? - I'm using it as a heart of my [web framework][rad_core], this site http://ruby-lang.info for example powered with it.
|
10
|
+
|
9
11
|
## Usage
|
10
12
|
|
11
13
|
Let's suppose you are building the Ruby on Rails clone, there are lots of modules let's try to deal with them
|
@@ -89,4 +91,5 @@ there's no multithreading in ruby.
|
|
89
91
|
|
90
92
|
Copyright (c) Alexey Petrushin [http://4ire.net](http://4ire.net), released under the MIT license.
|
91
93
|
|
92
|
-
[ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
|
94
|
+
[ioc]: http://en.wikipedia.org/wiki/Inversion_of_control
|
95
|
+
[rad_core]: https://github.com/alexeypetrushin/rad_core
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Configuration" do
|
4
|
+
before{self.micon = Micon::Core.new}
|
5
|
+
|
6
|
+
it "should configure component if config provided" do
|
7
|
+
micon.register(:logger){OpenStruct.new}
|
8
|
+
with_load_path "#{spec_dir}/basic/lib" do
|
9
|
+
micon[:logger].level.should == :info
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should merge in order: conf <- conf.mode <- runtime <- runtime.mode" do
|
14
|
+
micon.register(:object){OpenStruct.new}
|
15
|
+
with_load_path "#{spec_dir}/order/lib" do
|
16
|
+
micon.runtime_path = "#{spec_dir}/order/app"
|
17
|
+
micon.mode = :production
|
18
|
+
micon[:object].tap do |o|
|
19
|
+
o.a.should == 'object.production.yml'
|
20
|
+
o.b.should == 'runtime.object.yml'
|
21
|
+
o.c.should == 'runtime.object.production.yml'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
level: :info
|
@@ -0,0 +1 @@
|
|
1
|
+
c: 'runtime.object.production.yml'
|
data/spec/micelaneous_spec.rb
CHANGED
@@ -3,13 +3,8 @@ require 'spec_helper'
|
|
3
3
|
describe "Micelaneous" do
|
4
4
|
with_load_path "#{spec_dir}/autoload/lib"
|
5
5
|
|
6
|
-
before
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
after do
|
11
|
-
remove_constants :TheRouter, :TheRad
|
12
|
-
end
|
6
|
+
before{self.micon = Micon::Core.new}
|
7
|
+
after{remove_constants :TheRouter, :TheRad}
|
13
8
|
|
14
9
|
describe "autoloading" do
|
15
10
|
it "should autoload component definition" do
|
@@ -22,27 +17,57 @@ describe "Micelaneous" do
|
|
22
17
|
# TheRad::TheView.should == "TheView"
|
23
18
|
# end
|
24
19
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
20
|
+
|
21
|
+
describe "complex circullar dependencies" do
|
22
|
+
it "should not initialize twice (from error)" do
|
23
|
+
micon.register :kit do
|
24
|
+
micon[:kit]
|
25
|
+
'kit'
|
26
|
+
end
|
27
|
+
lambda{micon[:kit]}.should raise_error(/component :kit used before it's initialization is finished/)
|
28
|
+
end
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
it "should not initialize twice if called from dependency (from error)" do
|
31
|
+
micon.register :environment do
|
32
|
+
micon[:router]
|
33
|
+
'environment'
|
34
|
+
end
|
35
|
+
|
36
|
+
micon.register :router, depends_on: :environment do
|
37
|
+
'router'
|
38
|
+
end
|
39
|
+
|
40
|
+
-> {micon[:router]}.should raise_error(/component .* used before it's initialization is finished/)
|
34
41
|
end
|
35
42
|
|
36
|
-
|
37
|
-
check
|
38
|
-
|
43
|
+
it "should allow to use circullar dependency in :after callback" do
|
44
|
+
check = mock
|
45
|
+
check.should_receive(:initialized).once
|
46
|
+
micon.register :kit do
|
47
|
+
check.initialized
|
48
|
+
'kit'
|
49
|
+
end
|
50
|
+
micon.after :kit do
|
51
|
+
micon[:kit]
|
52
|
+
end
|
53
|
+
micon[:kit].should == 'kit'
|
39
54
|
end
|
40
|
-
micon.after :environment do
|
41
|
-
# some code that needs :router
|
42
|
-
micon[:router]
|
43
|
-
end
|
44
55
|
|
45
|
-
|
56
|
+
it "should allow circullar dependencies in :after callback" do
|
57
|
+
micon.register :environment do
|
58
|
+
'environment'
|
59
|
+
end
|
60
|
+
|
61
|
+
micon.register :router, depends_on: :environment do
|
62
|
+
'router'
|
63
|
+
end
|
64
|
+
|
65
|
+
micon.after :environment do
|
66
|
+
micon[:router]
|
67
|
+
end
|
68
|
+
|
69
|
+
micon[:router]
|
70
|
+
end
|
46
71
|
end
|
47
72
|
|
48
73
|
it "helper method generation" do
|
data/spec/static_scope_spec.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Application and Instance scopes" do
|
4
|
-
before
|
5
|
-
self.micon = Micon::Core.new
|
6
|
-
end
|
4
|
+
before{self.micon = Micon::Core.new}
|
7
5
|
|
8
6
|
it "dependencies" do
|
9
7
|
micon.register(:another_object, depends_on: :the_object){"another_object"}
|
10
|
-
-> {micon[:another_object]}.should raise_error(/the_object/)
|
8
|
+
-> {micon[:another_object]}.should raise_error(/the_object.*not managed/)
|
11
9
|
micon.register(:the_object){"the_object"}
|
12
10
|
micon[:another_object]
|
13
11
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: micon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-07-04 00:00:00.000000000 +04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
description:
|
@@ -21,6 +21,7 @@ files:
|
|
21
21
|
- Rakefile
|
22
22
|
- readme.md
|
23
23
|
- lib/micon/class.rb
|
24
|
+
- lib/micon/config.rb
|
24
25
|
- lib/micon/core.rb
|
25
26
|
- lib/micon/helper.rb
|
26
27
|
- lib/micon/metadata.rb
|
@@ -30,6 +31,12 @@ files:
|
|
30
31
|
- lib/micon/support.rb
|
31
32
|
- lib/micon.rb
|
32
33
|
- spec/callbacks_spec.rb
|
34
|
+
- spec/config_spec/basic/lib/components/logger.yml
|
35
|
+
- spec/config_spec/order/app/config/object.production.yml
|
36
|
+
- spec/config_spec/order/app/config/object.yml
|
37
|
+
- spec/config_spec/order/lib/components/object.production.yml
|
38
|
+
- spec/config_spec/order/lib/components/object.yml
|
39
|
+
- spec/config_spec.rb
|
33
40
|
- spec/constants_spec/get_constant_component/lib/components/TheController.rb
|
34
41
|
- spec/constants_spec.rb
|
35
42
|
- spec/custom_scope_spec.rb
|