Class: Rails::GemDependency

Inherits:
Gem::Dependency
  • Object
show all
Defined in:
lib/rails/gem_dependency.rb

Constant Summary collapse

@@framework_gems =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, options = {}) ⇒ GemDependency

Returns a new instance of GemDependency.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rails/gem_dependency.rb', line 50

def initialize(name, options = {})
  require 'rubygems' unless Object.const_defined?(:Gem)

  if options[:requirement]
    req = options[:requirement]
  elsif options[:version]
    req = Gem::Requirement.create(options[:version])
  else
    req = Gem::Requirement.default
  end

  @lib      = options[:lib]
  @source   = options[:source]
  @loaded   = @frozen = @load_paths_added = false

  super(name, req)
end

Instance Attribute Details

#depObject

Returns the value of attribute dep.



11
12
13
# File 'lib/rails/gem_dependency.rb', line 11

def dep
  @dep
end

#libObject

Returns the value of attribute lib.



11
12
13
# File 'lib/rails/gem_dependency.rb', line 11

def lib
  @lib
end

#sourceObject

Returns the value of attribute source.



11
12
13
# File 'lib/rails/gem_dependency.rb', line 11

def source
  @source
end

Class Method Details

.add_frozen_gem_pathObject



19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/rails/gem_dependency.rb', line 19

def self.add_frozen_gem_path
  @@paths_loaded ||= begin
    source_index = Rails::VendorGemSourceIndex.new(Gem.source_index)
    Gem.clear_paths
    Gem.source_index = source_index
    # loaded before us - we can't change them, so mark them
    Gem.loaded_specs.each do |name, spec|
      @@framework_gems[name] = spec
    end
    true
  end
end

.from_directory_name(directory_name, load_spec = true) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/rails/gem_dependency.rb', line 32

def self.from_directory_name(directory_name, load_spec=true)
  directory_name_parts = File.basename(directory_name).split('-')
  
  version = directory_name_parts.find { |s| s.match(/^\d(\.\d|\.\w+)*$/) }
  name    = directory_name_parts[0..directory_name_parts.index(version)-1].join('-') if version
  
  result = self.new(name, :version => version)
  spec_filename = File.join(directory_name, '.specification')
  if load_spec
    raise "Missing specification file in #{File.dirname(spec_filename)}. Perhaps you need to do a 'rake gems:refresh_specs'\?" unless File.exists?(spec_filename)
    spec = YAML::load_file(spec_filename)
    result.specification = spec
  end
  result
rescue ArgumentError => e
  raise "Unable to determine gem name and version from '#{directory_name}'"
end

.unpacked_pathObject



13
14
15
# File 'lib/rails/gem_dependency.rb', line 13

def self.unpacked_path
  @unpacked_path ||= File.join(RAILS_ROOT, 'vendor', 'gems')
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



272
273
274
275
# File 'lib/rails/gem_dependency.rb', line 272

def ==(other)
  Gem::Dependency === other.class &&
    self.name == other.name && self.requirement == other.requirement
end

#add_load_pathsObject



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

def add_load_paths
  self.class.add_frozen_gem_path
  return if @loaded || @load_paths_added
  if framework_gem?
    @load_paths_added = @loaded = @frozen = true
    return
  end

  begin
    dep = Gem::Dependency.new(name, requirement)
    spec = Gem.source_index.find { |_,s| s.satisfies_requirement?(dep) }.last
    spec.activate           # a way that exists
  rescue
    gem self.name, self.requirement # <  1.8 unhappy way
  end

  @spec = Gem.loaded_specs[name]
  @frozen = @spec.loaded_from.include?(self.class.unpacked_path) if @spec
  @load_paths_added = true
rescue Gem::LoadError
end

#build(options = {}) ⇒ Object



191
192
193
194
195
196
197
198
199
200
201
# File 'lib/rails/gem_dependency.rb', line 191

def build(options={})
  require 'rails/gem_builder'
  return if specification.nil?
  if options[:force] || !built?
    return unless File.exists?(unpacked_specification_filename)
    spec = YAML::load_file(unpacked_specification_filename)
    Rails::GemBuilder.new(spec, unpacked_gem_directory).build_extensions
    puts "Built gem: '#{unpacked_gem_directory}'"
  end
  dependencies.each { |dep| dep.build(options) }
end

#built?Boolean

Returns:

  • (Boolean)


128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/rails/gem_dependency.rb', line 128

def built?
  return false unless frozen?

  if vendor_gem?
    specification.extensions.each do |ext|
      makefile = File.join(unpacked_gem_directory, File.dirname(ext), 'Makefile')
      return false unless File.exists?(makefile)
    end
  end

  true
end

#dependenciesObject



90
91
92
93
94
95
96
97
98
# File 'lib/rails/gem_dependency.rb', line 90

def dependencies
  return [] if framework_gem?
  return [] unless installed?
  specification.dependencies.reject do |dependency|
    dependency.type == :development
  end.map do |dependency|
    GemDependency.new(dependency.name, :requirement => (dependency.respond_to?(:requirement) ? dependency.requirement : dependency.version_requirements))
  end
end

#framework_gem?Boolean

Returns:

  • (Boolean)


141
142
143
# File 'lib/rails/gem_dependency.rb', line 141

def framework_gem?
  @@framework_gems.has_key?(name)
end

#frozen?Boolean

Returns:

  • (Boolean)


145
146
147
# File 'lib/rails/gem_dependency.rb', line 145

def frozen?
  @frozen ||= vendor_rails? || vendor_gem?
end

#installObject



203
204
205
206
207
208
209
# File 'lib/rails/gem_dependency.rb', line 203

def install
  unless installed?
    cmd = "#{gem_command} #{install_command.join(' ')}"
    puts cmd
    puts %x(#{cmd})
  end
end

#installed?Boolean

Returns:

  • (Boolean)


149
150
151
# File 'lib/rails/gem_dependency.rb', line 149

def installed?
  Gem.loaded_specs.keys.include?(name)
end

#loadObject



211
212
213
214
215
216
217
218
# File 'lib/rails/gem_dependency.rb', line 211

def load
  return if @loaded || @load_paths_added == false
  require(@lib || name) unless @lib == false
  @loaded = true
rescue LoadError
  puts $!.to_s
  $!.backtrace.each { |b| puts b }
end

#load_paths_added?Boolean

Returns:

  • (Boolean)


153
154
155
156
157
158
# File 'lib/rails/gem_dependency.rb', line 153

def load_paths_added?
  # always try to add load paths - even if a gem is loaded, it may not
  # be a compatible version (ie random_gem 0.4 is loaded and a later spec
  # needs >= 0.5 - gem 'random_gem' will catch this and error out)
  @load_paths_added
end

#loaded?Boolean

Returns:

  • (Boolean)


160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/rails/gem_dependency.rb', line 160

def loaded?
  @loaded ||= begin
    if vendor_rails?
      true
    elsif specification.nil?
      false
    else
      # check if the gem is loaded by inspecting $"
      # specification.files lists all the files contained in the gem
      gem_files = specification.files
      # select only the files contained in require_paths - typically in bin and lib
      require_paths_regexp = Regexp.new("^(#{specification.require_paths*'|'})/")
      gem_lib_files = gem_files.select { |f| require_paths_regexp.match(f) }
      # chop the leading directory off - a typical file might be in
      # lib/gem_name/file_name.rb, but it will be 'require'd as gem_name/file_name.rb
      gem_lib_files.map! { |f| f.split('/', 2)[1] }
      # if any of the files from the above list appear in $", the gem is assumed to
      # have been loaded
      !(gem_lib_files & $").empty?
    end
  end
end

#refreshObject



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/rails/gem_dependency.rb', line 220

def refresh
  Rails::VendorGemSourceIndex.silence_spec_warnings = true
  real_gems = Gem.source_index.installed_source_index
  exact_dep = Gem::Dependency.new(name, "= #{specification.version}")
  matches = real_gems.search(exact_dep)
  installed_spec = matches.first
  if frozen?
    if installed_spec
      # we have a real copy
      # get a fresh spec - matches should only have one element
      # note that there is no reliable method to check that the loaded
      # spec is the same as the copy from real_gems - Gem.activate changes
      # some of the fields
      real_spec = Gem::Specification.load(matches.first.loaded_from)
      write_specification(real_spec)
      puts "Reloaded specification for #{name} from installed gems."
    else
      # the gem isn't installed locally - write out our current specs
      write_specification(specification)
      puts "Gem #{name} not loaded locally - writing out current spec."
    end
  else
    if framework_gem?
      puts "Gem directory for #{name} not found - check if it's loading before rails."
    else
      puts "Something bad is going on - gem directory not found for #{name}."
    end
  end
end

#specificationObject



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rails/gem_dependency.rb', line 100

def specification
  # code repeated from Gem.activate. Find a matching spec, or the currently loaded version.
  # error out if loaded version and requested version are incompatible.
  @spec ||= begin
    matches = Gem.source_index.search(self)
    matches << @@framework_gems[name] if framework_gem?
    if Gem.loaded_specs[name] then
      # This gem is already loaded.  If the currently loaded gem is not in the
      # list of candidate gems, then we have a version conflict.
      existing_spec = Gem.loaded_specs[name]
      unless matches.any? { |spec| spec.version == existing_spec.version } then
        raise Gem::Exception,
              "can't activate #{@dep}, already activated #{existing_spec.full_name}"
      end
      # we're stuck with it, so change to match
      version_requirements = Gem::Requirement.create("=#{existing_spec.version}")
      existing_spec
    else
      # new load
      matches.last
    end
  end
end

#specification=(s) ⇒ Object



124
125
126
# File 'lib/rails/gem_dependency.rb', line 124

def specification=(s)
  @spec = s
end

#unpack(options = {}) ⇒ Object



250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/rails/gem_dependency.rb', line 250

def unpack(options={})
  unless frozen? || framework_gem?
    FileUtils.mkdir_p unpack_base
    Dir.chdir unpack_base do
      Gem::GemRunner.new.run(unpack_command)
    end
    # Gem.activate changes the spec - get the original
    real_spec = Gem::Specification.load(specification.loaded_from)
    write_specification(real_spec)
  end
  dependencies.each { |dep| dep.unpack(options) } if options[:recursive]
end

#vendor_gem?Boolean

Returns:

  • (Boolean)


187
188
189
# File 'lib/rails/gem_dependency.rb', line 187

def vendor_gem?
  specification && File.exists?(unpacked_gem_directory)
end

#vendor_rails?Boolean

Returns:

  • (Boolean)


183
184
185
# File 'lib/rails/gem_dependency.rb', line 183

def vendor_rails?
  Gem.loaded_specs.has_key?(name) && Gem.loaded_specs[name].loaded_from.empty?
end

#write_specification(spec) ⇒ Object



263
264
265
266
267
268
269
270
# File 'lib/rails/gem_dependency.rb', line 263

def write_specification(spec)
  # copy the gem's specification into GEMDIR/.specification so that
  # we can access information about the gem on deployment systems
  # without having the gem installed
  File.open(unpacked_specification_filename, 'w') do |file|
    file.puts spec.to_yaml
  end
end