ruby_archive 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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