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