Class: LibGems::DependencyList

Inherits:
Object
  • Object
show all
Includes:
Enumerable, TSort
Defined in:
lib/libgems/dependency_list.rb

Overview

LibGems::DependencyList is used for installing and uninstalling gems in the correct order to avoid conflicts.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(development = false) ⇒ DependencyList

Creates a new DependencyList. If development is true, development dependencies will be included.



40
41
42
43
44
# File 'lib/libgems/dependency_list.rb', line 40

def initialize development = false
  @specs = []

  @development = development
end

Instance Attribute Details

#developmentObject

Allows enabling/disabling use of development dependencies



21
22
23
# File 'lib/libgems/dependency_list.rb', line 21

def development
  @development
end

Class Method Details

.from_source_index(source_index) ⇒ Object

Creates a DependencyList from a LibGems::SourceIndex source_index



26
27
28
29
30
31
32
33
34
# File 'lib/libgems/dependency_list.rb', line 26

def self.from_source_index(source_index)
  list = new

  source_index.each do |full_name, spec|
    list.add spec
  end

  list
end

Instance Method Details

#add(*gemspecs) ⇒ Object

Adds gemspecs to the dependency list.



49
50
51
# File 'lib/libgems/dependency_list.rb', line 49

def add(*gemspecs)
  @specs.push(*gemspecs)
end

#dependency_orderObject

Return a list of the gem specifications in the dependency list, sorted in order so that no gemspec in the list depends on a gemspec earlier in the list.

This is useful when removing gems from a set of installed gems. By removing them in the returned order, you don’t get into as many dependency issues.

If there are circular dependencies (yuck!), then gems will be returned in order until only the circular dependents and anything they reference are left. Then arbitrary gemspecs will be returned until the circular dependency is broken, after which gems will be returned in dependency order again.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/libgems/dependency_list.rb', line 68

def dependency_order
  sorted = strongly_connected_components.flatten

  result = []
  seen = {}

  sorted.each do |spec|
    if index = seen[spec.name] then
      if result[index].version < spec.version then
        result[index] = spec
      end
    else
      seen[spec.name] = result.length
      result << spec
    end
  end

  result.reverse
end

#each(&block) ⇒ Object

Iterator over dependency_order



91
92
93
# File 'lib/libgems/dependency_list.rb', line 91

def each(&block)
  dependency_order.each(&block)
end

#find_name(full_name) ⇒ Object



95
96
97
# File 'lib/libgems/dependency_list.rb', line 95

def find_name(full_name)
  @specs.find { |spec| spec.full_name == full_name }
end

#inspectObject

:nodoc:



99
100
101
# File 'lib/libgems/dependency_list.rb', line 99

def inspect # :nodoc:
  "#<%s:0x%x %p>" % [self.class, object_id, map { |s| s.full_name }]
end

#ok?Boolean

Are all the dependencies in the list satisfied?

Returns:

  • (Boolean)


106
107
108
109
110
111
112
# File 'lib/libgems/dependency_list.rb', line 106

def ok?
  @specs.all? do |spec|
    spec.runtime_dependencies.all? do |dep|
      @specs.find { |s| s.satisfies_requirement? dep }
    end
  end
end

#ok_to_remove?(full_name) ⇒ Boolean

Is is ok to remove a gemspec from the dependency list?

If removing the gemspec creates breaks a currently ok dependency, then it is NOT ok to remove the gemspec.

Returns:

  • (Boolean)


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/libgems/dependency_list.rb', line 120

def ok_to_remove?(full_name)
  gem_to_remove = find_name full_name

  siblings = @specs.find_all { |s|
    s.name == gem_to_remove.name &&
      s.full_name != gem_to_remove.full_name
  }

  deps = []

  @specs.each do |spec|
    spec.dependencies.each do |dep|
      deps << dep if gem_to_remove.satisfies_requirement?(dep)
    end
  end

  deps.all? { |dep|
    siblings.any? { |s|
      s.satisfies_requirement? dep
    }
  }
end

#remove_by_name(full_name) ⇒ Object

Removes the gemspec matching full_name from the dependency list



146
147
148
# File 'lib/libgems/dependency_list.rb', line 146

def remove_by_name(full_name)
  @specs.delete_if { |spec| spec.full_name == full_name }
end

#spec_predecessorsObject

Return a hash of predecessors. result[spec] is an Array of gemspecs that have a dependency satisfied by the named gemspec.



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/libgems/dependency_list.rb', line 154

def spec_predecessors
  result = Hash.new { |h,k| h[k] = [] }

  specs = @specs.sort.reverse

  specs.each do |spec|
    specs.each do |other|
      next if spec == other

      other.dependencies.each do |dep|
        if spec.satisfies_requirement? dep then
          result[spec] << other
        end
      end
    end
  end

  result
end

#tsort_each_child(node, &block) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/libgems/dependency_list.rb', line 178

def tsort_each_child(node, &block)
  specs = @specs.sort.reverse

  dependencies = node.runtime_dependencies
  dependencies.push(*node.development_dependencies) if @development

  dependencies.each do |dep|
    specs.each do |spec|
      if spec.satisfies_requirement? dep then
        begin
          yield spec
        rescue TSort::Cyclic
        end
        break
      end
    end
  end
end

#tsort_each_node(&block) ⇒ Object



174
175
176
# File 'lib/libgems/dependency_list.rb', line 174

def tsort_each_node(&block)
  @specs.each(&block)
end