codependency 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { 'spec' }
5
+ watch(%r{spec/support/.+\.rb}){ 'spec' }
6
+ end
data/codependency.gemspec CHANGED
@@ -15,5 +15,7 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Codependency::VERSION
17
17
 
18
- gem.add_development_dependency 'rspec', '>= 2.10.0'
18
+ gem.add_development_dependency 'rspec', '2.11.0'
19
+ gem.add_development_dependency 'guard-rspec', '1.2.1'
20
+ gem.add_development_dependency 'rb-fsevent', '0.9.1'
19
21
  end
data/lib/codependency.rb CHANGED
@@ -5,3 +5,5 @@ module Codependency
5
5
  autoload :Node, 'codependency/node'
6
6
  autoload :Parser, 'codependency/parser'
7
7
  end
8
+
9
+ class CircularDependencyError < StandardError; end
@@ -1,3 +1,5 @@
1
+ require 'open3'
2
+
1
3
  module Codependency
2
4
  class Graph
3
5
  def initialize( start, options={} )
@@ -6,24 +8,37 @@ module Codependency
6
8
  @start = @nodes[ start ]
7
9
  end
8
10
 
11
+ ##
12
+ # a topologically sorted list of all dependencies of the `start` file.
9
13
  def files
10
- [ ].tap { |list| resolve @start, list }.reverse.map &:filename
14
+ deps = resolve( @start, [ ] ).map( &:dependencies ).join ' '
15
+
16
+ cmd, out, err = Open3.popen3 "echo '#{deps}' | tsort"
17
+
18
+ if msg = err.gets
19
+ raise CircularDependencyError, msg
20
+ end
21
+
22
+ out.readlines.map( &:chomp ).reverse
11
23
  end
12
24
 
13
25
  protected
14
26
 
27
+ ##
28
+ # adds a node's dependencies to a list (memo).
29
+ # intended to be used recursively.
15
30
  def resolve( node, list )
16
- list << node # TODO if the node were in the list here,
17
- # would that indicate a circular dependency?
18
- node.dependencies.map { |filename| @nodes[ filename ] }.each do |dep|
19
- if list.include?( dep )
20
- list << list.slice!( list.index( dep ) )
21
- else
22
- resolve dep, list
23
- end
31
+ list << node
32
+
33
+ node.edges.map { |filename| @nodes[ filename ] }.each do |dep|
34
+ resolve dep, list unless list.include?( dep )
24
35
  end
36
+
37
+ list
25
38
  end
26
39
 
40
+ ##
41
+ # the parser to use for this graph. shared by all nodes.
27
42
  def parser
28
43
  @parser ||= Parser.new @options
29
44
  end
@@ -9,8 +9,20 @@ module Codependency
9
9
  end
10
10
  attr_reader :filename, :parser
11
11
 
12
+ ##
13
+ # all of this node's edges
14
+ def edges
15
+ @edges ||= begin
16
+ parser.parse( filename ).map do |f|
17
+ dirname.join( "#{f}#{extname}" ).to_s
18
+ end
19
+ end
20
+ end
21
+
22
+ ##
23
+ # a string representing this node's edges, formatted for `tsort`.
12
24
  def dependencies
13
- parser.parse( filename ).map { |f| dirname.join( "#{f}#{extname}" ).to_s }
25
+ edges.map { |edge| [ filename, edge ] }.flatten.join ' '
14
26
  end
15
27
 
16
28
  protected
@@ -6,6 +6,8 @@ module Codependency
6
6
  @comment = options.delete( :comment ) || '#'
7
7
  end
8
8
 
9
+ ##
10
+ # determines a file's dependencies based on the configured comment pattern.
9
11
  def parse( file )
10
12
  IO.readlines( file ).take_while do |line|
11
13
  line =~ pattern
@@ -14,6 +16,9 @@ module Codependency
14
16
 
15
17
  protected
16
18
 
19
+ ##
20
+ # the comment pattern to use.
21
+ # TODO allow this to be more configurable
17
22
  def pattern
18
23
  @pattern ||= /^#{@comment} require (.+)$/
19
24
  end
@@ -1,3 +1,3 @@
1
1
  module Codependency
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -20,7 +20,17 @@ describe Codependency::Graph do
20
20
 
21
21
  context 'sandwich' do
22
22
  let( :graph ){ 'sandwich.js' }
23
- its( :files ){ should eq( %w| butter.js toast.js egg.js sandwich.js | ) }
23
+ its( :files ){ should eq( %w| butter.js egg.js toast.js sandwich.js | ) }
24
+ end
25
+ end
26
+
27
+ context 'circular dependencies', :files => :circular do
28
+ subject { Codependency::Graph.new graph }
29
+
30
+ let( :graph ){ 'money.rb' }
31
+
32
+ it 'should raise an error' do
33
+ expect { subject.files }.to raise_error( CircularDependencyError )
24
34
  end
25
35
  end
26
36
  end
@@ -5,7 +5,7 @@ describe Codependency::Node do
5
5
 
6
6
  context 'when the file exists', :files => :planets do
7
7
  subject { Codependency::Node.new 'planet.rb', parser }
8
- its( :dependencies ){ should eq( [ 'body.rb' ] ) }
8
+ its( :edges ){ should eq( [ 'body.rb' ] ) }
9
9
  end
10
10
 
11
11
  context 'when the file does not exist' do
@@ -15,4 +15,11 @@ describe Codependency::Node do
15
15
  }.to raise_error( Errno::ENOENT, 'No such file or directory - pluto.rb' )
16
16
  end
17
17
  end
18
+
19
+ describe 'dependencies', :files => :planets do
20
+ let( :parser ){ double 'Parser', :parse => [ 'body', 'mars' ] }
21
+ subject { Codependency::Node.new 'phobos.rb', parser }
22
+
23
+ its( :dependencies ){ should eq( 'phobos.rb body.rb phobos.rb mars.rb' ) }
24
+ end
18
25
  end
data/spec/spec_helper.rb CHANGED
@@ -4,7 +4,5 @@ Dir[ './spec/support/*.rb' ].each { |f| require f }
4
4
 
5
5
  RSpec.configure do |config|
6
6
  config.color_enabled = true
7
- config.formatter = :documentation
8
-
9
7
  config.include FileSystemStubs
10
8
  end
@@ -0,0 +1,25 @@
1
+ shared_context 'circular dependencies', :files => :circular do
2
+
3
+ before do
4
+ file 'money.rb', <<-EOS
5
+ # require power
6
+
7
+ class Money
8
+ end
9
+ EOS
10
+
11
+ file 'power.rb', <<-EOS
12
+ # require respect
13
+
14
+ class Power
15
+ end
16
+ EOS
17
+
18
+ file 'respect.rb', <<-EOS
19
+ # require money
20
+
21
+ class Respect
22
+ end
23
+ EOS
24
+ end
25
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codependency
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,24 +9,56 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-29 00:00:00.000000000 Z
12
+ date: 2012-09-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ! '>='
19
+ - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 2.10.0
21
+ version: 2.11.0
22
22
  type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - ! '>='
27
+ - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 2.10.0
29
+ version: 2.11.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: guard-rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - '='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.2.1
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - '='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.2.1
46
+ - !ruby/object:Gem::Dependency
47
+ name: rb-fsevent
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.1
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.1
30
62
  description: Simple comment-based dependency graph for arbitrary files
31
63
  email:
32
64
  - jeremy.ruppel@gmail.com
@@ -36,6 +68,7 @@ extra_rdoc_files: []
36
68
  files:
37
69
  - .gitignore
38
70
  - Gemfile
71
+ - Guardfile
39
72
  - LICENSE
40
73
  - README.md
41
74
  - Rakefile
@@ -50,6 +83,7 @@ files:
50
83
  - spec/codependency/parser_spec.rb
51
84
  - spec/spec_helper.rb
52
85
  - spec/support/breakfasts_context.rb
86
+ - spec/support/circular_context.rb
53
87
  - spec/support/file_system_stubs.rb
54
88
  - spec/support/planets_context.rb
55
89
  homepage: ''
@@ -82,5 +116,6 @@ test_files:
82
116
  - spec/codependency/parser_spec.rb
83
117
  - spec/spec_helper.rb
84
118
  - spec/support/breakfasts_context.rb
119
+ - spec/support/circular_context.rb
85
120
  - spec/support/file_system_stubs.rb
86
121
  - spec/support/planets_context.rb