rumld 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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