rumld 0.4.0

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/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ VERSION 0.1
2
+ = Initial ideas pertaining to the permission layer
data/README ADDED
@@ -0,0 +1 @@
1
+ Ruby UML Diagrammer
data/Rakefile ADDED
@@ -0,0 +1,102 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/testtask'
6
+ require 'spec/rake/spectask'
7
+ require 'lib/rumld'
8
+
9
+ NAME = 'rumld'
10
+ VERS = '0.4.0'
11
+ RDOC_OPTS = ['--all', '--quiet', '--title', 'Ruby UML Diagrammer', '--main', 'README', '--inline-source']
12
+
13
+ desc "Does a full compile, test run"
14
+ task :default => [:test]
15
+
16
+ desc "Run all examples"
17
+ Spec::Rake::SpecTask.new('spec') do |t|
18
+ t.spec_files = FileList['spec/**/*.rb']
19
+ end
20
+
21
+ Rake::RDocTask.new do |rdoc|
22
+ rdoc.rdoc_dir = 'doc/rdoc'
23
+ rdoc.options += RDOC_OPTS
24
+ rdoc.main = "README"
25
+ rdoc.rdoc_files.add ['README', 'CHANGELOG', 'lib/**/*.rb']
26
+ end
27
+
28
+ spec =
29
+ Gem::Specification.new do |s|
30
+ s.name = NAME
31
+ s.add_dependency('mocha', '>=0.5.2')
32
+ s.add_dependency('activesupport', '>=1.3.1')
33
+ s.add_dependency('hpricot', '>=0.6')
34
+ s.bindir = 'bin'
35
+ s.executables = ['rumld']
36
+
37
+ s.version = VERS
38
+ s.platform = Gem::Platform::RUBY
39
+ s.has_rdoc = true
40
+ s.rdoc_options += RDOC_OPTS
41
+ s.extra_rdoc_files = ["README", "CHANGELOG", "TODO"]
42
+ s.summary = "A simple UML Grapher for Rails objects"
43
+ s.description = s.summary
44
+ s.author = "Jeremy Friesen"
45
+ s.email = 'jeremyf@lightsky.com'
46
+ s.homepage = 'http://www.lightsky.com/'
47
+
48
+ s.files = %w(README Rakefile CHANGELOG TODO) +
49
+ Dir.glob("{doc,test,lib,spec,bin}/**/*") +
50
+
51
+ s.require_path = ["lib"]
52
+ end
53
+
54
+ Rake::GemPackageTask.new(spec) do |p|
55
+ p.need_tar = true
56
+ p.gem_spec = spec
57
+ end
58
+
59
+ desc "Run all the tests"
60
+ Rake::TestTask.new do |t|
61
+ t.libs << "test"
62
+ t.test_files = FileList['test/**/*_test.rb']
63
+ t.verbose = true
64
+ end
65
+
66
+
67
+ namespace :doc do
68
+ desc "Generate documentation for the application"
69
+ Rake::RDocTask.new("app") { |rdoc|
70
+ rdoc.rdoc_dir = 'doc/'
71
+ rdoc.title = "Rails Application Documentation"
72
+ rdoc.options << '--line-numbers'
73
+ rdoc.rdoc_files.include('lib/rumld/**/*.rb')
74
+ }
75
+
76
+ task :graph => :reapp do
77
+
78
+ Dir.glob(File.join(File.dirname(__FILE__), 'test', '**', '*.rb')).each do |f|
79
+ require f
80
+ end
81
+ file_list = ARGV.grep(/^FILE(S)=/)
82
+ files =
83
+ if file_list.empty?
84
+ ['*.rb']
85
+ else
86
+ file_list.pop.sub(/^FILE(S)=/, '').split(/(,\ )/).collect{|f| "#{f}#{'.rb' unless f.match(/\.rb$/)}"}
87
+ end
88
+ doc_folder = (ARGV.grep(/^DOC_DIR=(.*)/).pop.sub(/^DOC_DIR=/, '') rescue File.join(File.dirname(__FILE__), 'doc'))
89
+
90
+ source_folder_list = ARGV.grep(/^SOURCE_DIR(S)=/)
91
+ source_folders =
92
+ if source_folder_list.empty?
93
+ [File.join(File.dirname(__FILE__), 'lib' ), File.join(File.dirname(__FILE__), 'app', 'models' )]
94
+ else
95
+ source_folder_list.pop.sub(/^SOURCE_DIR(S)=/, '').split(/(,\ )/).collect{|f| "#{f}"}
96
+ end
97
+
98
+ File.open(File.join(File.dirname(__FILE__), 'my_graph.dot'), 'w') do |f|
99
+ f.puts Rumld::Graph.new( doc_folder, source_folders , files ).to_dot
100
+ end
101
+ end
102
+ end
data/TODO ADDED
@@ -0,0 +1,16 @@
1
+ ✓ Better define how to layout a Module that has methods as well as sub-Modules
2
+ ✓ Draw edges for included Modules as Interface
3
+ ✓ Draw edges for ActiveRecord::Association
4
+ ✓ Subclass edges
5
+ ✓ Try to determine polymorphic relations
6
+ ✓ Generate a command line interface for rumld
7
+ ✓ Need to run the process against a rails project
8
+ ✓ Need to switch on whether rumld is running against a rails project
9
+ - Refactor/rethink collection vs. render
10
+ - Convert to RSpec
11
+ - Check for referenced modules inside methods to infer additional relations
12
+ - Exception Nodes should appear differently
13
+ - Research ruby new gem
14
+
15
+ Bug?
16
+ - Check generator for like named constants in different module spaces (i.e. A::E & B::E)
data/bin/rumld ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
3
+
4
+ class RailsLoader
5
+ class << self
6
+ # Prevents Rails application from writing to STDOUT
7
+ def disable_stdout
8
+ @old_stdout = STDOUT.dup
9
+ STDOUT.reopen(PLATFORM =~ /mswin/ ? "NUL" : "/dev/null")
10
+ end
11
+
12
+ # Restore STDOUT
13
+ def enable_stdout
14
+ STDOUT.reopen(@old_stdout)
15
+ end
16
+
17
+ def load_environment
18
+ begin
19
+ disable_stdout
20
+ puts 'Loading Rails...'
21
+ require "config/environment"
22
+ enable_stdout
23
+ rescue LoadError
24
+ enable_stdout
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ RailsLoader.load_environment
31
+
32
+ require 'rumld'
33
+ require 'rumld/options_struct'
34
+ RUMLD_DEFAULT_FILES = ['*.rb']
35
+ options = Rumld::OptionsStruct.new
36
+
37
+ options.parse ARGV
38
+
39
+
40
+ grapher = Rumld::Graph.new( options.doc_dir, options.source_dirs , options.files )
41
+
42
+
43
+ `rm -rf #{options.doc_dir}`
44
+
45
+ rdoc = "rdoc --op #{options.doc_dir} #{grapher.files_to_process.join(' ')}"
46
+ `#{rdoc}`
47
+
48
+ File.open(options.outfile, 'w') do |f|
49
+ f.puts grapher.to_dot
50
+ end
@@ -0,0 +1,66 @@
1
+ class Rumld::Graph
2
+ extend Forwardable
3
+ attr_accessor :files, :doc_dir, :source_dirs
4
+
5
+ def initialize(doc_dir, source_dirs = [], files = [])
6
+ self.doc_dir = doc_dir
7
+ self.source_dirs = source_dirs
8
+ self.files = files
9
+ end
10
+ def_delegator :tree, :to_dot
11
+
12
+ def files_to_process
13
+ unless @files_to_process
14
+ @files_to_process = []
15
+ source_dirs.each do |dir|
16
+ files.each { |file| @files_to_process += Dir.glob(File.join(dir, '**', file)) } if files
17
+ end
18
+ @files_to_process.uniq!
19
+ @files_to_process.each{|f| require f}
20
+ end
21
+ @files_to_process
22
+ end
23
+
24
+ def tree
25
+ @tree ||= Rumld::Tree.new(self, defined_constant_names)
26
+ end
27
+
28
+ protected
29
+
30
+ # Get a list of constants that RDoc says have been defined
31
+ def defined_constant_names
32
+ @defined_constant_names ||=
33
+ files_to_process.collect do |filename|
34
+ collect_possible_constant_names(constants_defined(File.readlines(filename))).select do |constant_name|
35
+ File.exists?(Rumld::RDocInspector.doc_file_for(doc_dir, constant_name))
36
+ end
37
+ end.flatten
38
+ end
39
+
40
+
41
+ # This is a little on the ugly. Psuedo-combinatorially collect the constants
42
+ # You'll want to check the tests to see what I mean
43
+ def collect_possible_constant_names(constant_names = [], prefix = nil)
44
+ work = []
45
+ constant_names.each_with_index do |c1, i|
46
+ constant_name ="#{(prefix + '::') if prefix}#{c1}"
47
+ work << constant_name
48
+ work += collect_possible_constant_names(constant_names[(i+1)..-1], constant_name).flatten
49
+ end
50
+ work.uniq.sort
51
+ end
52
+
53
+ # This method makes no effort to properly establish the constant hierarchy
54
+ # It just tries to determine the constants that are being defined
55
+ def constants_defined(strings = [])
56
+ constants = strings.grep(/^\W*(class|module)/).collect do |constant|
57
+ constant.sub(/^\W*(class\W*<<|class|module)/, '').strip.sub(/\W\<.*/, '')
58
+ end
59
+
60
+ # only keeping constants
61
+ constants.select do |c|
62
+ c.match(/[A-Z]/)
63
+ end
64
+ end
65
+
66
+ end
data/lib/rumld/node.rb ADDED
@@ -0,0 +1,151 @@
1
+ class Rumld::Node
2
+ extend Forwardable
3
+ attr_reader :constant_name, :tree, :constant
4
+
5
+ def_delegator :tree, :doc_dir
6
+ def_delegator :rdoc_inspector, :doc_is_for_module?, :constant_is_module?
7
+ def_delegator :rdoc_inspector, :methods_by_section
8
+ def_delegator :rdoc_inspector, :doc_file_for
9
+
10
+ def initialize(tree, constant_name)
11
+ @constant_name = constant_name
12
+ @tree = tree
13
+ end
14
+
15
+ def constant
16
+ @constant ||= constant_name.constantize
17
+ end
18
+
19
+ def node_to_dot
20
+ if children?
21
+ children.sort!{|a,b| a.constant_name <=> b.constant_name}
22
+ %(subgraph cluster#{detached_constant_name} {
23
+ label = "#{detached_constant_name}";
24
+ color = grey;
25
+ #{self_to_dot(:style=>"dotted")}
26
+ #{children.collect{|n| n.node_to_dot}.join("\n")}
27
+ })
28
+ else
29
+ self_to_dot
30
+ end
31
+ end
32
+
33
+ def inheritence_edge_to_dot
34
+ if constant.respond_to?(:superclass) && ancestor_node = tree.node_for(constant.superclass)
35
+ %("#{constant_name}" -> "#{ancestor_node.constant_name}" [arrowhead=empty])
36
+ end
37
+ end
38
+
39
+ def included_associations_to_dot
40
+ active_record_associations.collect do |assoc|
41
+ case assoc.macro.to_s
42
+ when 'belongs_to' then to_dot_for_belongs_to(assoc)
43
+ when 'has_one' then has_one_to_dot(assoc)
44
+ when 'has_many' then has_many_to_dot(assoc)
45
+ when 'has_and_belongs_to_many' then habtm_to_dot(assoc)
46
+ end
47
+ end
48
+ end
49
+
50
+ def included_modules_to_dot
51
+ included_modules.collect do |mod|
52
+ %("#{constant_name}" -> "#{mod}" [style=dotted, arrowhead=empty])
53
+ end
54
+ end
55
+
56
+ def self_and_descendants
57
+ ([self] + children.collect{|n| n.self_and_descendants}).flatten
58
+ end
59
+
60
+ def children
61
+ @children ||= []
62
+ end
63
+
64
+ def children?
65
+ !children.empty?
66
+ end
67
+
68
+ def included_modules
69
+ rdoc_inspector.all_included_modules & tree.constant_names
70
+ end
71
+
72
+ # I only want constants that are one module level
73
+ # deeper than the current constant_name
74
+ def should_be_parent_of?(other_constant_name)
75
+ if match = other_constant_name.match(/^#{Regexp.escape(constant_name + '::')}/)
76
+ %(#{match}#{other_constant_name.split('::').last}) == other_constant_name
77
+ else
78
+ false
79
+ end
80
+ end
81
+
82
+ protected
83
+
84
+ # We can skip this one because, for now its un-needed
85
+ def to_dot_for_belongs_to(assoc)
86
+ if assoc.options[:polymorphic]
87
+ %(
88
+ "#{assoc.class_name}" [shape = "record"]
89
+ "#{constant_name}" -> "#{assoc.class_name}" [headlabel="*", taillabel="1"]
90
+ )
91
+ else
92
+ ''
93
+ end
94
+ end
95
+
96
+ def has_one_to_dot(assoc)
97
+ if assoc.options[:as]
98
+ %("#{constant_name}" -> "#{assoc.options[:as].to_s.classify}" [arrowhead=empty, style=dotted, label="by :#{assoc.name}"])
99
+ elsif tree.constant_names.include?(assoc.class_name)
100
+ %("#{constant_name}" -> "#{assoc.class_name}" [headlabel="1", taillabel="1"])
101
+ else
102
+ ''
103
+ end
104
+ end
105
+
106
+ def has_many_to_dot(assoc)
107
+ if assoc.options[:as]
108
+ %("#{constant_name}" -> "#{assoc.options[:as].to_s.classify}" [arrowhead=empty, style=dotted, label="by :#{assoc.name}"])
109
+ elsif tree.constant_names.include?(assoc.class_name)
110
+ %("#{constant_name}" -> "#{assoc.class_name}" [headlabel="1", taillabel="*"])
111
+ else
112
+ ''
113
+ end
114
+ end
115
+
116
+ def habtm_to_dot(assoc)
117
+ ''
118
+ end
119
+
120
+ def active_record_associations
121
+ constant.respond_to?(:reflect_on_all_associations) ? constant.reflect_on_all_associations : []
122
+ end
123
+
124
+ def self_to_dot(options = {})
125
+ default_options = { :shape => "record", :label => "{#{dot_formatted_node_header}||#{format_methods(methods_by_section[:public_class], '.')}#{format_methods(methods_by_section[:public_instance], '#')}}"}
126
+ options = default_options.merge(options)
127
+ %("#{constant_name}" [#{options.collect{|key, value| key.to_s + '="' + value.to_s + '"'}.join(', ') }] )
128
+ end
129
+
130
+ def detached_constant_name
131
+ constant_name.split('::').last
132
+ end
133
+
134
+ def rdoc_inspector
135
+ @rdoc_inspector ||= Rumld::RDocInspector.new( self, constant_name )
136
+ end
137
+
138
+ # Add a << module >> to the doc if its a Module
139
+ def dot_formatted_node_header
140
+ "#{'\\<\\< module \\>\\>\\l' if constant_is_module?}#{detached_constant_name}"
141
+ end
142
+
143
+ def format_methods(methods = [], prefix = '')
144
+ if (methods && !methods.empty?)
145
+ methods.collect do |method|
146
+ prefix.to_s + method.gsub(/([{}>\|])/){|match| "\\#{match.to_s}"}
147
+ end.join('\\l') + '\\l'
148
+ end
149
+ end
150
+
151
+ end
@@ -0,0 +1,59 @@
1
+ require 'ostruct'
2
+
3
+ module Rumld
4
+ class OptionsStruct < OpenStruct
5
+
6
+ require 'optparse'
7
+
8
+ def initialize
9
+ default_options = { :doc_dir => './doc',
10
+ :files => RUMLD_DEFAULT_FILES,
11
+ :outfile => './ruml.dot',
12
+ :source_dirs => ['./lib', './app/models'] }
13
+ super(default_options)
14
+ end
15
+
16
+ def parse(args)
17
+ @opt_parser = OptionParser.new do |opts|
18
+ opts.banner = "Usage: rumld [options]"
19
+ opts.separator ""
20
+ opts.separator "Options:"
21
+ opts.on("-d", "--doc_dir ./ruml_doc", "Directory to generate rumld's", "working RDoc") do |value|
22
+ self.doc_dir = value
23
+ end
24
+
25
+ opts.on("-o", "--outfile ruml.dot", "Output file") do |value|
26
+ self.outfile = value
27
+ end
28
+
29
+ opts.on("-s", "--source_dirs lib,app/models", Array, "Directories for files") do |value|
30
+ self.source_dirs = value
31
+ end
32
+ opts.on("-f", "--files file1[,fileN]", Array, "Files to graph", "defaults to #{RUMLD_DEFAULT_FILES.join(',')}") do |value|
33
+ self.files = value
34
+ end
35
+
36
+ end
37
+
38
+ begin
39
+ @opt_parser.parse!(args)
40
+ rescue OptionParser::AmbiguousOption
41
+ option_error "Ambiguous option"
42
+ rescue OptionParser::InvalidOption
43
+ option_error "Invalid option"
44
+ rescue OptionParser::InvalidArgument
45
+ option_error "Invalid argument"
46
+ rescue OptionParser::MissingArgument
47
+ option_error "Missing argument"
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def option_error(msg)
54
+ STDERR.print "Error: #{msg}\n\n #{@opt_parser}\n"
55
+ exit 1
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,70 @@
1
+ class Rumld::RDocInspector
2
+
3
+ class << self
4
+ def doc_file_for(doc_dir, constant_name)
5
+ File.join(doc_dir, 'classes', "#{constant_name.gsub('::', '/')}.html")
6
+ end
7
+ end
8
+
9
+ XPATH_TO_METHOD_SECTION_HEADER = '#methods > h3'
10
+ METHOD_HEADING_TABLE = {'Public Class methods' => :public_class,
11
+ 'Public Instance methods' => :public_instance,
12
+ 'Protected Instance methods' => :protected_instance,
13
+ 'Protected Class methods' => :protected_class
14
+ }
15
+ attr_reader :node, :constant_name
16
+ def initialize(node, constant_name)
17
+ @node = node
18
+ @constant_name = constant_name
19
+ end
20
+
21
+ def doc
22
+ @doc ||= open( doc_file_for ) {|f| Hpricot(f)}
23
+ end
24
+
25
+ def doc_file_for
26
+ self.class.doc_file_for(node.doc_dir, constant_name)
27
+ end
28
+
29
+ def all_included_modules
30
+ self.doc.search('#includes #includes-list .include-name').collect{|n| n.inner_text}
31
+ end
32
+
33
+ def doc_is_for_module?
34
+ if @doc_is_for_module.nil?
35
+ @doc_is_for_module = (self.doc.search('#classHeader table.header-table tr td strong')[0].inner_html == 'Module')
36
+ end
37
+ @doc_is_for_module
38
+ end
39
+
40
+ # Given an RDoc class.html file, kick back a hash of methods
41
+ def methods_by_section
42
+ unless @methods_by_section
43
+ @methods_by_section = {}
44
+ (self.doc/XPATH_TO_METHOD_SECTION_HEADER).each do |method_section|
45
+ if collector_key = METHOD_HEADING_TABLE[method_section.inner_html]
46
+ @methods_by_section[collector_key] = find_methods_in_section(method_section)
47
+ end
48
+ end
49
+ end
50
+ @methods_by_section
51
+ end
52
+
53
+ def find_methods_in_section(method_section)
54
+ collector = []
55
+ # Oh why did method_section lose the following method?
56
+ child = method_section.next_sibling
57
+ while child && !child.css_path.include?(XPATH_TO_METHOD_SECTION_HEADER)
58
+ # We got to a new section, so drop out of this silly non-sense
59
+ break if child.css_path.include?(XPATH_TO_METHOD_SECTION_HEADER)
60
+ (child/'.method-heading a').each do |signature|
61
+ if string = signature.inner_text.strip.chomp
62
+ collector << string
63
+ end
64
+ end
65
+ child = child.next_sibling
66
+ end
67
+ collector.sort!
68
+ end
69
+
70
+ end
data/lib/rumld/tree.rb ADDED
@@ -0,0 +1,62 @@
1
+ class Rumld::Tree
2
+ extend Forwardable
3
+ def_delegator :graph, :doc_dir
4
+ attr_reader :constant_names, :graph
5
+ def initialize( graph, constant_names = [])
6
+ @graph = graph
7
+ @constant_names = constant_names.uniq.sort
8
+ build_nodes
9
+ end
10
+
11
+ def to_dot
12
+ %(digraph uml_diagram {\n graph[rotate=landscape, ratio=fill, overlap=false, splines=true]
13
+ #{draw_nodes}
14
+ #{draw_included_modules}
15
+ #{draw_associations}
16
+ #{draw_inheritence_edges}
17
+ }
18
+ )
19
+ end
20
+
21
+ def nodes
22
+ @nodes ||= []
23
+ end
24
+
25
+ def all_nodes
26
+ nodes.collect{|n| n.self_and_descendants}.flatten
27
+ end
28
+
29
+ def node_for( constant )
30
+ all_nodes.detect{|node| node.constant == constant || node.constant_name == constant}
31
+ end
32
+
33
+ protected
34
+
35
+ def draw_inheritence_edges
36
+ all_nodes.collect{|n| n.inheritence_edge_to_dot}.flatten.join("\n")
37
+ end
38
+
39
+ def draw_nodes
40
+ nodes.collect{|n| n.node_to_dot}.flatten.join("\n")
41
+ end
42
+
43
+ def draw_associations
44
+ all_nodes.collect{|n| n.included_associations_to_dot}.flatten.join("\n")
45
+ end
46
+
47
+ def draw_included_modules
48
+ all_nodes.collect{|n| n.included_modules_to_dot}.flatten.join("\n")
49
+ end
50
+
51
+ def build_nodes
52
+ constant_names.each do |constant_name|
53
+ if node = all_nodes.detect{|node| node.should_be_parent_of?(constant_name)}
54
+ node.children << Rumld::Node.new(self, constant_name)
55
+ else
56
+ nodes << Rumld::Node.new(self, constant_name)
57
+ end
58
+ end
59
+ nodes.sort!{|a,b| a.constant_name <=> b.constant_name}
60
+ end
61
+
62
+ end
data/lib/rumld.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ gem 'hpricot'
3
+
4
+ require 'hpricot'
5
+ require 'mocha'
6
+
7
+ unless defined? RAILS_ENV
8
+ gem 'activesupport'
9
+ require 'active_support/core_ext/string'
10
+ end
11
+
12
+ module Rumld
13
+ end
14
+
15
+ require File.join(File.dirname(__FILE__), 'rumld','graph')
16
+ require File.join(File.dirname(__FILE__), 'rumld','tree')
17
+ require File.join(File.dirname(__FILE__), 'rumld','node')
18
+ require File.join(File.dirname(__FILE__), 'rumld','rdoc_inspector')
@@ -0,0 +1,43 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ module Rumld
4
+ describe Graph do
5
+ before(:each) do
6
+ @graph = Rumld::Graph.new('', [],[])
7
+ end
8
+ it 'delegates to_dot to tree' do
9
+ @graph.expects(:tree).returns(stub('Tree', :to_dot => :to_dot))
10
+ @graph.to_dot.should == :to_dot
11
+ end
12
+
13
+ it 'collects possible constant names should recursively build a larger constant list' do
14
+ @graph.send(:collect_possible_constant_names, ['One', 'Two::A', 'Three']).should == ['One', 'One::Two::A', 'One::Two::A::Three', 'Three', 'Two::A', 'Two::A::Three']
15
+ end
16
+
17
+ it 'collects all of the demodulized constants that are declared' do
18
+ file = <<-EOV
19
+ class One
20
+ class Two::Three < One
21
+ include Eight
22
+ extend Nine
23
+ def function(one)
24
+ end
25
+ end
26
+ module Four
27
+ end
28
+ class << self
29
+ end
30
+
31
+ class << Five
32
+ end
33
+ end
34
+ EOV
35
+ @graph.send(:constants_defined, file.split("\n")).should == ['One', 'Two::Three', 'Four', 'Five']
36
+ end
37
+
38
+ it 'uniquely determines all the matching files to process' do
39
+ @graph = Rumld::Graph.new(nil, [File.dirname(__FILE__),File.dirname(__FILE__)], [File.basename(__FILE__)])
40
+ @graph.send(:files_to_process).should == [__FILE__]
41
+ end
42
+ end
43
+ end