Class: RuGUI::GemDependency

Inherits:
Gem::Dependency
  • Object
show all
Defined in:
lib/rugui/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.



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

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/rugui/gem_dependency.rb', line 11

def dep
  @dep
end

#libObject

Returns the value of attribute lib.



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

def lib
  @lib
end

#sourceObject

Returns the value of attribute source.



11
12
13
# File 'lib/rugui/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/rugui/gem_dependency.rb', line 19

def self.add_frozen_gem_path
  @@paths_loaded ||= begin
    source_index = RuGUI::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

.unpacked_pathObject



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

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

Instance Method Details

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



238
239
240
# File 'lib/rugui/gem_dependency.rb', line 238

def ==(other)
  self.name == other.name && self.requirement == other.requirement
end

#add_load_pathsObject



50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rugui/gem_dependency.rb', line 50

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
  gem self
  @spec = Gem.loaded_specs[name]
  @frozen = @spec.loaded_from.include?(self.class.unpacked_path) if @spec
  @load_paths_added = true
rescue Gem::LoadError
end

#buildObject



158
159
160
161
162
163
164
165
166
167
# File 'lib/rugui/gem_dependency.rb', line 158

def build
  require 'rugui/gem_builder'
  unless built?
    return unless File.exists?(unpacked_specification_filename)
    spec = YAML::load_file(unpacked_specification_filename)
    RuGUI::GemBuilder.new(spec, unpacked_gem_directory).build_extensions
    puts "Built gem: '#{unpacked_gem_directory}'"
  end
  dependencies.each { |dep| dep.build }
end

#built?Boolean

Returns:

  • (Boolean)


103
104
105
106
# File 'lib/rugui/gem_dependency.rb', line 103

def built?
  # TODO: If Rubygems ever gives us a way to detect this, we should use it
  false
end

#dependenciesObject



64
65
66
67
68
69
70
71
72
# File 'lib/rugui/gem_dependency.rb', line 64

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.version_requirements)
  end
end

#framework_gem?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/rugui/gem_dependency.rb', line 108

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

#frozen?Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/rugui/gem_dependency.rb', line 112

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

#installObject



169
170
171
172
173
174
175
# File 'lib/rugui/gem_dependency.rb', line 169

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

#installed?Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/rugui/gem_dependency.rb', line 116

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

#loadObject



177
178
179
180
181
182
183
184
# File 'lib/rugui/gem_dependency.rb', line 177

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)


120
121
122
123
124
125
# File 'lib/rugui/gem_dependency.rb', line 120

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)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/rugui/gem_dependency.rb', line 127

def loaded?
  @loaded ||= begin
    if vendor_rugui?
      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



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/rugui/gem_dependency.rb', line 186

def refresh
  RuGUI::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 rugui."
    else
      puts "Something bad is going on - gem directory not found for #{name}."
    end
  end
end

#requirementObject



98
99
100
101
# File 'lib/rugui/gem_dependency.rb', line 98

def requirement
  r = version_requirements
  (r == Gem::Requirement.default) ? nil : r
end

#specificationObject



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/rugui/gem_dependency.rb', line 74

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

#unpack(options = {}) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/rugui/gem_dependency.rb', line 216

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 } if options[:recursive]
end

#vendor_gem?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/rugui/gem_dependency.rb', line 154

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

#vendor_rugui?Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/rugui/gem_dependency.rb', line 150

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

#write_specification(spec) ⇒ Object



229
230
231
232
233
234
235
236
# File 'lib/rugui/gem_dependency.rb', line 229

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