ruby_archive 0.1.2

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.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,24 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## RUBINIUS
14
+ *.rbc
15
+
16
+ ## VIM
17
+ *.swp
18
+
19
+ ## PROJECT::GENERAL
20
+ coverage
21
+ rdoc
22
+ pkg
23
+
24
+ ## PROJECT::SPECIFIC
@@ -0,0 +1,106 @@
1
+ = ruby_archive
2
+
3
+ Seamless access to Ruby source and other files inside zip archives
4
+
5
+ Works with all rubies I have tested it with... ruby-1.8.7, rubinius, jruby, and ruby-head.
6
+
7
+ Includes a modified version of rubyzip. Readme and license for rubyzip are
8
+ available in README.rubyzip. Note that ruby_archive may fail if the program uses
9
+ a different version of rubyzip.
10
+
11
+ A Ruby Summer of Code 2010 Project.
12
+
13
+ == Usage
14
+
15
+ Using ruby_archive in your project is easy! It allows you to use zip or jar archives
16
+ much the same way you already use normal operating system directories.
17
+
18
+ To use it, simply <code>require 'ruby_archive'</code> in your project. After this, you can:
19
+ * open files for reading or writing within an archive using <code>Kernel#open</code> or
20
+ <code>File.open</code>
21
+ * <code>load</code> or <code>require</code> Ruby source files from within an archive
22
+ * <code>glob</code> files within an archive directory
23
+ * much more...
24
+
25
+ The format for accessing files within an archive is: "(archive_file)!/(file_within_archive)"
26
+ So to open <code>information.txt</code> inside <code>archive.jar</code>, you might:
27
+
28
+ <code>f = File.open('./archive.jar!/information.txt','r')</code>
29
+
30
+ Or to load <code>source.rb</code> inside <code>program.zip</code>, you might:
31
+
32
+ <code>require './program.zip!/source'</code>
33
+
34
+ You can also add archive directories to the load path:
35
+
36
+ <code>$LOAD_PATH << 'program.zip!/' ; require 'source'</code>
37
+
38
+ Note that if the specified path (including the exclamation point) exists as a
39
+ file on the filesystem (i.e. not an archive), it will load the file instead of
40
+ the archive. So, if you have an archive named <code>archive.zip</code> and a
41
+ directory name <code>archive.zip!</code> with a file named <code>text.txt</code>
42
+ inside, a request for <code>'archive.zip!/text.txt'</code> will load the file
43
+ rather than look for text.txt inside <code>archive.zip</code>.
44
+
45
+ == Launcher
46
+
47
+ There is also a simple launcher for programs packaged as archive files in the
48
+ bin folder. If you include a file named <code>start.rb</code> in your archive,
49
+ this launcher will run this file. The launcher always adds the base path of the
50
+ archive to the load path.
51
+
52
+ The launcher can be used from the shell as follows:
53
+
54
+ <code>rba_launch program.zip</code>
55
+
56
+ You can also specify a specific file to load with the launcher, though often on some
57
+ shells you may need to escape the '!' or single-quote the filename:
58
+
59
+ <code>rba_launch 'program.zip!/alternate_start.rb'</code>
60
+
61
+ <code>rba_launch program.zip\!/alternate_start.rb</code>
62
+
63
+ == To-do
64
+
65
+ A lot of work has gone into making this work great, but there are still many features
66
+ that we should be able to implement.
67
+
68
+ * <b>autoload</b> - initially I thought it would not be possible to make it work without
69
+ patches to the Ruby interpreter, but some research on the topic has led me to
70
+ believe it is indeed possible.
71
+ * <b>launcher</b> - the included launcher is extremely basic. We would like one that can
72
+ do things like read jar manifests and load configuration options from the archive.
73
+ * <b>File.*** and Dir.***</b> - while most common methods work, there are a couple that may
74
+ come up from time to time that are currently marked as forward_method_unsupported
75
+ (meaning they will fail if called on an archive location)
76
+ * <b>More archive handlers</b> - zip_handler.rb works great for zip and jar files, but I'd like
77
+ to add more supported formats. A handler for gem files, for example, would be great.
78
+ * <b>Various fixes to zip_handler/rubyzip</b> - for example, currently you can only load files
79
+ within a zip archive with string modes ('r','w',etc). Trying to use a constant mode (File::RDONLY,
80
+ etc) will raise an exception.
81
+
82
+ == Bugs?
83
+
84
+ Please put bug reports on the issue tracker. Include any error messages, exceptions,
85
+ and (if applicable) source code that is causing the problem.
86
+
87
+ == Note on Patches/Pull Requests
88
+
89
+ * Fork the project.
90
+ * Make your feature addition or bug fix.
91
+ * Add tests for it. This is important so I don't break it in a
92
+ future version unintentionally.
93
+ * Commit, do not mess with rakefile, version, or history.
94
+ (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)
95
+ * Send me a pull request. Bonus points for topic branches.
96
+
97
+ == Thanks
98
+
99
+ * <b>Ruby Summer of Code</b> and all those involved in it, for being awesome - http://rubysoc.org
100
+ * <b>Evan Phoenix</b> for being my mentor on this project
101
+ * <b>Authors of rubyzip</b> for making a really great way to work with zip files in Ruby
102
+
103
+ == Copyright
104
+
105
+ Copyright (c) 2010 Jonathan Nielsen.
106
+ Released under Ruby's license, including GPL option.
@@ -0,0 +1,72 @@
1
+ = rubyzip
2
+
3
+ rubyzip is a ruby library for reading and writing zip files.
4
+
5
+ = Install
6
+
7
+ If you have rubygems you can install rubyzip directly from the gem
8
+ repository
9
+
10
+ gem install rubyzip
11
+
12
+ Otherwise obtain the source (see below) and run
13
+
14
+ ruby install.rb
15
+
16
+ To run the unit tests you need to have test::unit installed
17
+
18
+ rake test
19
+
20
+
21
+ = Documentation
22
+
23
+ There is more than one way to access or create a zip archive with
24
+ rubyzip. The basic API is modeled after the classes in
25
+ java.util.zip from the Java SDK. This means there are classes such
26
+ as Zip::ZipInputStream, Zip::ZipOutputStream and
27
+ Zip::ZipFile. Zip::ZipInputStream provides a basic interface for
28
+ iterating through the entries in a zip archive and reading from the
29
+ entries in the same way as from a regular File or IO
30
+ object. ZipOutputStream is the corresponding basic output
31
+ facility. Zip::ZipFile provides a mean for accessing the archives
32
+ central directory and provides means for accessing any entry without
33
+ having to iterate through the archive. Unlike Java's
34
+ java.util.zip.ZipFile rubyzip's Zip::ZipFile is mutable, which means
35
+ it can be used to change zip files as well.
36
+
37
+ Another way to access a zip archive with rubyzip is to use rubyzip's
38
+ Zip::ZipFileSystem API. Using this API files can be read from and
39
+ written to the archive in much the same manner as ruby's builtin
40
+ classes allows files to be read from and written to the file system.
41
+
42
+ rubyzip also features the
43
+ zip/ziprequire.rb[link:files/lib/zip/ziprequire_rb.html] module which
44
+ allows ruby to load ruby modules from zip archives.
45
+
46
+ For details about the specific behaviour of classes and methods refer
47
+ to the test suite. Finally you can generate the rdoc documentation or
48
+ visit http://rubyzip.sourceforge.net.
49
+
50
+ = License
51
+
52
+ rubyzip is distributed under the same license as ruby. See
53
+ http://www.ruby-lang.org/en/LICENSE.txt
54
+
55
+
56
+ = Website and Project Home
57
+
58
+ http://rubyzip.sourceforge.net
59
+
60
+ http://sourceforge.net/projects/rubyzip
61
+
62
+ == Download (tarballs and gems)
63
+
64
+ http://sourceforge.net/project/showfiles.php?group_id=43107&package_id=35377
65
+
66
+ = Authors
67
+
68
+ Thomas Sondergaard (thomas at sondergaard.cc)
69
+
70
+ Technorama Ltd. (oss-ruby-zip at technorama.net)
71
+
72
+ extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org)
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ruby_archive"
8
+ gem.summary = %Q{Seamless access to ruby source and other files inside zip archives}
9
+ gem.description = %Q{Allows loading applications, libraries, and data from easily distributable archive files}
10
+ gem.email = "jonathan@jmnet.us"
11
+ gem.homepage = "http://github.com/byuni/ruby_archive"
12
+ gem.authors = ["Jonathan Nielsen"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
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 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "rubyarchive-pure #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ # default options
5
+ options = {
6
+ :entry_point => 'start.rb'
7
+ }
8
+
9
+ # overrides in archive
10
+ options_archive = {}
11
+
12
+ # overrides by command line
13
+ options_cmdline = {}
14
+
15
+ help_banner = nil
16
+ opts = OptionParser.new do |opts|
17
+ opts.banner =
18
+ %{Usage: #{$0} [options] [archive] [arguments]
19
+ To run a specific file within an archive, use archive.zip!/ruby_file.rb
20
+
21
+ }
22
+
23
+ #opts.on("-v", "--[no-]verbose", "Verbose errors/warnings") do |v|
24
+ # options[:verbose] = v
25
+ #end
26
+
27
+ opts.on("-e", "--entry-point=FILE", String, "Force a specific default file to load within the archive") do |l|
28
+ options_cmdline[:entry_point] = l
29
+ end
30
+
31
+ opts.on_tail("-h", "--help", "Print this message") do
32
+ puts opts
33
+ exit
34
+ end
35
+ end
36
+
37
+ opts.order! # parse up to archive name
38
+
39
+ if ARGV.empty? # no archive was specified, print banner and exit
40
+ puts opts
41
+ exit
42
+ end
43
+
44
+ require File.expand_path("../../lib/ruby_archive",__FILE__)
45
+
46
+ archive_file = File.expand_path(ARGV.shift,Dir.getwd)
47
+ file_to_load = nil
48
+
49
+ location_info = File.in_archive?(archive_file)
50
+ unless location_info == false
51
+ archive_file = location_info[0]
52
+ file_to_load = location_info[1]
53
+ end
54
+
55
+ options.merge!(options_archive)
56
+ options.merge!(options_cmdline)
57
+ # TODO: load archive specific options
58
+
59
+ file_to_load = options[:entry_point] if file_to_load.nil?
60
+
61
+ $LOAD_PATH << "#{archive_file}!/"
62
+ load("#{archive_file}!#{file_to_load}",false)
@@ -0,0 +1,79 @@
1
+ require File.expand_path('../ruby_archive/patch.rb',__FILE__)
2
+
3
+ module RubyArchive
4
+ class Handler
5
+ # ruby_archive/handler.rb
6
+ require File.expand_path('../ruby_archive/handler.rb',__FILE__)
7
+ end
8
+
9
+ module Handlers
10
+ # ruby_archive/handlers/*.rb
11
+ # loaded at end of file
12
+ end
13
+
14
+ @@archive_handlers ||= []
15
+ # Adds an archive handler to the list used. Provided handler must be a
16
+ # subclass of +RubyArchive::Handler+
17
+ def add_handler_class handler_class
18
+ unless (handler_class.is_a? Class) && (handler_class <= RubyArchive::Handler)
19
+ raise TypeError, "#{handler_class} is not a RubyArchive::Handler"
20
+ end
21
+ @@archive_handlers << handler_class
22
+ true
23
+ end
24
+ module_function :add_handler_class
25
+
26
+ # Finds the appropriate +RubyArchive::Handler+ subclass for a given location.
27
+ # Returns nil if no supported handler found.
28
+ def find_handler_class location
29
+ @@archive_handlers.each do |h|
30
+ return h if h.handles?(location)
31
+ end
32
+ return nil
33
+ end
34
+ module_function :find_handler_class
35
+
36
+ @@loaded_archives ||= {}
37
+ # Retrieves an archive from the loaded_archives cache, or automatically
38
+ # loads the archive. Returns the archive on success. Returns nil if
39
+ # archive is not available and autoload is false. Raises +LoadError+
40
+ # if autoload is attempted and fails.
41
+ def get location, autoload=true
42
+ @@archive_handlers.each do |h|
43
+ normalized = h.normalize_path(location)
44
+ return @@loaded_archives[normalized] if @@loaded_archives.has_key?(normalized)
45
+ end
46
+ return load(location) if autoload
47
+ nil
48
+ end
49
+ module_function :get
50
+
51
+ # Loads the specified archive location. Returns the handler object on
52
+ # success. Raises +LoadError+ if no handler can be found or it does not
53
+ # exist. May also pass exceptions passed along by creating the handler.
54
+ def load location
55
+ handler_class = find_handler_class(location)
56
+ if handler_class.nil?
57
+ raise LoadError, "No handler found or does not exist for archive -- #{location}"
58
+ end
59
+ archive = handler_class.new(location)
60
+ @@loaded_archives[archive.name] = archive
61
+ end
62
+ module_function :load
63
+
64
+ def close_all_archives
65
+ @@loaded_archives.each_value do |archive|
66
+ archive.close
67
+ end
68
+ @@loaded_archives.clear
69
+ true
70
+ end
71
+ module_function :close_all_archives
72
+
73
+ end
74
+
75
+ # Set RubyArchive::close_all_archives to at_exit
76
+ at_exit { RubyArchive::close_all_archives }
77
+
78
+ # load builtin handlers
79
+ require File.expand_path('../ruby_archive/handlers/zip_handler.rb',__FILE__)
@@ -0,0 +1,55 @@
1
+ module RubyArchive
2
+ # RubyArchive::Handler
3
+ class Handler
4
+ # Should return true if the class can handle the given location as an
5
+ # archive. Returns false otherwise. The default implementation always
6
+ # returns false, this must be overridden in your subclasses.
7
+ #
8
+ # This method must NOT raise an exception.
9
+ def self.handles? location
10
+ false
11
+ end
12
+
13
+ # Should return a normalized version of the location specified.
14
+ # +File.expand_path+ works well in many cases, and is provided as the
15
+ # default.
16
+ def self.normalize_path location
17
+ File.expand_path(location)
18
+ end
19
+
20
+ # Initialize a handler object for the location given. The default
21
+ # implementation raises a +NotImplementedError+.
22
+ #
23
+ # Your implementation needs to set +@name+ to identify the archive
24
+ def initialize location
25
+ raise NotImplementedError, "Cannot initialize a handler of class #{self.class}"
26
+ end
27
+
28
+ # Close the handler. This will be executed when +RubyArchive::close_all_archives+
29
+ # is executed, or at_exit
30
+ #
31
+ # Should always return nil
32
+ def close
33
+ nil
34
+ end
35
+
36
+ # Should return a +File+-like object for the archive. The default
37
+ # implementation raises a +NotImplentedError+, must be overridden.
38
+ def file
39
+ raise NotImplementedError, "Cannot retrieve a file object for class #{self.class}"
40
+ end
41
+
42
+ # Should return a +Dir+-like object for the archive (optional)
43
+ # Should return +nil+ if not supported.
44
+ def dir
45
+ nil
46
+ end
47
+
48
+ # reader for +@name+, which should be set in +initialize+
49
+ attr_reader :name
50
+
51
+ def inspect
52
+ "<#{self.class}:#{self.name}>"
53
+ end
54
+ end
55
+ end