1require 'tempfile' 2require 'rubygems' 3require 'rubygems/remote_fetcher' 4 5## 6# A fake Gem::RemoteFetcher for use in tests or to avoid real live HTTP 7# requests when testing code that uses RubyGems. 8# 9# Example: 10# 11# @fetcher = Gem::FakeFetcher.new 12# @fetcher.data['http://gems.example.com/yaml'] = source_index.to_yaml 13# Gem::RemoteFetcher.fetcher = @fetcher 14# 15# # invoke RubyGems code 16# 17# paths = @fetcher.paths 18# assert_equal 'http://gems.example.com/yaml', paths.shift 19# assert paths.empty?, paths.join(', ') 20# 21# See RubyGems' tests for more examples of FakeFetcher. 22 23class Gem::FakeFetcher 24 25 attr_reader :data 26 attr_reader :last_request 27 attr_reader :api_endpoints 28 attr_accessor :paths 29 30 def initialize 31 @data = {} 32 @paths = [] 33 @api_endpoints = {} 34 end 35 36 def api_endpoint(uri) 37 @api_endpoints[uri] || uri 38 end 39 40 def find_data(path) 41 if URI === path and "URI::#{path.scheme.upcase}" != path.class.name then 42 raise ArgumentError, 43 "mismatch for scheme #{path.scheme} and class #{path.class}" 44 end 45 46 path = path.to_s 47 @paths << path 48 raise ArgumentError, 'need full URI' unless path =~ %r'^https?://' 49 50 unless @data.key? path then 51 raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", path) 52 end 53 54 @data[path] 55 end 56 57 def fetch_path path, mtime = nil, head = false 58 data = find_data(path) 59 60 if data.respond_to?(:call) then 61 data.call 62 else 63 if path.to_s =~ /gz$/ and not data.nil? and not data.empty? then 64 data = Gem.gunzip data 65 end 66 67 data 68 end 69 end 70 71 def cache_update_path uri, path = nil, update = true 72 if data = fetch_path(uri) 73 open(path, 'wb') { |io| io.write data } if path and update 74 data 75 else 76 Gem.read_binary(path) if path 77 end 78 end 79 80 # Thanks, FakeWeb! 81 def open_uri_or_path(path) 82 data = find_data(path) 83 body, code, msg = data 84 85 response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, msg) 86 response.instance_variable_set(:@body, body) 87 response.instance_variable_set(:@read, true) 88 response 89 end 90 91 def request(uri, request_class, last_modified = nil) 92 data = find_data(uri) 93 body, code, msg = data 94 95 @last_request = request_class.new uri.request_uri 96 yield @last_request if block_given? 97 98 response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, msg) 99 response.instance_variable_set(:@body, body) 100 response.instance_variable_set(:@read, true) 101 response 102 end 103 104 def fetch_size(path) 105 path = path.to_s 106 @paths << path 107 108 raise ArgumentError, 'need full URI' unless path =~ %r'^http://' 109 110 unless @data.key? path then 111 raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", path) 112 end 113 114 data = @data[path] 115 116 data.respond_to?(:call) ? data.call : data.length 117 end 118 119 def download spec, source_uri, install_dir = Gem.dir 120 name = File.basename spec.cache_file 121 path = if Dir.pwd == install_dir then # see fetch_command 122 install_dir 123 else 124 File.join install_dir, "cache" 125 end 126 127 path = File.join path, name 128 129 if source_uri =~ /^http/ then 130 File.open(path, "wb") do |f| 131 f.write fetch_path(File.join(source_uri, "gems", name)) 132 end 133 else 134 FileUtils.cp source_uri, path 135 end 136 137 path 138 end 139 140 def download_to_cache dependency 141 found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dependency 142 143 return if found.empty? 144 145 spec, source = found.first 146 147 download spec, source.uri.to_s 148 end 149 150end 151 152# :stopdoc: 153class Gem::RemoteFetcher 154 155 def self.fetcher=(fetcher) 156 @fetcher = fetcher 157 end 158 159end 160# :startdoc: 161 162## 163# A StringIO duck-typed class that uses Tempfile instead of String as the 164# backing store. 165# 166# This is available when rubygems/test_utilities is required. 167#-- 168# This class was added to flush out problems in Rubinius' IO implementation. 169 170class TempIO < Tempfile 171 def initialize(string = '') 172 super "TempIO" 173 binmode 174 write string 175 rewind 176 end 177 178 def string 179 flush 180 Gem.read_binary path 181 end 182end 183 184