unpacker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.bnsignore ADDED
@@ -0,0 +1,16 @@
1
+ # The list of files that should be ignored by Mr Bones.
2
+ # Lines that start with '#' are comments.
3
+ #
4
+ # A .gitignore file can be used instead by setting it as the ignore
5
+ # file in your Rakefile:
6
+ #
7
+ # PROJ.ignore_file = '.gitignore'
8
+ #
9
+ # For a project with a C extension, the following would be a good set of
10
+ # exclude patterns (uncomment them if you want to use them):
11
+ # *.[oa]
12
+ # *~
13
+ announcement.txt
14
+ coverage
15
+ doc
16
+ pkg
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ .rake_tasks
data/History.txt ADDED
@@ -0,0 +1,8 @@
1
+ == 1.0.1 / 2009-06-10
2
+
3
+ * Moved to RSpec, ported some fixes and enhancements from unpacked instance.
4
+ * Removed rar call in favor of unrar.
5
+
6
+ == 1.0.0 / 2009-04-20
7
+
8
+ * Birthday!
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Petyo Ivanov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,62 @@
1
+ = unpacker
2
+
3
+ == DESCRIPTION
4
+
5
+ Small library for unpacking various archives, extracted from Beanstalk (http://beanstalkapp.com) (and rewritten, in fact).
6
+
7
+ == FEATURES/PROBLEMS
8
+
9
+ None so far. Won't run on Windows, haven't tested.
10
+
11
+ == SAMPLE USAGE
12
+
13
+ To test archives do:
14
+
15
+ Unpacker.valid? 'path/to/file.zip'
16
+
17
+ The method optionally accepts second argument, file name (if it is different than the file path). Handy if you test temp uploaded files.
18
+
19
+ To extract files do:
20
+
21
+ Unpacker.unpack('path/to/myfile.zip') do |directory_that_contains_extracted_files|
22
+
23
+ end
24
+
25
+ To recognize archives do:
26
+
27
+ Unpacker.archive? 'path/to/archive.txt'
28
+
29
+ In case the archive is not supported (currently working with zip, bzip, gzip, tar and rar) you may get UnrecognizedArchiveError in both methods.
30
+
31
+ The gem takes care to remove any temporary extractings after the block is executed; (uses /tmp/ directory).
32
+
33
+ When working with .gz files (single archive), the extracted file is always called **gz-contents**.
34
+
35
+ == REQUIREMENTS
36
+
37
+ Relies on system calls, so you should have
38
+ - unzip
39
+ - unrar
40
+ - tar
41
+ - gunzip
42
+ - bunzip
43
+
44
+ In path.
45
+
46
+ == INSTALL
47
+
48
+ sudo gem install unpacker
49
+
50
+ == Note on Patches/Pull Requests
51
+
52
+ * Fork the project.
53
+ * Make your feature addition or bug fix.
54
+ * Add tests for it. This is important so I don't break it in a
55
+ future version unintentionally.
56
+ * Commit, do not mess with rakefile, version, or history.
57
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
58
+ * Send me a pull request. Bonus points for topic branches.
59
+
60
+ == Copyright
61
+
62
+ Copyright (c) 2010 Petyo Ivanov. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "unpacker"
8
+ gem.summary = %Q{Abstraction for extracting various archives }
9
+ gem.description = %Q{The tool relies on the presence of the command-line tools.}
10
+ gem.email = "underlog@gmail.com"
11
+ gem.homepage = "http://github.com/underlog/unpacker"
12
+ gem.authors = ["Petyo Ivanov"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "unpacker #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/unpacker ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib unpacker]))
5
+
6
+ # Put your code here
7
+
8
+ # EOF
data/lib/unpacker.rb ADDED
@@ -0,0 +1,105 @@
1
+ require 'fileutils'
2
+ require 'tmpdir'
3
+
4
+ module Unpacker
5
+
6
+ class UnrecognizedArchiveError < StandardError; end
7
+ class UnpackedFailedError < StandardError; end
8
+
9
+ SUPPORTED_FILEEXTS = %w[tar rar zip gz bz tgz bgz tar]
10
+
11
+ def self.unpack(file, tmpdir = "/tmp", &block)
12
+ Dir.mktmpdir 'unpacker' do |dir|
13
+ cmd = command_by_file_ext(file)% [file, dir]
14
+ system("#{cmd} 1>/dev/null") or raise UnrecognizedArchiveError($?)
15
+ block.call(Dir.new(dir))
16
+ end
17
+ end
18
+
19
+ def self.archive?(file_name)
20
+ SUPPORTED_FILEEXTS.include? File.extname(file_name).sub('.', '')
21
+ end
22
+
23
+ def self.valid?(file_path, file_name = file_path)
24
+ cmd = test_cmd_by_file_ext(file_name)% file_path
25
+ system("#{cmd} 1>/dev/null 2>/dev/null")
26
+ end
27
+
28
+ # :stopdoc:
29
+ VERSION = '1.0.1'
30
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
31
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
32
+ # :startdoc:
33
+
34
+ # Returns the version string for the library.
35
+ #
36
+ def self.version
37
+ VERSION
38
+ end
39
+
40
+ # Returns the library path for the module. If any arguments are given,
41
+ # they will be joined to the end of the libray path using
42
+ # <tt>File.join</tt>.
43
+ #
44
+ def self.libpath( *args )
45
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
46
+ end
47
+
48
+ # Returns the lpath for the module. If any arguments are given,
49
+ # they will be joined to the end of the path using
50
+ # <tt>File.join</tt>.
51
+ #
52
+ def self.path( *args )
53
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
54
+ end
55
+
56
+ # Utility method used to require all files ending in .rb that lie in the
57
+ # directory below this file that has the same name as the filename passed
58
+ # in. Optionally, a specific _directory_ name can be passed in such that
59
+ # the _filename_ does not have to be equivalent to the directory.
60
+ #
61
+ def self.require_all_libs_relative_to( fname, dir = nil )
62
+ dir ||= ::File.basename(fname, '.*')
63
+ search_me = ::File.expand_path(
64
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
65
+
66
+ Dir.glob(search_me).sort.each {|rb| require rb}
67
+ end
68
+
69
+ private
70
+
71
+ def self.test_cmd_by_file_ext(file_name)
72
+ case file_name
73
+ when /rar$/
74
+ 'unrar t "%s"'
75
+ when /(tar|tar\.bz|tbz)$/
76
+ 'tar tf "%s"'
77
+ when /zip$/
78
+ 'zip -T "%s"'
79
+ when /gz|tgz$/
80
+ 'gunzip -t "%s"'
81
+ else
82
+ raise UnrecognizedArchiveError
83
+ end
84
+ end
85
+
86
+ def self.command_by_file_ext(file_name)
87
+ case file_name
88
+ when /rar$/
89
+ 'unrar x -y "%s" "%s"'
90
+ when /(tar|tgz|tar\.gz|tar\.bz|tbz)$/
91
+ 'tar xf "%s" --directory "%s"'
92
+ when /zip$/
93
+ 'unzip "%s" -d "%s"'
94
+ when /gz$/
95
+ '(gunzip -c "%s" > "%s/gz-contents")'
96
+ else
97
+ raise UnrecognizedArchiveError
98
+ end
99
+ end
100
+
101
+ end # module Unpacker
102
+
103
+ Unpacker.require_all_libs_relative_to(__FILE__)
104
+
105
+ # EOF
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,116 @@
1
+ Cras eget augue.
2
+
3
+
4
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
5
+ Duis congue urna ac lectus.
6
+ Fusce arcu est, sodales nec, convallis sit amet, ultricies sed, ante.
7
+ In cursus odio.
8
+ Duis congue urna ac lectus.
9
+ Donec condimentum velit eget sapien.
10
+ Vestibulum porttitor, enim nec commodo lacinia, nibh orci pulvinar lorem, sit amet rutrum massa ante laoreet mi.
11
+ In cursus odio.
12
+ Praesent in tortor sed purus ornare pellentesque.
13
+ Vivamus mattis nisi sed ipsum.
14
+ Curabitur bibendum tincidunt lorem.
15
+ In risus nisl, vulputate eget, tristique vitae, aliquet eu, ipsum.
16
+ Curabitur bibendum tincidunt lorem.
17
+ Curabitur tortor.
18
+ Donec condimentum velit eget sapien.
19
+ Curabitur tortor.
20
+ In id mi.
21
+ Curabitur tortor.
22
+ Donec condimentum velit eget sapien.
23
+ Duis a turpis.
24
+ Curabitur tortor.
25
+
26
+
27
+ Mauris tempus velit ut metus.
28
+ Fusce libero magna, mattis vel, porttitor vitae, ornare et, metus.
29
+ Pellentesque orci.
30
+ Maecenas blandit neque.
31
+ In cursus odio.
32
+ Duis laoreet egestas nibh.
33
+ Nulla adipiscing, libero quis faucibus interdum, lacus enim viverra purus, quis feugiat magna justo sed lorem.
34
+ Fusce libero magna, mattis vel, porttitor vitae, ornare et, metus.
35
+ Phasellus purus dolor, tempor non, tristique sit amet, porttitor porta, velit.
36
+ Sed faucibus tempus eros.
37
+
38
+
39
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
40
+ Duis laoreet egestas nibh.
41
+ Maecenas quis nulla eget nunc volutpat hendrerit.
42
+ Etiam velit.
43
+ Integer dignissim augue at velit.
44
+ In id mi.
45
+ Donec velit diam, laoreet gravida, pretium ac, tristique quis, lacus.
46
+ Suspendisse eleifend pretium massa.
47
+ Maecenas quis nulla eget nunc volutpat hendrerit.
48
+ In id mi.
49
+ Cras pulvinar.
50
+ Vestibulum at tellus sed augue rutrum dictum.
51
+ Cras eget augue.
52
+ Donec rhoncus.
53
+ Fusce libero magna, mattis vel, porttitor vitae, ornare et, metus.
54
+ Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
55
+ Duis congue urna ac lectus.
56
+ Nunc ut purus.
57
+ Nunc ut purus.
58
+ Proin sit amet augue ut arcu accumsan mollis.
59
+ Quisque eros felis, lacinia non, tempus et, vehicula eu, sem.
60
+ Donec condimentum velit eget sapien.
61
+ Fusce libero magna, mattis vel, porttitor vitae, ornare et, metus.
62
+ Fusce gravida.
63
+
64
+
65
+ Mauris tempus velit ut metus.
66
+ Donec condimentum velit eget sapien.
67
+ In risus nisl, vulputate eget, tristique vitae, aliquet eu, ipsum.
68
+ Vestibulum porttitor, enim nec commodo lacinia, nibh orci pulvinar lorem, sit amet rutrum massa ante laoreet mi.
69
+ Praesent in tortor sed purus ornare pellentesque.
70
+
71
+
72
+ Mauris tempus velit ut metus.
73
+ Praesent vestibulum, arcu et semper fringilla, magna urna sodales lacus, vel aliquet turpis tortor ac libero.
74
+ Ut commodo, nisl a lobortis dictum, quam nisi pharetra dolor, quis ullamcorper orci tortor posuere felis.
75
+ Maecenas et lorem.
76
+ Cras felis eros, placerat eget, adipiscing vitae, sodales quis, dolor.
77
+ Cras eget augue.
78
+ Etiam et neque.
79
+
80
+
81
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
82
+ Praesent vel erat at mi vehicula elementum.
83
+ Vivamus tincidunt felis ut libero.
84
+ In vestibulum mauris eu sapien.
85
+ Vivamus tincidunt felis ut libero.
86
+ Maecenas blandit neque.
87
+ Duis a turpis.
88
+ Phasellus est quam, faucibus vitae, euismod feugiat, ultrices et, quam.
89
+ Donec consectetur, ante in volutpat tristique, nulla metus ornare urna, vestibulum ullamcorper dui nulla fringilla eros.
90
+ Cras a ligula at diam malesuada tincidunt.
91
+ Vestibulum porttitor, enim nec commodo lacinia, nibh orci pulvinar lorem, sit amet rutrum massa ante laoreet mi.
92
+ Vivamus varius dui ac leo.
93
+ Etiam et neque.
94
+ Duis a turpis.
95
+ Pellentesque orci.
96
+ Donec condimentum velit eget sapien.
97
+ Vivamus dui orci, volutpat ac, blandit id, commodo quis, massa.
98
+ Suspendisse in sem at enim laoreet placerat.
99
+ Mauris dapibus nulla vitae tellus.
100
+ Nunc ut purus.
101
+
102
+
103
+ Etiam elementum.
104
+ Suspendisse eleifend pretium massa.
105
+ Nullam quis nulla.
106
+ Etiam velit.
107
+ Praesent vel erat at mi vehicula elementum.
108
+ In dapibus augue quis leo.
109
+ Nulla adipiscing, libero quis faucibus interdum, lacus enim viverra purus, quis feugiat magna justo sed lorem.
110
+ Curabitur bibendum tincidunt lorem.
111
+
112
+
113
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
114
+ Donec cursus, velit vel mollis ultrices, augue dui ornare ipsum, at ultricies mi leo in tellus.
115
+ Duis placerat purus sed dui.
116
+ Curabitur tortor.
Binary file
Binary file
Binary file
@@ -0,0 +1,15 @@
1
+ Spec::Matchers.define :be_unpacked_correctly_to do |contents|
2
+ match do |file, matcher|
3
+ Unpacker.unpack(file) do |result|
4
+ result.entries.include?(contents)
5
+ end
6
+ end
7
+
8
+ failure_message_for_should do |file|
9
+ "#{file} was not unpacked"
10
+ end
11
+
12
+ description do
13
+ "expects to unpack a file"
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ Spec::Matchers.define :be_valid_archive do
2
+ match do |file|
3
+ Unpacker.valid?(file)
4
+ end
5
+
6
+ failure_message_for_should do |file|
7
+ "#{file} not recognized as valid archive"
8
+ end
9
+
10
+ failure_message_for_should_not do |file|
11
+ "#{file} wrongly recognized as valid archive"
12
+ end
13
+
14
+ description do
15
+ "expected a valid archive file"
16
+ end
17
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format specdoc
3
+ --loadby mtime
4
+ --backtrace
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'unpacker'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Dir[ File.join(File.dirname(__FILE__), 'matchers/*') ].each do |matcher|
8
+ require matcher
9
+ end
10
+
11
+ Spec::Runner.configure do |config|
12
+
13
+ end
14
+
@@ -0,0 +1,37 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Unpacker do
4
+
5
+ %w[file.rar file.tar file.tar.gz file.tgz file.tar.bz file.tbz file.zip].each do |file|
6
+ it "should unpack #{file}" do
7
+ fixture_archive(file).should be_unpacked_correctly_to('archive-contents')
8
+ end
9
+
10
+ it "should recognize #{file} as valid archive" do
11
+ fixture_archive(file).should be_valid_archive
12
+ end
13
+ end
14
+
15
+ %w[invalid-file.rar invalid-file.tar.gz invalid-file.zip invalid-file.gz].each do |file|
16
+ it "should recognize #{file} as invalid archive" do
17
+ fixture_archive(file).should_not be_valid_archive
18
+ end
19
+ end
20
+
21
+ it "should extract gz" do
22
+ fixture_archive('lipsum.txt.gz').should be_unpacked_correctly_to('gz-contents')
23
+ end
24
+
25
+ it "should recognize archive" do
26
+ Unpacker.archive?(fixture_archive('test.tgz')).should be_true
27
+ end
28
+
29
+ it "should recognize other files as non-archives" do
30
+ Unpacker.archive?(fixture_archive('test.txt')).should be_false
31
+ end
32
+
33
+ def fixture_archive(file)
34
+ File.join("spec", "fixtures", file)
35
+ end
36
+
37
+ end
File without changes
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unpacker
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Petyo Ivanov
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-02 00:00:00 +03:00
18
+ default_executable: unpacker
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
31
+ version: 1.2.9
32
+ type: :development
33
+ version_requirements: *id001
34
+ description: The tool relies on the presence of the command-line tools.
35
+ email: underlog@gmail.com
36
+ executables:
37
+ - unpacker
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - LICENSE
42
+ - README.rdoc
43
+ files:
44
+ - .bnsignore
45
+ - .document
46
+ - .gitignore
47
+ - History.txt
48
+ - LICENSE
49
+ - README.rdoc
50
+ - Rakefile
51
+ - VERSION
52
+ - bin/unpacker
53
+ - lib/unpacker.rb
54
+ - spec/fixtures/archive-contents/sample-file
55
+ - spec/fixtures/file.rar
56
+ - spec/fixtures/file.tar
57
+ - spec/fixtures/file.tar.bz
58
+ - spec/fixtures/file.tar.gz
59
+ - spec/fixtures/file.tbz
60
+ - spec/fixtures/file.tgz
61
+ - spec/fixtures/file.zip
62
+ - spec/fixtures/invalid-file.gz
63
+ - spec/fixtures/invalid-file.rar
64
+ - spec/fixtures/invalid-file.tar.gz
65
+ - spec/fixtures/invalid-file.zip
66
+ - spec/fixtures/lipsum.txt.gz
67
+ - spec/matchers/unpacked_correctly.rb
68
+ - spec/matchers/valid_archive.rb
69
+ - spec/spec.opts
70
+ - spec/spec_helper.rb
71
+ - spec/unpacker_spec.rb
72
+ - test/test_unpacker.rb
73
+ has_rdoc: true
74
+ homepage: http://github.com/underlog/unpacker
75
+ licenses: []
76
+
77
+ post_install_message:
78
+ rdoc_options:
79
+ - --charset=UTF-8
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ requirements: []
97
+
98
+ rubyforge_project:
99
+ rubygems_version: 1.3.6
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: Abstraction for extracting various archives
103
+ test_files:
104
+ - spec/matchers/unpacked_correctly.rb
105
+ - spec/matchers/valid_archive.rb
106
+ - spec/spec_helper.rb
107
+ - spec/unpacker_spec.rb
108
+ - test/test_unpacker.rb