molinillo 0.5.4 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f53e46c97a53227bf496401139787e902f29c31c
4
- data.tar.gz: 4c702b61c8eb41ddbcb899579e226588ca6ea8c1
3
+ metadata.gz: a3f407e98934857813a1d4e17fbf807171bfbd02
4
+ data.tar.gz: 5ca9cff1741fb50a1c8767a7fb6aadc6465d1b70
5
5
  SHA512:
6
- metadata.gz: 531ffbe26a13d5c3d9883b4de8b0f5d01d3df2aeba3b6f6bfe5ebbbed06187f0594aab1532268894ad8e7f12bef790cc68ebc8e1ef0ebd2e86eac8f74c3a0941
7
- data.tar.gz: 1323d5f6cad31427e8bf44e07237de6ee8f9c1f272ec3a2ad803cd33684f634f4d0f6d86013fc49c84c981bddf856638eab1dda7906a397712e9fb8854660a31
6
+ metadata.gz: 0a683263d7bf6566b74e88d948c20a6b2ec18cbbf26ae68e335ec27ab61708c25b9565329b6295e90bad515322196792d94df6f1d651997d84f32066253b6d85
7
+ data.tar.gz: d529667799bbb115b1fadd3fffa107fadca0ec456b0c00a97af9404713b45d1ec6a4ae54a8f2309acd68ea068018f7cf63c494b91effcbbf80fc112390340bbb
@@ -119,6 +119,7 @@ module Molinillo
119
119
  # {Vertex#successors}
120
120
  def ==(other)
121
121
  return false unless other
122
+ return true if equal?(other)
122
123
  vertices.each do |name, vertex|
123
124
  other_vertex = other.vertex_named(name)
124
125
  return false unless other_vertex
@@ -134,6 +135,7 @@ module Molinillo
134
135
  def add_child_vertex(name, payload, parent_names, requirement)
135
136
  root = !parent_names.delete(nil) { true }
136
137
  vertex = add_vertex(name, payload, root)
138
+ vertex.explicit_requirements << requirement if root
137
139
  parent_names.each do |parent_name|
138
140
  parent_node = vertex_named(parent_name)
139
141
  add_edge(parent_node, vertex, requirement)
@@ -152,7 +154,7 @@ module Molinillo
152
154
  # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
153
155
  # removing any non-root vertices that were orphaned in the process
154
156
  # @param [String] name
155
- # @return [void]
157
+ # @return [Array<Vertex>] the vertices which have been detached
156
158
  def detach_vertex_named(name)
157
159
  log.detach_vertex_named(self, name)
158
160
  end
@@ -14,16 +14,23 @@ module Molinillo
14
14
 
15
15
  # (see Action#up)
16
16
  def up(graph)
17
- return unless @vertex = graph.vertices.delete(name)
17
+ return [] unless @vertex = graph.vertices.delete(name)
18
+
19
+ removed_vertices = [@vertex]
18
20
  @vertex.outgoing_edges.each do |e|
19
21
  v = e.destination
20
22
  v.incoming_edges.delete(e)
21
- graph.detach_vertex_named(v.name) unless v.root? || v.predecessors.any?
23
+ if !v.root? && v.incoming_edges.empty?
24
+ removed_vertices.concat graph.detach_vertex_named(v.name)
25
+ end
22
26
  end
27
+
23
28
  @vertex.incoming_edges.each do |e|
24
29
  v = e.origin
25
30
  v.outgoing_edges.delete(e)
26
31
  end
32
+
33
+ removed_vertices
27
34
  end
28
35
 
29
36
  # (see Action#down)
@@ -81,6 +81,7 @@ module Molinillo
81
81
  # @return [Boolean] whether the two vertices are equal, determined
82
82
  # by a recursive traversal of each {Vertex#successors}
83
83
  def ==(other)
84
+ return true if equal?(other)
84
85
  shallow_eql?(other) &&
85
86
  successors.to_set == other.successors.to_set
86
87
  end
@@ -89,6 +90,7 @@ module Molinillo
89
90
  # @return [Boolean] whether the two vertices are equal, determined
90
91
  # solely by {#name} and {#payload} equality
91
92
  def shallow_eql?(other)
93
+ return true if equal?(other)
92
94
  other &&
93
95
  name == other.name &&
94
96
  payload == other.payload
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module Molinillo
3
3
  # The version of Molinillo.
4
- VERSION = '0.5.4'.freeze
4
+ VERSION = '0.5.5'.freeze
5
5
  end
@@ -366,13 +366,12 @@ module Molinillo
366
366
  if matching_deps.empty? && !succ.root? && succ.predecessors.to_a == [vertex]
367
367
  debug(depth) { "Removing orphaned spec #{succ.name} after swapping #{name}" }
368
368
  succ.requirements.each { |r| @parent_of.delete(r) }
369
- activated.detach_vertex_named(succ.name)
370
369
 
371
- all_successor_names = succ.recursive_successors.map(&:name)
372
-
373
- requirements.delete_if do |requirement|
374
- requirement_name = name_for(requirement)
375
- (requirement_name == succ.name) || all_successor_names.include?(requirement_name)
370
+ removed_names = activated.detach_vertex_named(succ.name).map(&:name)
371
+ requirements.delete_if do |r|
372
+ # the only removed vertices are those with no other requirements,
373
+ # so it's safe to delete only based upon name here
374
+ removed_names.include?(name_for(r))
376
375
  end
377
376
  elsif !matching_deps.include?(outgoing_edge.requirement)
378
377
  activated.delete_edge(outgoing_edge)
@@ -57,7 +57,7 @@ module Molinillo
57
57
  @graph.detach_vertex_named(root.name)
58
58
  expect(@graph.vertex_named(root.name)).to be_nil
59
59
  expect(@graph.vertex_named(child.name)).to eq(child)
60
- expect(child.predecessors).to eq([root2])
60
+ expect(child.predecessors).to contain_exactly(root2)
61
61
  expect(@graph.vertices.count).to eq(2)
62
62
  end
63
63
 
data/spec/fuzz_spec.rb ADDED
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+ require 'spec_helper/naive_resolver'
4
+
5
+ describe 'fuzzing' do
6
+ CONSTRAINTS = %w(<= ~> > < >= =).freeze
7
+ let(:dependencies) do
8
+ index.specs.keys.sample(Random.rand(5)).
9
+ map do |d|
10
+ VersionKit::Dependency.new(
11
+ d,
12
+ "#{CONSTRAINTS.sample} #{Random.rand(2)}.#{Random.rand(2)}"
13
+ )
14
+ end
15
+ end
16
+ let(:index) { Molinillo::TestIndex.from_fixture('fuzz') }
17
+ let(:ui) { Molinillo::TestUI.new }
18
+ let(:resolver) { Molinillo::Resolver.new(index, ui) }
19
+
20
+ subject { resolver.resolve(dependencies) }
21
+
22
+ def validate_dependency_graph_from(graph, dependency)
23
+ vertex = graph.vertex_named(dependency.name)
24
+ spec = vertex.payload
25
+ expect(dependency).to be_satisfied_by(spec.version)
26
+ expect(spec.dependencies).to match_array(vertex.outgoing_edges.map(&:requirement))
27
+ spec.dependencies.each do |d|
28
+ validate_dependency_graph_from(graph, d)
29
+ end
30
+ end
31
+
32
+ def validate_dependency_graph(graph)
33
+ dependencies.each do |d|
34
+ validate_dependency_graph_from(graph, d)
35
+ end
36
+ end
37
+
38
+ def all_possible_graphs
39
+ dependencies.reduce([]) { |d| strings(graphs, d) }
40
+ end
41
+
42
+ let(:naive) { Molinillo::NaiveResolver.resolve(index, dependencies) }
43
+
44
+ def validate_unresolvable(error)
45
+ expect(naive).to be_nil,
46
+ 'Got an error resolving but the naive resolver found ' \
47
+ "#{naive && naive.map(&:payload).map(&:to_s)}:\n#{error}"
48
+ end
49
+
50
+ def self.fuzz!(seeds = [])
51
+ seeds.each do |seed|
52
+ it "fuzzes with seed #{seed}" do
53
+ Random.srand seed
54
+ graph, error = begin
55
+ subject
56
+ [subject, nil]
57
+ rescue => e
58
+ [nil, e]
59
+ end
60
+ validate_dependency_graph(graph) if graph
61
+ validate_unresolvable(error) if error
62
+ expect(graph).to eq(naive),
63
+ "#{graph && graph.map(&:payload).map(&:to_s)} vs #{naive && naive.map(&:payload).map(&:to_s)}"
64
+ end
65
+ end
66
+ end
67
+
68
+ fuzz! [
69
+ 8,
70
+ 9,
71
+ 125,
72
+ 188,
73
+ 666,
74
+ 7_898_789,
75
+ 0.35096144504316984,
76
+ 3.14159,
77
+ ].concat(Array.new(ENV.fetch('MOLINILLO_FUZZER', '0').to_i) { Random.rand })
78
+ end if RUBY_VERSION >= '1.9'
@@ -1,25 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
  require File.expand_path('../spec_helper', __FILE__)
3
- require 'json'
4
- require 'pathname'
5
3
 
6
4
  module Molinillo
7
- FIXTURE_DIR = Pathname.new('spec/resolver_integration_specs')
8
- FIXTURE_INDEX_DIR = FIXTURE_DIR + 'index'
9
5
  FIXTURE_CASE_DIR = FIXTURE_DIR + 'case'
10
6
 
11
7
  class TestCase
12
- require File.expand_path('../spec_helper/index', __FILE__)
13
- require File.expand_path('../spec_helper/specification', __FILE__)
14
- require File.expand_path('../spec_helper/ui', __FILE__)
15
-
16
8
  attr_accessor :name, :requested, :base, :conflicts, :resolver, :result, :index
17
9
 
18
10
  def initialize(fixture_path)
19
11
  File.open(fixture_path) do |fixture|
20
12
  JSON.load(fixture).tap do |test_case|
21
13
  self.name = test_case['name']
22
- self.index = TestIndex.new(test_case['index'] || 'awesome')
14
+ self.index = TestIndex.from_fixture(test_case['index'] || 'awesome')
23
15
  self.requested = test_case['requested'].map do |(name, reqs)|
24
16
  VersionKit::Dependency.new name, reqs.split(',').map(&:chomp)
25
17
  end
@@ -90,7 +82,7 @@ module Molinillo
90
82
 
91
83
  describe 'in general' do
92
84
  before do
93
- @resolver = described_class.new(TestIndex.new('awesome'), TestUI.new)
85
+ @resolver = described_class.new(TestIndex.from_fixture('awesome'), TestUI.new)
94
86
  end
95
87
 
96
88
  it 'can resolve a list of 0 requirements' do
@@ -122,7 +114,7 @@ module Molinillo
122
114
  end
123
115
 
124
116
  it 'can resolve when two specs have the same dependencies' do
125
- index = BundlerIndex.new('rubygems-2016-09-11')
117
+ index = BundlerIndex.from_fixture('rubygems-2016-09-11')
126
118
  @resolver = described_class.new(index, TestUI.new)
127
119
  demands = [
128
120
  VersionKit::Dependency.new('chef', '~> 12.1.2'),
@@ -182,7 +174,7 @@ module Molinillo
182
174
  end
183
175
 
184
176
  it 'can resolve when two specs have the same dependencies and swapping happens' do
185
- index = BundlerIndex.new('rubygems-2016-10-06')
177
+ index = BundlerIndex.from_fixture('rubygems-2016-10-06')
186
178
  @resolver = described_class.new(index, TestUI.new)
187
179
  demands = [
188
180
  VersionKit::Dependency.new('avro_turf', '0.6.2'),
@@ -243,7 +235,7 @@ module Molinillo
243
235
  end
244
236
 
245
237
  it 'can unwind when the conflict has a common parent' do
246
- index = BundlerIndex.new('rubygems-2016-11-05')
238
+ index = BundlerIndex.from_fixture('rubygems-2016-11-05')
247
239
  @resolver = described_class.new(index, TestUI.new)
248
240
  demands = [
249
241
  VersionKit::Dependency.new('github-pages', '>= 0'),
@@ -256,7 +248,7 @@ module Molinillo
256
248
  end
257
249
 
258
250
  it 'can resolve when swapping changes transitive dependencies' do
259
- index = TestIndex.new('restkit')
251
+ index = TestIndex.from_fixture('restkit')
260
252
  def index.sort_dependencies(dependencies, activated, conflicts)
261
253
  dependencies.sort_by do |d|
262
254
  [
@@ -315,11 +307,11 @@ module Molinillo
315
307
  end
316
308
 
317
309
  def versions_of(dependency_name)
318
- specs[dependency_name].count
310
+ Array(specs[dependency_name]).count
319
311
  end
320
312
  end
321
313
 
322
- index = swap_child_with_successors_index.new('swap_child_with_successors')
314
+ index = swap_child_with_successors_index.from_fixture('swap_child_with_successors')
323
315
  @resolver = described_class.new(index, TestUI.new)
324
316
  demands = [
325
317
  VersionKit::Dependency.new('build-essential', '>= 0.0.0'),
@@ -340,6 +332,50 @@ module Molinillo
340
332
 
341
333
  expect(resolved.map(&:payload).map(&:to_s)).to match_array(expected)
342
334
  end
335
+
336
+ it 'can resolve ur face' do
337
+ index = TestIndex.new(
338
+ 'a' => [
339
+ TestSpecification.new('name' => 'a', 'version' => '1.0.0', 'dependencies' => { 'z' => '= 2.0.0' }),
340
+ TestSpecification.new('name' => 'a', 'version' => '2.0.0', 'dependencies' => { 'z' => '= 1.0.0' }),
341
+ ],
342
+ 'b' => [
343
+ TestSpecification.new('name' => 'b', 'version' => '1.0.0', 'dependencies' => { 'a' => '< 2' }),
344
+ TestSpecification.new('name' => 'b', 'version' => '2.0.0', 'dependencies' => { 'a' => '< 2' }),
345
+ ],
346
+ 'c' => [
347
+ TestSpecification.new('name' => 'c', 'version' => '1.0.0'),
348
+ TestSpecification.new('name' => 'c', 'version' => '2.0.0', 'dependencies' => { 'b' => '< 2' }),
349
+ ],
350
+ 'z' => [
351
+ TestSpecification.new('name' => 'z', 'version' => '1.0.0'),
352
+ TestSpecification.new('name' => 'z', 'version' => '2.0.0'),
353
+ ]
354
+ )
355
+ def index.sort_dependencies(dependencies, _activated, _conflicts)
356
+ index = ['c (>= 1.0.0)', 'b (< 2.0.0)', 'a (< 2.0.0)', 'c (= 1.0.0)']
357
+ dependencies.sort_by do |dep|
358
+ [
359
+ index.index(dep.to_s) || 999,
360
+ ]
361
+ end
362
+ end
363
+ @resolver = described_class.new(index, TestUI.new)
364
+ demands = [
365
+ VersionKit::Dependency.new('c', '= 1.0.0'),
366
+ VersionKit::Dependency.new('c', '>= 1.0.0'),
367
+ VersionKit::Dependency.new('z', '>= 1.0.0'),
368
+ ]
369
+
370
+ resolved = @resolver.resolve(demands, DependencyGraph.new)
371
+
372
+ expected = [
373
+ 'c (1.0.0)',
374
+ 'z (2.0.0)',
375
+ ]
376
+
377
+ expect(resolved.map(&:payload).map(&:to_s)).to match_array(expected)
378
+ end
343
379
  end
344
380
  end
345
381
  end
data/spec/spec_helper.rb CHANGED
@@ -24,6 +24,7 @@ end
24
24
  #-----------------------------------------------------------------------------#
25
25
 
26
26
  require 'pathname'
27
+ require 'json'
27
28
  ROOT = Pathname.new(File.expand_path('../../', __FILE__))
28
29
  $LOAD_PATH.unshift((ROOT + 'lib').to_s)
29
30
  $LOAD_PATH.unshift((ROOT + 'spec').to_s)
@@ -31,6 +32,10 @@ $LOAD_PATH.unshift((ROOT + 'spec').to_s)
31
32
  require 'version_kit'
32
33
  require 'molinillo'
33
34
 
35
+ require 'spec_helper/index'
36
+ require 'spec_helper/specification'
37
+ require 'spec_helper/ui'
38
+
34
39
  RSpec.configure do |config|
35
40
  # Enable flags like --only-failures and --next-failure
36
41
  config.example_status_persistence_file_path = '.rspec_status'
@@ -1,19 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
  module Molinillo
3
+ FIXTURE_DIR = Pathname.new('spec/resolver_integration_specs')
4
+ FIXTURE_INDEX_DIR = FIXTURE_DIR + 'index'
5
+
3
6
  class TestIndex
4
7
  attr_accessor :specs
5
8
  include SpecificationProvider
6
9
 
7
- def initialize(fixture_name)
10
+ def self.from_fixture(fixture_name)
8
11
  File.open(FIXTURE_INDEX_DIR + (fixture_name + '.json'), 'r') do |fixture|
9
- self.specs = JSON.load(fixture).reduce(Hash.new([])) do |specs_by_name, (name, versions)|
12
+ sorted_specs = JSON.load(fixture).reduce(Hash.new([])) do |specs_by_name, (name, versions)|
10
13
  specs_by_name.tap do |specs|
11
14
  specs[name] = versions.map { |s| TestSpecification.new s }.sort_by(&:version)
12
15
  end
13
16
  end
17
+ return new(sorted_specs)
14
18
  end
15
19
  end
16
20
 
21
+ def initialize(specs_by_name)
22
+ self.specs = specs_by_name
23
+ end
24
+
17
25
  def requirement_satisfied_by?(requirement, _activated, spec)
18
26
  case requirement
19
27
  when TestSpecification
@@ -27,7 +35,7 @@ module Molinillo
27
35
  @search_for ||= {}
28
36
  @search_for[dependency] ||= begin
29
37
  pre_release = dependency_pre_release?(dependency)
30
- specs[dependency.name].select do |spec|
38
+ Array(specs[dependency.name]).select do |spec|
31
39
  (pre_release ? true : !spec.version.pre_release?) &&
32
40
  dependency.satisfied_by?(spec.version)
33
41
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/CyclomaticComplexity
4
+ # rubocop:disable Metrics/LineLength
5
+ # rubocop:disable Style/Semicolon
6
+
7
+ module Molinillo
8
+ class NaiveResolver
9
+ def self.resolve(index, dependencies)
10
+ activated = Molinillo::DependencyGraph.new
11
+ level = 0
12
+ dependencies.each { |d| activated.add_child_vertex(d.name, nil, [nil], d) }
13
+ activated.tag(level)
14
+ possibilities_by_level = {}
15
+ loop do
16
+ vertex = activated.find { |a| !a.requirements.empty? && a.payload.nil? }
17
+ break unless vertex
18
+ possibilities = possibilities_by_level[level] ||= index.search_for(VersionKit::Dependency.new(vertex.name, '>= 0.0.0-a'))
19
+ possibilities.select! do |spec|
20
+ vertex.requirements.all? { |r| r.satisfied_by?(spec.version) && (!spec.version.pre_release? || index.send(:dependency_pre_release?, r)) } &&
21
+ spec.dependencies.all? { |d| v = activated.vertex_named(d.name); !v || !v.payload || d.satisfied_by?(v.payload.version) }
22
+ end
23
+ warn "level = #{level} possibilities = #{possibilities.map(&:to_s)} requirements = #{vertex.requirements.map(&:to_s)}"
24
+ if spec = possibilities.pop
25
+ warn "trying #{spec}"
26
+ activated.set_payload(vertex.name, spec)
27
+ spec.dependencies.each do |d|
28
+ activated.add_child_vertex(d.name, nil, [spec.name], d)
29
+ end
30
+ level += 1
31
+ warn "tagging level #{level}"
32
+ activated.tag(level)
33
+ next
34
+ end
35
+ level = possibilities_by_level.reverse_each.find(proc { [-1, nil] }) { |_l, p| !p.empty? }.first
36
+ warn "going back to level #{level}"
37
+ possibilities_by_level.reject! { |l, _| l > level }
38
+ return nil if level < 0
39
+ activated.rewind_to(level)
40
+ activated.tag(level)
41
+ end
42
+
43
+ activated
44
+ end
45
+
46
+ def self.warn(*); end
47
+ end
48
+ end
@@ -5,8 +5,9 @@ module Molinillo
5
5
  def initialize(hash)
6
6
  self.name = hash['name']
7
7
  self.version = VersionKit::Version.new(hash['version'])
8
- self.dependencies = hash['dependencies'].map do |(name, requirement)|
9
- VersionKit::Dependency.new(name, requirement.split(',').map(&:chomp))
8
+ self.dependencies = hash.fetch('dependencies') { Hash.new }.map do |(name, requirement)|
9
+ requirements = requirement.split(',').map(&:chomp)
10
+ VersionKit::Dependency.new(name, requirements)
10
11
  end
11
12
  end
12
13
 
metadata CHANGED
@@ -1,41 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: molinillo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.5.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel E. Giddins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-14 00:00:00.000000000 Z
11
+ date: 2017-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.5'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  description:
@@ -70,10 +70,12 @@ files:
70
70
  - spec/dependency_graph/log_spec.rb
71
71
  - spec/dependency_graph_spec.rb
72
72
  - spec/errors_spec.rb
73
+ - spec/fuzz_spec.rb
73
74
  - spec/resolver_integration_specs/index_from_rubygems.rb
74
75
  - spec/resolver_spec.rb
75
76
  - spec/spec_helper.rb
76
77
  - spec/spec_helper/index.rb
78
+ - spec/spec_helper/naive_resolver.rb
77
79
  - spec/spec_helper/specification.rb
78
80
  - spec/spec_helper/ui.rb
79
81
  - spec/state_spec.rb
@@ -87,12 +89,12 @@ require_paths:
87
89
  - lib
88
90
  required_ruby_version: !ruby/object:Gem::Requirement
89
91
  requirements:
90
- - - ">="
92
+ - - '>='
91
93
  - !ruby/object:Gem::Version
92
94
  version: '0'
93
95
  required_rubygems_version: !ruby/object:Gem::Requirement
94
96
  requirements:
95
- - - ">="
97
+ - - '>='
96
98
  - !ruby/object:Gem::Version
97
99
  version: '0'
98
100
  requirements: []
@@ -105,9 +107,11 @@ test_files:
105
107
  - spec/dependency_graph/log_spec.rb
106
108
  - spec/dependency_graph_spec.rb
107
109
  - spec/errors_spec.rb
110
+ - spec/fuzz_spec.rb
108
111
  - spec/resolver_integration_specs/index_from_rubygems.rb
109
112
  - spec/resolver_spec.rb
110
113
  - spec/spec_helper/index.rb
114
+ - spec/spec_helper/naive_resolver.rb
111
115
  - spec/spec_helper/specification.rb
112
116
  - spec/spec_helper/ui.rb
113
117
  - spec/spec_helper.rb