apple_epf 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.md +90 -0
- data/Rakefile +35 -0
- data/lib/apple_epf.rb +43 -0
- data/lib/apple_epf/downloader.rb +164 -0
- data/lib/apple_epf/errors.rb +8 -0
- data/lib/apple_epf/extractor.rb +43 -0
- data/lib/apple_epf/logging.rb +32 -0
- data/lib/apple_epf/main.rb +113 -0
- data/lib/apple_epf/parser.rb +95 -0
- data/lib/apple_epf/version.rb +3 -0
- data/lib/core_ext/array.rb +30 -0
- data/lib/core_ext/module.rb +63 -0
- data/lib/tasks/apple_epf_tasks.rake +4 -0
- data/spec/lib/apple_epf/downloader_spec.rb +220 -0
- data/spec/lib/apple_epf/exctractor_spec.rb +72 -0
- data/spec/lib/apple_epf/main_spec.rb +185 -0
- data/spec/lib/apple_epf/parser_spec.rb +66 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/support/fixture_helper.rb +13 -0
- data/spec/support/fixtures/itunes/epf/current_full_list.html +20 -0
- data/spec/support/fixtures/itunes/epf/current_inc_list.html +19 -0
- data/spec/support/fixtures/itunes/epf/incremental/itunes20130111.tbz +0 -0
- data/spec/support/fixtures/itunes/epf/incremental/itunes20130111/application +21 -0
- data/spec/support/fixtures/itunes/epf/incremental/itunes20130111/application_with_nil +7 -0
- data/spec/support/fixtures/itunes/epf/incremental/itunes20130111/test_file.txt +0 -0
- data/spec/support/fixtures/itunes/epf/incremental/popularity20130111.tbz +0 -0
- data/spec/support/fixtures/itunes/epf/incremental/popularity20130111/popularity1 +0 -0
- data/spec/support/fixtures/itunes/epf/incremental/popularity20130111/popularity2 +0 -0
- metadata +255 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
module AppleEpf
|
2
|
+
class Parser
|
3
|
+
FIELD_SEPARATOR = 1.chr
|
4
|
+
RECORD_SEPARATOR = 2.chr + "\n"
|
5
|
+
COMMENT_CHAR = '#'
|
6
|
+
|
7
|
+
attr_accessor :filename, :header_info, :footer_info
|
8
|
+
|
9
|
+
def initialize(filename)
|
10
|
+
@filename = filename
|
11
|
+
@header_info = {}
|
12
|
+
@footer_info = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_metadata
|
16
|
+
begin
|
17
|
+
parse_file
|
18
|
+
load_header_info
|
19
|
+
load_footer_info
|
20
|
+
@header_info.merge(@footer_info)
|
21
|
+
ensure
|
22
|
+
close_file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def process_rows(&block)
|
27
|
+
File.foreach( @filename, RECORD_SEPARATOR ) do |line|
|
28
|
+
unless line[0].chr == COMMENT_CHAR
|
29
|
+
line = line.chomp( RECORD_SEPARATOR )
|
30
|
+
block.call( line.split( FIELD_SEPARATOR, -1) ) if block_given?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def parse_file
|
38
|
+
@file = File.new( @filename, 'r', encoding: 'UTF-8' )
|
39
|
+
end
|
40
|
+
|
41
|
+
def close_file
|
42
|
+
@file.close if @file
|
43
|
+
end
|
44
|
+
|
45
|
+
def read_line(accept_comment = false)
|
46
|
+
valid_line = false
|
47
|
+
until valid_line
|
48
|
+
begin
|
49
|
+
line = @file.readline( RECORD_SEPARATOR )
|
50
|
+
rescue EOFError => e
|
51
|
+
return nil
|
52
|
+
end
|
53
|
+
valid_line = accept_comment ? true : !line.start_with?( COMMENT_CHAR )
|
54
|
+
end
|
55
|
+
line.sub!( COMMENT_CHAR, '' ) if accept_comment
|
56
|
+
line.chomp!( RECORD_SEPARATOR )
|
57
|
+
end
|
58
|
+
|
59
|
+
def load_header_info
|
60
|
+
# File
|
61
|
+
file_hash = { :file => File.basename( @filename ) }
|
62
|
+
@header_info.merge! ( file_hash )
|
63
|
+
|
64
|
+
# Columns
|
65
|
+
line = read_line(true)
|
66
|
+
column_hash = { :columns => line.split( FIELD_SEPARATOR ) }
|
67
|
+
@header_info.merge! ( column_hash )
|
68
|
+
|
69
|
+
# Primary keys
|
70
|
+
line = read_line(true).sub!( 'primaryKey:', '' )
|
71
|
+
primary_hash = { :primary_keys => line.split( FIELD_SEPARATOR ) }
|
72
|
+
@header_info.merge! ( primary_hash )
|
73
|
+
|
74
|
+
# DB types
|
75
|
+
line = read_line(true).sub!( 'dbTypes:', '' )
|
76
|
+
primary_hash = { :db_types => line.split( FIELD_SEPARATOR ) }
|
77
|
+
@header_info.merge! ( primary_hash )
|
78
|
+
|
79
|
+
# Export type
|
80
|
+
line = read_line(true).sub!( 'exportMode:', '' )
|
81
|
+
primary_hash = { :export_type => line.split( FIELD_SEPARATOR ) }
|
82
|
+
@header_info.merge! ( primary_hash )
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def load_footer_info
|
87
|
+
@file.seek(-40, IO::SEEK_END)
|
88
|
+
records = @file.read.split( COMMENT_CHAR ).last.chomp!( RECORD_SEPARATOR ).sub( 'recordsWritten:', '' )
|
89
|
+
records_hash = { :records => records }
|
90
|
+
@footer_info.merge! ( records_hash )
|
91
|
+
@file.rewind
|
92
|
+
@footer_info
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# activesupport/lib/active_support/core_ext/array/extract_options.rb
|
2
|
+
class Hash
|
3
|
+
# By default, only instances of Hash itself are extractable.
|
4
|
+
# Subclasses of Hash may implement this method and return
|
5
|
+
# true to declare themselves as extractable. If a Hash
|
6
|
+
# is extractable, Array#extract_options! pops it from
|
7
|
+
# the Array when it is the last element of the Array.
|
8
|
+
def extractable_options?
|
9
|
+
instance_of?(Hash)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Array
|
14
|
+
# Extracts options from a set of arguments. Removes and returns the last
|
15
|
+
# element in the array if it's a hash, otherwise returns a blank hash.
|
16
|
+
#
|
17
|
+
# def options(*args)
|
18
|
+
# args.extract_options!
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# options(1, 2) # => {}
|
22
|
+
# options(1, 2, :a => :b) # => {:a=>:b}
|
23
|
+
def extract_options!
|
24
|
+
if last.is_a?(Hash) && last.extractable_options?
|
25
|
+
pop
|
26
|
+
else
|
27
|
+
{}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
|
2
|
+
class Module
|
3
|
+
def mattr_reader(*syms)
|
4
|
+
options = syms.extract_options!
|
5
|
+
syms.each do |sym|
|
6
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
7
|
+
@@#{sym} = nil unless defined? @@#{sym}
|
8
|
+
|
9
|
+
def self.#{sym}
|
10
|
+
@@#{sym}
|
11
|
+
end
|
12
|
+
EOS
|
13
|
+
|
14
|
+
unless options[:instance_reader] == false || options[:instance_accessor] == false
|
15
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
16
|
+
def #{sym}
|
17
|
+
@@#{sym}
|
18
|
+
end
|
19
|
+
EOS
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def mattr_writer(*syms)
|
25
|
+
options = syms.extract_options!
|
26
|
+
syms.each do |sym|
|
27
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
28
|
+
def self.#{sym}=(obj)
|
29
|
+
@@#{sym} = obj
|
30
|
+
end
|
31
|
+
EOS
|
32
|
+
|
33
|
+
unless options[:instance_writer] == false || options[:instance_accessor] == false
|
34
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
35
|
+
def #{sym}=(obj)
|
36
|
+
@@#{sym} = obj
|
37
|
+
end
|
38
|
+
EOS
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Extends the module object with module and instance accessors for class attributes,
|
44
|
+
# just like the native attr* accessors for instance attributes.
|
45
|
+
#
|
46
|
+
# module AppConfiguration
|
47
|
+
# mattr_accessor :google_api_key
|
48
|
+
# self.google_api_key = "123456789"
|
49
|
+
#
|
50
|
+
# mattr_accessor :paypal_url
|
51
|
+
# self.paypal_url = "www.sandbox.paypal.com"
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# AppConfiguration.google_api_key = "overriding the api key!"
|
55
|
+
#
|
56
|
+
# To opt out of the instance writer method, pass :instance_writer => false.
|
57
|
+
# To opt out of the instance reader method, pass :instance_reader => false.
|
58
|
+
# To opt out of both instance methods, pass :instance_accessor => false.
|
59
|
+
def mattr_accessor(*syms)
|
60
|
+
mattr_reader(*syms)
|
61
|
+
mattr_writer(*syms)
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
3
|
+
|
4
|
+
describe AppleEpf::Downloader do
|
5
|
+
|
6
|
+
let(:type) { 'incremental' }
|
7
|
+
let(:filedate) { Date.parse('17-01-2013') }
|
8
|
+
let(:file) { 'popularity' }
|
9
|
+
let(:downloader) {AppleEpf::Downloader.new(type, file, filedate)}
|
10
|
+
let(:file_exists) { true }
|
11
|
+
|
12
|
+
describe "#get_filename_by_date_and_type" do
|
13
|
+
before do
|
14
|
+
downloader.stub(:file_exists?){ file_exists }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should raise exception if path can not be determined" do
|
18
|
+
downloader.type = 'crazytype'
|
19
|
+
expect {
|
20
|
+
downloader.get_filename_by_date_and_type
|
21
|
+
}.to raise_exception
|
22
|
+
end
|
23
|
+
|
24
|
+
context "type is full" do
|
25
|
+
let(:type) { 'full' }
|
26
|
+
|
27
|
+
context "and file exists" do
|
28
|
+
let(:file_exists) { true }
|
29
|
+
|
30
|
+
it "should return valid url if file exists" do
|
31
|
+
downloader.filedate = Date.parse('17-01-2013')
|
32
|
+
downloader.get_filename_by_date_and_type.should == "20130116/popularity20130116.tbz"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "and file does not exists" do
|
37
|
+
let(:file_exists) { false }
|
38
|
+
|
39
|
+
it "should raise exception" do
|
40
|
+
downloader.filedate = Date.parse('17-01-2013')
|
41
|
+
expect {
|
42
|
+
downloader.get_filename_by_date_and_type
|
43
|
+
}.to raise_exception(AppleEpf::FileNotExist)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
context "type is incremental" do
|
50
|
+
let(:type) { 'incremental' }
|
51
|
+
|
52
|
+
context "and file exists" do
|
53
|
+
let(:file_exists) { true }
|
54
|
+
|
55
|
+
it "should return valid url if file exists" do
|
56
|
+
downloader.filedate = Date.parse('17-01-2013')
|
57
|
+
downloader.get_filename_by_date_and_type.should == "20130109/incremental/20130117/popularity20130117.tbz"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "and file does not exists" do
|
62
|
+
let(:file_exists) { false }
|
63
|
+
|
64
|
+
it "should raise exception" do
|
65
|
+
downloader.filedate = Date.parse('17-01-2013')
|
66
|
+
expect {
|
67
|
+
downloader.get_filename_by_date_and_type
|
68
|
+
}.to raise_exception(AppleEpf::FileNotExist)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
context "type is file" do
|
75
|
+
pending
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#main_dir_date" do
|
81
|
+
|
82
|
+
context "full" do
|
83
|
+
let(:type) { 'full' }
|
84
|
+
it "should return the same week wednesday" do
|
85
|
+
downloader.filedate = Date.parse('17-01-2013') #thursday
|
86
|
+
downloader.send(:main_dir_date).should == "20130116"
|
87
|
+
end
|
88
|
+
# it "should return wednesday of this week if filedate is thur-sun" do
|
89
|
+
# downloader.filedate = Date.parse('17-01-2013') #thursday
|
90
|
+
# downloader.send(:main_dir_date).should == "20130116"
|
91
|
+
|
92
|
+
# downloader.filedate = Date.parse('19-01-2013') #sut
|
93
|
+
# downloader.send(:main_dir_date).should == "20130116"
|
94
|
+
# end
|
95
|
+
|
96
|
+
# it "should return wednesday of prev week if filedate is mon-wed" do
|
97
|
+
# downloader.filedate = Date.parse('21-01-2013') #monday
|
98
|
+
# downloader.send(:main_dir_date).should == "20130123"
|
99
|
+
|
100
|
+
# downloader.filedate = Date.parse('23-01-2013') #wednesday
|
101
|
+
# downloader.send(:main_dir_date).should == "20130123"
|
102
|
+
# end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "incremental" do
|
106
|
+
let(:type) { 'incremental' }
|
107
|
+
it "should return wednesday of this week if filedate is friday-sunday" do
|
108
|
+
downloader.filedate = Date.parse('18-01-2013') #friday
|
109
|
+
downloader.send(:main_dir_date).should == "20130116"
|
110
|
+
|
111
|
+
downloader.filedate = Date.parse('19-01-2013') #sut
|
112
|
+
downloader.send(:main_dir_date).should == "20130116"
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should return wednesday of prev week if filedate is monday-thursday" do
|
116
|
+
downloader.filedate = Date.parse('21-01-2013') #monday
|
117
|
+
downloader.send(:main_dir_date).should == "20130116"
|
118
|
+
|
119
|
+
downloader.filedate = Date.parse('24-01-2013') #thursday
|
120
|
+
downloader.send(:main_dir_date).should == "20130116"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "download" do
|
126
|
+
let(:filedate) { Date.parse('21-01-2013') }
|
127
|
+
|
128
|
+
before do
|
129
|
+
@tmp_dir = [Dir.tmpdir, 'epm_files'].join('/')
|
130
|
+
FileUtils.mkpath @tmp_dir
|
131
|
+
|
132
|
+
AppleEpf.configure do |config|
|
133
|
+
config.apple_id = 'test'
|
134
|
+
config.apple_password = 'test'
|
135
|
+
config.extract_dir = @tmp_dir
|
136
|
+
end
|
137
|
+
|
138
|
+
downloader.stub(:download_and_compare_md5_checksum)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should properly set url for download" do
|
142
|
+
downloader.stub(:file_exists?){ file_exists }
|
143
|
+
downloader.stub(:start_download)
|
144
|
+
downloader.download
|
145
|
+
downloader.apple_filename_full.should eq("http://feeds.itunes.apple.com/feeds/epf/v3/full/20130116/incremental/20130121/popularity20130121.tbz")
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should properly set local file to store file in" do
|
149
|
+
downloader.stub(:file_exists?){ file_exists }
|
150
|
+
downloader.stub(:start_download)
|
151
|
+
downloader.download
|
152
|
+
downloader.download_to.should eq("#{@tmp_dir}/incremental/popularity20130121.tbz")
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should download and save file" do
|
156
|
+
stub_request(:get, "http://test:test@feeds.itunes.apple.com/feeds/epf/v3/full/20130123/popularity20130123.tbz").
|
157
|
+
to_return(:status => 200, :body => "Test\nWow", :headers => {})
|
158
|
+
|
159
|
+
downloader = AppleEpf::Downloader.new('full', file, filedate)
|
160
|
+
downloader.stub(:download_and_compare_md5_checksum)
|
161
|
+
downloader.stub(:file_exists?){ file_exists }
|
162
|
+
downloader.download
|
163
|
+
IO.read(downloader.download_to).should eq("Test\nWow")
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should retry 3 times to download" do
|
167
|
+
pending
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "dirpath" do
|
171
|
+
before do
|
172
|
+
downloader.stub(:file_exists?){ file_exists }
|
173
|
+
downloader.stub(:start_download)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should be able to change dir where to save files" do
|
177
|
+
tmp_dir = Dir.tmpdir
|
178
|
+
downloader.dirpath = [tmp_dir, 'whatever_path'].join('/')
|
179
|
+
downloader.download.should == "#{tmp_dir}/whatever_path/incremental/popularity20130121.tbz"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "#download_and_compare_md5_checksum" do
|
184
|
+
before do
|
185
|
+
downloader.unstub(:download_and_compare_md5_checksum)
|
186
|
+
end
|
187
|
+
it "should raise exception if md5 file does not match real md5 checksum of file" do
|
188
|
+
stub_request(:get, "http://test:test@feeds.itunes.apple.com/feeds/epf/v3/full/20130116/incremental/20130121/popularity20130121.tbz").
|
189
|
+
to_return(:status => 200, :body => "Test\nWow", :headers => {})
|
190
|
+
|
191
|
+
stub_request(:get, "http://test:test@feeds.itunes.apple.com/feeds/epf/v3/full/20130116/incremental/20130121/popularity20130121.tbz.md5").
|
192
|
+
to_return(:status => 200, :body => "tupo", :headers => {})
|
193
|
+
|
194
|
+
downloader.stub(:file_exists?){ file_exists }
|
195
|
+
|
196
|
+
expect {
|
197
|
+
downloader.download
|
198
|
+
}.to raise_exception(AppleEpf::Md5CompareError)
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should not raise exception if md5 is ok" do
|
203
|
+
stub_request(:get, "http://test:test@feeds.itunes.apple.com/feeds/epf/v3/full/20130116/incremental/20130121/popularity20130121.tbz").
|
204
|
+
to_return(:status => 200, :body => "Test\nWow", :headers => {})
|
205
|
+
|
206
|
+
stub_request(:get, "http://test:test@feeds.itunes.apple.com/feeds/epf/v3/full/20130116/incremental/20130121/popularity20130121.tbz.md5").
|
207
|
+
to_return(:status => 200, :body => "MD5 (popularity20130116.tbz) = 0371a79664856494e840af9e1e6c0152\n", :headers => {})
|
208
|
+
|
209
|
+
|
210
|
+
downloader.stub(:file_exists?){ file_exists }
|
211
|
+
|
212
|
+
expect {
|
213
|
+
downloader.download
|
214
|
+
}.not_to raise_exception(AppleEpf::Md5CompareError)
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
3
|
+
|
4
|
+
describe AppleEpf::Extractor do
|
5
|
+
let(:file_basename) { 'itunes20130111.tbz' }
|
6
|
+
let(:files_to_extract) { ['application', 'test_file.txt'] }
|
7
|
+
|
8
|
+
before do
|
9
|
+
@tmp_dir = [Dir.tmpdir, 'test_epm_files'].join('/')
|
10
|
+
FileUtils.mkpath @tmp_dir
|
11
|
+
|
12
|
+
AppleEpf.configure do |config|
|
13
|
+
config.apple_id = 'test'
|
14
|
+
config.apple_password = 'test'
|
15
|
+
config.extract_dir = @tmp_dir
|
16
|
+
end
|
17
|
+
|
18
|
+
@copy_to = "#{@tmp_dir}/#{file_basename}"
|
19
|
+
FileUtils.copy_file(apple_epf_inc_filename(file_basename), @copy_to)
|
20
|
+
end
|
21
|
+
|
22
|
+
after do
|
23
|
+
FileUtils.remove_dir(@tmp_dir)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "initialize" do
|
27
|
+
it "should set instance variables" do
|
28
|
+
extractor = AppleEpf::Extractor.new(@copy_to, files_to_extract)
|
29
|
+
|
30
|
+
extractor.filename.should == @copy_to
|
31
|
+
extractor.dirname.should == @tmp_dir
|
32
|
+
extractor.basename.should == file_basename
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "perform" do
|
37
|
+
it "should raise error if extracting was not successful" do
|
38
|
+
files_to_extract = ['application', 'wrong_file.txt']
|
39
|
+
extractor = AppleEpf::Extractor.new(@copy_to, files_to_extract)
|
40
|
+
|
41
|
+
expect {
|
42
|
+
extractor.perform
|
43
|
+
}.to raise_exception ("Unable to extract files '#{files_to_extract.join(' ')}' from #{@copy_to}")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return list if extracted files" do
|
47
|
+
extractor = AppleEpf::Extractor.new(@copy_to, files_to_extract)
|
48
|
+
extractor.perform
|
49
|
+
extractor.file_entry.tbz_file.should == @copy_to
|
50
|
+
|
51
|
+
expected_extracted = files_to_extract.map do |f|
|
52
|
+
File.join(@tmp_dir, 'itunes20130111', f)
|
53
|
+
end
|
54
|
+
|
55
|
+
extractor.file_entry.extracted_files.should == Hash[files_to_extract.zip(expected_extracted)]
|
56
|
+
extractor.file_entry.tbz_file.should == @copy_to
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should remove file if successfully untarred" do
|
60
|
+
extractor = AppleEpf::Extractor.new(@copy_to, files_to_extract)
|
61
|
+
extractor.perform
|
62
|
+
File.exists?(extractor.filename).should be_false
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should not remove file if successfully untarred and it was asked to leave file" do
|
66
|
+
extractor = AppleEpf::Extractor.new(@copy_to, files_to_extract)
|
67
|
+
extractor.keep_tbz_after_extract = true
|
68
|
+
extractor.perform
|
69
|
+
File.exists?(extractor.filename).should be_true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|