codependency 0.2.0 → 0.3.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/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