class_dependencies 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +13 -12
- data/VERSION +1 -1
- data/lib/class_dependencies.rb +71 -44
- data/lib/inflector.rb +32 -0
- data/spec/class_dependencies_spec.rb +35 -38
- metadata +4 -3
data/README.rdoc
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
= class_dependencies
|
2
2
|
|
3
|
-
say you have a bunch of classes which have
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class A
|
9
|
-
class B
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
say you have a bunch of classes which have a dependency relationship
|
4
|
+
e.g. you have A, B and C and a relationship depends_on. you can express
|
5
|
+
this as follows :
|
6
|
+
|
7
|
+
module DependsOn ; include Sonar::ClassDependencies ; end
|
8
|
+
class A ; include DependsOn ; depends_on :b ; end
|
9
|
+
class B ; include DependsOn ; depends_on :c ; end
|
10
|
+
class C ; include DependsOn ; end
|
11
|
+
|
12
|
+
DependsOn.ordered_dependencies
|
13
|
+
=>[:c, :b, :a]
|
14
|
+
DependsOn.ordered_dependent_classes
|
15
|
+
=>[C, B, A]
|
15
16
|
|
16
17
|
== Install
|
17
18
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/class_dependencies.rb
CHANGED
@@ -1,56 +1,93 @@
|
|
1
1
|
require 'set'
|
2
|
+
require 'inflector.rb'
|
2
3
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
4
|
+
# include Sonar::ClassDependencies onto a Module or Class
|
5
|
+
# then include that Module, or inherit from that Class,
|
6
|
+
# and declare dependencies amongst the descendants of
|
7
|
+
# that Module or Class, which can be queried on
|
8
|
+
# the Module or Class, and ordered by dependency
|
6
9
|
# e.g.
|
7
|
-
# class Top ; include Sonar::ClassDependencies ; end
|
8
|
-
# class A < Top ; depends_on :b ; end
|
9
|
-
# class B < Top ; depends_on :c ; end
|
10
|
-
# class C < Top ; end
|
11
10
|
#
|
12
|
-
#
|
11
|
+
# module SomeDep ; include Sonar::ClassDependencies ; end
|
12
|
+
# class A ; include Base ; some_dep :b ; end
|
13
|
+
# class B ; include Base ; some_dep :c ; end
|
14
|
+
# class C ; include Base ; end
|
15
|
+
# SomeDep.ordered_dependencies
|
13
16
|
# => [:c, :b, :a]
|
14
|
-
#
|
17
|
+
# SomeDep.ordered_dependent_classes
|
15
18
|
# => [C, B, A]
|
16
19
|
#
|
20
|
+
# class AnotherDep ; include Sonar::ClassDependencies ; end
|
21
|
+
# class D < Top ; another_dep :e ; end
|
22
|
+
# class E < Top ; another_dep :f ; end
|
23
|
+
# class F < Top ; end
|
24
|
+
# AnotherDep.ordered_dependencies
|
25
|
+
# => [:f, :e, :d]
|
26
|
+
# AnotherDep.ordered_dependent_classes
|
27
|
+
# => [F, E, D]
|
28
|
+
|
17
29
|
module Sonar
|
18
30
|
module ClassDependencies
|
31
|
+
module ClassName
|
32
|
+
def class_to_sym(klass)
|
33
|
+
klass.to_s.underscore.to_sym
|
34
|
+
end
|
35
|
+
|
36
|
+
def sym_to_class(sym)
|
37
|
+
eval(sym.to_s.camelize)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
19
41
|
class << self
|
42
|
+
include Sonar::ClassDependencies::ClassName
|
20
43
|
|
21
|
-
# generates
|
22
|
-
|
23
|
-
|
24
|
-
|
44
|
+
# generates an inclusion method [suitable for included() or inherited() ] on the module
|
45
|
+
# we are included into,
|
46
|
+
# which generates value proxys for the class_dependencies and obj_descendants
|
47
|
+
def generate_inclusion_method(mod, method_name)
|
48
|
+
mc = mod.instance_eval{class << self ; self ; end}
|
49
|
+
|
50
|
+
mc.send(:define_method, method_name) do |mod2|
|
51
|
+
raise "include #{mod.to_s} on a Class... doesn't work with intermediate modules" if ! mod2.is_a? Class
|
52
|
+
mod.descendants << class_to_sym(mod2)
|
53
|
+
dep_method_name = class_to_sym(mod)
|
54
|
+
mod2.instance_eval do
|
55
|
+
mc2 = class << self ; self ; end
|
56
|
+
mc2.send(:define_method, dep_method_name){|*params| mod.add_dependency(mod2, *params)}
|
57
|
+
end
|
25
58
|
end
|
26
59
|
end
|
27
|
-
|
60
|
+
|
28
61
|
def included(mod)
|
29
|
-
mod.instance_eval do
|
30
|
-
class << self
|
31
|
-
ClassDependencies::generate_closure_value_method(self, :class_dependencies, {})
|
32
|
-
ClassDependencies::generate_closure_value_method(self, :descendants, [])
|
33
|
-
include( ClassMethods )
|
34
|
-
end
|
62
|
+
mc = mod.instance_eval do
|
63
|
+
class << self ; include BaseModuleMethods ; self ; end
|
35
64
|
end
|
65
|
+
# generate the dependency list value and the descendants value accessors
|
66
|
+
# on first include : they return a closed over value
|
67
|
+
dependencies = {}
|
68
|
+
descendants = []
|
69
|
+
mc.send(:define_method, :class_dependencies){dependencies}
|
70
|
+
mc.send(:define_method, :descendants){descendants}
|
71
|
+
|
72
|
+
# generate an included method if we are included into a module
|
73
|
+
ClassDependencies::generate_inclusion_method(mod, :included)
|
74
|
+
# and if we are included into a Class, then generate an inherited method too
|
75
|
+
ClassDependencies::generate_inclusion_method(mod, :inherited) if mod.is_a? Class
|
36
76
|
end
|
37
77
|
end
|
38
|
-
|
39
|
-
module ClassMethods
|
40
|
-
def inherited(subclass)
|
41
|
-
descendants << subclass.to_s.underscore.to_sym
|
42
|
-
end
|
43
78
|
|
44
|
-
|
45
|
-
|
46
|
-
|
79
|
+
# methods for the base module, on which the dependency map and descendants list live
|
80
|
+
module BaseModuleMethods
|
81
|
+
include Sonar::ClassDependencies::ClassName
|
47
82
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
83
|
+
def add_dependency(from, to)
|
84
|
+
from_sym = class_to_sym(from)
|
85
|
+
to_sym = class_to_sym(to)
|
86
|
+
return if from_sym == to_sym
|
87
|
+
deps = (class_dependencies[from_sym] ||= [])
|
88
|
+
raise "circular dependency" if all_dependencies_of(to_sym).include?(from_sym)
|
89
|
+
deps << to_sym
|
90
|
+
nil
|
54
91
|
end
|
55
92
|
|
56
93
|
def all_dependencies_of(from)
|
@@ -76,16 +113,6 @@ module Sonar
|
|
76
113
|
|
77
114
|
private
|
78
115
|
|
79
|
-
def add_dependency(from, to)
|
80
|
-
from_sym = class_to_sym(from)
|
81
|
-
to_sym = class_to_sym(to)
|
82
|
-
return if from_sym == to_sym
|
83
|
-
deps = (class_dependencies[from_sym] ||= [])
|
84
|
-
raise "circular dependency" if all_dependencies_of(to_sym).include?(from_sym)
|
85
|
-
deps << to_sym
|
86
|
-
nil
|
87
|
-
end
|
88
|
-
|
89
116
|
def find_dependencies_of(from, deps)
|
90
117
|
deps << from
|
91
118
|
(class_dependencies[from]||[]).each do |dep|
|
data/lib/inflector.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# camelize and underscore taken from ActiveSupport
|
2
|
+
|
3
|
+
if !defined? Inflector
|
4
|
+
module Inflector
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
|
8
|
+
if first_letter_in_uppercase
|
9
|
+
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
10
|
+
else
|
11
|
+
lower_case_and_underscored_word.first.downcase + camelize(lower_case_and_underscored_word)[1..-1]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def underscore(camel_cased_word)
|
16
|
+
camel_cased_word.to_s.gsub(/::/, '/').
|
17
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
18
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
19
|
+
tr("-", "_").
|
20
|
+
downcase
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class String
|
25
|
+
def camelize
|
26
|
+
Inflector::camelize(self)
|
27
|
+
end
|
28
|
+
def underscore
|
29
|
+
Inflector::underscore(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,62 +1,59 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
# camelize and underscore take from ActiveSupport
|
4
|
-
module Inflector
|
5
|
-
extend self
|
6
|
-
|
7
|
-
def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
|
8
|
-
if first_letter_in_uppercase
|
9
|
-
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
10
|
-
else
|
11
|
-
lower_case_and_underscored_word.first.downcase + camelize(lower_case_and_underscored_word)[1..-1]
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def underscore(camel_cased_word)
|
16
|
-
camel_cased_word.to_s.gsub(/::/, '/').
|
17
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
18
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
19
|
-
tr("-", "_").
|
20
|
-
downcase
|
21
|
-
end
|
22
|
-
end
|
23
|
-
class String
|
24
|
-
def camelize
|
25
|
-
Inflector::camelize(self)
|
26
|
-
end
|
27
|
-
def underscore
|
28
|
-
Inflector::underscore(self)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
3
|
describe "ClassDependencies" do
|
33
4
|
|
34
|
-
class
|
5
|
+
class BaseDep
|
35
6
|
include Sonar::ClassDependencies
|
36
7
|
end
|
37
8
|
|
38
|
-
class A <
|
39
|
-
|
9
|
+
class A < BaseDep
|
10
|
+
base_dep :b
|
40
11
|
end
|
41
12
|
|
42
|
-
class B <
|
43
|
-
|
13
|
+
class B < BaseDep
|
14
|
+
base_dep :c
|
44
15
|
end
|
45
16
|
|
46
|
-
class C <
|
17
|
+
class C < BaseDep
|
47
18
|
end
|
48
19
|
|
49
20
|
|
50
21
|
it "should correctly order class dependences" do
|
51
|
-
|
22
|
+
BaseDep.ordered_dependencies.should == [:c, :b, :a]
|
52
23
|
end
|
53
24
|
|
54
25
|
it "should record dependency declarations" do
|
55
|
-
|
26
|
+
BaseDep.class_dependencies.should == {:a=>[:b], :b=>[:c]}
|
56
27
|
end
|
57
28
|
|
58
29
|
it "should record class inheritance" do
|
59
|
-
|
30
|
+
BaseDep.descendants == [:a, :b, :c]
|
31
|
+
end
|
32
|
+
|
33
|
+
module AnotherDep
|
34
|
+
include Sonar::ClassDependencies
|
35
|
+
end
|
36
|
+
|
37
|
+
class D
|
38
|
+
include AnotherDep
|
39
|
+
another_dep :e
|
40
|
+
end
|
41
|
+
|
42
|
+
class E
|
43
|
+
include AnotherDep
|
44
|
+
another_dep :f
|
45
|
+
end
|
46
|
+
|
47
|
+
class F
|
48
|
+
include AnotherDep
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should correctly order class dependencies for module include" do
|
52
|
+
AnotherDep.ordered_dependencies.should == [:f, :e, :d]
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should record dependency declarations for module include" do
|
56
|
+
AnotherDep.class_dependencies.should == {:d=>[:e], :e=>[:f]}
|
60
57
|
end
|
61
58
|
|
62
59
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 2
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- mccraig mccraig of the clan mccraig
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-23 00:00:00 +00:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -48,6 +48,7 @@ files:
|
|
48
48
|
- Rakefile
|
49
49
|
- VERSION
|
50
50
|
- lib/class_dependencies.rb
|
51
|
+
- lib/inflector.rb
|
51
52
|
- spec/class_dependencies_spec.rb
|
52
53
|
- spec/spec.opts
|
53
54
|
- spec/spec_helper.rb
|