rbdi 0.0.1
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/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/README.md +0 -0
- data/lib/rdi.rb +12 -0
- data/lib/rdi/bean.rb +123 -0
- data/lib/rdi/chain.rb +71 -0
- data/lib/rdi/context.rb +57 -0
- data/lib/rdi/context_builder.rb +18 -0
- data/lib/rdi/dependency_graph_builder.rb +50 -0
- data/lib/rdi/graphs.rb +116 -0
- data/lib/rdi/logger.rb +7 -0
- data/lib/rdi/object_builder.rb +103 -0
- data/lib/rdi/ref.rb +23 -0
- data/lib/rdi/utils.rb +116 -0
- metadata +75 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'graphs'
|
2
|
+
|
3
|
+
module Rdi
|
4
|
+
module DependencyGraphBuilder
|
5
|
+
|
6
|
+
def self.build(context)
|
7
|
+
graph = Rdi::Graphs::DirectedGraph.new
|
8
|
+
|
9
|
+
context.beans.each do |bean_id, bean|
|
10
|
+
graph.add_vertex(bean_id)
|
11
|
+
end
|
12
|
+
|
13
|
+
context.beans.each do |bean_id, bean|
|
14
|
+
bean.constructor_args.each do |arg|
|
15
|
+
add_dependencies(bean_id, arg, graph)
|
16
|
+
end
|
17
|
+
|
18
|
+
bean.properties.each do |name, value|
|
19
|
+
add_dependencies(bean_id, value, graph)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
graph
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.add_dependencies(bean_id, value, graph)
|
27
|
+
if value.kind_of?(Rdi::Ref)
|
28
|
+
graph.add_edge(bean_id, value.bean_id)
|
29
|
+
elsif value.kind_of?(Hash)
|
30
|
+
add_dependencies_from_map(bean_id, value, graph)
|
31
|
+
elsif value.kind_of?(Array)
|
32
|
+
add_dependencies_from_collection(bean_id, value, graph)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.add_dependencies_from_collection(bean_id, collection, graph)
|
37
|
+
collection.each do |e|
|
38
|
+
add_dependencies(bean_id, e, graph)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.add_dependencies_from_map(bean_id, map, graph)
|
43
|
+
map.each do |key, value|
|
44
|
+
add_dependencies(bean_id, key, graph)
|
45
|
+
add_dependencies(bean_id, value, graph)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
data/lib/rdi/graphs.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
module Rdi
|
2
|
+
module Graphs
|
3
|
+
|
4
|
+
class DirectedGraph
|
5
|
+
|
6
|
+
attr_reader :vertices
|
7
|
+
attr_reader :adjacencies
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@vertices = {}
|
11
|
+
@adjacencies = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_vertex(label)
|
15
|
+
vertex = Vertex.new(label)
|
16
|
+
@vertices[label] = vertex
|
17
|
+
@adjacencies[vertex] = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_edge(from, to)
|
21
|
+
@adjacencies[@vertices[from]] << @vertices[to]
|
22
|
+
end
|
23
|
+
|
24
|
+
def cycle?
|
25
|
+
cycle_vertices.any?
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def path?(from, to)
|
30
|
+
_path?(Vertex.new(from), Vertex.new(to), @adjacencies.clone)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return the vertices that are part of a cycle.
|
34
|
+
#
|
35
|
+
# If there is no cycle, it returns an empty array.
|
36
|
+
#
|
37
|
+
# @return Array Vertices labels
|
38
|
+
def cycle_vertices
|
39
|
+
# Makes a copy of vertices and searches for ones with input grade of 0.
|
40
|
+
#
|
41
|
+
# Then it removes those vertices and searches again
|
42
|
+
# until there are not vertices with input grade of 0.
|
43
|
+
#
|
44
|
+
# At this point, if there are some vertices it implies that a cycle exists.
|
45
|
+
|
46
|
+
vertices = @vertices
|
47
|
+
adjacencies = @adjacencies
|
48
|
+
|
49
|
+
while vertices.any?
|
50
|
+
leafs = in0(vertices, adjacencies)
|
51
|
+
|
52
|
+
if leafs.empty?
|
53
|
+
return vertices.keys
|
54
|
+
else
|
55
|
+
vertices = vertices.reject { |k, v| leafs.include?(v) }
|
56
|
+
adjacencies = adjacencies.reject { |k, v| leafs.include?(k) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
[]
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
# Returns the vertices from adjacencies that have an input grade of 0.
|
65
|
+
#
|
66
|
+
# @param [Hash<Object, Vertex>] vertices
|
67
|
+
# @param [Hash<Vertext, Array<Vertext>>] adjacencies
|
68
|
+
#
|
69
|
+
# @return [Array<Vertext>]
|
70
|
+
def in0(vertices, adjacencies)
|
71
|
+
vertices.values.select { |vertex|
|
72
|
+
adjacencies.count { |v, adjacents|
|
73
|
+
adjacents.count { |adjacent_vertext|
|
74
|
+
adjacent_vertext == vertex
|
75
|
+
} != 0
|
76
|
+
} == 0
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def _path?(from, to, adjacencies)
|
81
|
+
adjacents = adjacencies.delete(from) { [] }
|
82
|
+
|
83
|
+
adjacents.any? do |adjacent|
|
84
|
+
if adjacent == to
|
85
|
+
true
|
86
|
+
else
|
87
|
+
_path?(adjacent, to, adjacencies)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
class Vertex
|
96
|
+
attr_reader :label
|
97
|
+
|
98
|
+
def initialize(label)
|
99
|
+
@label = label
|
100
|
+
end
|
101
|
+
|
102
|
+
def ==(other)
|
103
|
+
eql?(other)
|
104
|
+
end
|
105
|
+
|
106
|
+
def eql?(other)
|
107
|
+
label == other.label
|
108
|
+
end
|
109
|
+
|
110
|
+
def hash
|
111
|
+
label.hash
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
data/lib/rdi/logger.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
module Rdi
|
2
|
+
module ObjectBuilder
|
3
|
+
|
4
|
+
def self.create(bean, context)
|
5
|
+
args = bean.constructor_args.map do |arg|
|
6
|
+
if arg.kind_of?(Rdi::Ref)
|
7
|
+
context.get(arg.bean_id)
|
8
|
+
elsif arg.kind_of?(Rdi::Bean)
|
9
|
+
arg.evaluate
|
10
|
+
|
11
|
+
else
|
12
|
+
arg
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
obj = if bean.factory_method
|
17
|
+
bean.klass.send(bean.factory_method)
|
18
|
+
else
|
19
|
+
bean.klass.new(*args)
|
20
|
+
end
|
21
|
+
|
22
|
+
Rdi::ObjectBuilder.set_properties(obj, bean.properties, context)
|
23
|
+
|
24
|
+
if bean.init_method
|
25
|
+
obj.send bean.init_method
|
26
|
+
end
|
27
|
+
|
28
|
+
obj
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.evaluate_collection(collection, context)
|
32
|
+
collection.map do |e|
|
33
|
+
if e.kind_of?(Rdi::Ref)
|
34
|
+
context.get(e.bean_id)
|
35
|
+
|
36
|
+
elsif e.kind_of?(Rdi::Bean)
|
37
|
+
e.evaluate
|
38
|
+
|
39
|
+
else
|
40
|
+
e
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.evaluate_hash(hash, context)
|
46
|
+
value = {}
|
47
|
+
|
48
|
+
hash.each do |k, v|
|
49
|
+
if v.kind_of?(Rdi::Ref)
|
50
|
+
value[k] = context.get(v.bean_id)
|
51
|
+
|
52
|
+
elsif v.kind_of?(Rdi::Bean)
|
53
|
+
value[k] = v.evaluate
|
54
|
+
|
55
|
+
else
|
56
|
+
value[k] = v
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
value
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.evaluate_proc(proc_, context)
|
64
|
+
params = proc_.parameters.map { |_, param| param }
|
65
|
+
|
66
|
+
values = params.map { |param| context.get(param) }
|
67
|
+
|
68
|
+
proc_.call(*values)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.set_properties(obj, properties, context)
|
72
|
+
properties.each do |name, value|
|
73
|
+
set_property(obj, name, value, context)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.set_property(obj, name, value, context)
|
78
|
+
value = evaluate(value, context)
|
79
|
+
obj.public_send "#{name}=", value
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.evaluate(value, context)
|
83
|
+
if value.kind_of?(Rdi::Ref)
|
84
|
+
context.get(value.bean_id)
|
85
|
+
|
86
|
+
elsif value.kind_of?(Rdi::Bean)
|
87
|
+
value.evaluate
|
88
|
+
|
89
|
+
elsif value.kind_of?(Array) || value.kind_of?(Set)
|
90
|
+
evaluate_collection(value, context)
|
91
|
+
|
92
|
+
elsif value.kind_of?(Hash)
|
93
|
+
evaluate_hash(value, context)
|
94
|
+
|
95
|
+
elsif value.kind_of?(Proc) && !value.lambda?
|
96
|
+
p 'waa'
|
97
|
+
p evaluate_proc(value, context)
|
98
|
+
else
|
99
|
+
value
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/rdi/ref.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rdi
|
2
|
+
class Ref
|
3
|
+
|
4
|
+
attr_reader :bean_id
|
5
|
+
|
6
|
+
def initialize(bean_id)
|
7
|
+
@bean_id = bean_id
|
8
|
+
end
|
9
|
+
|
10
|
+
def eql?(other)
|
11
|
+
if other.respond_to?(:bean_id)
|
12
|
+
bean_id.eql?(other.bean_id)
|
13
|
+
else
|
14
|
+
false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def hash
|
19
|
+
bean_id.hash
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/rdi/utils.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
module Rdi
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
# Extracts values from a given array
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Suppose there is a method named 'm'
|
8
|
+
#
|
9
|
+
# def m(id, name, options); end
|
10
|
+
#
|
11
|
+
# Which is expected to be called as:
|
12
|
+
#
|
13
|
+
# m(1, 'foo', :x => true, :y => true)
|
14
|
+
#
|
15
|
+
# and also:
|
16
|
+
#
|
17
|
+
# m('foo')
|
18
|
+
#
|
19
|
+
# In the second case, 'foo' is expected to be pased as the 'name' parameter,
|
20
|
+
# and id parameter is expected to be nil
|
21
|
+
#
|
22
|
+
# It would be good to define m as:
|
23
|
+
#
|
24
|
+
# def m(id = nil, name, options = {})
|
25
|
+
#
|
26
|
+
# So, we start to implement m as:
|
27
|
+
#
|
28
|
+
# def m(*args)
|
29
|
+
#
|
30
|
+
# id = 0
|
31
|
+
# name = nil
|
32
|
+
# options = {}
|
33
|
+
#
|
34
|
+
# if args.empty?
|
35
|
+
# raise ArgumentError, 'wrong number of arguments (0 for 1..3)'
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# if args.length == 1
|
39
|
+
# name = args[0]
|
40
|
+
# elsif args.length == 2
|
41
|
+
# id = args[0]
|
42
|
+
# name = args[1]
|
43
|
+
# elsif args.length == 3
|
44
|
+
# id = args[0]
|
45
|
+
# name = args[1]
|
46
|
+
# options = args[3]
|
47
|
+
# else
|
48
|
+
# raise ArgumentError, "wrong number of arguments (#{args.length} for 1..3)"
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# # ...
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# By using extract_args, the above code could be refactored as follows:
|
55
|
+
#
|
56
|
+
# def m(*args)
|
57
|
+
# id, name, options = extract_args(args, 3, {:0 => nil, :2 => {}})
|
58
|
+
#
|
59
|
+
# // ...
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# @param [Array] args Arguments passed
|
63
|
+
# @param [Integer] args_number Maximum number of expected arguments
|
64
|
+
# @param [Hash<Integer, Object>] Default argument values.
|
65
|
+
# keys => index of the argument
|
66
|
+
# values => argument value
|
67
|
+
#
|
68
|
+
# @return [Array] Extracted arguments
|
69
|
+
#
|
70
|
+
# @raise [ArgumentError] if less params than expected are passed
|
71
|
+
def self.extract_args(args, args_number, defaults = {})
|
72
|
+
min_args_number = args_number - defaults.length
|
73
|
+
|
74
|
+
if args.length < min_args_number
|
75
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for #{min_args_number}..#{args_number}"
|
76
|
+
elsif args.length > args_number
|
77
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for #{min_args_number}..#{args_number}"
|
78
|
+
end
|
79
|
+
|
80
|
+
# extracted args are put here
|
81
|
+
values = Array.new(args_number)
|
82
|
+
|
83
|
+
default_indexes = defaults.keys.sort
|
84
|
+
non_default_indexes = (0...args_number).to_a - default_indexes
|
85
|
+
|
86
|
+
defaults.each do |index, default|
|
87
|
+
values[index] = default
|
88
|
+
end
|
89
|
+
|
90
|
+
# number of args that will override default args
|
91
|
+
extra_args = args.length - (args_number - defaults.length)
|
92
|
+
|
93
|
+
# TODO: make this more legible
|
94
|
+
args.each_with_index do |arg, index|
|
95
|
+
if extra_args > 0
|
96
|
+
possible_default_index = default_indexes.first || (args_number + 1)
|
97
|
+
possible_non_default_index = non_default_indexes.first || (args_number + 1)
|
98
|
+
if possible_default_index < possible_non_default_index
|
99
|
+
values[possible_default_index] = arg
|
100
|
+
default_indexes.delete_at(0)
|
101
|
+
extra_args -= 1
|
102
|
+
else
|
103
|
+
values[possible_non_default_index] = arg
|
104
|
+
non_default_indexes.delete_at(0)
|
105
|
+
end
|
106
|
+
else
|
107
|
+
possible_non_default_index = non_default_indexes.delete_at(0)
|
108
|
+
values[possible_non_default_index] = arg
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
values
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rbdi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gianfranco Zas
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-09-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.10.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.10.0
|
30
|
+
description: Based on spring core.
|
31
|
+
email: snmgian@gmail.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- lib/rdi/utils.rb
|
37
|
+
- lib/rdi/object_builder.rb
|
38
|
+
- lib/rdi/ref.rb
|
39
|
+
- lib/rdi/context_builder.rb
|
40
|
+
- lib/rdi/graphs.rb
|
41
|
+
- lib/rdi/context.rb
|
42
|
+
- lib/rdi/chain.rb
|
43
|
+
- lib/rdi/logger.rb
|
44
|
+
- lib/rdi/bean.rb
|
45
|
+
- lib/rdi/dependency_graph_builder.rb
|
46
|
+
- lib/rdi.rb
|
47
|
+
- COPYING
|
48
|
+
- COPYING.LESSER
|
49
|
+
- README.md
|
50
|
+
homepage: http://rubygems.org/gems/rbdi
|
51
|
+
licenses: []
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.8.23
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Brings dependency injection to ruby.
|
74
|
+
test_files: []
|
75
|
+
has_rdoc:
|