diff --git a/CHANGELOG b/CHANGELOG index c7506e09..d8e49998 100755 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,189 +1,193 @@ - * trunk: - Fixed --daemon option. - - * 0.10.2: - Upgraded to Rails 0.13.1 - Fixed HTML export - Added layout=no option to the export_html action (it exports page contents processed - by the markup engine, but without the default layout - so that they can be wrapped in - some other layout) - tag can span several lines (before it was applied when both opening and closing - tags were on the same line only) - Resolved the "endless redirection loop" condition and otherwise improved handling of - errors in the rendering engines - Fixed rendering of Markdown hyperlinks such as [Text](http://something.com/foo) - - * 0.10.1: - Upgraded Rails to 0.12.0 - Upgraded rubyzip to version 0.5.8 - BlueCloth is back (RedCloth didn't do pure Markdown well enough) - Handling of line breaks in Textile is as in 0.9 (inserts
tag) - Fixed HTML export (to enclose the output in tags, include the stylesheet etc) - Corrected some compatibility issues with storages from earlier Instiki versions - Some other bug fixes - - * 0.10.0: - Ported to ActionPack - RedCloth 3.0.3 - BlueCloth is phased out, Markdown is rendered by RedCloth - Mix markup option understands both Textile and Markdown on the same page - Instiki can serve static content (such as HTML or plain-text files) from ./public - directory - Much friendlier admin interface - Wiki link syntax doesn't conflict with Textile hyperlink syntax. Therefore - "textile link":LinkToSomePlace will not look insane. - RSS feeds accept query parameters, sush as - http://localhost:2500/wiki/rss_with_headlines?start=2005-02-18&end=2005-02-19&limit=10 - RSS feed with page contents for a password-protected web behaves as follows: - if the web is published, RSS feed links to the published version of the web - otherwise, the feed is not available - Madeleine will check every hour if there are new commands in the log or 24 hours have - passed since last snapshot, and take snapshot if either of these conditions is true - Madeleine will also not log read-only operations, resulting in a better performance - Wiki extracts (to HTML and plain text) will leave only the last extract file in ./storage - Wiki search handles multibyte (UTF-8) characters correctly - Local hyperlinks in published pages point to published pages [Michael DeHaan] - Fixed a bug that sometimes caused all past revisions of a page to be "forgotten" on - restart - Fixed parsing of URIs with a port number (http://someplace.org:8080) - Instiki will not fork itself on a *nix, unless explicitly asked to - Instiki can bind to IPs other than 127.0.0.1 (command-line option) - Revisions that do not change anything on the page are rejected - Automated tests for all controller actions - category: lines are presented as links to "All Pages" for relevant categories - Search looks at page titles, as well as content - Multiple other usability enhancements and bug fixes - - * 0.9.2: - Rollback takes the user to an edit form. The form has to be submitted for the change to - take place. - Changed to use inline style on published pages - Fixed "forward in time" on the last revision before current page - Instiki won't log bogus error messages when creating a new Wiki - Fixed deprecation warning for Object.id (introduced in Ruby 1.8.2) - Madeleine upgraded to 0.7.1 - Madeleine snapshots are compressed - Packaged as a gem - - * 0.9.1: - Added performance improvements for updating existing pages - Fixed IP logging and RSS feeds behind proxies [With help from Guan Yang] - Fixed default storage directory (borked running on Windows) [Spotted by Curt Hibbs] - - * 0.9.0: - Added aliased links such as [[HomePage|that nice home page]] [Mark Reid] - Added include other page content with [[!include TableOfContents]] [Mark Reid] - Added delete orphan pages from the Edit Web screen [by inspiration from Simon Arnaud] - Added logging of IP address for authors (who's behind the rollback wars) - Added Categories pages through backlinks (use "categories: news, instiki" on start of line) [Mark Reid] - Added option to use bracket-style wiki links only (and hence ban WikiWords) - Added command-line option to specify different storage path - Added print view without navigation - Added character and page (2275 characters including spaces) counter (important for student papers) - Off by default, activate it on the Edit Web screen - Added LaTeX/PDF integration on Textile installations with pdflatex installed on system (EXPERIMENTAL) - Use the home page as a table of contents with a unordered list to control sections - Added limit of 15 to the number of pages included in RSS feed - Moved static parts of stylesheet to separate file [Lau TŒrnskov] - Fixed better semantics for revision movement [Ryan Singer] - Fixed color diffs to work much better [Xen/Mertz/Atkins] - Fixed performance problems for All Pages list [Dennis Mertz] - Fixed lots of rendering bugs [Mark Reid] - Upgraded to RedCloth 2.0.11 [integrating the fine work of Dennis Mertz] - - * 0.8.9: - Added color diffs to see changes between revisions [Bill Atkins] - They're aren't quite perfect yet as new paragraphs split the tags (hence 0.8.9, not 0.9.0) - Added redirect to edit if content of page generates an error - (so the page doesn't become unusable on bugs in the markup engines) - Fixed update Web with different address bug [Denis Metz] - Fixed a bunch of wiki word rendering issues by doing wiki word detection and replacment at once - Upgraded to BlueCloth 0.0.3b (should fix loads of problems on Markdown wikis) - - * 0.8.5: - Instiki can now serve as a CMS by running a password-protected web with a published front - Added version check at startup (Instiki needs Ruby 1.8.1) - - * 0.8.1: - Actually included RedCloth 2.0.7 in the release - - * 0.8.0: - NOTE: Single-web wikis created in versions prior to 0.8.0 have "instiki" as their system password - Accepts wiki words in bracket style. Ex: [[wiki word]], [[c]], [[We could'nt have done it!]] - Accepts camel-case wiki words in all latin, greek, cyrillian, and armenian unicode characters - Many thanks to Guan Yang for building the higher- and lower-case lookup tables - And thanks to Simon Arnaud for the initial patch that got the work started - Changed charset to UTF-8 - Cut down on command-line options and replaced them with an per-web config screen - Added option to extend the stylesheet on a per-web basis to tweak the look in details - Added simple color options for variety - Added option to add/remove password protection on each web - Added the wiki name of the author locking a given page (instead of just "someone") - Removed single/multi-web distinction -- all Instikis are now multi-web - Load libraries from an unshifted load path, so that old installed libraries doesn't clash [Emiel van de Laar] - Keeps the author cookie forever, so you don't have to enter your name again and again - Fixed XHTML so it validates [Bruce D'Arcus] - Authors are no longer listed under orphan pages - Added export to markup (great for backups, potentially for switching wiki engine) - Don't link wiki words that proceeds from either /, = or ? - (http://c2.com/cgi/wiki?WikiWikiClones, /show/HomePage, cgi.pl?show=WikiWord without escaping) - Accessing an unexisting page redirects to a different url (/new/PageName) - Increased snapshot time to just once a day (cuts down on disk storage requirements) - Made RDoc support work better with 1.8.1 [Mauricio Fern‡ndez] - Added convinient redirect from /wiki/ to /wiki/show/HomePage - Fixed BlueCloth bug with backticks at start of line - Updated to RedCloth 2.0.7 (and linked to the new Textile reference) - - * 0.7.0: - Added Markdown (BlueCloth) and RDoc [Mauricio Fern‡ndez] as command-line markup choices - Added wanted and orphan page lists to All pages (only show up if there's actually orphan or wanted pages) - Added ISO-8859-1 as XML encoding in RSS feeds (makes FeedReader among others happy for special entities) - Added proper links in the RSS feed (but the body links are still relative, which NNW and others doesn't grok) - Added access keys: E => Edit, H => HomePage, A => All Pages, U => Recently Revised, X => Export - Added password-login through URL (so you can subscribe to feed on a protected web) - Added web passwords to the feed links for protected webs, so they work without manual login - Added the web name in small letters above all pages within a web - Polished authors and recently revised - Updated to RedCloth 2.0.6 - Changed content type for RSS feeds to text/xml (makes Mozilla Aggreg8 happy) - Changed searching to be case insensitive - Changed HomePage to display the name of the web instead - Changed exported HTML pages to be valid XHTML (which can be preprocessed by XSLT) - Fixed broken recently revised - - * 0.6.0: - Fixed Windows compatibility [Florian] - Fixed bug that would prevent Madeleine from taking snapshots in Daemon mode - Added export entire web as HTML in a zip file - Added RSS feeds - Added proper getops support for the growing number of options [Florian] - Added safe mode that forbids style options in RedCloth [Florian] - Updated RedCloth to 2.0.5 - - * 0.5.0: - NOTE: 0.5.0 is NOT compatible with databases from earlier versions - Added revisions - Added multiple webs - Added password protection for webs on multi-web setups - Added the notion of authors (that are saved in a cookie) - Added command-line option for not running as a Daemon on Unix - - * 0.3.1: - Added option to escape wiki words with \ - - * 0.3.0: - Brought all files into common style (including Textile help on the edit page) - Added page locking (if someone already is editing a page there's a warning) - Added daemon abilities on Unix (keep Instiki running after you close the terminal) - Made port 2500 the default port, so Instiki can be launched by dobbelt-click - Added Textile cache to speed-up rendering of large pages - Made WikiWords look like "Wiki Words" - Updated RedCloth to 2.0.4 - - * 0.2.5: - Upgraded to RedCloth 2.0.2 and Madeleine 0.6.1, which means the - Windows problems are gone. Also fixed a problem with wikiwords - that used part of other wikiwords. - - * 0.2.0: - First public release + * instiki-ar: + SQL-based backend (ActiveRecord) + Replaced internal link generator with routing + Fixed --daemon option + Upgraded to Rails 0.14.2 + Re-enabled file uploads + + * 0.10.2: + Upgraded to Rails 0.13.1 + Fixed HTML export + Added layout=no option to the export_html action (it exports page contents processed + by the markup engine, but without the default layout - so that they can be wrapped in + some other layout) + tag can span several lines (before it was applied when both opening and closing + tags were on the same line only) + Resolved the "endless redirection loop" condition and otherwise improved handling of + errors in the rendering engines + Fixed rendering of Markdown hyperlinks such as [Text](http://something.com/foo) + + * 0.10.1: + Upgraded Rails to 0.12.0 + Upgraded rubyzip to version 0.5.8 + BlueCloth is back (RedCloth didn't do pure Markdown well enough) + Handling of line breaks in Textile is as in 0.9 (inserts
tag) + Fixed HTML export (to enclose the output in tags, include the stylesheet etc) + Corrected some compatibility issues with storages from earlier Instiki versions + Some other bug fixes + + * 0.10.0: + Ported to ActionPack + RedCloth 3.0.3 + BlueCloth is phased out, Markdown is rendered by RedCloth + Mix markup option understands both Textile and Markdown on the same page + Instiki can serve static content (such as HTML or plain-text files) from ./public + directory + Much friendlier admin interface + Wiki link syntax doesn't conflict with Textile hyperlink syntax. Therefore + "textile link":LinkToSomePlace will not look insane. + RSS feeds accept query parameters, sush as + http://localhost:2500/wiki/rss_with_headlines?start=2005-02-18&end=2005-02-19&limit=10 + RSS feed with page contents for a password-protected web behaves as follows: + if the web is published, RSS feed links to the published version of the web + otherwise, the feed is not available + Madeleine will check every hour if there are new commands in the log or 24 hours have + passed since last snapshot, and take snapshot if either of these conditions is true + Madeleine will also not log read-only operations, resulting in a better performance + Wiki extracts (to HTML and plain text) will leave only the last extract file in ./storage + Wiki search handles multibyte (UTF-8) characters correctly + Local hyperlinks in published pages point to published pages [Michael DeHaan] + Fixed a bug that sometimes caused all past revisions of a page to be "forgotten" on + restart + Fixed parsing of URIs with a port number (http://someplace.org:8080) + Instiki will not fork itself on a *nix, unless explicitly asked to + Instiki can bind to IPs other than 127.0.0.1 (command-line option) + Revisions that do not change anything on the page are rejected + Automated tests for all controller actions + category: lines are presented as links to "All Pages" for relevant categories + Search looks at page titles, as well as content + Multiple other usability enhancements and bug fixes + + * 0.9.2: + Rollback takes the user to an edit form. The form has to be submitted for the change to + take place. + Changed to use inline style on published pages + Fixed "forward in time" on the last revision before current page + Instiki won't log bogus error messages when creating a new Wiki + Fixed deprecation warning for Object.id (introduced in Ruby 1.8.2) + Madeleine upgraded to 0.7.1 + Madeleine snapshots are compressed + Packaged as a gem + + * 0.9.1: + Added performance improvements for updating existing pages + Fixed IP logging and RSS feeds behind proxies [With help from Guan Yang] + Fixed default storage directory (borked running on Windows) [Spotted by Curt Hibbs] + + * 0.9.0: + Added aliased links such as [[HomePage|that nice home page]] [Mark Reid] + Added include other page content with [[!include TableOfContents]] [Mark Reid] + Added delete orphan pages from the Edit Web screen [by inspiration from Simon Arnaud] + Added logging of IP address for authors (who's behind the rollback wars) + Added Categories pages through backlinks (use "categories: news, instiki" on start of line) [Mark Reid] + Added option to use bracket-style wiki links only (and hence ban WikiWords) + Added command-line option to specify different storage path + Added print view without navigation + Added character and page (2275 characters including spaces) counter (important for student papers) + Off by default, activate it on the Edit Web screen + Added LaTeX/PDF integration on Textile installations with pdflatex installed on system (EXPERIMENTAL) + Use the home page as a table of contents with a unordered list to control sections + Added limit of 15 to the number of pages included in RSS feed + Moved static parts of stylesheet to separate file [Lau TŒrnskov] + Fixed better semantics for revision movement [Ryan Singer] + Fixed color diffs to work much better [Xen/Mertz/Atkins] + Fixed performance problems for All Pages list [Dennis Mertz] + Fixed lots of rendering bugs [Mark Reid] + Upgraded to RedCloth 2.0.11 [integrating the fine work of Dennis Mertz] + + * 0.8.9: + Added color diffs to see changes between revisions [Bill Atkins] + They're aren't quite perfect yet as new paragraphs split the tags (hence 0.8.9, not 0.9.0) + Added redirect to edit if content of page generates an error + (so the page doesn't become unusable on bugs in the markup engines) + Fixed update Web with different address bug [Denis Metz] + Fixed a bunch of wiki word rendering issues by doing wiki word detection and replacment at once + Upgraded to BlueCloth 0.0.3b (should fix loads of problems on Markdown wikis) + + * 0.8.5: + Instiki can now serve as a CMS by running a password-protected web with a published front + Added version check at startup (Instiki needs Ruby 1.8.1) + + * 0.8.1: + Actually included RedCloth 2.0.7 in the release + + * 0.8.0: + NOTE: Single-web wikis created in versions prior to 0.8.0 have "instiki" as their system password + Accepts wiki words in bracket style. Ex: [[wiki word]], [[c]], [[We could'nt have done it!]] + Accepts camel-case wiki words in all latin, greek, cyrillian, and armenian unicode characters + Many thanks to Guan Yang for building the higher- and lower-case lookup tables + And thanks to Simon Arnaud for the initial patch that got the work started + Changed charset to UTF-8 + Cut down on command-line options and replaced them with an per-web config screen + Added option to extend the stylesheet on a per-web basis to tweak the look in details + Added simple color options for variety + Added option to add/remove password protection on each web + Added the wiki name of the author locking a given page (instead of just "someone") + Removed single/multi-web distinction -- all Instikis are now multi-web + Load libraries from an unshifted load path, so that old installed libraries doesn't clash [Emiel van de Laar] + Keeps the author cookie forever, so you don't have to enter your name again and again + Fixed XHTML so it validates [Bruce D'Arcus] + Authors are no longer listed under orphan pages + Added export to markup (great for backups, potentially for switching wiki engine) + Don't link wiki words that proceeds from either /, = or ? + (http://c2.com/cgi/wiki?WikiWikiClones, /show/HomePage, cgi.pl?show=WikiWord without escaping) + Accessing an unexisting page redirects to a different url (/new/PageName) + Increased snapshot time to just once a day (cuts down on disk storage requirements) + Made RDoc support work better with 1.8.1 [Mauricio Fern‡ndez] + Added convinient redirect from /wiki/ to /wiki/show/HomePage + Fixed BlueCloth bug with backticks at start of line + Updated to RedCloth 2.0.7 (and linked to the new Textile reference) + + * 0.7.0: + Added Markdown (BlueCloth) and RDoc [Mauricio Fern‡ndez] as command-line markup choices + Added wanted and orphan page lists to All pages (only show up if there's actually orphan or wanted pages) + Added ISO-8859-1 as XML encoding in RSS feeds (makes FeedReader among others happy for special entities) + Added proper links in the RSS feed (but the body links are still relative, which NNW and others doesn't grok) + Added access keys: E => Edit, H => HomePage, A => All Pages, U => Recently Revised, X => Export + Added password-login through URL (so you can subscribe to feed on a protected web) + Added web passwords to the feed links for protected webs, so they work without manual login + Added the web name in small letters above all pages within a web + Polished authors and recently revised + Updated to RedCloth 2.0.6 + Changed content type for RSS feeds to text/xml (makes Mozilla Aggreg8 happy) + Changed searching to be case insensitive + Changed HomePage to display the name of the web instead + Changed exported HTML pages to be valid XHTML (which can be preprocessed by XSLT) + Fixed broken recently revised + + * 0.6.0: + Fixed Windows compatibility [Florian] + Fixed bug that would prevent Madeleine from taking snapshots in Daemon mode + Added export entire web as HTML in a zip file + Added RSS feeds + Added proper getops support for the growing number of options [Florian] + Added safe mode that forbids style options in RedCloth [Florian] + Updated RedCloth to 2.0.5 + + * 0.5.0: + NOTE: 0.5.0 is NOT compatible with databases from earlier versions + Added revisions + Added multiple webs + Added password protection for webs on multi-web setups + Added the notion of authors (that are saved in a cookie) + Added command-line option for not running as a Daemon on Unix + + * 0.3.1: + Added option to escape wiki words with \ + + * 0.3.0: + Brought all files into common style (including Textile help on the edit page) + Added page locking (if someone already is editing a page there's a warning) + Added daemon abilities on Unix (keep Instiki running after you close the terminal) + Made port 2500 the default port, so Instiki can be launched by dobbelt-click + Added Textile cache to speed-up rendering of large pages + Made WikiWords look like "Wiki Words" + Updated RedCloth to 2.0.4 + + * 0.2.5: + Upgraded to RedCloth 2.0.2 and Madeleine 0.6.1, which means the + Windows problems are gone. Also fixed a problem with wikiwords + that used part of other wikiwords. + + * 0.2.0: + First public release diff --git a/README b/README index adbaaaf1..ae268ea1 100755 --- a/README +++ b/README @@ -1,68 +1,97 @@ -===What is Instiki? - -Admitted, it's YetAnotherWikiClone[http://c2.com/cgi/wiki?WikiWikiClones], but with a strong focus -on simplicity of installation and running: - -Step 1. Download - -Step 2. Run "instiki" - -Step 3. Chuckle... "There's no step three!" (TM) - -You're now running a perfectly suitable wiki on port 2500 -that'll present you with one-step setup, followed by a textarea for the home page -on http://localhost:2500. - -Instiki lowers the barriers of interest for when you might consider -using a wiki. It's so simple to get running that you'll find yourself -using it for anything -- taking notes, brainstorming, organizing a -gathering. - -===Features: -* Regular expression search: Find deep stuff really fast -* Revisions: Follow the changes on every page from birth. Rollback to an earlier rev -* Export to HTML or markup in a zip: Take the entire wiki with you home or for reference -* RSS feeds to track recently revised pages -* Multiple webs: Create separate wikis with their own namespace -* Password-protected webs: Keep it private -* Authors: Each revision is associated with an author, so you can see who changed what -* Reference tracker: Which other pages are pointing to the current? -* Speed: Using Madelein[http://madeleine.sourceforge.net] for persistence (all pages are in memory) -* Three markup choices: Textile[http://www.textism.com/tools/textile] - (default / RedCloth[http://www.whytheluckystiff.net/ruby/redcloth]), - Markdown (BlueCloth[http://bluecloth.rubyforge.org]), and RDoc[http://rdoc.sourceforge.net/doc] -* Embedded webserver: Through WEBrick[http://www.webrick.org] -* Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters -* Color diffs: Track changes through revisions - -===Missing: -* File attachments - -===Install from gem: -* Install rubygems -* Run "gem install instiki" -* Change to a directory where you want Instiki to keep its data files (for example, ~/instiki/) -* Run "instiki" - this will create a "storage" directory (for example, ~/instiki/storage), and start a new Wiki service - -Make sure that you always launch Instiki from the same working directory, or specify the storage directory in runtime parameters, such as: - instiki --storage ~/instiki/storage - -===Command-line options: -* Run "instiki --help" - -===History: - * See CHANGELOG - -===Download latest from: -* http://rubyforge.org/project/showfiles.php?group_id=186 - -===Visit the official Instiki wiki: -* http://www.instiki.org - -===License: -* same as Ruby's - ---- -Author:: David Heinemeier Hansson -Email:: david@loudthinking.com -Weblog:: http://www.loudthinking.com +===What is Instiki? + +Admitted, it's YetAnotherWikiClone[http://c2.com/cgi/wiki?WikiWikiClones], but with a strong focus +on simplicity of installation and running: + +Step 1. Download +Step 2. Run "instiki" + +Here it should say: "Step 3. Chuckle... "There's no step three!" (TM)" +... but this is a beta version that introduces an SQL-based backend, so: + +3. Kill 'instiki' +4. Install SQLite 3 database engine from http://www.sqlite.org/ +5. Install SQLite 3 driver for Ruby from http://sqlite-ruby.rubyforge.org/ +6. Install Rake from http://rake.rubyforge.org/ +7. Execute 'rake db_schema_import create_sessions_table' +8. Make an embarrassed sigh (as I do while writing this) +9. Run 'instiki' again +10. Pat yourself on the shoulder for being such a talented geek +11. At least, there is no step eleven! (TM) + +You're now running a perfectly suitable wiki on port 2500 +that'll present you with one-step setup, followed by a textarea for the home page +on http://localhost:2500. + +Instiki lowers the barriers of interest for when you might consider +using a wiki. It's so simple to get running that you'll find yourself +using it for anything -- taking notes, brainstorming, organizing a +gathering. + +===Features: +* Regular expression search: Find deep stuff really fast +* Revisions: Follow the changes on every page from birth. Rollback to an earlier rev +* Export to HTML or markup in a zip: Take the entire wiki with you home or for reference +* RSS feeds to track recently revised pages +* Multiple webs: Create separate wikis with their own namespace +* Password-protected webs: Keep it private +* Authors: Each revision is associated with an author, so you can see who changed what +* Reference tracker: Which other pages are pointing to the current? +* Speed: Using Madelein[http://madeleine.sourceforge.net] for persistence (all pages are in memory) +* Three markup choices: Textile[http://www.textism.com/tools/textile] + (default / RedCloth[http://www.whytheluckystiff.net/ruby/redcloth]), + Markdown (BlueCloth[http://bluecloth.rubyforge.org]), and RDoc[http://rdoc.sourceforge.net/doc] +* Embedded webserver: Through WEBrick[http://www.webrick.org] +* Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters +* Color diffs: Track changes through revisions + +===Missing: +* File attachments + +===Command-line options: +* Run "instiki --help" + +===History: + * See CHANGELOG + +===Migrating Instiki 0.10.2 storage to Instiki-AR database +1. Install Instiki-AR and check that it works (you should be able to create a web, edit and save a HomePage) +2. Execute + ruby script\import_storage \ + -t /full/path/to/instiki0.10/storage \ + -i /full/path/to/instiki0.10/installation \ + -d sqlite (or mysql, or postgres, depending on what you use) \ + -o instiki_import.sql + for example: + ruby script\import_storage -t c:\instiki-0.10.2\storage\2500 -i c:\instiki-0.10.2 -d sqlite -o instiki_import.sql +3. This will produce instiki_import.sql file in the current working directory. + Open it in a text editor and inspect carefully. +4. Connect to your production database (e.g., 'sqlite3 db\prod.db'), + and have it execute instiki_import.sql (e.g., '.read instiki_import.sql') +5. Execute ruby script\reset_references + (this script parses all pages for crosslinks between them, so it may take a few minutes) +6. Restart Instiki +7. Go over some pages, especially those with a lot of complex markup, and see if anything is broken. + +The most common migration problem is this: +If you open All Pages screen and see a lot of orphaned pages, +you forgot to run ruby script\reset_references after importing the data. + +===Download latest from: +* http://rubyforge.org/project/showfiles.php?group_id=186 + +===Visit the official Instiki wiki: +* http://www.instiki.org + +===License: +* same as Ruby's + +--- +Authors:: + +Versions 0.1 to 0.9.1:: David Heinemeier Hansson +Email:: david@loudthinking.com +Weblog:: http://www.loudthinking.com + +From 0.9.2 onwards:: Alexey Verkhovsky +Email:: alex@verk.info diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index 6bca0f15..a52b2005 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -46,7 +46,6 @@ class AdminController < ApplicationController end def edit_web - system_password = @params['system_password'] if system_password # form submitted @@ -67,6 +66,7 @@ class AdminController < ApplicationController flash[:info] = "Web '#{@params['address']}' was successfully updated" redirect_home(@params['address']) rescue Instiki::ValidationError => e + logger.warn e.message @error = e.message # and re-render the same template again end diff --git a/app/controllers/application.rb b/app/controllers/application.rb index 552eec83..6fc309b7 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -2,42 +2,31 @@ # Likewise will all the methods added be available for all controllers. class ApplicationController < ActionController::Base - before_filter :set_utf8_http_header, :connect_to_model, :check_snapshot_thread - after_filter :remember_location + before_filter :connect_to_model, :check_authorization, :setup_url_generator, :set_content_type_header, :set_robots_metatag + after_filter :remember_location, :teardown_url_generator # For injecting a different wiki model implementation. Intended for use in tests def self.wiki=(the_wiki) # a global variable is used here because Rails reloads controller and model classes in the # development environment; therefore, storing it as a class variable does not work # class variable is, anyway, not much different from a global variable - $instiki_wiki_service = the_wiki + #$instiki_wiki_service = the_wiki logger.debug("Wiki service: #{the_wiki.to_s}") end def self.wiki - $instiki_wiki_service + Wiki.new end protected - def authorized? - @web.nil? || - @web.password.nil? || - cookies['web_address'] == @web.password || - password_check(@params['password']) - end - def check_authorization - if in_a_web? and needs_authorization?(@action_name) and not authorized? and + if in_a_web? and authorization_needed? and not authorized? redirect_to :controller => 'wiki', :action => 'login', :web => @web_name return false end end - def check_snapshot_thread - WikiService.check_snapshot_thread - end - def connect_to_model @action_name = @params['action'] || 'index' @web_name = @params['web'] @@ -45,14 +34,13 @@ class ApplicationController < ActionController::Base if @web_name @web = @wiki.webs[@web_name] if @web.nil? - render_text "Unknown web '#{@web_name}'", '404 Not Found' + render :status => 404, :text => "Unknown web '#{@web_name}'" return false end end @page_name = @file_name = @params['id'] @page = @wiki.read_page(@web_name, @page_name) unless @page_name.nil? @author = cookies['author'] || 'AnonymousCoward' - check_authorization end FILE_TYPES = { @@ -71,10 +59,6 @@ class ApplicationController < ActionController::Base super(file, options) end - def in_a_web? - not @web_name.nil? - end - def password_check(password) if password == @web.password cookies['web_address'] = password @@ -102,28 +86,26 @@ class ApplicationController < ActionController::Base def redirect_to_page(page_name = @page_name, web = @web_name) redirect_to :web => web, :controller => 'wiki', :action => 'show', - :id => (page_name || 'HomePage') + :id => (page_name or 'HomePage') end - @@REMEMBER_NOT = ['locked', 'save', 'back', 'file', 'pic', 'import'] def remember_location - if @response.headers['Status'] == '200 OK' - unless @@REMEMBER_NOT.include? action_name or @request.method != :get - @session[:return_to] = @request.request_uri - logger.debug("Session ##{session.object_id}: remembered URL '#{@session[:return_to]}'") - end + if @request.method == :get and + @response.headers['Status'] == '200 OK' and not + %w(locked save back file pic import).include?(action_name) + @session[:return_to] = @request.request_uri + logger.debug "Session ##{session.object_id}: remembered URL '#{@session[:return_to]}'" end end def rescue_action_in_public(exception) - message = <<-EOL + render :status => 500, :text => <<-EOL -

Internal Error 500

+

Internal Error

An application error occurred while processing your request.

- + EOL - render_text message, 'Internal Error 500' end def return_to_last_remembered @@ -146,16 +128,48 @@ class ApplicationController < ActionController::Base end end - def set_utf8_http_header - @response.headers['Content-Type'] = 'text/html; charset=UTF-8' + def set_content_type_header + if %w(rss_with_content rss_with_headlines).include?(action_name) + @response.headers['Content-Type'] = 'text/xml; charset=UTF-8' + else + @response.headers['Content-Type'] = 'text/html; charset=UTF-8' + end + end + + def set_robots_metatag + if controller_name == 'wiki' and %w(show published).include? action_name + @robots_metatag_value = 'index,follow' + else + @robots_metatag_value = 'noindex,nofollow' + end + end + + def setup_url_generator + PageRenderer.setup_url_generator(UrlGenerator.new(self)) + end + + def teardown_url_generator + PageRenderer.teardown_url_generator end def wiki - $instiki_wiki_service + self.class.wiki end - def needs_authorization?(action) - not %w( login authenticate published rss_with_content rss_with_headlines ).include?(action) + private + + def in_a_web? + not @web_name.nil? + end + + def authorization_needed? + not %w( login authenticate published rss_with_content rss_with_headlines ).include?(action_name) + end + + def authorized? + @web.password.nil? or + cookies['web_address'] == @web.password or + password_check(@params['password']) end end diff --git a/app/controllers/file_controller.rb b/app/controllers/file_controller.rb index bf0ee964..61e5f000 100644 --- a/app/controllers/file_controller.rb +++ b/app/controllers/file_controller.rb @@ -1,9 +1,4 @@ -require 'fileutils' -require 'application' -require 'instiki_errors' - -# Controller that is responsible for serving files and pictures. -# Disabled in version 0.10 +# Controller responsible for serving files and pictures. class FileController < ApplicationController @@ -17,7 +12,6 @@ class FileController < ApplicationController # form supplied file_yard.upload_file(@file_name, @params['file']) flash[:info] = "File '#{@file_name}' successfully uploaded" - @web.refresh_pages_with_references(@file_name) return_to_last_remembered elsif file_yard.has_file?(@file_name) send_file(file_yard.file_path(@file_name)) @@ -36,7 +30,6 @@ class FileController < ApplicationController if @params['file'] # form supplied file_yard.upload_file(@file_name, @params['file']) - @web.refresh_pages_with_references(@file_name) flash[:info] = "Image '#{@file_name}' successfully uploaded" return_to_last_remembered elsif file_yard.has_file?(@file_name) @@ -48,8 +41,6 @@ class FileController < ApplicationController end def import - return if file_uploads_disabled? - check_authorization if @params['file'] @problems = [] @@ -71,15 +62,8 @@ class FileController < ApplicationController protected def check_allow_uploads - - # TODO enable file uploads again after 0.10 release - unless RAILS_ENV == 'test' - render_text 'File uploads are not ready for general use in Instiki 0.10', '403 Forbidden' - return false - end - - unless @web.allow_uploads - render_text 'File uploads are blocked by the webmaster', '403 Forbidden' + unless @web.allow_uploads? + render :status => 403, :text => 'File uploads are blocked by the webmaster' return false end end diff --git a/app/controllers/revision_sweeper.rb b/app/controllers/revision_sweeper.rb new file mode 100644 index 00000000..28284ce6 --- /dev/null +++ b/app/controllers/revision_sweeper.rb @@ -0,0 +1,32 @@ +class RevisionSweeper < ActionController::Caching::Sweeper + observe Revision, Page + + def after_save(record) + if record.is_a?(Revision) + expire_caches(record.page) + end + end + + def after_delete(record) + if record.is_a?(Page) + expire_caches(record) + end + end + + private + + def expire_caches(page) + web = page.web + + ([page.name] + WikiReference.pages_that_reference(page.name)).uniq.each do |page_name| + expire_action :controller => 'wiki', :web => web.address, + :action => %w(show published), :id => page_name + end + + expire_action :controller => 'wiki', :web => web.address, + :action => %w(authors recently_revised list) + expire_fragment :controller => 'wiki', :web => web.address, + :action => %w(rss_with_headlines rss_with_content) + end + +end diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index 92f602e9..2e7eb3b7 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -1,10 +1,13 @@ -require 'application' require 'fileutils' require 'redcloth_for_tex' require 'parsedate' +require 'zip/zip' class WikiController < ApplicationController + caches_action :show, :published, :authors, :recently_revised, :list + cache_sweeper :revision_sweeper + layout 'default', :except => [:rss_feed, :rss_with_content, :rss_with_headlines, :tex, :export_tex, :export_html] def index @@ -42,14 +45,46 @@ class WikiController < ApplicationController # Within a single web --------------------------------------------------------- def authors - @authors = @web.select.authors.sort + @page_names_by_author = @web.page_names_by_author + @authors = @page_names_by_author.keys.sort end def export_html + stylesheet = File.read(File.join(RAILS_ROOT, 'public', 'stylesheets', 'instiki.css')) export_pages_as_zip('html') do |page| - @page = page - @link_mode = :export - render_to_string('wiki/print', use_layout = (@params['layout'] != 'no')) + + renderer = PageRenderer.new(page.revisions.last) + rendered_page = <<-EOL + + + + #{page.plain_name} in #{@web.name} + + + + + + + #{renderer.display_content_for_export} + + + + EOL + rendered_page end end @@ -58,7 +93,7 @@ class WikiController < ApplicationController end def export_pdf - file_name = "#{@web.address}-tex-#{@web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')}" + file_name = "#{@web.address}-tex-#{@web.revised_at.strftime('%Y-%m-%d-%H-%M-%S')}" file_path = File.join(@wiki.storage_path, file_name) export_web_to_tex "#{file_path}.tex" unless FileTest.exists? "#{file_path}.tex" @@ -67,7 +102,7 @@ class WikiController < ApplicationController end def export_tex - file_name = "#{@web.address}-tex-#{@web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')}.tex" + file_name = "#{@web.address}-tex-#{@web.revised_at.strftime('%Y-%m-%d-%H-%M-%S')}.tex" file_path = File.join(@wiki.storage_path, file_name) export_web_to_tex(file_path) unless FileTest.exists?(file_path) send_file file_path @@ -141,7 +176,7 @@ class WikiController < ApplicationController def pdf page = wiki.read_page(@web_name, @page_name) safe_page_name = @page.name.gsub(/\W/, '') - file_name = "#{safe_page_name}-#{@web.address}-#{@page.created_at.strftime('%Y-%m-%d-%H-%M-%S')}" + file_name = "#{safe_page_name}-#{@web.address}-#{@page.revised_at.strftime('%Y-%m-%d-%H-%M-%S')}" file_path = File.join(@wiki.storage_path, file_name) export_page_to_tex("#{file_path}.tex") unless FileTest.exists?("#{file_path}.tex") @@ -151,20 +186,30 @@ class WikiController < ApplicationController end def print + if @page.nil? + redirect_home + end @link_mode ||= :show + @renderer = PageRenderer.new(@page.revisions.last) # to template end def published - if @web.published - @page = wiki.read_page(@web_name, @page_name || 'HomePage') - else - redirect_home + if not @web.published? + render(:text => "Published version of web '#{@web_name}' is not available", :status => 404) + return end + + page_name = @page_name || 'HomePage' + page = wiki.read_page(@web_name, page_name) + render(:text => "Page '#{page_name}' not found", status => 404) and return unless page + + @renderer = PageRenderer.new(page.revisions.last) end def revision get_page_and_revision + @renderer = PageRenderer.new(@revision) end def rollback @@ -172,24 +217,22 @@ class WikiController < ApplicationController end def save - redirect_home if @page_name.nil? - cookies['author'] = @params['author'] + render(:status => 404, :text => 'Undefined page name') and return if @page_name.nil? + cookies['author'] = { :value => @params['author'], :expires => Time.utc(2030) } begin - check_for_spam(@params['content'], remote_ip) - check_blocked_ips(remote_ip) - if @page wiki.revise_page(@web_name, @page_name, @params['content'], Time.now, - Author.new(@params['author'], remote_ip)) + Author.new(@params['author'], remote_ip), PageRenderer.new) @page.unlock else wiki.write_page(@web_name, @page_name, @params['content'], Time.now, - Author.new(@params['author'], remote_ip)) + Author.new(@params['author'], remote_ip), PageRenderer.new) end redirect_to_page @page_name rescue => e flash[:error] = e + logger.error e flash[:content] = @params['content'] if @page @page.unlock @@ -203,6 +246,7 @@ class WikiController < ApplicationController def show if @page begin + @renderer = PageRenderer.new(@page.revisions.last) render_action 'page' # TODO this rescue should differentiate between errors due to rendering and errors in # the application itself (for application errors, it's better not to rescue the error at all) @@ -230,26 +274,7 @@ class WikiController < ApplicationController private - - def check_blocked_ips(ip) - if defined? BLOCKED_IPS and not BLOCKED_IPS.nil? - BLOCKED_IPS.each do |blocked_ip| - raise Instiki::ValidationError.new('Revision rejected by spam filter') if ip == blocked_ip - end - end - end - - def check_for_spam(new_content, ip) - if defined? SPAM_PATTERNS and not SPAM_PATTERNS.nil? - SPAM_PATTERNS.each do |pattern| - if new_content =~ pattern - logger.info "Spam attempt from IP address #{ip}" - raise Instiki::ValidationError.new('Revision rejected by spam filter') - end - end - end - end - + def convert_tex_to_pdf(tex_path) # TODO remove earlier PDF files with the same prefix # TODO handle gracefully situation where pdflatex is not available @@ -264,13 +289,13 @@ class WikiController < ApplicationController def export_page_to_tex(file_path) tex - File.open(file_path, 'w') { |f| f.write(render_to_string('wiki/tex')) } + File.open(file_path, 'w') { |f| f.write(render_to_string(:template => 'wiki/tex', :layout => nil)) } end def export_pages_as_zip(file_type, &block) file_prefix = "#{@web.address}-#{file_type}-" - timestamp = @web.revised_on.strftime('%Y-%m-%d-%H-%M-%S') + timestamp = @web.revised_at.strftime('%Y-%m-%d-%H-%M-%S') file_path = File.join(@wiki.storage_path, file_prefix + timestamp + '.zip') tmp_path = "#{file_path}.tmp" @@ -292,28 +317,25 @@ class WikiController < ApplicationController end def export_web_to_tex(file_path) - @tex_content = table_of_contents(@web.pages['HomePage'].content, render_tex_web) - File.open(file_path, 'w') { |f| f.write(render_to_string('wiki/tex_web')) } + @tex_content = table_of_contents(@web.page('HomePage').content, render_tex_web) + File.open(file_path, 'w') { |f| f.write(render_to_string(:template => 'wiki/tex_web', :layout => nil)) } end def get_page_and_revision - revision_index = (@params['rev'] || 0).to_i - if @page.nil? or @page.revisions[revision_index].nil? - render_text 'Page not found', '404 Not Found' - else - @revision = @page.revisions[revision_index] - end + @revision_number = @params['rev'].to_i + @revision = @page.revisions[@revision_number] end def parse_category - @categories = @web.categories @category = @params['category'] - if @categories.include?(@category) - @pages_in_category = @web.select { |page| page.in_category?(@category) } - @set_name = "category '#{@category}'" - else - @pages_in_category = PageSet.new(@web).by_name + @categories = WikiReference.list_categories.sort + page_names_in_category = WikiReference.pages_in_category(@category) + if (page_names_in_category.empty?) + @pages_in_category = @web.select_all.by_name @set_name = 'the web' + else + @pages_in_category = @web.select { |page| page_names_in_category.include?(page.name) }.by_name + @set_name = "category '#{@category}'" end end @@ -340,15 +362,14 @@ class WikiController < ApplicationController @pages_by_revision = @web.select.by_revision.first(limit) else @pages_by_revision = @web.select.by_revision - @pages_by_revision.reject! { |page| page.created_at < start_date } if start_date - @pages_by_revision.reject! { |page| page.created_at > end_date } if end_date + @pages_by_revision.reject! { |page| page.revised_at < start_date } if start_date + @pages_by_revision.reject! { |page| page.revised_at > end_date } if end_date end @hide_description = hide_description - @response.headers['Content-Type'] = 'text/xml' @link_action = @web.password ? 'published' : 'show' - render 'wiki/rss_feed' + render :action => 'rss_feed' end def render_tex_web @@ -358,18 +379,8 @@ class WikiController < ApplicationController end end - def render_to_string(template_name, with_layout = false) - add_variables_to_assigns - self.assigns['content_for_layout'] = @template.render_file(template_name) - if with_layout - @template.render_file('layouts/default') - else - self.assigns['content_for_layout'] - end - end - def rss_with_content_allowed? - @web.password.nil? or @web.published + @web.password.nil? or @web.published? end def truncate(text, length = 30, truncate_string = '...') diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 134df0bf..3056541e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -44,7 +44,12 @@ module ApplicationHelper # Creates a hyperlink to a Wiki page, or to a "new page" form if the page doesn't exist yet def link_to_page(page_name, web = @web, text = nil, options = {}) raise 'Web not defined' if web.nil? - web.make_link(page_name, text, options.merge(:base_url => "#{base_url}/#{web.address}")) + UrlGenerator.new(@controller).make_link(page_name, web, text, + options.merge(:base_url => "#{base_url}/#{web.address}")) + end + + def author_link(page, options = {}) + UrlGenerator.new(@controller).make_link(page.author.name, page.web, nil, options) end def base_url @@ -72,4 +77,19 @@ module ApplicationHelper h(text).gsub(/\n/, '
') end + def format_date(date, include_time = true) + # Must use DateTime because Time doesn't support %e on at least some platforms + date_time = DateTime.new(date.year, date.mon, date.day, date.hour, date.min, + date.sec) + if include_time + return date_time.strftime("%B %e, %Y %H:%M:%S") + else + return date_time.strftime("%B %e, %Y") + end + end + + def rendered_content(page) + PageRenderer.new(page.revisions.last).display_content + end + end diff --git a/app/models/author.rb b/app/models/author.rb index 258cc2b8..be8a5cf7 100644 --- a/app/models/author.rb +++ b/app/models/author.rb @@ -1,4 +1,18 @@ class Author < String attr_accessor :ip - def initialize(name, ip) @ip = ip; super(name) end + attr_reader :name + def initialize(name, ip = nil) + @ip = ip + super(name) + end + + def name=(value) + self.gsub!(/.+/, value) + end + + alias_method :name, :to_s + + def <=>(other) + name <=> other.to_s + end end \ No newline at end of file diff --git a/app/models/page.rb b/app/models/page.rb index 5926fb85..1896ac5f 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -1,120 +1,117 @@ -require 'date' -require 'page_lock' -require 'revision' -require 'wiki_words' -require 'chunks/wiki' +class Page < ActiveRecord::Base + belongs_to :web + has_many :revisions, :order => 'id' + has_many :wiki_references, :order => 'referenced_name' + has_one :current_revision, :class_name => 'Revision', :order => 'id DESC' -class Page - include PageLock - - attr_reader :name, :web - attr_accessor :revisions - - def initialize(web, name) - raise 'nil web' if web.nil? - raise 'nil name' if name.nil? - @web, @name, @revisions = web, name, [] - end - - def revise(content, created_at, author) - - if not @revisions.empty? and content == @revisions.last.content + def revise(content, time, author, renderer) + revisions_size = new_record? ? 0 : revisions.size + if (revisions_size > 0) and content == current_revision.content raise Instiki::ValidationError.new( "You have tried to save page '#{name}' without changing its content") end + + author = Author.new(author.to_s) unless author.is_a?(Author) # Try to render content to make sure that markup engine can take it, - # before addin a revision to the page - Revision.new(self, @revisions.length, content, created_at, author).force_rendering + renderer.revision = Revision.new( + :page => self, :content => content, :author => author, :revised_at => time) + renderer.display_content(update_references = true) # A user may change a page, look at it and make some more changes - several times. # Not to record every such iteration as a new revision, if the previous revision was done # by the same author, not more than 30 minutes ago, then update the last revision instead of # creating a new one - if !@revisions.empty? && continous_revision?(created_at, author) - @revisions.last.created_at = created_at - @revisions.last.content = content - @revisions.last.clear_display_cache + if (revisions_size > 0) && continous_revision?(time, author) + current_revision.update_attributes(:content => content, :revised_at => time) else - @revisions << Revision.new(self, @revisions.length, content, created_at, author) + revisions.create(:content => content, :author => author, :revised_at => time) end - - self.revisions.last.force_rendering - # at this point the page may not be inserted in the web yet, and therefore - # references to the page itself are rendered as "unresolved". Clearing the cache allows - # the page to re-render itself once again, hopefully _after_ it is inserted in the web - self.revisions.last.clear_display_cache - - @web.refresh_pages_with_references(@name) if @revisions.length == 1 - + save self - end - def rollback(revision_number, created_at, author_ip = nil) - roll_back_revision = @revisions[revision_number].dup - revise(roll_back_revision.content, created_at, Author.new(roll_back_revision.author, author_ip)) + def rollback(revision_number, time, author_ip, renderer) + roll_back_revision = self.revisions[revision_number] + if roll_back_revision.nil? + raise Instiki::ValidationError.new("Revision #{revision_number} not found") + end + author = Author.new(roll_back_revision.author.name, author_ip) + revise(roll_back_revision.content, time, author, renderer) end - + def revisions? - revisions.length > 1 + revisions.size > 1 end - def revised_on - created_on - end - - def in_category?(cat) - cat.nil? || cat.empty? || categories.include?(cat) - end - - def categories - display_content.find_chunks(Category).map { |cat| cat.list }.flatten - end - - def authors - revisions.collect { |rev| rev.author } + def previous_revision(revision) + revision_index = revisions.each_with_index do |rev, index| + if rev.id == revision.id + break index + else + nil + end + end + if revision_index.nil? or revision_index == 0 + nil + else + revisions[revision_index - 1] + end end def references - @web.select.pages_that_reference(name) + web.select.pages_that_reference(name) end def linked_from - @web.select.pages_that_link_to(name) + web.select.pages_that_link_to(name) end def included_from - @web.select.pages_that_include(name) + web.select.pages_that_include(name) end # Returns the original wiki-word name as separate words, so "MyPage" becomes "My Page". def plain_name - @web.brackets_only ? name : WikiWords.separate(name) + web.brackets_only? ? name : WikiWords.separate(name) end - # used to build chunk ids. - def id - @id ||= name.unpack('H*').first + LOCKING_PERIOD = 30.minutes + + def lock(time, locked_by) + update_attributes(:locked_at => time, :locked_by => locked_by) + end + + def lock_duration(time) + ((time - locked_at) / 60).to_i unless locked_at.nil? + end + + def unlock + update_attribute(:locked_at, nil) + end + + def locked?(comparison_time) + locked_at + LOCKING_PERIOD > comparison_time unless locked_at.nil? end - def link(options = {}) - @web.make_link(name, nil, options) - end - - def author_link(options = {}) - @web.make_link(author, nil, options) + def to_param + name end private - def continous_revision?(created_at, author) - @revisions.last.author == author && @revisions.last.created_at + 30.minutes > created_at - end - - # Forward method calls to the current revision, so the page responds to all revision calls - def method_missing(method_symbol) - revisions.last.send(method_symbol) - end + def continous_revision?(time, author) + (current_revision.author == author) && (revised_at + 30.minutes > time) + end + # Forward method calls to the current revision, so the page responds to all revision calls + def method_missing(method_id, *args, &block) + method_name = method_id.to_s + # Perform a hand-off to AR::Base#method_missing + if @attributes.include?(method_name) or md = /(=|\?|_before_type_cast)$/.match(method_name) + super(method_id, *args, &block) + else + current_revision.send(method_id) + end + end end diff --git a/app/models/page_lock.rb b/app/models/page_lock.rb deleted file mode 100644 index 276274e6..00000000 --- a/app/models/page_lock.rb +++ /dev/null @@ -1,23 +0,0 @@ -# Contains all the lock methods to be mixed in with the page -module PageLock - LOCKING_PERIOD = 30 * 60 # 30 minutes - - attr_reader :locked_by - - def lock(time, locked_by) - @locked_at, @locked_by = time, locked_by - end - - def lock_duration(time) - ((time - @locked_at) / 60).to_i unless @locked_at.nil? - end - - def unlock - @locked_at = nil - end - - def locked?(comparison_time) - @locked_at + LOCKING_PERIOD > comparison_time unless @locked_at.nil? - end - -end \ No newline at end of file diff --git a/app/models/page_observer.rb b/app/models/page_observer.rb new file mode 100644 index 00000000..13211a14 --- /dev/null +++ b/app/models/page_observer.rb @@ -0,0 +1,15 @@ +# This class maintains the state of wiki references for newly created or newly deleted pages +class PageObserver < ActiveRecord::Observer + + def after_create(page) + WikiReference.update_all("link_type = '#{WikiReference::LINKED_PAGE}'", + ['referenced_name = ?', page.name]) + end + + def before_destroy(page) + WikiReference.delete_all ['page_id = ?', page.id] + WikiReference.update_all("link_type = '#{WikiReference::WANTED_PAGE}'", + ['referenced_name = ?', page.name]) + end + +end \ No newline at end of file diff --git a/app/models/page_set.rb b/app/models/page_set.rb index 5b298ea6..9589b36c 100644 --- a/app/models/page_set.rb +++ b/app/models/page_set.rb @@ -7,7 +7,7 @@ class PageSet < Array @web = web # if pages is not specified, make a list of all pages in the web if pages.nil? - super(web.pages.values) + super(web.pages) # otherwise use specified pages and condition to produce a set of pages elsif condition.nil? super(pages) @@ -17,10 +17,9 @@ class PageSet < Array end def most_recent_revision - self.map { |page| page.created_at }.max || Time.at(0) + self.map { |page| page.revised_at }.max || Time.at(0) end - def by_name PageSet.new(@web, sort_by { |page| page.name }) end @@ -28,22 +27,28 @@ class PageSet < Array alias :sort :by_name def by_revision - PageSet.new(@web, sort_by { |page| page.created_at }).reverse + PageSet.new(@web, sort_by { |page| page.revised_at }).reverse end def pages_that_reference(page_name) - self.select { |page| page.wiki_references.include?(page_name) } + all_referring_pages = WikiReference.pages_that_reference(page_name) + self.select { |page| all_referring_pages.include?(page.name) } end def pages_that_link_to(page_name) - self.select { |page| page.wiki_words.include?(page_name) } + all_linking_pages = WikiReference.pages_that_link_to(page_name) + self.select { |page| all_linking_pages.include?(page.name) } end def pages_that_include(page_name) - self.select { |page| page.wiki_includes.include?(page_name) } + all_including_pages = WikiReference.pages_that_include(page_name) + self.select { |page| all_including_pages.include?(page.name) } end def pages_authored_by(author) + all_pages_authored_by_the_author = + Page.connection.select_all(sanitize_sql([ + "SELECT page_id FROM revision WHERE author = '?'", author])) self.select { |page| page.authors.include?(author) } end @@ -57,7 +62,7 @@ class PageSet < Array # references and so cannot be orphans # Pages that refer to themselves and have no links from outside are oprphans. def orphaned_pages - never_orphans = web.select.authors + ['HomePage'] + never_orphans = web.authors + ['HomePage'] self.select { |page| if never_orphans.include? page.name false @@ -79,11 +84,11 @@ class PageSet < Array end def wiki_words - self.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq - end - - def authors - self.inject([]) { |authors, page| authors << page.authors }.flatten.uniq.sort + self.inject([]) { |wiki_words, page| + wiki_words + page.wiki_references. + select { |ref| ref.link_type != WikiReference::CATEGORY }. + map { |ref| ref.referenced_name } + }.flatten.uniq end end diff --git a/app/models/revision.rb b/app/models/revision.rb index c5f0eb8a..3af2384d 100644 --- a/app/models/revision.rb +++ b/app/models/revision.rb @@ -1,127 +1,4 @@ -require 'diff' -require 'wiki_content' -require 'chunks/wiki' -require 'date' -require 'author' -require 'page' - -class Revision - - attr_accessor :page, :number, :content, :created_at, :author - - def initialize(page, number, content, created_at, author) - @page, @number, @created_at, @author = page, number, created_at, author - self.content = content - @display_cache = nil - end - - def created_on - Date.new(@created_at.year, @created_at.mon, @created_at.day) - end - - def pretty_created_at - # Must use DateTime because Time doesn't support %e on at least some platforms - DateTime.new( - @created_at.year, @created_at.mon, @created_at.day, @created_at.hour, @created_at.min - ).strftime "%B %e, %Y %H:%M" - end - - -# todo: drop next_revision, previuous_revision and number from here - unused code - def next_revision - page.revisions[number + 1] - end - - def previous_revision - number > 0 ? page.revisions[number - 1] : nil - end - - # Returns an array of all the WikiIncludes present in the content of this revision. - def wiki_includes - unless @wiki_includes_cache - chunks = display_content.find_chunks(Include) - @wiki_includes_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq - end - @wiki_includes_cache - end - - # Returns an array of all the WikiReferences present in the content of this revision. - def wiki_references - unless @wiki_references_cache - chunks = display_content.find_chunks(WikiChunk::WikiReference) - @wiki_references_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq - end - @wiki_references_cache - end - - # Returns an array of all the WikiWords present in the content of this revision. - def wiki_words - unless @wiki_words_cache - wiki_chunks = display_content.find_chunks(WikiChunk::WikiLink) - @wiki_words_cache = wiki_chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq - end - @wiki_words_cache - end - - # Returns an array of all the WikiWords present in the content of this revision. - # that already exists as a page in the web. - def existing_pages - wiki_words.select { |wiki_word| page.web.pages[wiki_word] } - end - - # Returns an array of all the WikiWords present in the content of this revision - # that *doesn't* already exists as a page in the web. - def unexisting_pages - wiki_words - existing_pages - end - - # Explicit check for new type of display cache with chunks_by_type method. - # Ensures new version works with older snapshots. - def display_content - unless @display_cache && @display_cache.respond_to?(:chunks_by_type) - @display_cache = WikiContent.new(self) - @display_cache.render! - end - @display_cache - end - - def display_diff - previous_revision ? HTMLDiff.diff(previous_revision.display_content, display_content) : display_content - end - - def clear_display_cache - @wiki_words_cache = @published_cache = @display_cache = @wiki_includes_cache = - @wiki_references_cache = nil - end - - def display_published - unless @published_cache && @published_cache.respond_to?(:chunks_by_type) - @published_cache = WikiContent.new(self, {:mode => :publish}) - @published_cache.render! - end - @published_cache - end - - def display_content_for_export - WikiContent.new(self, {:mode => :export} ).render! - end - - def force_rendering - begin - display_content.render! - rescue => e - ApplicationController.logger.error "Failed rendering page #{@name}" - ApplicationController.logger.error e - message = e.message - # substitute content with an error message - self.content = <<-EOL -

Markup engine has failed to render this page, raising the following error:

-

#{message}

-
#{self.content}
- EOL - clear_display_cache - raise e - end - end - +class Revision < ActiveRecord::Base + belongs_to :page + composed_of :author, :mapping => [ %w(author name), %w(ip ip) ] end diff --git a/app/models/system.rb b/app/models/system.rb new file mode 100644 index 00000000..7ac1ad08 --- /dev/null +++ b/app/models/system.rb @@ -0,0 +1,4 @@ +class System < ActiveRecord::Base + set_table_name 'system' + validates_presence_of :password +end \ No newline at end of file diff --git a/app/models/web.rb b/app/models/web.rb index 60e936ee..a53fc25b 100644 --- a/app/models/web.rb +++ b/app/models/web.rb @@ -1,133 +1,114 @@ -require 'cgi' -require 'page' -require 'page_set' -require 'wiki_words' -require 'zip/zip' +class Web < ActiveRecord::Base + has_many :pages -class Web - attr_accessor :name, :password, :safe_mode, :pages - attr_accessor :additional_style, :allow_uploads, :published - attr_reader :address - - # there are getters for all these attributes, too - attr_writer :markup, :color, :brackets_only, :count_pages, :max_upload_size - - def initialize(parent_wiki, name, address, password = nil) - self.address = address - @wiki, @name, @password = parent_wiki, name, password - - set_compatible_defaults - - @pages = {} - @allow_uploads = true - @additional_style = nil - @published = false - @count_pages = false - end - - # Explicitly sets value of some web attributes to defaults, unless they are already set - def set_compatible_defaults - @markup = markup() - @color = color() - @safe_mode = safe_mode() - @brackets_only = brackets_only() - @max_upload_size = max_upload_size() - @wiki = wiki + def wiki + Wiki.new end - # All below getters know their default values. This is necessary to ensure compatibility with - # 0.9 storages, where they were not defined. - def brackets_only() @brackets_only || false end - def color() @color ||= '008B26' end - def count_pages() @count_pages || false end - def markup() @markup ||= :textile end - def max_upload_size() @max_upload_size || 100; end - def wiki() @wiki ||= WikiService.instance; end - - def add_page(name, content, created_at, author) - page = Page.new(self, name) - page.revise(content, created_at, author) - @pages[page.name] = page - end - - def address=(the_address) - if the_address != CGI.escape(the_address) - raise Instiki::ValidationError.new('Web name should contain only valid URI characters') - end - @address = the_address + def file_yard + @file_yard ||= FileYard.new("#{Wiki.storage_path}/#{address}", max_upload_size) end - + + def settings_changed?(markup, safe_mode, brackets_only) + self.markup != markup || + self.safe_mode != safe_mode || + self.brackets_only != brackets_only + end + + def add_page(name, content, time, author, renderer) + page = page(name) || Page.new(:web => self, :name => name) + page.revise(content, time, author, renderer) + end + def authors - select.authors + connection.select_all( + 'SELECT DISTINCT r.author AS author ' + + 'FROM revisions r ' + + 'JOIN pages p ON p.id = r.page_id ' + + 'ORDER by 1').collect { |row| row['author'] } end def categories select.map { |page| page.categories }.flatten.uniq.sort end + def page(name) + pages.find(:first, :conditions => ['name = ?', name]) + end + def has_page?(name) - pages[name] + Page.count(['web_id = ? AND name = ?', id, name]) > 0 end def has_file?(name) wiki.file_yard(self).has_file?(name) end - # Create a link for the given page name and link text based - # on the render mode in options and whether the page exists - # in the this web. - # The links a relative, and will work only if displayed on another WikiPage. - # It should not be used in menus, templates and such - instead, use link_to_page helper - def make_link(name, text = nil, options = {}) - text = CGI.escapeHTML(text || WikiWords.separate(name)) - mode = options[:mode] || :show - base_url = options[:base_url] || '..' - link_type = options[:link_type] || :show - case link_type.to_sym - when :show - UrlGenerator.new.make_page_link(mode, name, text, base_url, has_page?(name)) - when :file - UrlGenerator.new.make_file_link(mode, name, text, base_url, has_file?(name)) - when :pic - UrlGenerator.new.make_pic_link(mode, name, text, base_url, has_file?(name)) - else - raise "Unknown link type: #{link_type}" - end + def markup + read_attribute('markup').to_sym end - # Clears the display cache for all the pages with references to - def refresh_pages_with_references(page_name) - select.pages_that_reference(page_name).each { |page| - page.revisions.each { |revision| revision.clear_display_cache } + def page_names_by_author + connection.select_all( + 'SELECT DISTINCT r.author AS author, p.name AS page_name ' + + 'FROM revisions r ' + + 'JOIN pages p ON r.page_id = p.id ' + + "WHERE p.web_id = #{self.id} " + + 'ORDER by p.name' + ).inject({}) { |result, row| + author, page_name = row['author'], row['page_name'] + result[author] = [] unless result.has_key?(author) + result[author] << page_name + result } end - - def refresh_revisions - select.each { |page| page.revisions.each { |revision| revision.clear_display_cache } } - end def remove_pages(pages_to_be_removed) - pages.delete_if { |page_name, page| pages_to_be_removed.include?(page) } + pages_to_be_removed.each { |p| p.destroy } end - def revised_on + def revised_at select.most_recent_revision end def select(&condition) - PageSet.new(self, @pages.values, condition) + PageSet.new(self, pages, condition) + end + + def select_all + PageSet.new(self, pages, nil) + end + + def to_param + address end private # Returns an array of all the wiki words in any current revision def wiki_words - pages.values.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq + pages.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq end # Returns an array of all the page names on this web def page_names - pages.keys + pages.map { |p| p.name } end + protected + before_save :sanitize_markup + before_validation :validate_address + validates_uniqueness_of :address + validates_length_of :color, :in => 3..6 + + def sanitize_markup + self.markup = markup.to_s + end + + def validate_address + unless address == CGI.escape(address) + self.errors.add(:address, 'should contain only valid URI characters') + raise Instiki::ValidationError.new("#{self.class.human_attribute_name('address')} #{errors.on(:address)}") + end + end end diff --git a/app/models/wiki.rb b/app/models/wiki.rb new file mode 100644 index 00000000..e0da8644 --- /dev/null +++ b/app/models/wiki.rb @@ -0,0 +1,96 @@ +class Wiki + + cattr_accessor :storage_path, :logger + self.storage_path = "#{RAILS_ROOT}/storage/" + self.logger = RAILS_DEFAULT_LOGGER + + def authenticate(password) + password == (system.password || 'instiki') + end + + def create_web(name, address, password = nil) + @webs = nil + Web.create(:name => name, :address => address, :password => password) + end + + def delete_web(address) + web = Web.find_by_address(address) + unless web.nil? + web.destroy + @webs = nil + end + end + + def file_yard(web) + web.file_yard + end + + def edit_web(old_address, new_address, name, markup, color, additional_style, safe_mode = false, + password = nil, published = false, brackets_only = false, count_pages = false, + allow_uploads = true, max_upload_size = nil) + + if not (web = Web.find_by_address(old_address)) + raise Instiki::ValidationError.new("Web with address '#{old_address}' does not exist") + end + + web.update_attributes(:address => new_address, :name => name, :markup => markup, :color => color, + :additional_style => additional_style, :safe_mode => safe_mode, :password => password, :published => published, + :brackets_only => brackets_only, :count_pages => count_pages, :allow_uploads => allow_uploads, :max_upload_size => max_upload_size) + @webs = nil + raise Instiki::ValidationError.new("There is already a web with address '#{new_address}'") unless web.errors.on(:address).nil? + web + end + + def read_page(web_address, page_name) + self.class.logger.debug "Reading page '#{page_name}' from web '#{web_address}'" + web = Web.find_by_address(web_address) + if web.nil? + self.class.logger.debug "Web '#{web_address}' not found" + return nil + else + page = web.pages.find(:first, :conditions => ['name = ?', page_name]) + self.class.logger.debug "Page '#{page_name}' #{page.nil? ? 'not' : ''} found" + return page + end + end + + def remove_orphaned_pages(web_address) + web = Web.find_by_address(web_address) + web.remove_pages(web.select.orphaned_pages) + end + + def revise_page(web_address, page_name, content, revised_at, author, renderer) + page = read_page(web_address, page_name) + page.revise(content, revised_at, author, renderer) + end + + def rollback_page(web_address, page_name, revision_number, time, author_id = nil) + page = read_page(web_address, page_name) + page.rollback(revision_number, time, author_id) + end + + def setup(password, web_name, web_address) + system.update_attribute(:password, password) + create_web(web_name, web_address) + end + + def system + @system ||= (System.find(:first) || System.create) + end + + def setup? + Web.count > 0 + end + + def webs + @webs ||= Web.find(:all).inject({}) { |webs, web| webs.merge(web.address => web) } + end + + def storage_path + self.class.storage_path + end + + def write_page(web_address, page_name, content, written_on, author, renderer) + Web.find_by_address(web_address).add_page(page_name, content, written_on, author, renderer) + end +end \ No newline at end of file diff --git a/app/models/wiki_reference.rb b/app/models/wiki_reference.rb new file mode 100644 index 00000000..9f4534a7 --- /dev/null +++ b/app/models/wiki_reference.rb @@ -0,0 +1,67 @@ +class WikiReference < ActiveRecord::Base + + LINKED_PAGE = 'L' + WANTED_PAGE = 'W' + INCLUDED_PAGE = 'I' + CATEGORY = 'C' + AUTHOR = 'A' + + belongs_to :page + validates_inclusion_of :link_type, :in => [LINKED_PAGE, WANTED_PAGE, INCLUDED_PAGE, CATEGORY, AUTHOR] + + # FIXME all finders below MUST restrict their results to pages belonging to a particular web + + def self.link_type(web, page_name) + web.has_page?(page_name) ? LINKED_PAGE : WANTED_PAGE + end + + def self.pages_that_reference(page_name) + query = 'SELECT name FROM pages JOIN wiki_references ON pages.id = wiki_references.page_id ' + + 'WHERE wiki_references.referenced_name = ?' + + "AND wiki_references.link_type in ('#{LINKED_PAGE}', '#{WANTED_PAGE}', '#{INCLUDED_PAGE}')" + names = connection.select_all(sanitize_sql([query, page_name])).map { |row| row['name'] } + end + + def self.pages_that_link_to(page_name) + query = 'SELECT name FROM pages JOIN wiki_references ON pages.id = wiki_references.page_id ' + + 'WHERE wiki_references.referenced_name = ? ' + + "AND wiki_references.link_type in ('#{LINKED_PAGE}', '#{WANTED_PAGE}')" + names = connection.select_all(sanitize_sql([query, page_name])).map { |row| row['name'] } + end + + def self.pages_that_include(page_name) + query = 'SELECT name FROM pages JOIN wiki_references ON pages.id = wiki_references.page_id ' + + 'WHERE wiki_references.referenced_name = ? ' + + "AND wiki_references.link_type = '#{INCLUDED_PAGE}'" + names = connection.select_all(sanitize_sql([query, page_name])).map { |row| row['name'] } + end + + def self.pages_in_category(category) + query = 'SELECT name FROM pages JOIN wiki_references ON pages.id = wiki_references.page_id ' + + 'WHERE wiki_references.referenced_name = ? ' + + "AND wiki_references.link_type = '#{CATEGORY}'" + names = connection.select_all(sanitize_sql([query, category])).map { |row| row['name'] } + end + + def self.list_categories + query = "SELECT DISTINCT referenced_name FROM wiki_references WHERE link_type = '#{CATEGORY}'" + connection.select_all(query).map { |row| row['referenced_name'] } + end + + def wiki_link? + linked_page? or wanted_page? + end + + def linked_page? + link_type == LINKED_PAGE + end + + def wanted_page? + link_type == WANTED_PAGE + end + + def included_page? + link_type == INCLUDED_PAGE + end + +end diff --git a/app/models/wiki_service.rb b/app/models/wiki_service.rb deleted file mode 100644 index 6c8c683b..00000000 --- a/app/models/wiki_service.rb +++ /dev/null @@ -1,259 +0,0 @@ -require 'open-uri' -require 'yaml' -require 'madeleine' -require 'madeleine/automatic' -require 'madeleine/zmarshal' - -require 'web' -require 'page' -require 'author' -require 'file_yard' -require 'instiki_errors' - -module AbstractWikiService - - attr_reader :webs, :system - - def authenticate(password) - # system['password'] variant is for compatibility with storages from older versions - password == (@system[:password] || @system['password'] || 'instiki') - end - - def create_web(name, address, password = nil) - @webs[address] = Web.new(self, name, address, password) unless @webs[address] - end - - def delete_web(address) - @webs[address] = nil - end - - def file_yard(web) - raise "Web #{@web.name} does not belong to this wiki service" unless @webs.values.include?(web) - # TODO cache FileYards - FileYard.new("#{self.storage_path}/#{web.address}", web.max_upload_size) - end - - def init_wiki_service - @webs = {} - @system = {} - end - - def edit_web(old_address, new_address, name, markup, color, additional_style, safe_mode = false, - password = nil, published = false, brackets_only = false, count_pages = false, - allow_uploads = true, max_upload_size = nil) - - if not @webs.key? old_address - raise Instiki::ValidationError.new("Web with address '#{old_address}' does not exist") - end - - if old_address != new_address - if @webs.key? new_address - raise Instiki::ValidationError.new("There is already a web with address '#{new_address}'") - end - @webs[new_address] = @webs[old_address] - @webs.delete(old_address) - @webs[new_address].address = new_address - end - - web = @webs[new_address] - web.refresh_revisions if settings_changed?(web, markup, safe_mode, brackets_only) - - web.name, web.markup, web.color, web.additional_style, web.safe_mode = - name, markup, color, additional_style, safe_mode - - web.password, web.published, web.brackets_only, web.count_pages = - password, published, brackets_only, count_pages, allow_uploads - web.allow_uploads, web.max_upload_size = allow_uploads, max_upload_size.to_i - end - - def read_page(web_address, page_name) - ApplicationController.logger.debug "Reading page '#{page_name}' from web '#{web_address}'" - web = @webs[web_address] - if web.nil? - ApplicationController.logger.debug "Web '#{web_address}' not found" - return nil - else - page = web.pages[page_name] - ApplicationController.logger.debug "Page '#{page_name}' #{page.nil? ? 'not' : ''} found" - return page - end - end - - def remove_orphaned_pages(web_address) - @webs[web_address].remove_pages(@webs[web_address].select.orphaned_pages) - end - - def revise_page(web_address, page_name, content, revised_on, author) - page = read_page(web_address, page_name) - page.revise(content, revised_on, author) - end - - def rollback_page(web_address, page_name, revision_number, created_at, author_id = nil) - page = read_page(web_address, page_name) - page.rollback(revision_number, created_at, author_id) - end - - def setup(password, web_name, web_address) - @system[:password] = password - create_web(web_name, web_address) - end - - def setup? - not (@webs.empty?) - end - - def storage_path - self.class.storage_path - end - - def write_page(web_address, page_name, content, written_on, author) - @webs[web_address].add_page(page_name, content, written_on, author) - end - - private - def settings_changed?(web, markup, safe_mode, brackets_only) - web.markup != markup || - web.safe_mode != safe_mode || - web.brackets_only != brackets_only - end -end - -class WikiService - - include AbstractWikiService - include Madeleine::Automatic::Interceptor - - # These methods do not change the state of persistent objects, and - # should not be logged by Madeleine - automatic_read_only :authenticate, :read_page, :setup?, :webs, :storage_path, :file_yard - - @@storage_path = './storage/' - - class << self - - def check_snapshot_thread - # @madeleine may not be initialised in unit tests, and in such case there is no need to do anything - @madeleine.check_snapshot_thread unless @madeleine.nil? - end - - def clean_storage - MadeleineServer.clean_storage(self) - end - - # One interesting property of Madeleine as persistence mechanism is that it saves - # (and restores) the whole ObjectSpace. And in there, storage from older version may contain - # who knows what in temporary variables, such as caches of various kinds. - # The reason why it is nearly impossible to control is that there may be bugs, people may - # use modified versions of things, etc etc etc - # Therefore, upon loading the storage from a file, it is a good idea to clear all such - # variables. It would be better yet if Madeleine could be somehow instructed not to save that - # data in a snapshot at all. Alas, such a feature is not presently available. - def clear_all_caches - return if @system.webs.nil? - @system.webs.each_value do |web| - next if web.nil? or web.pages.nil? - web.pages.each_value do |page| - next if page.nil? or page.revisions.nil? - page.revisions.each { |revision| revision.clear_display_cache } - end - end - end - - def instance - @madeleine ||= MadeleineServer.new(self) - @system = @madeleine.system - clear_all_caches - return @system - end - - def snapshot - @madeleine.snapshot - end - - def storage_path=(storage_path) - @@storage_path = storage_path - end - - def storage_path - @@storage_path - end - - end - - def initialize - init_wiki_service - end - -end - -class MadeleineServer - - attr_reader :storage_path - - # Clears all the command_log and snapshot files located in the storage directory, so the - # database is essentially dropped and recreated as blank - def self.clean_storage(service) - begin - Dir.foreach(service.storage_path) do |file| - if file =~ /(command_log|snapshot)$/ - File.delete(File.join(service.storage_path, file)) - end - end - rescue - Dir.mkdir(service.storage_path) - end - end - - def initialize(service) - @storage_path = service.storage_path - @server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path, - Madeleine::ZMarshal.new) { - service.new - } - @snapshoot_thread_running = false - end - - def command_log_present? - not Dir[storage_path + '/*.command_log'].empty? - end - - def snapshot - @server.take_snapshot - end - - def check_snapshot_thread - start_snapshot_thread unless @snapshoot_thread_running - end - - def start_snapshot_thread - @snapshoot_thread_running = true - Thread.new(@server) { - hours_since_last_snapshot = 0 - while true - begin - hours_since_last_snapshot += 1 - # Take a snapshot if there is a command log, or 24 hours - # have passed since the last snapshot - if command_log_present? or hours_since_last_snapshot >= 24 - ActionController::Base.logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] " + - 'Taking a Madeleine snapshot' - snapshot - hours_since_last_snapshot = 0 - end - sleep(1.hour) - rescue => e - ActionController::Base.logger.error(e) - # wait for a minute (not to spoof the log with the same error) - # and go back into the loop, to keep trying - sleep(1.minute) - ActionController::Base.logger.info("Retrying to save a snapshot") - end - end - } - end - - def system - @server.system - end - -end diff --git a/app/views/layouts/default.rhtml b/app/views/layouts/default.rhtml index eb1472aa..fb5e550e 100644 --- a/app/views/layouts/default.rhtml +++ b/app/views/layouts/default.rhtml @@ -14,7 +14,8 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - + + - - - HTML - puts RedCloth.new( File.open( file_name ).read ).to_html - puts "" - puts "" -when 'QUICK-REFERENCE' - YAML::add_private_type( "example" ) do |type, val| - esc = val.dup - esc.htmlesc!( :NoQuotes ) - [ :example, esc.gsub( /\n/, '
' ), - RedCloth.new( val ).to_html ] - end - - content = YAML::load( File.open( 'REFERENCE' ) ) - - sections = content.collect { |c| c.keys.first } - sections.shift - - puts <<-HTML - - - - - Textile Quick Reference - - - - - - - HTML - - ct = 0 - content.each do |section| - section.each do |header, parags| - puts "" if ct.nonzero? - parags.each do |p| - if p.is_a?( Array ) and p[0] == :example - puts "" + - "" - end - end - end - ct += 1 - end - puts "

Textile Quick Reference

Sections: #{ sections.collect { |s| "#{ s.gsub( /\s/, ' ' ) }" }.join( ' | ' ) }
#{ header }
#{ p[1] }
#{ p[2] }
" - puts "" - puts "" - -when 'REFERENCE' - YAML::add_private_type( "example" ) do |type, val| - esc = val.dup - esc.htmlesc!( :NoQuotes ) - [ esc.gsub( /\n/, '
' ), - RedCloth.new( val ).to_html. - gsub( /;(\w)/, '; \1' ). - htmlesc!( :NoQuotes ). - gsub( /\n/, '
' ), - RedCloth.new( val ).to_html ] - end - - content = YAML::load( File.open( file_name ) ) - - sections = content.collect { |c| c.keys.first } - sections.shift - - puts <<-HTML - - - - - Textile Reference - - - - - - HTML - - ct = 0 - content.each do |section| - section.each do |header, parags| - if ct.zero? - puts "" - puts "" - else - puts "" - end - parags.each do |p| - if p.is_a? Array - puts "" + - "" + - "" - else - puts "" - end - end - unless ct.zero? - puts "" - end - end - ct += 1 - end - puts "

#{ header }

Sections: #{ sections.collect { |s| "#{ s.gsub( /\s/, ' ' ) }" }.join( ' | ' ) }
#{ ct }.
#{ header }
#{ p[0] }

#{ p[1] }

#{ p[2] }
" - puts RedCloth.new( p ).to_html - puts "
" - puts "" - puts "" -end diff --git a/vendor/RedCloth-3.0.3/install.rb b/vendor/RedCloth-3.0.3/install.rb deleted file mode 100644 index 2313f9e9..00000000 --- a/vendor/RedCloth-3.0.3/install.rb +++ /dev/null @@ -1,1032 +0,0 @@ -#!/usr/local/bin/ruby -# -# This file is automatically generated. DO NOT MODIFY! -# -# install.rb -# -# Copyright (c) 2000-2002 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU Lesser General Public License version 2. -# - -### begin compat.rb - -unless Enumerable.instance_methods.include? 'inject' then -module Enumerable - def inject( result ) - each do |i| - result = yield(result, i) - end - result - end -end -end - -def File.read_all( fname ) - File.open(fname, 'rb') {|f| return f.read } -end - -def File.write( fname, str ) - File.open(fname, 'wb') {|f| f.write str } -end - -### end compat.rb -### begin config.rb - -if i = ARGV.index(/\A--rbconfig=/) then - file = $' - ARGV.delete_at(i) - require file -else - require 'rbconfig' -end - - -class ConfigTable - - c = ::Config::CONFIG - - rubypath = c['bindir'] + '/' + c['ruby_install_name'] - - major = c['MAJOR'].to_i - minor = c['MINOR'].to_i - teeny = c['TEENY'].to_i - version = "#{major}.#{minor}" - - # ruby ver. >= 1.4.4? - newpath_p = ((major >= 2) or - ((major == 1) and - ((minor >= 5) or - ((minor == 4) and (teeny >= 4))))) - - re = Regexp.new('\A' + Regexp.quote(c['prefix'])) - subprefix = lambda {|path| - re === path and path.sub(re, '$prefix') - } - - if c['rubylibdir'] then - # 1.6.3 < V - stdruby = subprefix.call(c['rubylibdir']) - siteruby = subprefix.call(c['sitedir']) - versite = subprefix.call(c['sitelibdir']) - sodir = subprefix.call(c['sitearchdir']) - elsif newpath_p then - # 1.4.4 <= V <= 1.6.3 - stdruby = "$prefix/lib/ruby/#{version}" - siteruby = subprefix.call(c['sitedir']) - versite = siteruby + '/' + version - sodir = "$site-ruby/#{c['arch']}" - else - # V < 1.4.4 - stdruby = "$prefix/lib/ruby/#{version}" - siteruby = "$prefix/lib/ruby/#{version}/site_ruby" - versite = siteruby - sodir = "$site-ruby/#{c['arch']}" - end - - DESCRIPTER = [ - [ 'prefix', [ c['prefix'], - 'path', - 'path prefix of target environment' ] ], - [ 'std-ruby', [ stdruby, - 'path', - 'the directory for standard ruby libraries' ] ], - [ 'site-ruby-common', [ siteruby, - 'path', - 'the directory for version-independent non-standard ruby libraries' ] ], - [ 'site-ruby', [ versite, - 'path', - 'the directory for non-standard ruby libraries' ] ], - [ 'bin-dir', [ '$prefix/bin', - 'path', - 'the directory for commands' ] ], - [ 'rb-dir', [ '$site-ruby', - 'path', - 'the directory for ruby scripts' ] ], - [ 'so-dir', [ sodir, - 'path', - 'the directory for ruby extentions' ] ], - [ 'data-dir', [ '$prefix/share', - 'path', - 'the directory for shared data' ] ], - [ 'ruby-path', [ rubypath, - 'path', - 'path to set to #! line' ] ], - [ 'ruby-prog', [ rubypath, - 'name', - 'the ruby program using for installation' ] ], - [ 'make-prog', [ 'make', - 'name', - 'the make program to compile ruby extentions' ] ], - [ 'without-ext', [ 'no', - 'yes/no', - 'does not compile/install ruby extentions' ] ] - ] - - SAVE_FILE = 'config.save' - - def ConfigTable.each_name( &block ) - keys().each( &block ) - end - - def ConfigTable.keys - DESCRIPTER.collect {|k,*dummy| k } - end - - def ConfigTable.each_definition( &block ) - DESCRIPTER.each( &block ) - end - - def ConfigTable.get_entry( name ) - name, ent = DESCRIPTER.assoc(name) - ent - end - - def ConfigTable.get_entry!( name ) - get_entry(name) or raise ArgumentError, "no such config: #{name}" - end - - def ConfigTable.add_entry( name, vals ) - ConfigTable::DESCRIPTER.push [name,vals] - end - - def ConfigTable.remove_entry( name ) - get_entry name or raise ArgumentError, "no such config: #{name}" - DESCRIPTER.delete_if {|n,arr| n == name } - end - - def ConfigTable.config_key?( name ) - get_entry(name) ? true : false - end - - def ConfigTable.bool_config?( name ) - ent = get_entry(name) or return false - ent[1] == 'yes/no' - end - - def ConfigTable.value_config?( name ) - ent = get_entry(name) or return false - ent[1] != 'yes/no' - end - - def ConfigTable.path_config?( name ) - ent = get_entry(name) or return false - ent[1] == 'path' - end - - - class << self - - alias newobj new - - def new - c = newobj() - c.__send__ :init - c - end - - def load - c = newobj() - File.file? SAVE_FILE or - raise InstallError, "#{File.basename $0} config first" - File.foreach( SAVE_FILE ) do |line| - k, v = line.split( '=', 2 ) - c.instance_eval { - @table[k] = v.strip - } - end - c - end - - end - - def initialize - @table = {} - end - - def init - DESCRIPTER.each do |k, (default, vname, desc, default2)| - @table[k] = default - end - end - private :init - - def save - File.open( SAVE_FILE, 'w' ) {|f| - @table.each do |k, v| - f.printf "%s=%s\n", k, v if v - end - } - end - - def []=( k, v ) - ConfigTable.config_key? k or raise InstallError, "unknown config option #{k}" - if ConfigTable.path_config? k then - @table[k] = (v[0,1] != '$') ? File.expand_path(v) : v - else - @table[k] = v - end - end - - def []( key ) - @table[key] or return nil - @table[key].gsub( %r<\$([^/]+)> ) { self[$1] } - end - - def set_raw( key, val ) - @table[key] = val - end - - def get_raw( key ) - @table[key] - end - -end - - -class MetaConfigEnvironment - - def self.eval_file( file ) - return unless File.file? file - new.instance_eval File.read_all(file), file, 1 - end - - private - - def config_names - ConfigTable.keys - end - - def config?( name ) - ConfigTable.config_key? name - end - - def bool_config?( name ) - ConfigTable.bool_config? name - end - - def value_config?( name ) - ConfigTable.value_config? name - end - - def path_config?( name ) - ConfigTable.path_config? name - end - - def add_config( name, argname, default, desc ) - ConfigTable.add_entry name,[default,argname,desc] - end - - def add_path_config( name, default, desc ) - add_config name, 'path', default, desc - end - - def add_bool_config( name, default, desc ) - add_config name, 'yes/no', default ? 'yes' : 'no', desc - end - - def set_config_default( name, default ) - if bool_config? name then - ConfigTable.get_entry!(name)[0] = default ? 'yes' : 'no' - else - ConfigTable.get_entry!(name)[0] = default - end - end - - def remove_config( name ) - ent = ConfigTable.get_entry(name) - ConfigTable.remove_entry name - ent - end - -end - -### end config.rb -### begin fileop.rb - -module FileOperations - - def mkdir_p( dname, prefix = nil ) - dname = prefix + dname if prefix - $stderr.puts "mkdir -p #{dname}" if verbose? - return if no_harm? - - # does not check '/'... it's too abnormal case - dirs = dname.split(%r_(?=/)_) - if /\A[a-z]:\z/i === dirs[0] then - disk = dirs.shift - dirs[0] = disk + dirs[0] - end - dirs.each_index do |idx| - path = dirs[0..idx].join('') - Dir.mkdir path unless dir? path - end - end - - def rm_f( fname ) - $stderr.puts "rm -f #{fname}" if verbose? - return if no_harm? - - if File.exist? fname or File.symlink? fname then - File.chmod 0777, fname - File.unlink fname - end - end - - def rm_rf( dn ) - $stderr.puts "rm -rf #{dn}" if verbose? - return if no_harm? - - Dir.chdir dn - Dir.foreach('.') do |fn| - next if fn == '.' - next if fn == '..' - if dir? fn then - verbose_off { - rm_rf fn - } - else - verbose_off { - rm_f fn - } - end - end - Dir.chdir '..' - Dir.rmdir dn - end - - def mv( src, dest ) - rm_f dest - begin - File.link src, dest - rescue - File.write dest, File.read_all(src) - File.chmod File.stat(src).mode, dest - end - rm_f src - end - - def install( from, dest, mode, prefix = nil ) - $stderr.puts "install #{from} #{dest}" if verbose? - return if no_harm? - - realdest = prefix + dest if prefix - if dir? realdest then - realdest += '/' + File.basename(from) - end - str = File.read_all(from) - if diff? str, realdest then - verbose_off { - rm_f realdest if File.exist? realdest - } - File.write realdest, str - File.chmod mode, realdest - - File.open( objdir + '/InstalledFiles', 'a' ) {|f| f.puts realdest } - end - end - - def diff?( orig, targ ) - return true unless File.exist? targ - orig != File.read_all(targ) - end - - def command( str ) - $stderr.puts str if verbose? - system str or raise RuntimeError, "'system #{str}' failed" - end - - def ruby( str ) - command config('ruby-prog') + ' ' + str - end - - def dir?( dname ) - # for corrupted windows stat() - File.directory?( (dname[-1,1] == '/') ? dname : dname + '/' ) - end - - def all_files( dname ) - Dir.open( dname ) {|d| - return d.find_all {|n| File.file? "#{dname}/#{n}" } - } - end - - def all_dirs( dname ) - Dir.open( dname ) {|d| - return d.find_all {|n| dir? "#{dname}/#{n}" } - %w(. ..) - } - end - -end - -### end fileop.rb -### begin base.rb - -class InstallError < StandardError; end - - -class Installer - - Version = '3.1.2' - Copyright = 'Copyright (c) 2000-2002 Minero Aoki' - - - @toplevel = nil - - def self.declear_toplevel_installer( inst ) - @toplevel and - raise ArgumentError, 'more than one toplevel installer decleared' - @toplevel = inst - end - - def self.toplevel_installer - @toplevel - end - - - FILETYPES = %w( bin lib ext data ) - - include FileOperations - - def initialize( config, opt, srcroot, objroot ) - @config = config - @options = opt - @srcdir = File.expand_path(srcroot) - @objdir = File.expand_path(objroot) - @currdir = '.' - end - - def inspect - "#<#{type} #{__id__}>" - end - - # - # configs/options - # - - def get_config( key ) - @config[key] - end - - alias config get_config - - def set_config( key, val ) - @config[key] = val - end - - def no_harm? - @options['no-harm'] - end - - def verbose? - @options['verbose'] - end - - def verbose_off - save, @options['verbose'] = @options['verbose'], false - yield - @options['verbose'] = save - end - - # - # srcdir/objdir - # - - attr_reader :srcdir - alias srcdir_root srcdir - alias package_root srcdir - - def curr_srcdir - "#{@srcdir}/#{@currdir}" - end - - attr_reader :objdir - alias objdir_root objdir - - def curr_objdir - "#{@objdir}/#{@currdir}" - end - - def srcfile( path ) - curr_srcdir + '/' + path - end - - def srcexist?( path ) - File.exist? srcfile(path) - end - - def srcdirectory?( path ) - dir? srcfile(path) - end - - def srcfile?( path ) - File.file? srcfile(path) - end - - def srcentries( path = '.' ) - Dir.open( curr_srcdir + '/' + path ) {|d| - return d.to_a - %w(. ..) - hookfilenames - } - end - - def srcfiles( path = '.' ) - srcentries(path).find_all {|fname| - File.file? File.join(curr_srcdir, path, fname) - } - end - - def srcdirectories( path = '.' ) - srcentries(path).find_all {|fname| - dir? File.join(curr_srcdir, path, fname) - } - end - - def dive_into( rel ) - return unless dir? "#{@srcdir}/#{rel}" - - dir = File.basename(rel) - Dir.mkdir dir unless dir? dir - save = Dir.pwd - Dir.chdir dir - $stderr.puts '---> ' + rel if verbose? - @currdir = rel - yield - Dir.chdir save - $stderr.puts '<--- ' + rel if verbose? - @currdir = File.dirname(rel) - end - - # - # config - # - - def exec_config - exec_task_traverse 'config' - end - - def config_dir_bin( rel ) - end - - def config_dir_lib( rel ) - end - - def config_dir_ext( rel ) - extconf if extdir? curr_srcdir - end - - def extconf - opt = @options['config-opt'].join(' ') - command "#{config('ruby-prog')} #{curr_srcdir}/extconf.rb #{opt}" - end - - def config_dir_data( rel ) - end - - # - # setup - # - - def exec_setup - exec_task_traverse 'setup' - end - - def setup_dir_bin( relpath ) - all_files( curr_srcdir ).each do |fname| - add_rubypath "#{curr_srcdir}/#{fname}" - end - end - - SHEBANG_RE = /\A\#!\s*\S*ruby\S*/ - - def add_rubypath( path ) - $stderr.puts %Q if verbose? - return if no_harm? - - tmpfile = File.basename(path) + '.tmp' - begin - File.open( path ) {|r| - File.open( tmpfile, 'w' ) {|w| - first = r.gets - return unless SHEBANG_RE === first # reject '/usr/bin/env ruby' - - w.print first.sub( SHEBANG_RE, '#!' + config('ruby-path') ) - w.write r.read - } } - mv tmpfile, File.basename(path) - ensure - rm_f tmpfile if File.exist? tmpfile - end - end - - def setup_dir_lib( relpath ) - end - - def setup_dir_ext( relpath ) - if extdir? curr_srcdir then - make - end - end - - def make - command config('make-prog') - end - - def setup_dir_data( relpath ) - end - - # - # install - # - - def exec_install - exec_task_traverse 'install' - end - - def install_dir_bin( rel ) - install_files targfiles, config('bin-dir') + '/' + rel, 0755 - end - - def install_dir_lib( rel ) - install_files targfiles, config('rb-dir') + '/' + rel, 0644 - begin - require 'rdoc/rdoc' - ri_site = true - if RDOC_VERSION =~ /^0\./ - require 'rdoc/options' - unless Options::OptionList::OPTION_LIST.assoc('--ri-site') - ri_site = false - end - end - if ri_site - r = RDoc::RDoc.new - r.document(%w{--ri-site}) - end - rescue - puts "** Unable to install Ri documentation for RedCloth **" - end - end - - def install_dir_ext( rel ) - if extdir? curr_srcdir then - install_dir_ext_main File.dirname(rel) - end - end - - def install_dir_ext_main( rel ) - install_files allext('.'), config('so-dir') + '/' + rel, 0555 - end - - def install_dir_data( rel ) - install_files targfiles, config('data-dir') + '/' + rel, 0644 - end - - def install_files( list, dest, mode ) - mkdir_p dest, @options['install-prefix'] - list.each do |fname| - install fname, dest, mode, @options['install-prefix'] - end - end - - def targfiles - (targfilenames() - hookfilenames()).collect {|fname| - File.exist?(fname) ? fname : File.join(curr_srcdir(), fname) - } - end - - def targfilenames - [ curr_srcdir(), '.' ].inject([]) {|ret, dir| - ret | all_files(dir) - } - end - - def hookfilenames - %w( pre-%s post-%s pre-%s.rb post-%s.rb ).collect {|fmt| - %w( config setup install clean ).collect {|t| sprintf fmt, t } - }.flatten - end - - def allext( dir ) - _allext(dir) or raise InstallError, - "no extention exists: Have you done 'ruby #{$0} setup' ?" - end - - DLEXT = /\.#{ ::Config::CONFIG['DLEXT'] }\z/ - - def _allext( dir ) - Dir.open( dir ) {|d| - return d.find_all {|fname| DLEXT === fname } - } - end - - # - # clean - # - - def exec_clean - exec_task_traverse 'clean' - rm_f 'config.save' - rm_f 'InstalledFiles' - end - - def clean_dir_bin( rel ) - end - - def clean_dir_lib( rel ) - end - - def clean_dir_ext( rel ) - clean - end - - def clean - command config('make-prog') + ' clean' if File.file? 'Makefile' - end - - def clean_dir_data( rel ) - end - - # - # lib - # - - def exec_task_traverse( task ) - run_hook 'pre-' + task - FILETYPES.each do |type| - if config('without-ext') == 'yes' and type == 'ext' then - $stderr.puts 'skipping ext/* by user option' if verbose? - next - end - traverse task, type, task + '_dir_' + type - end - run_hook 'post-' + task - end - - def traverse( task, rel, mid ) - dive_into( rel ) { - run_hook 'pre-' + task - __send__ mid, rel.sub( %r_\A.*?(?:/|\z)_, '' ) - all_dirs( curr_srcdir ).each do |d| - traverse task, rel + '/' + d, mid - end - run_hook 'post-' + task - } - end - - def run_hook( name ) - try_run_hook curr_srcdir + '/' + name or - try_run_hook curr_srcdir + '/' + name + '.rb' - end - - def try_run_hook( fname ) - return false unless File.file? fname - - env = self.dup - begin - env.instance_eval File.read_all(fname), fname, 1 - rescue - raise InstallError, "hook #{fname} failed:\n" + $!.message - end - true - end - - def extdir?( dir ) - File.exist? dir + '/MANIFEST' - end - -end - -### end base.rb -### begin toplevel.rb - -class ToplevelInstaller < Installer - - TASKS = [ - [ 'config', 'saves your configurations' ], - [ 'show', 'shows current configuration' ], - [ 'setup', 'compiles extention or else' ], - [ 'install', 'installs files' ], - [ 'clean', "does `make clean' for each extention" ] - ] - - - def initialize( root ) - super nil, {'verbose' => true}, root, '.' - Installer.declear_toplevel_installer self - end - - - def execute - run_metaconfigs - - case task = parsearg_global() - when 'config' - @config = ConfigTable.new - else - @config = ConfigTable.load - end - parsearg_TASK task - - exectask task - end - - - def run_metaconfigs - MetaConfigEnvironment.eval_file "#{srcdir_root}/#{metaconfig}" - end - - def metaconfig - 'metaconfig' - end - - - def exectask( task ) - if task == 'show' then - exec_show - else - try task - end - end - - def try( task ) - $stderr.printf "#{File.basename $0}: entering %s phase...\n", task if verbose? - begin - __send__ 'exec_' + task - rescue - $stderr.printf "%s failed\n", task - raise - end - $stderr.printf "#{File.basename $0}: %s done.\n", task if verbose? - end - - # - # processing arguments - # - - def parsearg_global - task_re = /\A(?:#{TASKS.collect {|i| i[0] }.join '|'})\z/ - - while arg = ARGV.shift do - case arg - when /\A\w+\z/ - task_re === arg or raise InstallError, "wrong task: #{arg}" - return arg - - when '-q', '--quiet' - @options['verbose'] = false - - when '--verbose' - @options['verbose'] = true - - when '-h', '--help' - print_usage $stdout - exit 0 - - when '-v', '--version' - puts "#{File.basename $0} version #{Version}" - exit 0 - - when '--copyright' - puts Copyright - exit 0 - - else - raise InstallError, "unknown global option '#{arg}'" - end - end - - raise InstallError, 'no task or global option given' - end - - - def parsearg_TASK( task ) - mid = "parsearg_#{task}" - if respond_to? mid, true then - __send__ mid - else - ARGV.empty? or - raise InstallError, "#{task}: unknown options: #{ARGV.join ' '}" - end - end - - def parsearg_config - re = /\A--(#{ConfigTable.keys.join '|'})(?:=(.*))?\z/ - @options['config-opt'] = [] - - while i = ARGV.shift do - if /\A--?\z/ === i then - @options['config-opt'] = ARGV.dup - break - end - m = re.match(i) or raise InstallError, "config: unknown option #{i}" - name, value = m.to_a[1,2] - if value then - if ConfigTable.bool_config?(name) then - /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i === value or raise InstallError, "config: --#{name} allows only yes/no for argument" - value = (/\Ay(es)?|\At(rue)/i === value) ? 'yes' : 'no' - end - else - ConfigTable.bool_config?(name) or raise InstallError, "config: --#{name} requires argument" - value = 'yes' - end - @config[name] = value - end - end - - def parsearg_install - @options['no-harm'] = false - @options['install-prefix'] = '' - while a = ARGV.shift do - case a - when /\A--no-harm\z/ - @options['no-harm'] = true - when /\A--prefix=(.*)\z/ - path = $1 - path = File.expand_path(path) unless path[0,1] == '/' - @options['install-prefix'] = path - else - raise InstallError, "install: unknown option #{a}" - end - end - end - - - def print_usage( out ) - out.puts - out.puts 'Usage:' - out.puts " ruby #{File.basename $0} " - out.puts " ruby #{File.basename $0} [] []" - - fmt = " %-20s %s\n" - out.puts - out.puts 'Global options:' - out.printf fmt, '-q,--quiet', 'suppress message outputs' - out.printf fmt, ' --verbose', 'output messages verbosely' - out.printf fmt, '-h,--help', 'print this message' - out.printf fmt, '-v,--version', 'print version and quit' - out.printf fmt, '--copyright', 'print copyright and quit' - - out.puts - out.puts 'Tasks:' - TASKS.each do |name, desc| - out.printf " %-10s %s\n", name, desc - end - - out.puts - out.puts 'Options for config:' - ConfigTable.each_definition do |name, (default, arg, desc, default2)| - out.printf " %-20s %s [%s]\n", - '--'+ name + (ConfigTable.bool_config?(name) ? '' : '='+arg), - desc, - default2 || default - end - out.printf " %-20s %s [%s]\n", - '--rbconfig=path', 'your rbconfig.rb to load', "running ruby's" - - out.puts - out.puts 'Options for install:' - out.printf " %-20s %s [%s]\n", - '--no-harm', 'only display what to do if given', 'off' - - out.puts - end - - # - # config - # - - def exec_config - super - @config.save - end - - # - # show - # - - def exec_show - ConfigTable.each_name do |k| - v = @config.get_raw(k) - if not v or v.empty? then - v = '(not specified)' - end - printf "%-10s %s\n", k, v - end - end - -end - -### end toplevel.rb - -if $0 == __FILE__ then - begin - installer = ToplevelInstaller.new( Dir.pwd ) - installer.execute - rescue - raise if $DEBUG - $stderr.puts $!.message - $stderr.puts "try 'ruby #{$0} --help' for usage" - exit 1 - end -end diff --git a/vendor/RedCloth-3.0.3/run-tests.rb b/vendor/RedCloth-3.0.3/run-tests.rb deleted file mode 100644 index 65b5c969..00000000 --- a/vendor/RedCloth-3.0.3/run-tests.rb +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env ruby -require 'lib/redcloth' -require 'yaml' - -Dir["tests/*.yml"].each do |testfile| - YAML::load_documents( File.open( testfile ) ) do |doc| - if doc['in'] and doc['out'] - red = RedCloth.new( doc['in'] ) - html = if testfile =~ /markdown/ - red.to_html( :markdown ) - else - red.to_html - end - puts "---" - - html.gsub!( /\n+/, "\n" ) - doc['out'].gsub!( /\n+/, "\n" ) - if html == doc['out'] - puts "success: true" - else - puts "out: "; p html - puts "expected: "; p doc['out'] - end - end - end -end diff --git a/vendor/RedCloth-3.0.3/tests/code.yml b/vendor/RedCloth-3.0.3/tests/code.yml deleted file mode 100644 index bc7bd2cc..00000000 --- a/vendor/RedCloth-3.0.3/tests/code.yml +++ /dev/null @@ -1,105 +0,0 @@ ---- -in: 'This is an empty dictionary: @{}@' -out: '

This is an empty dictionary: {}

' ---- -in: |- - Testing nested pre tags... - -
-  
-    Good code here.
-
-    
-      a = 1
-    
- - Bad code here. - - -
-
- -out: |- -

Testing nested pre tags…

- - -
-  
-    Good code here.
-  
-    <pre>
-      a = 1
-    </pre>
-  
-    Bad code here.
-  
-    <script language="JavaScript">
-      window.open( "about:blank" );
-    </script>
-  
-  
---- -in: |- -
-  *** test
-  
-out: |- -
-  *** test
-  
---- -in: |- - - *** test - -out: |- - *** test ---- -in: '*this is strong*' -out: '

this is strong

' ---- -in: '*this test is strong*' -out: '

this test is strong

' ---- -in:
 __inline__
-out:
 __inline__
---- -in: |- - * @foo@ - * @bar@ - * and @x@ is also. -out: "
    \n\t
  • foo
  • \n\t\t
  • bar
  • \n\t\t
  • and x is also.
  • \n\t
" ---- -in: |- -
  
-
  
-out: |- -
 <hello> 
-
 <hello> 
---- -in: | - Test of Markdown-style indented code. - - a = [1, 2, 3] - a.each do |x| - puts "test number", x, - "and more!" - end - - Paragraph 2. - - Paragraph 3. -out: |- -

Test of Markdown-style indented code.

- -
a = [1, 2, 3]
-  a.each do |x|
-    puts "test number", x,
-      "and more!" 
-  end
- -

Paragraph 2.

- -

Paragraph 3.

diff --git a/vendor/RedCloth-3.0.3/tests/images.yml b/vendor/RedCloth-3.0.3/tests/images.yml deleted file mode 100644 index d097e0fb..00000000 --- a/vendor/RedCloth-3.0.3/tests/images.yml +++ /dev/null @@ -1,171 +0,0 @@ ---- -in: This is an !image.jpg! -out:

This is an

---- -in: This is an !image.jpg(with alt text)! -out:

This is an with alt text

---- -in: This is an !http://example.com/i/image.jpg! -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg#a1! -out:

This is an

---- -in: This is an !image.jpg!. -out:

This is an .

---- -in: This is an !image.jpg(with alt text)!. -out:

This is an with alt text.

---- -in: This is an !http://example.com/i/image.jpg!. -out:

This is an .

---- -in: This is an !http://example.com/i/image.jpg#a1!. -out:

This is an .

---- -in: This is not an image!!! -out:

This is not an image!!!

---- -in: This is an !http://example.com/i/image.jpg!:#1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:#a -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:#a1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:#a10 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:index.html -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:index.html#1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:index.html#a1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:index.html#a10 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:index.html?foo=bar -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:index.html?foo=bar#1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:index.html?foo=bar#a -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:index.html?foo=bar#a1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:index.html?foo=bar#a10 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/ -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/#1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/#a -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/#a1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/#a10 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html#1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html#a -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html#a1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html#a10 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#a -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#a1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#a10 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10 -out:

This is an

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b. -out:

This is an .

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1. -out:

This is an .

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a. -out:

This is an .

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1. -out:

This is an .

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10. -out:

This is an .

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b, but this is not. -out:

This is an , but this is not.

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1, but this is not. -out:

This is an , but this is not.

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a, but this is not. -out:

This is an , but this is not.

---- -in: This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1, but this is not. -out:

This is an , but this is not.

---- -in: (This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10) This is not. -out:

(This is an ) This is not.

---- -in: (This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b) This is not. -out:

(This is an ) This is not.

---- -in: (This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1) This is not. -out:

(This is an ) This is not.

---- -in: (This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a) This is not. -out:

(This is an ) This is not.

---- -in: (This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1) This is not. -out:

(This is an ) This is not.

---- -in: (This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10) This is not. -out:

(This is an ) This is not.

diff --git a/vendor/RedCloth-3.0.3/tests/instiki.yml b/vendor/RedCloth-3.0.3/tests/instiki.yml deleted file mode 100644 index 89b8ec6b..00000000 --- a/vendor/RedCloth-3.0.3/tests/instiki.yml +++ /dev/null @@ -1,39 +0,0 @@ ---- # Bugs filed at http://www.instiki.org/show/BugReports -in: |- - _Hi, Joe Bob?, this should all be in italic!_ -out: |- -

Hi, Joe Bob?, this should all be in italic!

---- -in: '*this span is strong*' -out: '

this span is strong

' ---- -in: '*this Camel Thing? is strong*' -out: '

this Camel Thing? is strong

' ---- -in: '_this span is italic_' -out: '

this span is italic

' ---- -in: '%{color:red}nested span because of Camel Word?%' -out: '

nested span because of Camel Word?

' ---- -in: |- - h2. Version History - - * "Version - 0.0":http://www.threewordslong.com/render-0-8-9b.patch - Early version using MD5 hashes. - * "Version - 0.1":http://www.threewordslong.com/chunk-0-1.patch.gz - First cut of new system. Much cleaner. - * "Version 0.2":http://www.threewordslong.com/chunk-0-2.patch.gz - Fixed problem with "authors" page and some tests. -out: |- -

Version History

- -
    -
  • Version - 0.0 – Early version using MD5 hashes.
  • -
  • Version - 0.1 – First cut of new system. Much cleaner.
  • -
  • Version 0.2 – Fixed problem with “authors” page and some tests.
  • -
---- -in: "--richSeymour --whyTheLuckyStiff" -out: "

—richSeymour—whyTheLuckyStiff

" diff --git a/vendor/RedCloth-3.0.3/tests/links.yml b/vendor/RedCloth-3.0.3/tests/links.yml deleted file mode 100644 index 16b63331..00000000 --- a/vendor/RedCloth-3.0.3/tests/links.yml +++ /dev/null @@ -1,155 +0,0 @@ ---- -in: '"link text":#1' -out:

link text

---- -in: '"link text":#a' -out:

link text

---- -in: '"link text":#a1' -out:

link text

---- -in: '"link text":#a10' -out:

link text

---- -in: '"link text":index.html' -out:

link text

---- -in: '"link text":index.html#1' -out:

link text

---- -in: '"link text":index.html#a' -out:

link text

---- -in: '"link text":index.html#a1' -out:

link text

---- -in: '"link text":index.html#a10' -out:

link text

---- -in: '"link text":http://example.com/' -out:

link text

---- -in: '"link text":http://example.com/#1' -out:

link text

---- -in: '"link text":http://example.com/#a' -out:

link text

---- -in: '"link text":http://example.com/#a1' -out:

link text

---- -in: '"link text":http://example.com/#a10' -out:

link text

---- -in: '"link text":http://example.com/index.html' -out:

link text

---- -in: '"link text":http://example.com/index.html#a' -out:

link text

---- -in: '"link text":http://example.com/index.html#1' -out:

link text

---- -in: '"link text":http://example.com/index.html#a1' -out:

link text

---- -in: '"link text":http://example.com/index.html#a10' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar#a' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar#1' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar#a1' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar#a10' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar&a=b' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar&a=b#1' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar&a=b#a' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar&a=b#a1' -out:

link text

---- -in: '"link text":http://example.com/?foo=bar&a=b#a10' -out:

link text

---- -in: 'This is a "link":http://example.com/' -out:

This is a link

---- -in: 'This is a "link":http://example.com/.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/index.html.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/index.html#a.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/index.html#1.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/index.html#a1.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/index.html#a10.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/?foo=bar.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/?foo=bar#1.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/?foo=bar#a.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/?foo=bar#a1.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/?foo=bar#a10.' -out:

This is a link.

---- -in: 'This is a "link":http://example.com/?foo=bar#a10, but this is not.' -out:

This is a link, but this is not.

---- -in: '(This is a "link":http://example.com/?foo=bar#a10) but this is not.' -out:

(This is a link) but this is not.

---- -in: '"link text(link title)":http://example.com/' -out:

link text

-# --- -# in: '"link text(link title) ":http://example.com/' -# out:

“link text(link title) “:http://example.com/

-# comments: this is a real test and should pass ---- -in: '"(link) text(link title)":http://example.com/' -out:

text

-comments: link text can not contain parentheses ---- -in: '"Dive Into XML":http://www.xml.com/pub/au/164' -out:

Dive Into XML

---- -in: '"Lab Exercises":../lab/exercises/exercises.html.' -out:

Lab Exercises.

---- -in: 'Go to "discuss":http://www.dreammoods.com/cgibin/cutecast/cutecast.pl?forum=1&thread=26627 to discuss.' -out:

Go to discuss to discuss.

---- -in: '* "rubylang":http://www.ruby-lang.org/en/' -out: "" ---- -in: 'The ION coding style document found at "IONCodingStyleGuide.doc":http://perforce:8081/@md=d&cd=//&c=82E@//depot/systest/system/main/pub/doc/IONCodingStyleGuide.doc?ac=22 codifies a couple of rules to ensure reasonably consistent code and documentation of libraries in ION. Test text' -out:

The ION coding style document found at IONCodingStyleGuide.doc codifies a couple of rules to ensure reasonably consistent code and documentation of libraries in ION. Test text

diff --git a/vendor/RedCloth-3.0.3/tests/lists.yml b/vendor/RedCloth-3.0.3/tests/lists.yml deleted file mode 100644 index cf8938f0..00000000 --- a/vendor/RedCloth-3.0.3/tests/lists.yml +++ /dev/null @@ -1,77 +0,0 @@ ---- # Bret Pettichord, Thanks. -in: |- - * first line - * second - line - * third line -out: |- -
    -
  • first line
  • -
  • second - line
  • -
  • third line
  • -
---- -in: |- - p. start - - * one - and one - * two - and two - * three - - p. end -out: |- -

start

-
    -
  • one - and one
  • -
  • two - and two
  • -
  • three
  • -
- -

end

---- -in: |- - Funky: - - * Testing - *# number - *##* bullet - *# number - *# number - yeah number - #* bullet - *** okay - ****# what - - -out: |- -

Funky:

-
    -
  • Testing -
      -
    1. number -
        -
      • bullet
      • -
      -
    2. -
    3. number
    4. -
    5. number - yeah number
    6. -
        -
      • bullet -
          -
        • okay -
            -
          1. what
          2. -
      • -
  • -
- - ---- -in: "* command run: @time ruby run-tests.rb > toto@" -out: "
    \n\t
  • command run: time ruby run-tests.rb > toto
  • \n\t
" diff --git a/vendor/RedCloth-3.0.3/tests/markdown.yml b/vendor/RedCloth-3.0.3/tests/markdown.yml deleted file mode 100644 index a053ea39..00000000 --- a/vendor/RedCloth-3.0.3/tests/markdown.yml +++ /dev/null @@ -1,218 +0,0 @@ -in: | - This is a regular paragraph. - - - - - -
Foo
- - This is another regular paragraph. -out: |- -

This is a regular paragraph.

- - - - - - -
Foo
-

This is another regular paragraph.

---- -in: '"Larry Bird":http://images.google.com/images?num=30&q=larry+bird' -out: '

"Larry Bird":http://images.google.com/images?num=30&q=larry+bird

' ---- -in: '©' -out:

©

---- -in: AT&T -out:

AT&T

- -# We don't do this. -# --- -# in: 4 < 5 -# out: 4 < 5 ---- -in: | - This is an H1 - ============= - - This is an H2 - ------------- -out: |- -

This is an H1

- -

This is an H2

---- -in: | - # This is an H1 - - ## This is an H2 - - ###### This is an H6 -out: |- -

This is an H1

- -

This is an H2

- -
This is an H6
---- -in: | - > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, - > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. - > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. - > - > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse - > id sem consectetuer libero luctus adipiscing. -out: |- -
-

This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, - consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. - Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

- -

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse - id sem consectetuer libero luctus adipiscing.

- -
---- -in: | - > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, - consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. - Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. - > - > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse - id sem consectetuer libero luctus adipiscing. -out: |- -
-

This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, - consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. - Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

- -

Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse - id sem consectetuer libero luctus adipiscing.

- -
---- -in: | - > This is the first level of quoting. - > - > > This is nested blockquote. - > - > Back to the first level. -out: |- -
-

This is the first level of quoting.

-
-

This is nested blockquote.

- -
- - - -

Back to the first level.

- -
---- -in: | - > ## This is a header. - > - > 1. This is the first list item. - > 2. This is the second list item. - > - > Here's some example code: - > - > return shell_exec("echo $input | $markdown_script"); -out: |- -
-

This is a header.

- - - -

1. This is the first list item. - 2. This is the second list item.

- -

Here's some example code:

-
return shell_exec("echo $input | $markdown_script");
- -
---- -in: | - * * * - - *** - - ***** - - - - - - - --------------------------------------- - - _ _ _ -out: |- -
- -
- -
- -
- -
- -
---- -in: | - This is [an example](http://example.com/ "Title") inline link. - - [This link](http://example.net/) has no title attribute. -out: |- -

This is an example inline link.

- -

This link has no title attribute.

---- -in: See my [About](/about/) page for details. -out:

See my About page for details.

---- -in: | - This is [an example][id] reference-style link. - - This is [an example] [id] reference-style link. - - [id]: http://example.com/ "Optional Title Here" -out: |- -

This is an example reference-style link.

- -

This is an example reference-style link.

---- -in: | - [Google][] - [Google]: http://google.com/ -out:

Google

---- -in: | - Visit [Daring Fireball][] for more information. - [Daring Fireball]: http://daringfireball.net/ -out:

Visit Daring Fireball for more information.

---- -in: | - I get 10 times more traffic from [Google] [1] than from - [Yahoo] [2] or [MSN] [3]. - - [1]: http://google.com/ "Google" - [2]: http://search.yahoo.com/ "Yahoo Search" - [3]: http://search.msn.com/ "MSN Search" - -out: |- -

I get 10 times more traffic from Google than from - Yahoo or MSN.

---- -in: | - I get 10 times more traffic from [Google][] than from - [Yahoo][] or [MSN][]. - - [google]: http://google.com/ "Google" - [yahoo]: http://search.yahoo.com/ "Yahoo Search" - [msn]: http://search.msn.com/ "MSN Search" -out: |- -

I get 10 times more traffic from Google than from - Yahoo or MSN.

diff --git a/vendor/RedCloth-3.0.3/tests/poignant.yml b/vendor/RedCloth-3.0.3/tests/poignant.yml deleted file mode 100644 index 1a0f6942..00000000 --- a/vendor/RedCloth-3.0.3/tests/poignant.yml +++ /dev/null @@ -1,64 +0,0 @@ ---- # Tests from the (Poignant Guide) -in: > - h3. False - - - ! - if plastic_cup - print "Plastic cup is on the up 'n' up!" - end - - - - If @plastic_cup@ contains either @nil@ or @false@, you won't see anything print - to the screen. They're not on the @if@ guest list. So @if@ isn't going to run - any of the code it's protecting. - - - But @nil@ and @false@ need not walk away in shame. They may be of questionable - character, but @unless@ runs a smaller establishment that caters to the bedraggled. - The @unless@ keyword has a policy of only allowing those with a negative charge in. - Who are: @nil@ and @false@. - - -
-    unless plastic_cup
-      print "Plastic cup is on the down low."
-    end
-  
- - - You can also use @if@ and @unless@ at the end of a single line of code, if that's - all that is being protected. - - -
-    print "Yeah, plastic cup is up again!" if plastic_cup
-    print "Hardly. It's down." unless plastic_cup
-  
- - - Now that you've met @false@, I'm sure you can see what's on next. - -out: "

False

\n\n\t

\"Shape

\n\n\t

The cat Trady Blix. Frozen in emptiness. Immaculate whiskers rigid. Placid eyes of lake. Tail of warm icicle. Sponsored by a Very Powerful Pause Button.

\n\n\t

The darkness surrounding Blix can be called negative space. Hang on to that phrase. Let it suggest that the emptiness has a negative connotation. In a similar way, nil has a slightly sour note that it whistles.

\n\n\t

Generally speaking, everything in Ruby has a positive charge to it. This spark flows through strings, numbers, regexps, all of it. Only two keywords wear a shady cloak: nil and false draggin us down.

\n\n\t

You can test that charge with an if keyword. It looks very much like the do blocks we saw in the last chapter, in that both end with an end.

\n\n\n
\n  if plastic_cup\n    print \"Plastic cup is on the up 'n' up!\" \n  end\n
\n\t

If plastic_cup contains either nil or false, you won’t see anything print to the screen. They’re not on the if guest list. So if isn’t going to run any of the code it’s protecting.

\n\n\t

But nil and false need not walk away in shame. They may be of questionable character, but unless runs a smaller establishment that caters to the bedraggled. The unless keyword has a policy of only allowing those with a negative charge in. Who are: nil and false.

\n\n\n
\n  unless plastic_cup\n    print \"Plastic cup is on the down low.\" \n  end\n
\n\t

You can also use if and unless at the end of a single line of code, if that’s all that is being protected.

\n\n\n
\n  print \"Yeah, plastic cup is up again!\" if plastic_cup\n  print \"Hardly. It's down.\" unless plastic_cup\n
\n\t

Now that you’ve met false, I’m sure you can see what’s on next.

" diff --git a/vendor/RedCloth-3.0.3/tests/table.yml b/vendor/RedCloth-3.0.3/tests/table.yml deleted file mode 100644 index bf5059e1..00000000 --- a/vendor/RedCloth-3.0.3/tests/table.yml +++ /dev/null @@ -1,198 +0,0 @@ -in: | - {background:#ddd}. |S|Target|Complete|App|Milestone| - |!/i/g.gif!|11/18/04|11/18/04|070|XML spec complete| - |!/i/g.gif!|11/29/04|11/29/04|011|XML spec complete (KH is on schedule)| - |!/i/g.gif!|11/29/04|11/29/04|051|XML spec complete (KH is on schedule)| - |!/i/g.gif!|11/29/04|11/29/04|081|XML spec complete (KH is on schedule)| - |!/i/g.gif!|11/19/04|11/22/04|070|Preprocessor complete| - |!/i/g.gif!|11/22/04|11/22/04|070|Dialog pass 1 builds an index file| - |!/i/g.gif!|11/24/04|11/24/04|070|Dialog pass 2 98% complete| - |!/i/g.gif!|11/30/04|11/30/04|070|Feature complete. Passes end-to-end smoke test.| - |!/i/g.gif!|11/30/04|11/30/04|011|Preprocessor updates complete| - |!/i/g.gif!|11/30/04|11/30/04|051|Preprocessor updates complete| - |!/i/g.gif!|11/30/04|11/29/04|081|Preprocessor updates complete| - |!/i/w.gif!|12/02/04|.|011|Dialog pass 1 and 2 complete (98+%)| - |!/i/w.gif!|12/02/04|.|051|Dialog pass 1 and 2 complete (98+%)| - |!/i/w.gif!|12/02/04|.|081|Dialog pass 1 and 2 complete (98+%)| - |!/i/w.gif!|12/03/04|.|011|Feature complete| - |!/i/w.gif!|12/03/04|.|051|Feature complete| - |!/i/w.gif!|12/03/04|.|081|Feature complete| - |!/i/w.gif!|12/10/04|.|011|Deployed to Napa test workstation. Passes smoke test.| - |!/i/w.gif!|12/10/04|.|051|Deployed to Napa test workstation. Passes smoke test.| - |!/i/w.gif!|12/10/04|.|081|Deployed to Napa test workstation. Passes smoke test.| - |!/i/w.gif!|12/10/04|.|070|Deployed to Napa test workstation. Passes smoke test.| - |!/i/w.gif!|12/17/04|.|011|System testing complete. Begin testing with live customer data.| - |!/i/w.gif!|12/17/04|.|051|System testing complete. Begin testing with live customer data.| - |!/i/w.gif!|12/17/04|.|081|System testing complete. Begin testing with live customer data.| - |!/i/w.gif!|12/17/04|.|070|System testing complete. Begin testing with live customer data.| -out: |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
STargetCompleteAppMilestone
11/18/0411/18/04070XML spec complete
11/29/0411/29/04011XML spec complete (KH is on schedule)
11/29/0411/29/04051XML spec complete (KH is on schedule)
11/29/0411/29/04081XML spec complete (KH is on schedule)
11/19/0411/22/04070Preprocessor complete
11/22/0411/22/04070Dialog pass 1 builds an index file
11/24/0411/24/04070Dialog pass 2 98% complete
11/30/0411/30/04070Feature complete. Passes end-to-end smoke test.
11/30/0411/30/04011Preprocessor updates complete
11/30/0411/30/04051Preprocessor updates complete
11/30/0411/29/04081Preprocessor updates complete
12/02/04011Dialog pass 1 and 2 complete (98+%)
12/02/04051Dialog pass 1 and 2 complete (98+%)
12/02/04081Dialog pass 1 and 2 complete (98+%)
12/03/04011Feature complete
12/03/04051Feature complete
12/03/04081Feature complete
12/10/04011Deployed to Napa test workstation. Passes smoke test.
12/10/04051Deployed to Napa test workstation. Passes smoke test.
12/10/04081Deployed to Napa test workstation. Passes smoke test.
12/10/04070Deployed to Napa test workstation. Passes smoke test.
12/17/04011System testing complete. Begin testing with live customer data.
12/17/04051System testing complete. Begin testing with live customer data.
12/17/04081System testing complete. Begin testing with live customer data.
12/17/04070System testing complete. Begin testing with live customer data.
diff --git a/vendor/RedCloth-3.0.3/tests/textism.yml b/vendor/RedCloth-3.0.3/tests/textism.yml deleted file mode 100644 index 5489c04d..00000000 --- a/vendor/RedCloth-3.0.3/tests/textism.yml +++ /dev/null @@ -1,397 +0,0 @@ ---- -in: h1. Header 1 -out:

Header 1

---- -in: h2. Header 2 -out:

Header 2

---- -in: h3. Header 3 -out:

Header 3

---- -in: |- - Any old text. - - bq. A block quotation. - - Any old text. - -out: |- -

Any old text.

- -
-

A block quotation.

-
- -

Any old text.

- ---- -in: This is covered elsewhere[1]. -out:

This is covered elsewhere1.

---- -in: fn1. Down here, in fact. -out:

1 Down here, in fact.

---- -in: |- - # A first item - # A second item - # A third item - # A fourth item -out: |- -
    -
  1. A first item
  2. -
  3. A second item
  4. -
  5. A third item
  6. -
  7. A fourth item
  8. -
---- -in: |- - * A first item - * A second item - * A third item - * A fourth item - -out: |- -
    -
  • A first item
  • -
  • A second item
  • -
  • A third item
  • -
  • A fourth item
  • -
- ---- -in: _a phrase_ -out:

a phrase

---- -in: __a phrase__ -out:

a phrase

---- -in: '*a phrase*' -out:

a phrase

---- -in: '**a phrase**' -out:

a phrase

---- -in: Nabokov's ??Pnin?? -out:

Nabokov’s Pnin

---- -in: -a phrase- -out:

a phrase

---- -in: +a phrase+ -out:

a phrase

---- -in: ^a phrase^ -out:

a phrase

---- -in: ~a phrase~ -out:

a phrase

-# --- -# in: %(caps)SPAN% -# out:

SPAN ---- -in: %{color:red}red% -out:

red

---- -in: %[fr]rouge% -out:

rouge

---- -in: _(big)red_ -out:

red

---- -in: p(bob). A paragraph -out:

A paragraph

---- -in: p{color:#ddd}. A paragraph -out:

A paragraph

---- -in: p[fr]. A paragraph -out:

A paragraph

---- -in: h2()>. right-aligned header2, indented 1em both side -out:

right-aligned header2, indented 1em both side

---- -in: h3=. centered header -out:

centered header

---- -in: '!>/image.gif! right-aligned image' -out:

right-aligned image

---- -in: p[no]{color:red}. A Norse of a different colour. -out:

A Norse of a different colour.

---- -in: |- - |This|is|a|simple|table| - |This|is|a|simple|row| -out: |- - - - - - - - - - - - - - - - -
Thisisasimpletable
Thisisasimplerow
---- -in: |- - table{border:1px solid black}. - |This|is|a|row| - |This|is|a|row| -out: |- - - - - - - - - - - - - - -
Thisisarow
Thisisarow
---- -in: '{background:#ddd}. |This|is|a|row|' -out: |- - - - - - - - -
Thisisarow
---- -in: |- - |{background:#ddd}. Cell with gray background| - |\2. Cell spanning 2 columns| - |/3. Cell spanning 3 rows| - |>. Right-aligned cell| -out: |- - - - - - - - - - - - - - -
Cell with gray background
Cell spanning 2 columns
Cell spanning 3 rows
Right-aligned cell
-# --- -# in: |- -# This is a "link":bob to Bob's website. -# -# [bob]http://itsbob.com/index.html ---- -in: ACLU(American Civil Liberties Union) -out:

ACLU

---- -in: |- - h2{color:green}. This is a title - - h3. This is a subhead - - p{color:red}. This is some text of dubious character. Isn't the use of "quotes" just lazy writing -- and theft of 'intellectual property' besides? I think the time has come to see a block quote. - - bq[fr]. This is a block quote. I'll admit it's not the most exciting block quote ever devised. - - Simple list: - - #{color:blue} one - # two - # three - - Multi-level list: - - # one - ## aye - ## bee - ## see - # two - ## x - ## y - # three - - Mixed list: - - * Point one - * Point two - ## Step 1 - ## Step 2 - ## Step 3 - * Point three - ** Sub point 1 - ** Sub point 2 - - - Well, that went well. How about we insert an old-fashioned hypertext link? Will the quote marks in the tags get messed up? No! - - "This is a link (optional title)":http://www.textism.com - - table{border:1px solid black}. - |_. this|_. is|_. a|_. header| - <{background:gray}. |\2. this is|{background:red;width:200px}. a|^<>{height:200px}. row| - |this|<>{padding:10px}. is|^. another|(bob#bob). row| - - An image: - - !/common/textist.gif(optional alt text)! - - # Librarians rule - # Yes they do - # But you knew that - - Some more text of dubious character. Here is a noisome string of CAPITAL letters. Here is something we want to _emphasize_. - That was a linebreak. And something to indicate *strength*. Of course I could use my own HTML tags if I felt like it. - - h3. Coding - - This is some code, "isn't it". Watch those quote marks! Now for some preformatted text: - -
-  
-      $text = str_replace("

%::%

","",$text); - $text = str_replace("%::%

","",$text); - $text = str_replace("%::%","",$text); - -
-
- - This isn't code. - - - So you see, my friends: - - * The time is now - * The time is not later - * The time is not yesterday - * We must act - -out: |- -

This is a title

- -

This is a subhead

- -

This is some text of dubious character. Isn’t the use of “quotes” just lazy writing—and theft of ‘intellectual property’ besides? I think the time has come to see a block quote.

- -
-

This is a block quote. I’ll admit it’s not the most exciting block quote ever devised.

-
- -

Simple list:

-
    -
  1. one
  2. -
  3. two
  4. -
  5. three
  6. -
- -

Multi-level list:

-
    -
  1. one -
      -
    1. aye
    2. -
    3. bee
    4. -
    5. see
    6. -
    -
  2. -
  3. two -
      -
    1. x
    2. -
    3. y
    4. -
    -
  4. -
  5. three
  6. -
- -

Mixed list:

-
    -
  • Point one
  • -
  • Point two -
      -
    1. Step 1
    2. -
    3. Step 2
    4. -
    5. Step 3
    6. -
    -
  • -
  • Point three -
      -
    • Sub point 1
    • -
    • Sub point 2
    • -
  • -
- -

Well, that went well. How about we insert an old-fashioned hypertext link? Will the quote marks in the tags get messed up? No!

- -

This is a link

- - - - - - - - - - - - - - - - - - - -
thisisaheader
this isarow
thisisanotherrow
- - - -

An image:

- -

optional alt text

-
    -
  1. Librarians rule
  2. -
  3. Yes they do
  4. -
  5. But you knew that
  6. -
- -

Some more text of dubious character. Here is a noisome string of CAPITAL letters. Here is something we want to emphasize. - That was a linebreak. And something to indicate strength. Of course I could use my own HTML tags if I felt like it.

- -

Coding

- -

This is some code, "isn't it". Watch those quote marks! Now for some preformatted text:

- - -
-  
-      $text = str_replace("<p>%::%</p>","",$text);
-      $text = str_replace("%::%</p>","",$text);
-      $text = str_replace("%::%","",$text);
-  
-  
-  
-

This isn’t code.

- -

So you see, my friends:

-
    -
  • The time is now
  • -
  • The time is not later
  • -
  • The time is not yesterday
  • -
  • We must act
  • -
- diff --git a/vendor/madeleine-0.7.1/.cvsignore b/vendor/madeleine-0.7.1/.cvsignore deleted file mode 100755 index c3c960b4..00000000 --- a/vendor/madeleine-0.7.1/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -PrevalenceBase -*.gem diff --git a/vendor/madeleine-0.7.1/COPYING b/vendor/madeleine-0.7.1/COPYING deleted file mode 100755 index 19d570ec..00000000 --- a/vendor/madeleine-0.7.1/COPYING +++ /dev/null @@ -1,31 +0,0 @@ - - Copyright (c) 2003-2004, Anders Bengtsson - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. The names of its contributors may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. diff --git a/vendor/madeleine-0.7.1/NEWS b/vendor/madeleine-0.7.1/NEWS deleted file mode 100755 index 8fd9d325..00000000 --- a/vendor/madeleine-0.7.1/NEWS +++ /dev/null @@ -1,55 +0,0 @@ - -Madeleine 0.7.1 (August 22, 2004): - - * ZMarshal changed to work around Zlib bug. - * automatic_read_only fixed when intercepted class is inherited from - -Madeleine 0.7 (July 23, 2004): - - * Broken clock unit test on win32 fixed. - * AutomaticSnapshotMadeleine detects snapshot format on recovery - * Snapshot compression with Madeleine::ZMarshal - * YAML snapshots supported for automatic commands - * SOAP snapshots supported for automatic commands - * Read-only methods for automatic commands - -Madeleine 0.6.1 (March 30, 2004): - - * Bug fix: Use binary mode for I/O, fixes log replay - on mswin32 port of Ruby (Patch from Martin Tampe) - -Madeleine 0.6 (March 28, 2004): - - * Changed license to BSD - * Added a RubyGem specification - * Re-designed initialization (but still backward-compatible) - * Bug fix: Fixed use of finalized object's id in AutomaticSnapshotMadeleine - -Madeleine 0.5 (August 31, 2003): - - * Bug fix: Log order on recovery was wrong on some platforms - (Reported by IIMA Susumu) - * No longer requires the system clock to always increase - * Shared locks for queries - -Madeleine 0.4 (July 4, 2003): - - * Deprecated ClockedSnapshotMadeleine - * Added execute_query() - * API documentation in RDoc format - -Madeleine 0.3 (May 15, 2003): - - * Automatic commands - * Some classes exported to the default module - * Clock support not loaded by default (require 'madeleine/clock') - * Bug fix: Error handling when replaying logged commands. - * New system through block instead of argument (API change) - * Works in $SAFE = 1 - -Madeleine 0.2: - - * Supports custom marshalling implementations. - * Changed interface for ClockedSystem and Clock. - * Some documentation added, including API docs. - diff --git a/vendor/madeleine-0.7.1/README b/vendor/madeleine-0.7.1/README deleted file mode 100755 index 3fb6ce17..00000000 --- a/vendor/madeleine-0.7.1/README +++ /dev/null @@ -1,78 +0,0 @@ - -Madeleine is a Ruby implementation of Object Prevalence: Transparent -persistence of business objects using command logging and complete -system snapshots. - - - -Madeleine's design is based on Prevayler, the original Java -prevalence layer. - -Learn more about object prevalence at . - - -Installation: - - Typical installation procedure is: - $ ruby install.rb config - $ ruby install.rb setup - # ruby install.rb install (may require root privilege) - Try 'ruby install.rb --help' for detailed usage. - - [From the documentation of Minero Aoki's 'install.rb'] - -Usage: - - require 'madeleine' - - # Create an application as a prevalent system - - madeleine = SnapshotMadeleine.new("my_example_storage") { - SomeExampleApplication.new() - } - - # Do modifications of the system by sending commands through - # the Madeleine instance. A command is an object with a suitable - # "execute(system)" method. - - madeleine.execute_command(command) - - -Requirements: - - * Ruby 1.8.1 or later - - Additionaly, some of the sample code also uses ruby/tk. - - -Known problems: - - * Won't run in some Windows-ports of Ruby due to missing - fsync() call. - -Contact: - - Homepage: - - - Questions, bug reports, patches, complaints? Use the mailing list: - - -License: - - BSD (see the file COPYING) - -Credits: - - Anders Bengtsson - Prevalence core impl. - Stephen Sykes - Automatic commands impl. - - With the help of patches, testing and feedback from: - - Steve Conover, David Heinemeier Hansson, Johan Lind, Håkan Råberg, - IIMA Susumu, Martin Tampe and Jon Tirsén - - Thanks to Klaus Wuestefeld and the Prevayler developers for the - model of this software; to Minero Aoki for the installer; to Matz and - the core developers for the Ruby language! - diff --git a/vendor/madeleine-0.7.1/TODO b/vendor/madeleine-0.7.1/TODO deleted file mode 100755 index d2e14f7b..00000000 --- a/vendor/madeleine-0.7.1/TODO +++ /dev/null @@ -1,23 +0,0 @@ - - -- Fix broken time-dependent unit test -* Rolling snapshots, with age limit -- Compressed snapshots -- Full support for YAML snapshots -- SOAP marshalling -* Configurable log marshaller (or use the snapshot marshaller?) -* Write a document about the different marshallers, for app. developers. - -* Move all default implementations into a "Default" module -* Introduce an object representing a log directory -* Move recovery out of DefaultSnapshotMadeleine entirely -* Write an example with a web server - -* Replace filesystem with mock objects for unit testing. -* ClockCommand -* Integrate batched-writes in SnapshotMadeleine -* More sample code -* More documentation -* DRb integration -* Rollback -* Handle broken logs? diff --git a/vendor/madeleine-0.7.1/contrib/batched.rb b/vendor/madeleine-0.7.1/contrib/batched.rb deleted file mode 100755 index 2532cd64..00000000 --- a/vendor/madeleine-0.7.1/contrib/batched.rb +++ /dev/null @@ -1,298 +0,0 @@ -# Batched writes for Madeleine -# -# Copyright(c) Håkan Råberg 2003 -# -# -# This is an experimental implementation of batched log writes to mininize -# calls to fsync. It uses a Shared/Exclusive-Lock, implemented in sync.rb, -# which is included in Ruby 1.8. -# -# Writes are batched for a specified amount of time, before written to disk and -# then executed. -# -# For a detailed discussion about the problem, see -# http://www.prevayler.org/wiki.jsp?topic=OvercomingTheWriteBottleneck -# -# -# Usage is identical to normal SnapshotMadeleine, and it can also be used as -# persister for AutomaticSnapshotMadeleine. (One difference: the log isn't -# visible on disk until any commands are executed.) -# -# You can also use the execute_query method for shared synchronzied queries, -# for eaay coarse-grained locking of the system. -# -# The exclusive lock is only locked during the actual execution of commands and -# while closing. -# -# Keeping both log writes and executes of commands in the originating thread -# is needed by AutomaticSnapshotPrevayler. Hence the strange SimplisticPipe -# class. -# -# Todo: -# - It seems like Sync (sync.rb) prefers shared locks. This should probably -# be changed. -# -# -# Madeleine - Ruby Object Prevalence -# -# Copyright(c) Anders Bengtsson 2003 -# - -require 'madeleine' -require 'madeleine/clock' - -include Madeleine::Clock - -module Madeleine - module Batch - class BatchedSnapshotMadeleine < SnapshotMadeleine - - def initialize(directory_name, marshaller=Marshal, &new_system_block) - super(directory_name, marshaller, &new_system_block) - @log_actor = LogActor.launch(self) - end - - def execute_command(command) - verify_command_sane(command) - queued_command = QueuedCommand.new(command) - @lock.synchronize(:SH) do - raise "closed" if @closed - @logger.store(queued_command) - end - queued_command.wait_for - end - - def execute_query(query) - verify_command_sane(query) - @lock.synchronize(:SH) do - execute_without_storing(query) - end - end - - def close - @log_actor.destroy - @lock.synchronize do - @logger.close - @closed = true - end - end - - def flush - @lock.synchronize do - @logger.flush - end - end - - def take_snapshot - @lock.synchronize(:SH) do - @lock.synchronize do - @logger.close - end - Snapshot.new(@directory_name, system, @marshaller).take - @logger.reset - end - end - - private - - def create_lock - Sync.new - end - - def create_logger(directory_name, log_factory) - BatchedLogger.new(directory_name, log_factory, self.system) - end - - def log_factory - BatchedLogFactory.new - end - end - - private - - class LogActor - def self.launch(madeleine, delay=0.01) - result = new(madeleine, delay) - result - end - - def destroy - @is_destroyed = true - if @thread.alive? - @thread.wakeup - @thread.join - end - end - - private - - def initialize(madeleine, delay) - @is_destroyed = false - - madeleine.flush - @thread = Thread.new { - until @is_destroyed - sleep(delay) - madeleine.flush - end - } - end - end - - class BatchedLogFactory - def create_log(directory_name) - BatchedLog.new(directory_name) - end - end - - class BatchedLogger < Logger - def initialize(directory_name, log_factory, system) - super(directory_name, log_factory) - @buffer = [] - @system = system - end - - def store(queued_command) - @buffer << queued_command - end - - def close - return if @log.nil? - flush - @log.close - @log = nil - end - - def flush - return if @buffer.empty? - - open_new_log if @log.nil? - - if @system.kind_of?(ClockedSystem) - @buffer.unshift(QueuedTick.new) - end - - @buffer.each do |queued_command| - queued_command.store(@log) - end - - @log.flush - - @buffer.each do |queued_command| - queued_command.execute(@system) - end - - @buffer.clear - end - end - - class BatchedLog < CommandLog - def store(command) - Marshal.dump(command, @file) - end - - def flush - @file.flush - @file.fsync - end - end - - class QueuedCommand - def initialize(command) - @command = command - @pipe = SimplisticPipe.new - end - - def store(log) - @pipe.write(log) - end - - def execute(system) - @pipe.write(system) - end - - def wait_for - @pipe.read do |log| - log.store(@command) - end - - @pipe.read do |system| - return @command.execute(system) - end - end - end - - class QueuedTick - def initialize - @tick = Tick.new(Time.now) - end - - def store(log) - log.store(@tick) - end - - def execute(system) - @tick.execute(system) - end - end - - class SimplisticPipe - def initialize - @receive_lock = Mutex.new.lock - @consume_lock = Mutex.new.lock - @message = nil - end - - def read - begin - wait_for_message_received - - if block_given? - yield @message - else - return @message - end - - ensure - message_consumed - end - end - - def write(message) - raise WriteBlockedException unless can_write? - - @message = message - message_received - wait_for_message_consumed - @message = nil - end - - def can_write? - @message.nil? - end - - private - - def message_received - @receive_lock.unlock - end - - def wait_for_message_received - @receive_lock.lock - end - - def message_consumed - @consume_lock.unlock - end - - def wait_for_message_consumed - @consume_lock.lock - end - end - - class WriteBlockedException < Exception - end - end -end - -BatchedSnapshotMadeleine = Madeleine::Batch::BatchedSnapshotMadeleine diff --git a/vendor/madeleine-0.7.1/contrib/benchmark.rb b/vendor/madeleine-0.7.1/contrib/benchmark.rb deleted file mode 100755 index 6bb89b42..00000000 --- a/vendor/madeleine-0.7.1/contrib/benchmark.rb +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/local/bin/ruby -w - -$LOAD_PATH.unshift("../lib") - -require 'madeleine' -require 'batched' - -class BenchmarkCommand - def initialize(value) - @value = value - end - - def execute(system) - # do nothing - end -end - -madeleine = BatchedSnapshotMadeleine.new("benchmark-base") { :the_system } - -RUNS = 2000 - -GC.start -GC.disable - -t0 = Time.now -RUNS.times { - madeleine.execute_command(BenchmarkCommand.new(1234)) -} -t1 = Time.now - -GC.enable - -tps = RUNS/(t1 - t0) - -puts "#{tps.to_i} transactions/s" diff --git a/vendor/madeleine-0.7.1/contrib/test_batched.rb b/vendor/madeleine-0.7.1/contrib/test_batched.rb deleted file mode 100755 index 7011634e..00000000 --- a/vendor/madeleine-0.7.1/contrib/test_batched.rb +++ /dev/null @@ -1,245 +0,0 @@ -#!/usr/local/bin/ruby -w -# -# Copyright(c) 2003 Håkan Råberg -# -# Some components taken from test_persistence.rb -# Copyright(c) 2003 Anders Bengtsson -# - -$LOAD_PATH.unshift("../lib") - -require 'batched' -require 'test/unit' -require 'madeleine/clock' - - -module Madeleine::Batch - class BatchedSnapshotMadeleineTest < Test::Unit::TestCase - - class ArraySystem < Array - include Madeleine::Clock::ClockedSystem - end - - class PushCommand - def initialize(value) - @value = value - end - - def execute(system) - system << @value - end - end - - class ArrayQuery - def initialize - @time = [] - end - - def execute(system) - length = system.length - @time << system.clock.time - - a = 1 - system.each do |n| - a *= n - end - - raise "inconsistent read" unless length == system.length - raise "inconsistent read" unless @time.last == system.clock.time - end - end - - def test_live_snapshot - system = ArraySystem.new - w, r = [], [] - going = true - - madeleine = BatchedSnapshotMadeleine.new(prevalence_base) { system } - - i = 0 - 10.times do |n| - w[n] = Thread.new { - while going - madeleine.execute_command(PushCommand.new(i)) - i += 1 - sleep(0.1) - end - } - end - - q = 0 - query = ArrayQuery.new - 100.times do |n| - r[n] = Thread.new { - while going - begin - madeleine.execute_query(query) - q += 1 - rescue - fail("Query blocks writing") - end - sleep(0.1) - end - } - end - - s = 0 - snapshot = Thread.new { - while going - madeleine.take_snapshot - s += 1 - sleep(0.01) - end - } - - sleep(1) - - going = false - - r.each do |t| - t.join - end - - w.each do |t| - t.join - end - - snapshot.join - - madeleine.close - - madeleine2 = SnapshotMadeleine.new(prevalence_base) - assert_equal(madeleine.system, madeleine2.system, "Take system snapshots while accessing") - end - - def prevalence_base - "BatchedSnapshot" - end - - def teardown - delete_directory(prevalence_base) - end - end - - class BatchedLogTest < Test::Unit::TestCase - - class MockMadeleine - def initialize(logger) - @logger = logger - end - - def flush - @logger.flush - end - end - - class MockCommand - attr_reader :text - - def initialize(text) - @text = text - end - - def execute(system) - end - - def ==(o) - o.text == @text - end - end - - module BufferInspector - def buffer_size - @buffer.size - end - end - - def setup - @target = BatchedLogger.new(".", BatchedLogFactory.new, nil) - @target.extend(BufferInspector) - @madeleine = MockMadeleine.new(@target) - @messages = [] - end - - def test_logging - actor = LogActor.launch(@madeleine, 0.1) - - append("Hello") - sleep(0.01) - append("World") - sleep(0.01) - - assert_equal(2, @target.buffer_size, "Batched command queue") - assert(!File.exist?(expected_file_name), "Batched commands not on disk") - - sleep(0.2) - - assert_equal(0, @target.buffer_size, "Queue emptied by batched write") - file_size = File.size(expected_file_name) - assert(file_size > 0, "Queue written to disk") - - append("Again") - sleep(0.2) - - assert(File.size(expected_file_name) > file_size, "Command written to disk") - - f = File.new(expected_file_name) - - @messages.each do |message| - assert_equal(message, Marshal.load(f), "Commands logged in order") - end - - f.close - - actor.destroy - @target.flush - @target.close - - end - - def append(text) - Thread.new { - message = MockCommand.new(text) - @messages << message - queued_command = QueuedCommand.new(message) - @target.store(queued_command) - queued_command.wait_for - } - end - - def expected_file_name - "000000000000000000001.command_log" - end - - def teardown - assert(File.delete(expected_file_name) == 1) - end - - end - - def delete_directory(directory_name) - Dir.foreach(directory_name) do |file| - next if file == "." - next if file == ".." - assert(File.delete(directory_name + File::SEPARATOR + file) == 1, - "Unable to delete #{file}") - end - Dir.delete(directory_name) - end -end - - include Madeleine::Batch - -def add_batched_tests(suite) - suite << BatchedSnapshotMadeleineTest.suite - suite << BatchedLogTest.suite -end - -if __FILE__ == $0 - suite = Test::Unit::TestSuite.new("BatchedLogTest") - add_batched_tests(suite) - - require 'test/unit/ui/console/testrunner' - Thread.abort_on_exception = true - Test::Unit::UI::Console::TestRunner.run(suite) -end diff --git a/vendor/madeleine-0.7.1/contrib/test_scalability.rb b/vendor/madeleine-0.7.1/contrib/test_scalability.rb deleted file mode 100755 index 99b7dc5d..00000000 --- a/vendor/madeleine-0.7.1/contrib/test_scalability.rb +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/local/bin/ruby -w -# -# Copyright(c) 2003 Håkan Råberg -# -# This test is based on Prevaylers TransactionTestRun, -# Copyright(c) 2001-2003 Klaus Wuestefeld. -# - -$LOAD_PATH.unshift("../lib") - -require 'madeleine' -require 'madeleine/clock' -require 'batched' - -module ScalabilityTest - - class TransactionTestRun - MIN_THREADS = 20 - MAX_THREADS = 20 - NUMBER_OF_OBJECTS = 100000 - ROUND_DURATION = 20 - DIR = "ScalabilityBase" - - def initialize - @system = TransactionSystem.new - @madeleine = BatchedSnapshotMadeleine.new(DIR) { @system } - - @system.replace_all_records(create_records(NUMBER_OF_OBJECTS)) - - @is_round_finished = false - - @best_round_ops_per_s = 0 - @best_round_threads = 0 - @operation_count = 0 - @last_operation = 0 - @active_round_threads = 0 - - @half_of_the_objects = NUMBER_OF_OBJECTS / 2 - - @connection_cache = [] - @connection_cache_lock = Mutex.new - - ObjectSpace.garbage_collect - - puts "========= Running " + name + " (" + (MAX_THREADS - MIN_THREADS + 1).to_s + " rounds). Subject: " + subject_name + "..." - puts "Each round will take approx. " + ROUND_DURATION.to_s + " seconds to run..." - perform_test - puts "----------- BEST ROUND: " + result_string(@best_round_ops_per_s, @best_round_threads) - - @madeleine.close - delete_directory(DIR) - end - - def name - "Transaction Test" - end - - def subject_name - "Madeleine" - end - - def result_string(ops_per_s, threads) - ops_per_s.to_s + " operations/second (" + threads.to_s + " threads)" - end - - def perform_test - for threads in MIN_THREADS..MAX_THREADS - ops_per_s = perform_round(threads) - if ops_per_s > @best_round_ops_per_s - @best_round_ops_per_s = ops_per_s - @best_round_threads = threads - end - end - end - - def perform_round(threads) - initial_operation_count = @operation_count - start_time = Time.now.to_f - - start_threads(threads) - sleep(ROUND_DURATION) - stop_threads - - seconds_ellapsed = Time.now.to_f - start_time - ops_per_second = (@operation_count - initial_operation_count) / seconds_ellapsed - - puts - puts "Seconds ellapsed: " + seconds_ellapsed.to_s - puts "--------- Round Result: " + result_string(ops_per_second, threads) - - ops_per_second - end - - def start_threads(threads) - @is_round_finished = false - for i in 1..threads - start_thread(@last_operation + i, threads) - end - end - - def start_thread(starting_operation, operation_increment) - Thread.new { - connection = accquire_connection - - operation = starting_operation - while not @is_round_finished - # puts "Operation " + operation.to_s - execute_operation(connection, operation) - operation += operation_increment - end - - @connection_cache_lock.synchronize do - @connection_cache << connection - @operation_count += (operation - starting_operation) / operation_increment - @last_operation = operation if @last_operation < operation - @active_round_threads -= 1 - end - } - @active_round_threads += 1 - end - - def execute_operation(connection, operation) - record_to_insert = Record.new(NUMBER_OF_OBJECTS + operation) - id_to_delete = spread_id(operation) - record_to_update = Record.new(@half_of_the_objects + id_to_delete) - - connection.perform_transaction(record_to_insert, record_to_update, id_to_delete) - end - - def spread_id(id) - (id / @half_of_the_objects) * @half_of_the_objects + ((id * 16807) % @half_of_the_objects) - end - - def create_test_connection - TransactionConnection.new(@madeleine) - end - - def accquire_connection - @connection_cache_lock.synchronize do - return @connection_cache.empty? ? create_test_connection : @connection_cache.shift - end - end - - def stop_threads - @is_round_finished = true - while @active_round_threads != 0 - sleep(0.001) - end - end - - def create_records(number_of_objects) - result = [] - for i in 0..number_of_objects - result << Record.new(i) - end - result - end - - - def delete_directory(directory_name) - Dir.foreach(directory_name) do |file| - next if file == "." - next if file == ".." - File.delete(directory_name + File::SEPARATOR + file) - end - Dir.delete(directory_name) - end - end - - class TransactionSystem - include Madeleine::Clock::ClockedSystem - - def initialize - @records_by_id = Hash.new - @transaction_lock = Mutex.new - end - - def perform_transaction(record_to_insert, record_to_update, id_to_delete) - @transaction_lock.synchronize do - put(record_to_insert) - put(record_to_update) - @records_by_id.delete(id_to_delete) - end - end - - def put(new_record) - @records_by_id[new_record.id] = new_record - end - - def replace_all_records(new_records) - @records_by_id.clear - new_records.each do |record| - put(record) - end - end - end - - class TransactionConnection - def initialize(madeleine) - @madeleine = madeleine - end - - def perform_transaction(record_to_insert, record_to_update, id_to_delete) - @madeleine.execute_command(TestTransaction.new(record_to_insert, record_to_update, id_to_delete)) - end - end - - class TestTransaction - def initialize(record_to_insert, record_to_update, id_to_delete) - @record_to_insert = record_to_insert - @record_to_update = record_to_update - @id_to_delete = id_to_delete - end - - def execute(system) - system.perform_transaction(@record_to_insert, @record_to_update, @id_to_delete) - end - end - - class Record - attr_reader :id, :name, :string_1, :date_1, :date_2 - - def initialize(id) - @id = id - @name = "NAME" + (id % 10000).to_s - @string_1 = (id % 10000).to_s == 0 ? Record.large_string + id : nil; - @date_1 = Record.random_date - @date_2 = Record.random_date - end - - def self.large_string - [].fill("A", 1..980).to_s - end - - def self.random_date - rand(10000000) - end - end -end - -if __FILE__ == $0 - puts "Madeleine Scalability Test" - puts "Based on Prevaylers Scalability Test" - puts - - Thread.abort_on_exception = true - ScalabilityTest::TransactionTestRun.new -end diff --git a/vendor/madeleine-0.7.1/contrib/threaded_benchmark.rb b/vendor/madeleine-0.7.1/contrib/threaded_benchmark.rb deleted file mode 100755 index 5e8f88a7..00000000 --- a/vendor/madeleine-0.7.1/contrib/threaded_benchmark.rb +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/local/bin/ruby -w - -$LOAD_PATH.unshift("../lib") - -require 'madeleine' -require 'batched' - -class BenchmarkCommand - def initialize(value) - @value = value - end - - def execute(system) - # do nothing - end -end - -madeleine = BattchedSnapshotMadeleine.new("benchmark-base") { :the_system } - -RUNS = 200 -THREADS = 10 - -GC.start -GC.disable - -t0 = Time.now - -threads = [] -THREADS.times { - threads << Thread.new { - RUNS.times { - madeleine.execute_command(BenchmarkCommand.new(1234)) - } - } -} -threads.each {|t| t.join } -t1 = Time.now - -GC.enable - -tps = (THREADS * RUNS)/(t1 - t0) - -puts "#{tps.to_i} transactions/s" - diff --git a/vendor/madeleine-0.7.1/docs/.cvsignore b/vendor/madeleine-0.7.1/docs/.cvsignore deleted file mode 100755 index eedd89b4..00000000 --- a/vendor/madeleine-0.7.1/docs/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -api diff --git a/vendor/madeleine-0.7.1/docs/designRules.html b/vendor/madeleine-0.7.1/docs/designRules.html deleted file mode 100755 index c6db4546..00000000 --- a/vendor/madeleine-0.7.1/docs/designRules.html +++ /dev/null @@ -1,87 +0,0 @@ - - - -Design rules - Madeleine - - - - - -

Design rules

- -

This is a summary of the design rules your application has to -follow to work with Madeleine. - - -

The Prevalent System

- -

Your objects have to fit into memory

- -

All of them. At the same time. - -

Your objects have to be marshallable

- -

Snapshots are taken of the system by marshalling the whole system to a -file. If your classes can't be marshalled/unmarshalled then Madeleine -won't be able to store/restore the system. - -

Your objects have to be deterministic

- -

Deterministic means that, given the same commands, they have -to always give the same results. - -

For the much of your code this won't -be a problem, but there are a few common issues: - -

The system clock

-

You can't use the system clock (see instead ClockedSystem and TimeActor). - -

Random numbers

-

Kernel.rand() uses the system clock internally by -default. Use Kernel.srand() to seed the random number -generator before using rand(). - -

Files, network and other IO

-

You generally can't access the outside world from within your -prevalent system. Instead do IO outside of the prevalent system and -call into the system when needed. - -

Changes to the system have to be done through command -objects

- -

Everything that modifies the prevalent system must be done through a -command object sent to the Madeleine instance, using -execute_command(aCommand). Queries that don't modify the -system can be done either through direct method calls or through -command objects. - -

Command Objects

- -

A command object is an object that implements the method -execute(system). They are an example of the "Command" -design pattern. - -

The command objects also have to be marshallable

- -

Madeleine keeps track of changes between snapshots by logging -marshalled commands. - -

The command must raise errors before modifying the system

- -

Unlike a RDBMS, Madeleine can't roll back a command (yet). This means -that your commands will have to do their error checking and raise any -errors before modifying the system. Failing to do this will cause an -inconsistent command log. - -

Command objects can't hold references to the system's objects

- -

Unmarshalling such a command would create clones of the original -objects, which would then be modified instead of the real -objects. The commands must find the objects to modify. - -


- -$Id: designRules.html,v 1.1 2005/01/07 23:03:27 alexeyv Exp $ - - - diff --git a/vendor/madeleine-0.7.1/docs/docs.css b/vendor/madeleine-0.7.1/docs/docs.css deleted file mode 100755 index 0c70ccde..00000000 --- a/vendor/madeleine-0.7.1/docs/docs.css +++ /dev/null @@ -1,28 +0,0 @@ -body { - background-color: #FFFFF0; -} -p { - width: 70ex -} -h1 { - font-family: verdana,arial,helvetica,sans-serif; -} -h2 { - font-family: verdana,arial,helvetica,sans-serif; - background: #EEEEE0; -} -h3 { - font-family: verdana,arial,helvetica,sans-serif; -} -h4 { - font-family: verdana,arial,helvetica,sans-serif; -} -.classMethod { - font-family: courier,monospace; - font-weight: bold; - background: #EEEEE0; -} -.instanceMethod { - font-family: courier,sans-serif; - background: #EEEEE0; -} diff --git a/vendor/madeleine-0.7.1/generate_rdoc.rb b/vendor/madeleine-0.7.1/generate_rdoc.rb deleted file mode 100755 index b4e0ba7b..00000000 --- a/vendor/madeleine-0.7.1/generate_rdoc.rb +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/local/bin/ruby - -`rdoc lib --op docs/api` diff --git a/vendor/madeleine-0.7.1/install.rb b/vendor/madeleine-0.7.1/install.rb deleted file mode 100755 index e624774e..00000000 --- a/vendor/madeleine-0.7.1/install.rb +++ /dev/null @@ -1,1098 +0,0 @@ -# -# This file is automatically generated. DO NOT MODIFY! -# -# install.rb -# -# Copyright (c) 2000-2003 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU Lesser General Public License version 2. -# - -### begin compat.rb - -module Enumerable - methods = instance_methods() - - unless methods.include?('map') - alias map collect - end - - unless methods.include?('select') - alias select find_all - end - - unless methods.include?('reject') - def reject - result = [] - each do |i| - result.push i unless yield(i) - end - result - end - end - - unless methods.include?('inject') - def inject( result ) - each do |i| - result = yield(result, i) - end - result - end - end - - unless methods.include?('any?') - def any? - each do |i| - return true if yield(i) - end - false - end - end -end - -def File.read_all( fname ) - File.open(fname, 'rb') {|f| return f.read } -end - -def File.write( fname, str ) - File.open(fname, 'wb') {|f| f.write str } -end - -### end compat.rb -### begin config.rb - -if i = ARGV.index(/\A--rbconfig=/) - file = $' - ARGV.delete_at(i) - require file -else - require 'rbconfig' -end - - -class ConfigTable - - c = ::Config::CONFIG - - rubypath = c['bindir'] + '/' + c['ruby_install_name'] - - major = c['MAJOR'].to_i - minor = c['MINOR'].to_i - teeny = c['TEENY'].to_i - version = "#{major}.#{minor}" - - # ruby ver. >= 1.4.4? - newpath_p = ((major >= 2) or - ((major == 1) and - ((minor >= 5) or - ((minor == 4) and (teeny >= 4))))) - - re = Regexp.new('\A' + Regexp.quote(c['prefix'])) - subprefix = lambda {|path| - re === path and path.sub(re, '$prefix') - } - - if c['rubylibdir'] - # V < 1.6.3 - stdruby = subprefix.call(c['rubylibdir']) - siteruby = subprefix.call(c['sitedir']) - versite = subprefix.call(c['sitelibdir']) - sodir = subprefix.call(c['sitearchdir']) - elsif newpath_p - # 1.4.4 <= V <= 1.6.3 - stdruby = "$prefix/lib/ruby/#{version}" - siteruby = subprefix.call(c['sitedir']) - versite = siteruby + '/' + version - sodir = "$site-ruby/#{c['arch']}" - else - # V < 1.4.4 - stdruby = "$prefix/lib/ruby/#{version}" - siteruby = "$prefix/lib/ruby/#{version}/site_ruby" - versite = siteruby - sodir = "$site-ruby/#{c['arch']}" - end - - DESCRIPTER = [ - [ 'prefix', [ c['prefix'], - 'path', - 'path prefix of target environment' ] ], - [ 'std-ruby', [ stdruby, - 'path', - 'the directory for standard ruby libraries' ] ], - [ 'site-ruby-common', [ siteruby, - 'path', - 'the directory for version-independent non-standard ruby libraries' ] ], - [ 'site-ruby', [ versite, - 'path', - 'the directory for non-standard ruby libraries' ] ], - [ 'bin-dir', [ '$prefix/bin', - 'path', - 'the directory for commands' ] ], - [ 'rb-dir', [ '$site-ruby', - 'path', - 'the directory for ruby scripts' ] ], - [ 'so-dir', [ sodir, - 'path', - 'the directory for ruby extentions' ] ], - [ 'data-dir', [ '$prefix/share', - 'path', - 'the directory for shared data' ] ], - [ 'ruby-path', [ rubypath, - 'path', - 'path to set to #! line' ] ], - [ 'ruby-prog', [ rubypath, - 'name', - 'the ruby program using for installation' ] ], - [ 'make-prog', [ 'make', - 'name', - 'the make program to compile ruby extentions' ] ], - [ 'without-ext', [ 'no', - 'yes/no', - 'does not compile/install ruby extentions' ] ] - ] - - SAVE_FILE = 'config.save' - - def ConfigTable.each_name( &block ) - keys().each(&block) - end - - def ConfigTable.keys - DESCRIPTER.map {|k,*dummy| k } - end - - def ConfigTable.each_definition( &block ) - DESCRIPTER.each(&block) - end - - def ConfigTable.get_entry( name ) - name, ent = DESCRIPTER.assoc(name) - ent - end - - def ConfigTable.get_entry!( name ) - get_entry(name) or raise ArgumentError, "no such config: #{name}" - end - - def ConfigTable.add_entry( name, vals ) - ConfigTable::DESCRIPTER.push [name,vals] - end - - def ConfigTable.remove_entry( name ) - get_entry name or raise ArgumentError, "no such config: #{name}" - DESCRIPTER.delete_if {|n,arr| n == name } - end - - def ConfigTable.config_key?( name ) - get_entry(name) ? true : false - end - - def ConfigTable.bool_config?( name ) - ent = get_entry(name) or return false - ent[1] == 'yes/no' - end - - def ConfigTable.value_config?( name ) - ent = get_entry(name) or return false - ent[1] != 'yes/no' - end - - def ConfigTable.path_config?( name ) - ent = get_entry(name) or return false - ent[1] == 'path' - end - - - class << self - alias newobj new - - def new - c = newobj() - c.__send__ :init - c - end - - def load - c = newobj() - raise InstallError, "#{File.basename $0} config first"\ - unless FileTest.file?(SAVE_FILE) - File.foreach(SAVE_FILE) do |line| - k, v = line.split(/=/, 2) - c.instance_eval { - @table[k] = v.strip - } - end - c - end - end - - def initialize - @table = {} - end - - def init - DESCRIPTER.each do |k, (default, vname, desc, default2)| - @table[k] = default - end - end - private :init - - def save - File.open(SAVE_FILE, 'w') {|f| - @table.each do |k, v| - f.printf "%s=%s\n", k, v if v - end - } - end - - def []=( k, v ) - ConfigTable.config_key? k or raise InstallError, "unknown config option #{k}" - if ConfigTable.path_config? k - @table[k] = (v[0,1] != '$') ? File.expand_path(v) : v - else - @table[k] = v - end - end - - def []( key ) - @table[key] or return nil - @table[key].gsub(%r<\$([^/]+)>) { self[$1] } - end - - def set_raw( key, val ) - @table[key] = val - end - - def get_raw( key ) - @table[key] - end - -end - - -module MetaConfigAPI - - def eval_file_ifexist( fname ) - instance_eval File.read_all(fname), fname, 1 if FileTest.file?(fname) - end - - def config_names - ConfigTable.keys - end - - def config?( name ) - ConfigTable.config_key? name - end - - def bool_config?( name ) - ConfigTable.bool_config? name - end - - def value_config?( name ) - ConfigTable.value_config? name - end - - def path_config?( name ) - ConfigTable.path_config? name - end - - def add_config( name, argname, default, desc ) - ConfigTable.add_entry name,[default,argname,desc] - end - - def add_path_config( name, default, desc ) - add_config name, 'path', default, desc - end - - def add_bool_config( name, default, desc ) - add_config name, 'yes/no', default ? 'yes' : 'no', desc - end - - def set_config_default( name, default ) - if bool_config? name - ConfigTable.get_entry!(name)[0] = default ? 'yes' : 'no' - else - ConfigTable.get_entry!(name)[0] = default - end - end - - def remove_config( name ) - ent = ConfigTable.get_entry(name) - ConfigTable.remove_entry name - ent - end - -end - -### end config.rb -### begin fileop.rb - -module FileOperations - - def mkdir_p( dname, prefix = nil ) - dname = prefix + dname if prefix - $stderr.puts "mkdir -p #{dname}" if verbose? - return if no_harm? - - # does not check '/'... it's too abnormal case - dirs = dname.split(%r<(?=/)>) - if /\A[a-z]:\z/i === dirs[0] - disk = dirs.shift - dirs[0] = disk + dirs[0] - end - dirs.each_index do |idx| - path = dirs[0..idx].join('') - Dir.mkdir path unless dir? path - end - end - - def rm_f( fname ) - $stderr.puts "rm -f #{fname}" if verbose? - return if no_harm? - - if File.exist? fname or File.symlink? fname - File.chmod 0777, fname - File.unlink fname - end - end - - def rm_rf( dn ) - $stderr.puts "rm -rf #{dn}" if verbose? - return if no_harm? - - Dir.chdir dn - Dir.foreach('.') do |fn| - next if fn == '.' - next if fn == '..' - if dir? fn - verbose_off { - rm_rf fn - } - else - verbose_off { - rm_f fn - } - end - end - Dir.chdir '..' - Dir.rmdir dn - end - - def mv( src, dest ) - rm_f dest - begin - File.link src, dest - rescue - File.write dest, File.read_all(src) - File.chmod File.stat(src).mode, dest - end - rm_f src - end - - def install( from, dest, mode, prefix = nil ) - $stderr.puts "install #{from} #{dest}" if verbose? - return if no_harm? - - realdest = prefix + dest if prefix - if dir? realdest - realdest += '/' + File.basename(from) - end - str = File.read_all(from) - if diff? str, realdest - verbose_off { - rm_f realdest if File.exist? realdest - } - File.write realdest, str - File.chmod mode, realdest - - File.open(objdir + '/InstalledFiles', 'a') {|f| f.puts realdest } - end - end - - def diff?( orig, targ ) - return true unless File.exist? targ - orig != File.read_all(targ) - end - - def command( str ) - $stderr.puts str if verbose? - system str or raise RuntimeError, "'system #{str}' failed" - end - - def ruby( str ) - command config('ruby-prog') + ' ' + str - end - - def dir?( dname ) - # for corrupted windows stat() - File.directory?((dname[-1,1] == '/') ? dname : dname + '/') - end - - def all_files_in( dname ) - Dir.open(dname) {|d| - return d.select {|n| FileTest.file? "#{dname}/#{n}" } - } - end - - REJECT_DIRS = %w( - CVS SCCS RCS CVS.adm - ) - - def all_dirs_in( dname ) - Dir.open(dname) {|d| - return d.select {|n| dir? "#{dname}/#{n}" } - %w(. ..) - REJECT_DIRS - } - end - -end - -### end fileop.rb -### begin base.rb - -class InstallError < StandardError; end - - -class Installer - - Version = '3.1.4' - Copyright = 'Copyright (c) 2000-2003 Minero Aoki' - - - @toplevel = nil - - def self.declare_toplevel_installer( inst ) - raise ArgumentError, 'two toplevel installers declared' if @toplevel - @toplevel = inst - end - - def self.toplevel_installer - @toplevel - end - - - FILETYPES = %w( bin lib ext data ) - - include FileOperations - - def initialize( config, opt, srcroot, objroot ) - @config = config - @options = opt - @srcdir = File.expand_path(srcroot) - @objdir = File.expand_path(objroot) - @currdir = '.' - end - - def inspect - "#<#{self.class} #{__id__}>" - end - - # - # configs/options - # - - def get_config( key ) - @config[key] - end - - alias config get_config - - def set_config( key, val ) - @config[key] = val - end - - def no_harm? - @options['no-harm'] - end - - def verbose? - @options['verbose'] - end - - def verbose_off - save, @options['verbose'] = @options['verbose'], false - yield - @options['verbose'] = save - end - - # - # srcdir/objdir - # - - attr_reader :srcdir - alias srcdir_root srcdir - alias package_root srcdir - - def curr_srcdir - "#{@srcdir}/#{@currdir}" - end - - attr_reader :objdir - alias objdir_root objdir - - def curr_objdir - "#{@objdir}/#{@currdir}" - end - - def srcfile( path ) - curr_srcdir + '/' + path - end - - def srcexist?( path ) - File.exist? srcfile(path) - end - - def srcdirectory?( path ) - dir? srcfile(path) - end - - def srcfile?( path ) - FileTest.file? srcfile(path) - end - - def srcentries( path = '.' ) - Dir.open(curr_srcdir + '/' + path) {|d| - return d.to_a - %w(. ..) - hookfilenames - } - end - - def srcfiles( path = '.' ) - srcentries(path).select {|fname| - FileTest.file? File.join(curr_srcdir, path, fname) - } - end - - def srcdirectories( path = '.' ) - srcentries(path).select {|fname| - dir? File.join(curr_srcdir, path, fname) - } - end - - def dive_into( rel ) - return unless dir?("#{@srcdir}/#{rel}") - - dir = File.basename(rel) - Dir.mkdir dir unless dir?(dir) - prevdir = Dir.pwd - Dir.chdir dir - $stderr.puts '---> ' + rel if verbose? - @currdir = rel - yield - Dir.chdir prevdir - $stderr.puts '<--- ' + rel if verbose? - @currdir = File.dirname(rel) - end - - # - # TASK config - # - - def exec_config - exec_task_traverse 'config' - end - - def config_dir_bin( rel ) - end - - def config_dir_lib( rel ) - end - - def config_dir_ext( rel ) - extconf if extdir? curr_srcdir - end - - def extconf - opt = @options['config-opt'].join(' ') - command "#{config('ruby-prog')} #{curr_srcdir}/extconf.rb #{opt}" - end - - def config_dir_data( rel ) - end - - # - # TASK setup - # - - def exec_setup - exec_task_traverse 'setup' - end - - def setup_dir_bin( relpath ) - all_files_in(curr_srcdir()).each do |fname| - add_rubypath "#{curr_srcdir}/#{fname}" - end - end - - SHEBANG_RE = /\A\#!\s*\S*ruby\S*/ - - def add_rubypath( path ) - $stderr.puts %Q if verbose? - return if no_harm? - - tmpfile = File.basename(path) + '.tmp' - begin - File.open(path) {|r| - File.open(tmpfile, 'w') {|w| - first = r.gets - return unless SHEBANG_RE === first # reject '/usr/bin/env ruby' - - w.print first.sub(SHEBANG_RE, '#!' + config('ruby-path')) - w.write r.read - } } - mv tmpfile, File.basename(path) - ensure - rm_f tmpfile if File.exist? tmpfile - end - end - - def setup_dir_lib( relpath ) - end - - def setup_dir_ext( relpath ) - make if extdir?(curr_srcdir) - end - - def setup_dir_data( relpath ) - end - - # - # TASK install - # - - def exec_install - exec_task_traverse 'install' - end - - def install_dir_bin( rel ) - install_files target_filenames(), config('bin-dir') + '/' + rel, 0755 - end - - def install_dir_lib( rel ) - install_files target_filenames(), config('rb-dir') + '/' + rel, 0644 - end - - def install_dir_ext( rel ) - install_dir_ext_main File.dirname(rel) if extdir?(curr_srcdir) - end - - def install_dir_ext_main( rel ) - install_files allext('.'), config('so-dir') + '/' + rel, 0555 - end - - def install_dir_data( rel ) - install_files target_filenames(), config('data-dir') + '/' + rel, 0644 - end - - def install_files( list, dest, mode ) - mkdir_p dest, @options['install-prefix'] - list.each do |fname| - install fname, dest, mode, @options['install-prefix'] - end - end - - def target_filenames - if FileTest.file? "#{curr_srcdir()}/MANIFEST" - mapdir(target_filenames_MANIFEST()) - else - mapdir(target_filenames_AUTO()) - end - end - - def mapdir( filelist ) - filelist.map {|fname| - if File.exist? fname # current objdir == '.' - fname - else - File.join(curr_srcdir(), fname) - end - } - end - - def target_filenames_MANIFEST - File.read_all("#{curr_srcdir()}/MANIFEST").split - end - - # picked up many entries from cvs-1.11.1/src/ignore.c - REJECT_PATTERNS = %w( - core RCSLOG tags TAGS .make.state - .nse_depinfo #* .#* cvslog.* ,* .del-* *.a *.olb *.o *.obj - *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$ - - *.org *.in .* - ).map {|pattern| - Regexp.compile('\A' + pattern.gsub(/[\.\$]/) {|s| '\\' + s }.gsub(/\*/, '.*') + '\z') - } - - def target_filenames_AUTO - (existfiles() - hookfiles()).reject {|fname| - REJECT_PATTERNS.any? {|re| re === fname } - } - end - - def existfiles - all_files_in(curr_srcdir()) | all_files_in(curr_objdir()) - end - - def hookfiles - %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| - %w( config setup install clean ).map {|t| sprintf(fmt, t) } - }.flatten - end - - def allext( dir ) - _allext(dir) or raise InstallError, - "no extention exists: Have you done 'ruby #{$0} setup' ?" - end - - DLEXT = /\.#{ ::Config::CONFIG['DLEXT'] }\z/ - - def _allext( dir ) - Dir.open(dir) {|d| - return d.select {|fname| DLEXT === fname } - } - end - - # - # TASK clean - # - - def exec_clean - exec_task_traverse 'clean' - rm_f 'config.save' - rm_f 'InstalledFiles' - end - - def clean_dir_bin( rel ) - end - - def clean_dir_lib( rel ) - end - - def clean_dir_ext( rel ) - make 'clean' if FileTest.file?('Makefile') - end - - def clean_dir_data( rel ) - end - - # - # TASK distclean - # - - def exec_distclean - exec_task_traverse 'distclean' - rm_f 'config.save' - rm_f 'InstalledFiles' - end - - def distclean_dir_bin( rel ) - end - - def distclean_dir_lib( rel ) - end - - def distclean_dir_ext( rel ) - make 'distclean' if FileTest.file?('Makefile') - end - - # - # lib - # - - def make( task = '' ) - command config('make-prog') + ' ' + task - end - - def exec_task_traverse( task ) - run_hook 'pre-' + task - FILETYPES.each do |type| - if config('without-ext') == 'yes' and type == 'ext' - $stderr.puts 'skipping ext/* by user option' if verbose? - next - end - traverse task, type, task + '_dir_' + type - end - run_hook 'post-' + task - end - - def traverse( task, rel, mid ) - dive_into(rel) { - run_hook 'pre-' + task - __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') - all_dirs_in(curr_srcdir()).each do |d| - traverse task, rel + '/' + d, mid - end - run_hook 'post-' + task - } - end - - def run_hook( name ) - try_run_hook curr_srcdir + '/' + name or - try_run_hook curr_srcdir + '/' + name + '.rb' - end - - def try_run_hook( fname ) - return false unless FileTest.file?(fname) - - env = self.dup - begin - env.instance_eval File.read_all(fname), fname, 1 - rescue - raise InstallError, "hook #{fname} failed:\n" + $!.message - end - true - end - - def extdir?( dir ) - File.exist? dir + '/MANIFEST' - end - -end - -### end base.rb -### begin toplevel.rb - -class ToplevelInstaller < Installer - - def self.invoke - new(File.dirname($0)).invoke - end - - - TASKS = [ - [ 'config', 'saves your configurations' ], - [ 'show', 'shows current configuration' ], - [ 'setup', 'compiles extention or else' ], - [ 'install', 'installs files' ], - [ 'clean', "does `make clean' for each extention" ], - [ 'distclean',"does `make distclean' for each extention" ] - ] - - - def initialize( root ) - super nil, {'verbose' => true}, root, '.' - Installer.declare_toplevel_installer self - end - - - def invoke - run_metaconfigs - - case task = parsearg_global() - when 'config' - @config = ConfigTable.new - else - @config = ConfigTable.load - end - parsearg_TASK task - - exectask task - end - - include MetaConfigAPI - - def run_metaconfigs - eval_file_ifexist "#{srcdir_root()}/metaconfig" - end - - - def exectask( task ) - if task == 'show' - exec_show - else - try task - end - end - - def try( task ) - $stderr.printf "#{File.basename $0}: entering %s phase...\n", task if verbose? - begin - __send__ 'exec_' + task - rescue - $stderr.printf "%s failed\n", task - raise - end - $stderr.printf "#{File.basename $0}: %s done.\n", task if verbose? - end - - # - # processing arguments - # - - def parsearg_global - task_re = /\A(?:#{TASKS.map {|i| i[0] }.join '|'})\z/ - - while arg = ARGV.shift - case arg - when /\A\w+\z/ - task_re === arg or raise InstallError, "wrong task: #{arg}" - return arg - - when '-q', '--quiet' - @options['verbose'] = false - - when '--verbose' - @options['verbose'] = true - - when '-h', '--help' - print_usage $stdout - exit 0 - - when '-v', '--version' - puts "#{File.basename $0} version #{Version}" - exit 0 - - when '--copyright' - puts Copyright - exit 0 - - else - raise InstallError, "unknown global option '#{arg}'" - end - end - - raise InstallError, "No task or global option given. -Typical installation procedure is: - $ ruby #{File.basename $0} config - $ ruby #{File.basename $0} setup - # ruby #{File.basename $0} install (may require root privilege) -" - end - - - def parsearg_TASK( task ) - mid = "parsearg_#{task}" - if respond_to? mid, true - __send__ mid - else - ARGV.empty? or - raise InstallError, "#{task}: unknown options: #{ARGV.join ' '}" - end - end - - def parsearg_config - re = /\A--(#{ConfigTable.keys.join '|'})(?:=(.*))?\z/ - @options['config-opt'] = [] - - while i = ARGV.shift - if /\A--?\z/ === i - @options['config-opt'] = ARGV.dup - break - end - m = re.match(i) or raise InstallError, "config: unknown option #{i}" - name, value = m.to_a[1,2] - if value - if ConfigTable.bool_config?(name) - /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i === value or raise InstallError, "config: --#{name} allows only yes/no for argument" - value = (/\Ay(es)?|\At(rue)/i === value) ? 'yes' : 'no' - end - else - ConfigTable.bool_config?(name) or raise InstallError, "config: --#{name} requires argument" - value = 'yes' - end - @config[name] = value - end - end - - def parsearg_install - @options['no-harm'] = false - @options['install-prefix'] = '' - while a = ARGV.shift - case a - when /\A--no-harm\z/ - @options['no-harm'] = true - when /\A--prefix=(.*)\z/ - path = $1 - path = File.expand_path(path) unless path[0,1] == '/' - @options['install-prefix'] = path - else - raise InstallError, "install: unknown option #{a}" - end - end - end - - - def print_usage( out ) - out.puts 'Typical Installation Procedure:' - out.puts " $ ruby #{File.basename $0} config" - out.puts " $ ruby #{File.basename $0} setup" - out.puts " # ruby #{File.basename $0} install (may require root privilege)" - out.puts - out.puts 'Detailed Usage:' - out.puts " ruby #{File.basename $0} " - out.puts " ruby #{File.basename $0} [] []" - - fmt = " %-20s %s\n" - out.puts - out.puts 'Global options:' - out.printf fmt, '-q,--quiet', 'suppress message outputs' - out.printf fmt, ' --verbose', 'output messages verbosely' - out.printf fmt, '-h,--help', 'print this message' - out.printf fmt, '-v,--version', 'print version and quit' - out.printf fmt, ' --copyright', 'print copyright and quit' - - out.puts - out.puts 'Tasks:' - TASKS.each do |name, desc| - out.printf " %-10s %s\n", name, desc - end - - out.puts - out.puts 'Options for config:' - ConfigTable.each_definition do |name, (default, arg, desc, default2)| - out.printf " %-20s %s [%s]\n", - '--'+ name + (ConfigTable.bool_config?(name) ? '' : '='+arg), - desc, - default2 || default - end - out.printf " %-20s %s [%s]\n", - '--rbconfig=path', 'your rbconfig.rb to load', "running ruby's" - - out.puts - out.puts 'Options for install:' - out.printf " %-20s %s [%s]\n", - '--no-harm', 'only display what to do if given', 'off' - out.printf " %-20s %s [%s]\n", - '--prefix', 'install path prefix', '$prefix' - - out.puts - end - - # - # config - # - - def exec_config - super - @config.save - end - - # - # show - # - - def exec_show - ConfigTable.each_name do |k| - v = @config.get_raw(k) - if not v or v.empty? - v = '(not specified)' - end - printf "%-10s %s\n", k, v - end - end - -end - -### end toplevel.rb - -if $0 == __FILE__ - begin - ToplevelInstaller.invoke - rescue - raise if $DEBUG - $stderr.puts $!.message - $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." - exit 1 - end -end diff --git a/vendor/madeleine-0.7.1/lib/madeleine.rb b/vendor/madeleine-0.7.1/lib/madeleine.rb deleted file mode 100755 index 3b6f8fdb..00000000 --- a/vendor/madeleine-0.7.1/lib/madeleine.rb +++ /dev/null @@ -1,420 +0,0 @@ -# -# Madeleine - Ruby Object Prevalence -# -# Author:: Anders Bengtsson -# Copyright:: Copyright (c) 2003-2004 -# -# Usage: -# -# require 'madeleine' -# -# madeleine = SnapshotMadeleine.new("my_example_storage") { -# SomeExampleApplication.new() -# } -# -# madeleine.execute_command(command) -# - -module Madeleine - - require 'thread' - require 'sync' - require 'madeleine/files' - - MADELEINE_VERSION = "0.7.1" - - class SnapshotMadeleine - - # Builds a new Madeleine instance. If there is a snapshot available - # then the system will be created from that, otherwise - # new_system will be used. The state of the system will - # then be restored from the command logs. - # - # You can provide your own snapshot marshaller, for instance using - # YAML or SOAP, instead of Ruby's built-in marshaller. The - # snapshot_marshaller must respond to - # load(stream) and dump(object, stream). You - # must use the same marshaller every time for a system. - # - # See: DefaultSnapshotMadeleine - # - # * directory_name - Storage directory to use. Will be created if needed. - # * snapshot_marshaller - Marshaller to use for system snapshots. (Optional) - # * new_system_block - Block to create a new system (if no stored system was found). - def self.new(directory_name, snapshot_marshaller=Marshal, &new_system_block) - log_factory = DefaultLogFactory.new - logger = Logger.new(directory_name, - log_factory) - snapshotter = Snapshotter.new(directory_name, - snapshot_marshaller) - lock = DefaultLock.new - recoverer = Recoverer.new(directory_name, - snapshot_marshaller) - system = recoverer.recover_snapshot(new_system_block) - - executer = Executer.new(system) - recoverer.recover_logs(executer) - DefaultSnapshotMadeleine.new(system, logger, snapshotter, lock, executer) - end - end - - class DefaultSnapshotMadeleine - - # The prevalent system - attr_reader :system - - def initialize(system, logger, snapshotter, lock, executer) - @system = system - @logger = logger - @snapshotter = snapshotter - @lock = lock - @executer = executer - - @closed = false - end - - # Execute a command on the prevalent system. - # - # Commands must have a method execute(aSystem). - # Otherwise an error, Madeleine::InvalidCommandException, - # will be raised. - # - # The return value from the command's execute() method is returned. - # - # * command - The command to execute on the system. - def execute_command(command) - verify_command_sane(command) - @lock.synchronize { - raise "closed" if @closed - @logger.store(command) - @executer.execute(command) - } - end - - # Execute a query on the prevalent system. - # - # Only differs from execute_command in that the command/query isn't logged, and - # therefore isn't allowed to modify the system. A shared lock is held, preventing others - # from modifying the system while the query is running. - # - # * query - The query command to execute - def execute_query(query) - @lock.synchronize_shared { - @executer.execute(query) - } - end - - # Take a snapshot of the current system. - # - # You need to regularly take a snapshot of a running system, - # otherwise the logs will grow big and restarting the system will take a - # long time. Your backups must also be done from the snapshot files, - # since you can't make a consistent backup of a live log. - # - # A practical way of doing snapshots is a timer thread: - # - # Thread.new(madeleine) {|madeleine| - # while true - # sleep(60 * 60 * 24) # 24 hours - # madeleine.take_snapshot - # end - # } - def take_snapshot - @lock.synchronize { - @logger.close - @snapshotter.take(@system) - @logger.reset - } - end - - # Close the system. - # - # The log file is closed and no new commands can be received - # by this Madeleine. - def close - @lock.synchronize { - @logger.close - @closed = true - } - end - - private - - def verify_command_sane(command) - unless command.respond_to?(:execute) - raise InvalidCommandException.new("Commands must have an 'execute' method") - end - end - end - - class InvalidCommandException < Exception - end - - # - # Internal classes below - # - - FILE_COUNTER_SIZE = 21 #:nodoc: - - class DefaultLock #:nodoc: - - def initialize - @lock = Sync.new - end - - def synchronize(&block) - @lock.synchronize(&block) - end - - def synchronize_shared(&block) - @lock.synchronize(:SH, &block) - end - end - - class Executer #:nodoc: - - def initialize(system) - @system = system - @in_recovery = false - end - - def execute(command) - begin - command.execute(@system) - rescue - raise unless @in_recovery - end - end - - def recovery - begin - @in_recovery = true - yield - ensure - @in_recovery = false - end - end - end - - class Recoverer #:nodoc: - - def initialize(directory_name, marshaller) - @directory_name, @marshaller = directory_name, marshaller - end - - def recover_snapshot(new_system_block) - system = nil - id = SnapshotFile.highest_id(@directory_name) - if id > 0 - snapshot_file = SnapshotFile.new(@directory_name, id).name - open(snapshot_file, "rb") {|snapshot| - system = @marshaller.load(snapshot) - } - else - system = new_system_block.call - end - system - end - - def recover_logs(executer) - executer.recovery { - CommandLog.log_file_names(@directory_name, FileService.new).each {|file_name| - open(@directory_name + File::SEPARATOR + file_name, "rb") {|log| - recover_log(executer, log) - } - } - } - end - - private - - def recover_log(executer, log) - while ! log.eof? - command = Marshal.load(log) - executer.execute(command) - end - end - end - - class NumberedFile #:nodoc: - - def initialize(path, name, id) - @path, @name, @id = path, name, id - end - - def name - result = @path - result += File::SEPARATOR - result += sprintf("%0#{FILE_COUNTER_SIZE}d", @id) - result += '.' - result += @name - end - end - - class CommandLog #:nodoc: - - def self.log_file_names(directory_name, file_service) - return [] unless file_service.exist?(directory_name) - result = file_service.dir_entries(directory_name).select {|name| - name =~ /^\d{#{FILE_COUNTER_SIZE}}\.command_log$/ - } - result.each {|name| name.untaint } - result.sort! - result - end - - def initialize(path, file_service) - id = self.class.highest_log(path, file_service) + 1 - numbered_file = NumberedFile.new(path, "command_log", id) - @file = file_service.open(numbered_file.name, 'wb') - end - - def close - @file.close - end - - def store(command) - Marshal.dump(command, @file) - @file.flush - @file.fsync - end - - def self.highest_log(directory_name, file_service) - highest = 0 - log_file_names(directory_name, file_service).each {|file_name| - match = /^(\d{#{FILE_COUNTER_SIZE}})/.match(file_name) - n = match[1].to_i - if n > highest - highest = n - end - } - highest - end - end - - class DefaultLogFactory #:nodoc: - def create_log(directory_name) - CommandLog.new(directory_name, FileService.new) - end - end - - class Logger #:nodoc: - - def initialize(directory_name, log_factory) - @directory_name = directory_name - @log_factory = log_factory - @log = nil - @pending_tick = nil - ensure_directory_exists - end - - def ensure_directory_exists - if ! File.exist?(@directory_name) - Dir.mkdir(@directory_name) - end - end - - def reset - close - delete_log_files - end - - def store(command) - if command.kind_of?(Madeleine::Clock::Tick) - @pending_tick = command - else - if @pending_tick - internal_store(@pending_tick) - @pending_tick = nil - end - internal_store(command) - end - end - - def internal_store(command) - if @log.nil? - open_new_log - end - @log.store(command) - end - - def close - return if @log.nil? - @log.close - @log = nil - end - - private - - def delete_log_files - Dir.glob(@directory_name + File::SEPARATOR + "*.command_log").each {|name| - name.untaint - File.delete(name) - } - end - - def open_new_log - @log = @log_factory.create_log(@directory_name) - end - end - - class SnapshotFile < NumberedFile #:nodoc: - - def self.highest_id(directory_name) - return 0 unless File.exist?(directory_name) - suffix = "snapshot" - highest = 0 - Dir.foreach(directory_name) {|file_name| - match = /^(\d{#{FILE_COUNTER_SIZE}}\.#{suffix}$)/.match(file_name) - next unless match - n = match[1].to_i - if n > highest - highest = n - end - } - highest - end - - def self.next(directory_name) - new(directory_name, highest_id(directory_name) + 1) - end - - def initialize(directory_name, id) - super(directory_name, "snapshot", id) - end - end - - class Snapshotter #:nodoc: - - def initialize(directory_name, marshaller) - @directory_name, @marshaller = directory_name, marshaller - end - - def take(system) - numbered_file = SnapshotFile.next(@directory_name) - name = numbered_file.name - open(name + '.tmp', 'wb') {|snapshot| - @marshaller.dump(system, snapshot) - snapshot.flush - snapshot.fsync - } - File.rename(name + '.tmp', name) - end - end - - module Clock #:nodoc: - class Tick #:nodoc: - - def initialize(time) - @time = time - end - - def execute(system) - system.clock.forward_to(@time) - end - end - end -end - -SnapshotMadeleine = Madeleine::SnapshotMadeleine - diff --git a/vendor/madeleine-0.7.1/lib/madeleine/automatic.rb b/vendor/madeleine-0.7.1/lib/madeleine/automatic.rb deleted file mode 100755 index 447d5ec3..00000000 --- a/vendor/madeleine-0.7.1/lib/madeleine/automatic.rb +++ /dev/null @@ -1,418 +0,0 @@ -require 'yaml' -require 'madeleine/zmarshal' -require 'soap/marshal' - -module Madeleine - -# Automatic commands for Madeleine -# -# Author:: Stephen Sykes -# Copyright:: Copyright (C) 2003-2004 -# Version:: 0.41 -# -# This module provides a way of automatically generating command objects for madeleine to -# store. It works by making a proxy object for all objects of any classes in which it is included. -# Method calls to these objects are intercepted, and stored as a command before being -# passed on to the real receiver. The command objects remember which object the command was -# destined for by using a pair of internal ids that are contained in each of the proxy objects. -# -# There is also a mechanism for specifying which methods not to intercept calls to by using -# automatic_read_only, and its opposite automatic_read_write. -# -# Should you require it, the snapshots can be stored as yaml, and can be compressed. Just pass -# the marshaller you want to use as the second argument to AutomaticSnapshotMadeleine.new. -# If the passed marshaller did not successfully deserialize the latest snapshot, the system -# will try to automatically detect and read either Marshal, YAML, SOAP, or their corresponding -# compressed versions. -# -# This module is designed to work correctly in the case there are multiple madeleine systems in use by -# a single program, and is also safe to use with threads. -# -# Usage: -# -# require 'madeleine' -# require 'madeleine/automatic' -# -# class A -# include Madeleine::Automatic::Interceptor -# attr_reader :foo -# automatic_read_only :foo -# def initialize(param1, ...) -# ... -# end -# def some_method(paramA, ...) -# ... -# end -# automatic_read_only -# def bigfoo -# foo.upcase -# end -# end -# -# mad = AutomaticSnapshotMadeleine.new("storage_directory") { A.new(param1, ...) } -# -# mad.system.some_method(paramA, ...) # logged as a command by madeleine -# print mad.foo # not logged -# print mad.bigfoo # not logged -# mad.take_snapshot -# - - module Automatic -# -# This module should be included (at the top) in any classes that are to be persisted. -# It will intercept method calls and make sure they are converted into commands that are logged by Madeleine. -# It does this by returning a Prox object that is a proxy for the real object. -# -# It also handles automatic_read_only and automatic_read_write, allowing user specification of which methods -# should be made into commands -# - module Interceptor -# -# When included, redefine new so that we can return a Prox object instead, and define methods to handle -# keeping track of which methods are read only -# - def self.included(klass) - class < "") - x - end - - end - -# -# The AutomaticSnapshotMadeleine class contains an instance of the persister -# (default is SnapshotMadeleine) and provides additional automatic functionality. -# -# The class is instantiated the same way as SnapshotMadeleine: -# madeleine_sys = AutomaticSnapshotMadeleine.new("storage_directory") { A.new(param1, ...) } -# The second initialisation parameter is the persister. Supported persisters are: -# -# * Marshal (default) -# * YAML -# * SOAP::Marshal -# * Madeleine::ZMarshal.new(Marshal) -# * Madeleine::ZMarshal.new(YAML) -# * Madeleine::ZMarshal.new(SOAP::Marshal) -# -# The class keeps a record of all the systems that currently exist. -# Each instance of the class keeps a record of Prox objects in that system by internal id (myid). -# -# We also add functionality to take_snapshot in order to set things up so that the custom Prox object -# marshalling will work correctly. -# - class AutomaticSnapshotMadeleine - attr_accessor :marshaller - attr_reader :list, :sysid - - def initialize(directory_name, marshaller=Marshal, persister=SnapshotMadeleine, &new_system_block) - @sysid ||= Time.now.to_f.to_s + Thread.current.object_id.to_s # Gererate a new sysid - @myid_count = 0 - @list = {} - Thread.current[:system] = self # during system startup system should not create commands - Thread.critical = true - @@systems ||= {} # holds systems by sysid - @@systems[@sysid] = self - Thread.critical = false - @marshaller = marshaller # until attrb - begin - @persister = persister.new(directory_name, Automatic_marshaller, &new_system_block) - @list.delete_if {|k,v| # set all the prox objects that now exist to have the right sysid - begin - ObjectSpace._id2ref(v).sysid = @sysid - false - rescue RangeError - true # Id was to a GC'd object, delete it - end - } - ensure - Thread.current[:system] = false - end - end -# -# Add a proxy object to the list, return the myid for that object -# - def add(proxo) - @list[@myid_count += 1] = proxo.object_id - @myid_count - end -# -# Restore a marshalled proxy object to list - myid_count is increased as required. -# If the object already exists in the system then the existing object must be used. -# - def restore(proxo) - if (@list[proxo.myid]) - proxo = myid2ref(proxo.myid) - else - @list[proxo.myid] = proxo.object_id - @myid_count = proxo.myid if (@myid_count < proxo.myid) - end - proxo - end -# -# Returns a reference to the object indicated by the internal id supplied. -# - def myid2ref(myid) - raise "Internal id #{myid} not found" unless objid = @list[myid] - ObjectSpace._id2ref(objid) - end -# -# Take a snapshot of the system. -# - def take_snapshot - begin - Thread.current[:system] = self - Thread.current[:snapshot_memory] = {} - @persister.take_snapshot - ensure - Thread.current[:snapshot_memory] = nil - Thread.current[:system] = false - end - end -# -# Returns the hash containing the systems. -# - def AutomaticSnapshotMadeleine.systems - @@systems - end -# -# Close method changes the sysid for Prox objects so they can't be mistaken for real ones in a new -# system before GC gets them -# - def close - begin - @list.each_key {|k| myid2ref(k).sysid = nil} - rescue RangeError - # do nothing - end - @persister.close - end - -# -# Pass on any other calls to the persister -# - def method_missing(symbol, *args, &block) - @persister.send(symbol, *args, &block) - end - end - - - module Deserialize #:nodoc: -# -# Detect format of an io stream. Leave it rewound. -# - def Deserialize.detect(io) - c = io.getc - c1 = io.getc - io.rewind - if (c == Marshal::MAJOR_VERSION && c1 <= Marshal::MINOR_VERSION) - Marshal - elsif (c == 31 && c1 == 139) # gzip magic numbers - ZMarshal - else - while (s = io.gets) - break if (s !~ /^\s*$/) # ignore blank lines - end - io.rewind - if (s && s =~ /^\s*<\?[xX][mM][lL]/) # " e - io.rewind - detected_marshaller = detect(io) - if (detected_marshaller == ZMarshal) - zio = Zlib::GzipReader.new(io) - detected_zmarshaller = detect(zio) - zio.finish - io.rewind - if (detected_zmarshaller) - ZMarshal.new(detected_zmarshaller).load(io) - else - raise e - end - elsif (detected_marshaller) - detected_marshaller.load(io) - else - raise e - end - end - end - end - - end -end - -AutomaticSnapshotMadeleine = Madeleine::Automatic::AutomaticSnapshotMadeleine diff --git a/vendor/madeleine-0.7.1/lib/madeleine/clock.rb b/vendor/madeleine-0.7.1/lib/madeleine/clock.rb deleted file mode 100755 index 012c6f27..00000000 --- a/vendor/madeleine-0.7.1/lib/madeleine/clock.rb +++ /dev/null @@ -1,94 +0,0 @@ -# -# Copyright(c) Anders Bengtsson 2003 -# - -require 'madeleine' - -module Madeleine - module Clock - - # Deprecated. Use SnapshotMadeleine instead. - class ClockedSnapshotMadeleine < ::Madeleine::SnapshotMadeleine # :nodoc: - end - - # Let your system extend this module if you need to access the - # machine time. Used together with a TimeActor that keeps - # the clock current. - module ClockedSystem - - # Returns this system's Clock. - def clock - unless defined? @clock - @clock = Clock.new - end - @clock - end - end - - # Sends clock ticks to update a ClockedSystem, so that time can be - # dealt with in a deterministic way. - class TimeActor - - # Create and launch a new TimeActor - # - # * madeleine - The SnapshotMadeleine instance to work on. - # * delay - Delay between ticks in seconds (Optional). - def self.launch(madeleine, delay=0.1) - result = new(madeleine, delay) - result - end - - # Stops the TimeActor. - def destroy - @is_destroyed = true - @thread.wakeup - @thread.join - end - - private_class_method :new - - private - - def initialize(madeleine, delay) #:nodoc: - @madeleine = madeleine - @is_destroyed = false - send_tick - @thread = Thread.new { - until @is_destroyed - sleep(delay) - send_tick - end - } - end - - def send_tick - @madeleine.execute_command(Tick.new(Time.now)) - end - end - - # Keeps track of time in a ClockedSystem. - class Clock - # Returns the system's time as a Ruby Time. - attr_reader :time - - def initialize - @time = Time.at(0) - end - - def forward_to(newTime) - @time = newTime - end - end - - # - # Internal classes below - # - - # Deprecated. Merged into default implementation. - class TimeOptimizingLogger < ::Madeleine::Logger # :nodoc: - end - - end -end - -ClockedSnapshotMadeleine = Madeleine::Clock::ClockedSnapshotMadeleine diff --git a/vendor/madeleine-0.7.1/lib/madeleine/files.rb b/vendor/madeleine-0.7.1/lib/madeleine/files.rb deleted file mode 100755 index 4276d8d5..00000000 --- a/vendor/madeleine-0.7.1/lib/madeleine/files.rb +++ /dev/null @@ -1,19 +0,0 @@ -# -# Wrapper for Ruby's file services, replaced during testing -# so we can run tests without touching a real filesystem. -# - -class FileService - - def open(*args) - super(*args) - end - - def exist?(name) - File.exist?(name) - end - - def dir_entries(name) - Dir.entries(name) - end -end diff --git a/vendor/madeleine-0.7.1/lib/madeleine/zmarshal.rb b/vendor/madeleine-0.7.1/lib/madeleine/zmarshal.rb deleted file mode 100755 index b01210ec..00000000 --- a/vendor/madeleine-0.7.1/lib/madeleine/zmarshal.rb +++ /dev/null @@ -1,60 +0,0 @@ -# -# Author:: Anders Bengtsson -# Copyright:: Copyright (c) 2004 -# - -require 'zlib' - -module Madeleine - # - # Snapshot marshaller for compressed snapshots. - # - # Compresses the snapshots created by another marshaller. Uses either - # Marshal (the default) or another supplied marshaller. - # - # Uses zlib to do on-the-fly compression/decompression. - # - # ZMarshal works with Ruby's own Marshal and YAML, but not with SOAP - # marshalling. - # - # Usage: - # - # require 'madeleine' - # require 'madeleine/zmarshal' - # - # marshaller = Madeleine::ZMarshal.new(YAML) - # madeleine = SnapshotMadeleine.new("my_example_storage", marshaller) { - # SomeExampleApplication.new() - # } - # - class ZMarshal - - def initialize(marshaller=Marshal) - @marshaller = marshaller - end - - def load(stream) - zstream = Zlib::GzipReader.new(stream) - begin - # Buffer into a string first, since GzipReader can't handle - # Marshal's 0-sized reads and SOAP can't handle streams at all. - # In a bright future we can revert to reading directly from the - # stream again. - buffer = zstream.read - return @marshaller.load(buffer) - ensure - zstream.finish - end - end - - def dump(system, stream) - zstream = Zlib::GzipWriter.new(stream) - begin - @marshaller.dump(system, zstream) - ensure - zstream.finish - end - nil - end - end -end diff --git a/vendor/madeleine-0.7.1/madeleine.gemspec b/vendor/madeleine-0.7.1/madeleine.gemspec deleted file mode 100755 index cd5d38f8..00000000 --- a/vendor/madeleine-0.7.1/madeleine.gemspec +++ /dev/null @@ -1,23 +0,0 @@ - -require 'rubygems' - -spec = Gem::Specification.new do |s| - s.name = 'madeleine' - s.version = '0.7.1' - s.platform = Gem::Platform::RUBY - s.required_ruby_version = ">= 1.8.1" - s.summary = "Madeleine is a Ruby implementation of Object Prevalence" - s.require_path = 'lib' - s.autorequire = 'madeleine' - s.author = "Anders Bengtsson" - s.email = "ndrsbngtssn@yahoo.se" - s.homepage = "http://madeleine.sourceforge.net" - s.files = Dir.glob("lib/**/*.rb") - s.files += Dir.glob("samples/**/*.rb") - s.files += Dir.glob("contrib/**/*.rb") - s.files += ['README', 'NEWS', 'COPYING'] -end - -if $0 == __FILE__ - Gem::Builder.new(spec).build -end diff --git a/vendor/madeleine-0.7.1/samples/.cvsignore b/vendor/madeleine-0.7.1/samples/.cvsignore deleted file mode 100755 index 5ca652ac..00000000 --- a/vendor/madeleine-0.7.1/samples/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -dictionary-base -painter-demo -clock-demo diff --git a/vendor/madeleine-0.7.1/samples/clock_click.rb b/vendor/madeleine-0.7.1/samples/clock_click.rb deleted file mode 100755 index c11d16a3..00000000 --- a/vendor/madeleine-0.7.1/samples/clock_click.rb +++ /dev/null @@ -1,73 +0,0 @@ -# -# Simple example of using time with Madeleine. -# - -$LOAD_PATH.unshift(".." + File::SEPARATOR + "lib") - -require 'madeleine/clock' -require 'tk' - -# The Clicker keeps track of when it was last clicked. -# -# To access the time it extends ClockedSystem, which provides -# it with the 'clock' attribute. -# -class Clicker - include Madeleine::Clock::ClockedSystem - - def initialize - @last_clicked = nil - end - - def click - @last_clicked = clock.time - end - - def last_clicked - return '-' if @last_clicked.nil? - @last_clicked.to_s - end -end - -# A command to update the Clicker with. -# -class Click - def execute(system) - system.click - end -end - -# Launch a ClockedSnapshotMadeleine. -# -# ClockedSnapshotMadeleine works like the regular SnapshotMadeleine, but -# optimizes away redundant commands from TimeActor. -# -madeleine = ClockedSnapshotMadeleine.new("clock-demo") { Clicker.new } - -# Launch the TimeActor. -# -# This provides time commands, without which the system's time would stand still. -# -Madeleine::Clock::TimeActor.launch(madeleine) - -clicker = madeleine.system - -# The GUI - -root = TkRoot.new() { title "Madeleine Clock Example" } -label = TkLabel.new(root) { - text "Last clicked " + clicker.last_clicked - width 40 - pack -} -button = TkButton.new(root) { - text 'Click' - command proc { - madeleine.execute_command(Click.new) - label.text("Last clicked " + clicker.last_clicked) - } - pack -} - -Tk.mainloop - diff --git a/vendor/madeleine-0.7.1/samples/dictionary_client.rb b/vendor/madeleine-0.7.1/samples/dictionary_client.rb deleted file mode 100755 index 596eab5f..00000000 --- a/vendor/madeleine-0.7.1/samples/dictionary_client.rb +++ /dev/null @@ -1,23 +0,0 @@ -# -# Dictionary client -# -# See dictionary_server.rb for details -# - -require 'drb' - -DRb.start_service -dictionary = DRbObject.new(nil, "druby://localhost:1234") - -if ARGV.length == 1 - puts dictionary.lookup(ARGV[0]) -elsif ARGV.length == 2 - dictionary.add(ARGV[0], ARGV[1]) - puts "Stored" -else - puts "Usage: dictionary_client []" -end - - - - diff --git a/vendor/madeleine-0.7.1/samples/dictionary_server.rb b/vendor/madeleine-0.7.1/samples/dictionary_server.rb deleted file mode 100755 index 76c8e925..00000000 --- a/vendor/madeleine-0.7.1/samples/dictionary_server.rb +++ /dev/null @@ -1,94 +0,0 @@ -# -# A dictionary server using Distributed Ruby (DRb). -# -# All modifications to the dictionary are done as commands, -# while read-only queries (i.e 'lookup') are done directly. -# -# First launch this server in the background, then use -# dictionary_client.rb to look up and add items to the -# dictionary. -# You can kill the server at any time. The contents of the -# dictionary will still be there when you restart it. -# -# DRb is available at http://raa.ruby-lang.org/list.rhtml?name=druby -# - -$LOAD_PATH.unshift(".." + File::SEPARATOR + "lib") -require 'madeleine' - -require 'drb' - - -class Dictionary - def initialize - @data = {} - end - - def add(key, value) - @data[key] = value - end - - def lookup(key) - @data[key] - end -end - - -class Addition - def initialize(key, value) - @key, @value = key, value - end - - def execute(system) - system.add(@key, @value) - end -end - - -class Lookup - def initialize(key) - @key = key - end - - def execute(system) - system.lookup(@key) - end -end - - -class DictionaryServer - - def initialize(madeleine) - @madeleine = madeleine - @dictionary = madeleine.system - end - - def add(key, value) - # When adding a new key-value pair we modify the system, so - # this operation has to be done through a command. - @madeleine.execute_command(Addition.new(key, value)) - end - - def lookup(key) - # A lookup is a read-only operation, so we can do it as a non-logged - # query. If we weren't worried about concurrency problems we could - # have just called @dictionary.lookup(key) directly instead. - @madeleine.execute_query(Lookup.new(key)) - end -end - - -madeleine = SnapshotMadeleine.new("dictionary-base") { Dictionary.new } - -Thread.new(madeleine) { - puts "Taking snapshot every 30 seconds." - while true - sleep(30) - madeleine.take_snapshot - end -} - -DRb.start_service("druby://localhost:1234", - DictionaryServer.new(madeleine)) -DRb.thread.join - diff --git a/vendor/madeleine-0.7.1/samples/painter.rb b/vendor/madeleine-0.7.1/samples/painter.rb deleted file mode 100755 index b9d21658..00000000 --- a/vendor/madeleine-0.7.1/samples/painter.rb +++ /dev/null @@ -1,60 +0,0 @@ -# -# Simple drawing program to show Madeleine's logging feature. -# -# When you restart the program, your old artwork is still there. -# -# (Note: The GUI components used here aren't marshal-able, -# so in a real app you would have to do custom marshaling for -# the Painter class to get working snapshots. Then again, in a real -# app you wouldn't use the GUI components to hold the app's data, -# would you?) -# - -$LOAD_PATH.unshift(".." + File::SEPARATOR + "lib") - -require 'madeleine' - -require 'tkclass' - -class Painter - - def initialize(canvas) - @canvas = canvas - end - - def draw(x, y) - line = Line.new(@canvas, x, y, x + 1, y + 1) - line.fill('black') - end -end - -class PaintCommand - - def initialize(x, y) - @x, @y = x, y - end - - def execute(system) - system.draw(@x, @y) - end -end - -root = TkRoot.new() { title "Madeleine Painter" } -canvas = Canvas.new(root) -canvas.pack - -$madeleine = Madeleine::SnapshotMadeleine.new("painter-demo") { Painter.new(canvas) } - -canvas.bind("1", - proc {|x, y| - $madeleine.execute_command(PaintCommand.new(x, y)) - }, - "%x %y") -canvas.bind("B1-Motion", - proc {|x, y| - $madeleine.execute_command(PaintCommand.new(x, y)) - }, - "%x %y") - -Tk.mainloop - diff --git a/vendor/madeleine-0.7.1/test/test.rb b/vendor/madeleine-0.7.1/test/test.rb deleted file mode 100755 index e252a53f..00000000 --- a/vendor/madeleine-0.7.1/test/test.rb +++ /dev/null @@ -1,320 +0,0 @@ -#!/usr/bin/env ruby -# - -$LOAD_PATH.unshift("lib") -$LOAD_PATH.unshift("test") - -require 'madeleine' -require 'test/unit' - - -class Append - def initialize(value) - @value = value - end - - def execute(system) - system << @value - end -end - - -module TestUtils - def delete_directory(directory_name) - return unless File.exists?(directory_name) - Dir.foreach(directory_name) do |file| - next if file == "." - next if file == ".." - assert(File.delete(directory_name + File::SEPARATOR + file) == 1, - "Unable to delete #{file}") - end - Dir.delete(directory_name) - end -end - - -class SnapshotMadeleineTest < Test::Unit::TestCase - include TestUtils - - def teardown - delete_directory(persistence_base) - end - - def persistence_base - "closing-test" - end - - def test_closing - madeleine = SnapshotMadeleine.new(persistence_base) { "hello" } - madeleine.close - assert_raises(RuntimeError) do - madeleine.execute_command(Append.new("world")) - end - end -end - -class NumberedFileTest < Test::Unit::TestCase - - def test_main - target = Madeleine::NumberedFile.new(File::SEPARATOR + "foo", "bar", 321) - assert_equal(File::SEPARATOR + "foo" + File::SEPARATOR + - "000000000000000000321.bar", - target.name) - end -end - - -class LoggerTest < Test::Unit::TestCase - include TestUtils - - def teardown - delete_directory("whoah") - end - - def test_creation - @log = Object.new - def @log.store(command) - unless defined? @commands - @commands = [] - end - @commands << command - end - def @log.commands - @commands - end - - log_factory = self - target = Madeleine::Logger.new("whoah", log_factory) - target.store(:foo) - assert(@log.commands.include?(:foo)) - end - - # Self-shunt - def create_log(directory_name) - @log - end -end - -class CommandVerificationTest < Test::Unit::TestCase - - def teardown - Dir.delete("foo") - end - - def test_broken_command - target = SnapshotMadeleine.new("foo") { :a_system } - assert_raises(Madeleine::InvalidCommandException) do - target.execute_command(:not_a_command) - end - end -end - - -class CustomMarshallerTest < Test::Unit::TestCase - include TestUtils - - def teardown - delete_directory(prevalence_base) - end - - def prevalence_base - "custom-marshaller-test" - end - - def madeleine_class - SnapshotMadeleine - end - - def test_changing_marshaller - @log = "" - marshaller = self - target = madeleine_class.new(prevalence_base, marshaller) { "hello world" } - target.take_snapshot - assert_equal("dump ", @log) - target = nil - - madeleine_class.new(prevalence_base, marshaller) { flunk() } - assert_equal("dump load ", @log) - end - - def load(io) - @log << "load " - assert_equal("dump data", io.read()) - end - - def dump(system, io) - @log << "dump " - assert_equal("hello world", system) - io.write("dump data") - end -end - - -class ErrorRaisingCommand - def execute(system) - raise "this is an exception from a command" - end -end - -class ErrorHandlingTest < Test::Unit::TestCase - include TestUtils - - def teardown - delete_directory(prevalence_base) - end - - def prevalence_base - "error-handling-base" - end - - def test_exception_in_command - madeleine = SnapshotMadeleine.new(prevalence_base) { "hello" } - assert_raises(RuntimeError) do - madeleine.execute_command(ErrorRaisingCommand.new) - end - madeleine.close - madeleine = SnapshotMadeleine.new(prevalence_base) { "hello" } - madeleine.close - end -end - -class QueryTest < Test::Unit::TestCase - include TestUtils - - def teardown - delete_directory(prevalence_base) - end - - def prevalence_base - "query-base" - end - - def test_querying - madeleine = SnapshotMadeleine.new(prevalence_base) { "hello" } - query = Object.new - def query.execute(system) - system.size - end - # 'query' is an un-marshallable singleton, so we implicitly test - # that querys aren't stored. - assert_equal(5, madeleine.execute_query(query)) - # TODO: assert that no logging was done - # TODO: assert that lock was held - end -end - - -class TimeOptimizingLoggerTest < Test::Unit::TestCase - include TestUtils - - def setup - @target = Madeleine::Logger.new("some_directory", self) - @log = [] - def @log.store(command) - self << command - end - end - - def teardown - delete_directory("some_directory") - end - - def test_optimizing_ticks - assert_equal(0, @log.size) - @target.store(Madeleine::Clock::Tick.new(Time.at(3))) - assert_equal(0, @log.size) - @target.store(Madeleine::Clock::Tick.new(Time.at(22))) - assert_equal(0, @log.size) - @target.store(Addition.new(100)) - assert_kind_of(Madeleine::Clock::Tick, @log[0]) - assert_equal(22, value_of_tick(@log[0])) - assert_equal(100, @log[1].value) - assert_equal(2, @log.size) - end - - def value_of_tick(tick) - @clock = Object.new - def @clock.forward_to(time) - @value = time.to_i - end - def @clock.value - @value - end - tick.execute(self) - @clock.value - end - - # Self-shunt - def create_log(directory_name) - assert_equal("some_directory", directory_name) - @log - end - - # Self-shunt - def clock - @clock - end -end - - -class SharedLockQueryTest < Test::Unit::TestCase - include TestUtils - - def prevalence_base - "shared_lock_test" - end - - def teardown - delete_directory(prevalence_base) - end - - def test_query - madeleine = SnapshotMadeleine.new(prevalence_base) { "hello" } - lock = Object.new - madeleine.instance_eval { @lock = lock } # FIXME: The horror, the horror - - $shared = false - $was_shared = false - def lock.synchronize_shared(&block) - $shared = true - block.call - $shared = false - end - query = Object.new - def query.execute(system) - $was_shared = $shared - end - madeleine.execute_query(query) - assert($was_shared) - end -end - -suite = Test::Unit::TestSuite.new("Madeleine") - -suite << SnapshotMadeleineTest.suite -suite << NumberedFileTest.suite -require 'test_command_log' -suite << CommandLogTest.suite -suite << LoggerTest.suite -suite << CommandVerificationTest.suite -suite << CustomMarshallerTest.suite -suite << ErrorHandlingTest.suite -suite << QueryTest.suite -suite << TimeOptimizingLoggerTest.suite -suite << SharedLockQueryTest.suite -require 'test_executer' -suite << ExecuterTest.suite - -require 'test_clocked' -add_clocked_tests(suite) -require 'test_automatic' -add_automatic_tests(suite) -require 'test_persistence' -add_persistence_tests(suite) -require 'test_platforms' -add_platforms_tests(suite) -require 'test_zmarshal' -add_zmarshal_tests(suite) - -require 'test/unit/ui/console/testrunner' -Test::Unit::UI::Console::TestRunner.run(suite) diff --git a/vendor/madeleine-0.7.1/test/test_automatic.rb b/vendor/madeleine-0.7.1/test/test_automatic.rb deleted file mode 100755 index da0c1719..00000000 --- a/vendor/madeleine-0.7.1/test/test_automatic.rb +++ /dev/null @@ -1,559 +0,0 @@ -#!/usr/local/bin/ruby -w -# -# Copyright(c) 2003-2004 Stephen Sykes -# Copyright(c) 2003-2004 Anders Bengtsson -# - -$LOAD_PATH.unshift("lib") - -require 'madeleine' -require 'madeleine/automatic' -require 'test/unit' -#require 'contrib/batched.rb' # uncomment if testing batched - -class A - include Madeleine::Automatic::Interceptor - attr_accessor :z,:k - def initialize - @k=1 - end -end - -class B - include Madeleine::Automatic::Interceptor - attr_accessor :yy, :s - def initialize(a) - @yy = C.new(a) - end -end - -class C - include Madeleine::Automatic::Interceptor - attr_accessor :x, :a - def initialize(x) - @x = x - @a ||= D.new - end -end - -# direct changes in this class are not saved, except at snapshot -class D - attr_accessor :w -end - -class F - include Madeleine::Automatic::Interceptor - attr_accessor :z,:a - def plus1 - @z += 1 - end -end - -class G - include Madeleine::Automatic::Interceptor - attr_accessor :yy,:a - def initialize - @yy = H.new - end -end - -class H - include Madeleine::Automatic::Interceptor - attr_accessor :w - def minus1 - @w -= 1 - end -end - -class I - include Madeleine::Automatic::Interceptor - def initialize - @x = J.new - end - def testyield - r = false - @x.yielder {|c| r = true if c == 1} - r - end -end - -class J - include Madeleine::Automatic::Interceptor - def yielder - yield 1 - end -end - -class K - include Madeleine::Automatic::Interceptor - attr_accessor :k - def initialize - @k=1 - end - def seven - @k=7 - end - def fourteen - @k=14 - end - automatic_read_only :fourteen - automatic_read_only - def twentyone - @k=21 - end -end - -class L - include Madeleine::Automatic::Interceptor - attr_reader :x - def initialize - @x = M.new(self) - end -end - -class M - include Madeleine::Automatic::Interceptor - attr_reader :yy - def initialize(yy) - @yy = yy - end -end - -class AutoTest < Test::Unit::TestCase - - def persister - SnapshotMadeleine - end - - def delete_directory(directory_name) - return unless File.exist?(directory_name) - Dir.foreach(directory_name) do |file| - next if file == "." - next if file == ".." - assert(File.delete(directory_name + File::SEPARATOR + file) == 1, - "Unable to delete #{file}") - end - Dir.delete(directory_name) - end - - def create_new_system(klass, dir, *arg) - delete_directory(dir) - Thread.critical = true - @system_bases << dir - Thread.critical = false - make_system(dir) { klass.new(*arg) } - end - - def make_system(dir, marshaller=Marshal, &block) - AutomaticSnapshotMadeleine.new(dir, marshaller, persister, &block) - end - - def prevalence_base - "AutoPrevalenceTestBase" + self.class.to_s - end - - def setup - @system_bases = [] - end - - def teardown - @system_bases.each {|dir| - delete_directory(dir) - } - end - - def simpletest(n) - pb = prevalence_base + n.to_s - mad_a = create_new_system(A, pb) - mad_a.close - mad_a1 = make_system(pb) { A.new } - assert_equal(1, mad_a1.system.k, "No commands or snapshot") - mad_a1.system.z = 0 - mad_a1.system.z += 1 - assert_equal(1, mad_a1.system.z, "Object changes") - mad_a1.system.z -= 10 - assert_equal(-9, mad_a1.system.z, "Object changes") - mad_a1.close - mad_a2 = make_system(pb) { A.new } - assert_equal(-9, mad_a2.system.z, "Commands but no snapshot") - mad_a2.take_snapshot - mad_a2.close - mad_a3 = make_system(pb) { A.new } - assert_equal(-9, mad_a3.system.z, "Snapshot but no commands") - mad_a3.system.z -= 6 - mad_a3.system.z -= 3 - mad_a3.close - mad_a4 = make_system(pb) { A.new } - assert_equal(-18, mad_a4.system.z, "Snapshot and commands") - mad_a4.close - end -end - -# Basic test, and that system works in SAFE level 1 -class BasicTest < AutoTest - def test_main - simpletest(1) - end - - def test_main_in_safe_level_one - thread = Thread.new { - $SAFE = 1 - test_main - } - thread.join - end -end - -class ObjectOutsideTest < AutoTest - def test_main - mad = create_new_system(A, prevalence_base) - assert_raises(RuntimeError) { - mad.system.z = A.new # app object created outside system - } - mad.close - end -end - -# Passing a block when it would generate a command is not allowed because blocks cannot -# be serialised. However, block passing/yielding inside the application is ok. -class BlockGivenTest < AutoTest - def test_main - mad = create_new_system(J, prevalence_base) - assert_raises(RuntimeError) { - mad.system.yielder {|a| a} - } - mad.close - mad2 = create_new_system(I, prevalence_base+"2") - assert(mad2.system.testyield, "Internal block passing") - mad2.close - end -end - -class NonPersistedObjectTest < AutoTest - def test_main - mad_b = create_new_system(B, prevalence_base, 0) - mad_b.system.yy.x -= 1 - assert_equal(-1, mad_b.system.yy.x, "Direct change of object inside main object") - - mad_b.system.yy.a.w ||= "hello" # not saved - mad_b.system.yy.a.w += " again" # not saved - - assert_equal("hello again", mad_b.system.yy.a.w, "Non persisted object before close") - - mad_b.close - mad_b2 = make_system(prevalence_base) { B.new(0) } - assert_equal(nil, mad_b2.system.yy.a.w, "Non persisted object after restart, no snapshot") - mad_b2.system.yy.a.w ||= "hello" # not saved - mad_b2.system.yy.a.w += " again" # not saved - mad_b2.take_snapshot # NOW saved - mad_b2.system.yy.a.w += " again" # not saved - assert_equal("hello again again", mad_b2.system.yy.a.w, "Non persisted object after take_snapshot and 1 change") - - mad_b2.close - mad_b3 = make_system(prevalence_base) { B.new(0) } - assert_equal("hello again", mad_b3.system.yy.a.w, "Non persisted object after restore (back to snapshotted state)") - mad_b3.close - end -end - -class RefInExternalObjTest < AutoTest - def test_main - mad_c = create_new_system(B, prevalence_base, 0) - x = D.new - x.w = mad_c.system.yy - mad_c.system.s = x # pass in an external object that contains a ref to obj in ths system - - mad_c.system.s.w.x += 1 # Increment counter via external obj - assert_equal(1, mad_c.system.yy.x, "Change via external object") - mad_c.system.yy.x += 1 # Increment counter directly - assert_equal(2, mad_c.system.s.w.x, "Direct change") - mad_c.close - - mad_c2 = make_system(prevalence_base) { B.new(0) } - assert_equal(2, mad_c2.system.s.w.x, "Value via external object after commands/restore") - assert_equal(2, mad_c2.system.yy.x, "Direct value after restore") - mad_c2.take_snapshot - mad_c2.close - - mad_c3 = make_system(prevalence_base) { B.new(0) } - assert_equal(2, mad_c3.system.s.w.x, "Value via external object after snapshot/restore") - assert_equal(2, mad_c3.system.yy.x, "Direct value after snapshot/restore") - - mad_c3.system.s.w.x += 1 # Increment counter via external obj - mad_c3.system.yy.x += 1 # Increment counter directly - mad_c3.close - - mad_c4 = make_system(prevalence_base) { B.new(0) } - assert_equal(4, mad_c4.system.s.w.x, "Value via external object after snapshot+commands/restore") - assert_equal(4, mad_c4.system.yy.x, "Direct value after snapshot+commands/restore") - mad_c4.close - end -end - -class BasicThreadSafetyTest < AutoTest - def test_main - x = Thread.new { - simpletest(1) - } - y = Thread.new { - simpletest(2) - } - x.join - y.join - end -end - -class ThreadConfidenceTest < AutoTest - def test_main - mad_d = create_new_system(F, prevalence_base) - mad_d.system.z = 0 - mad_e = create_new_system(G, prevalence_base+"2") - mad_e.system.yy.w = 0 - - x = [] - 25.times {|n| - x[n] = Thread.new { - 5.times { - sleep(rand/10) - mad_d.system.plus1 - mad_e.system.yy.minus1 - } - } - } - 25.times {|n| - x[n].join - } - assert_equal(125, mad_d.system.z, "125 commands") - assert_equal(-125, mad_e.system.yy.w, "125 commands") - - mad_e.close - mad_e2 = make_system(prevalence_base+"2") { G.new } - - 25.times {|n| - x[n] = Thread.new { - 5.times { - sleep(rand/10) - mad_d.system.plus1 - mad_e2.system.yy.minus1 - } - } - } - 25.times {|n| - x[n].join - } - assert_equal(250, mad_d.system.z, "restore/125 commands") - assert_equal(-250, mad_e2.system.yy.w, "restore/125 commands") - mad_d.close - mad_e2.close - end -end - -class InvalidMethodTest < AutoTest - def test_main - mad_f = create_new_system(A, prevalence_base) - mad_f.system.z = -1 - assert_raises(NoMethodError) { - mad_f.system.not_a_method - } - assert_equal(-1, mad_f.system.z, "System functions after NoMethodError") - mad_f.close - end -end - -class CircularReferenceTest < AutoTest - def test_main - mad_g = create_new_system(G, prevalence_base) - mad_g.system.yy.w = mad_g.system - mad_g.close - mad_g2 = make_system(prevalence_base) { G.new } - assert(mad_g2.system == mad_g2.system.yy.w.yy.w.yy.w, "Circular reference after command/restore") - mad_g2.take_snapshot - mad_g2.close - mad_g3 = make_system(prevalence_base) { G.new } - assert(mad_g3.system == mad_g3.system.yy.w.yy.w.yy.w, "Circular reference after snapshot/restore") - mad_g3.system.yy.w.yy.w.yy.w.a = 1 - assert_equal(1, mad_g3.system.a, "Circular reference change") - mad_g3.close - mad_g4 = make_system(prevalence_base) { G.new } - assert_equal(1, mad_g4.system.yy.w.yy.w.yy.w.a, "Circular reference after snapshot+commands/restore") - mad_g4.close -# The following tests would fail, cannot pass self (from class L to class M during init) -# self is the proxied object itself, not the Prox object it needs to be - mad_l = create_new_system(L, prevalence_base) -# assert_equal(mad_l.system, mad_l.system.x.yy, "Circular ref before snapshot/restore, passed self") - mad_l.take_snapshot - mad_l.close - mad_l = make_system(prevalence_base) { L.new } -# assert_equal(mad_l.system, mad_l.system.x.yy, "Circular ref after snapshot/restore, passed self") - mad_l.close - end -end - -class AutomaticCustomMarshallerTest < AutoTest - def test_main - custom_m(YAML) - custom_m(SOAP::Marshal) - custom_m(Madeleine::ZMarshal.new) - custom_m(Madeleine::ZMarshal.new(YAML)) - custom_m(Madeleine::ZMarshal.new(SOAP::Marshal)) - end - - def custom_m(marshaller) - dir = prevalence_base - delete_directory(dir) - @system_bases << dir - mad_h = make_system(dir) { G.new } - mad_h.system.yy.w = "abc" - mad_h.take_snapshot - mad_h.system.yy.w += "d" - assert_equal("abcd", mad_h.system.yy.w, "Custom marshalling after snapshot+commands with normal marshaller") - mad_h.close - mad_h = make_system(dir, marshaller) { G.new } - assert_equal("abcd", mad_h.system.yy.w, "Custom marshalling after snapshot+commands with normal marshaller, read with custom as marshaller") - mad_h.close - mad_h = make_system(dir) { G.new } - mad_h.marshaller = marshaller - mad_h.system.yy.w += "e" - assert_equal("abcde", mad_h.system.yy.w, "Custom marshalling after snapshot+commands+change marshaller+commands") - mad_h.take_snapshot - mad_h.close - if (marshaller == YAML) - File.open(dir + "/000000000000000000002.snapshot", "r") {|f| - assert_equal(f.gets, "--- !ruby/object:Madeleine::Automatic::Prox \n", "Custom marshalling marshaller change check") - } - end - mad_h = make_system(dir, marshaller) { G.new } - assert_equal("abcde", mad_h.system.yy.w, - "Custom marshalling after snapshot+commands+change marshaller+commands+snapshot+restore with normal marshaller") - mad_h.system.yy.w += "f" - mad_h.close - mad_h = make_system(dir) { G.new } - assert_equal("abcdef", mad_h.system.yy.w, "Custom marshalling snapshot custom+commands+restore normal") - mad_h.take_snapshot - mad_h.close - mad_h = make_system(dir, marshaller) { G.new } - assert_equal("abcdef", mad_h.system.yy.w, "Custom marshalling snapshot+restore custom") - mad_h.take_snapshot - mad_h.system.yy.w += "g" - mad_h.close - mad_h = make_system(dir, marshaller) { G.new } - assert_equal("abcdefg", mad_h.system.yy.w, "Custom marshalling after restore normal snapshot custom+commands+restore custom") - mad_h.system.yy.w = "abc" - mad_h.close - mad_h2 = make_system(dir, marshaller) { G.new } - assert_equal("abc", mad_h2.system.yy.w, "Custom marshalling after commands/restore") - mad_h2.take_snapshot - mad_h2.close - mad_h3 = make_system(dir, marshaller) { G.new } - assert_equal("abc", mad_h3.system.yy.w, "Custom marshalling after snapshot/restore") - mad_h3.system.yy.w += "d" - mad_h3.close - mad_h4 = make_system(dir, marshaller) { G.new } - assert_equal("abcd", mad_h4.system.yy.w, "Custom marshalling after snapshot+commands/restore") - mad_h4.close - mad_h = make_system(dir, marshaller) { G.new } - mad_h.system.yy.w = mad_h.system - mad_h.close - mad_h2 = make_system(dir, marshaller) { G.new } - assert_equal(mad_h2.system, mad_h2.system.yy.w, "Custom marshalling after commands/restore, circular ref") - mad_h2.take_snapshot - mad_h2.close - mad_h3 = make_system(dir, marshaller) { G.new } - assert_equal(mad_h3.system, mad_h3.system.yy.w, "Custom marshalling after snapshot/restore, circular ref") - mad_h3.system.yy.w = "sss" - mad_h3.system.yy.w = mad_h3.system - mad_h3.close - mad_h4 = make_system(dir, marshaller) { G.new } - assert_equal(mad_h4.system, mad_h4.system.yy.w, "Custom marshalling after snapshot+commands/restore, circular ref") - mad_h4.close - end -end - -# tests thread safety during system creation, particularly that different system ids are generated -class ThreadedStartupTest < AutoTest - def test_main - x,mad = [],[] - 20.times {|n| - x[n] = Thread.new { - sleep(rand/100) - mad[n] = create_new_system(F, prevalence_base+n.to_s) - mad[n].system.z = n - assert_equal(n, mad[n].system.z, "object change mad[#{n}].z") - mad[n].close - } - } - 20.times {|n| - x[n].join - mad_i = make_system(prevalence_base+n.to_s) { F.new } - assert_equal(n, mad_i.system.z, "restored mad[#{n}].z") - mad_i.close - } - end -end - -# tests restoring when objects get unreferenced and GC'd during restore -class FinalisedTest < AutoTest - def test_main - mad = create_new_system(B, prevalence_base, 0) - mad.system.yy = Array.new(200000) # make ruby run GC - mad.system.yy = Array.new(200000) # must be a better way, but running GC.start from inside - mad.system.yy = Array.new(50000) # class B didn't work for me - mad.close - mad2 = make_system(prevalence_base) { B.new(0) } - mad2.close - end -end - -class DontInterceptTest < AutoTest - def test_main - mad = create_new_system(K, prevalence_base) - mad.system.seven - assert_equal(7, mad.system.k, "Object changes") - mad.system.fourteen - assert_equal(14, mad.system.k, "Object changes, not intercepted") - mad.system.twentyone - assert_equal(21, mad.system.k, "Object changes, not intercepted") - mad.close - mad_1 = make_system(prevalence_base) { K.new } - assert_equal(7, mad_1.system.k, "Commands but no snapshot") - mad_1.take_snapshot - mad_1.close - mad_2 = make_system(prevalence_base) { K.new } - assert_equal(7, mad_2.system.k, "Snapshot but no commands") - mad_2.system.k -= 6 - mad_2.system.k -= 3 - mad_2.system.fourteen - mad_2.close - mad_3 = make_system(prevalence_base) { K.new } - assert_equal(-2, mad_3.system.k, "Snapshot and commands") - mad_3.close - end -end - -def add_automatic_tests(suite) - suite << BasicTest.suite - suite << ObjectOutsideTest.suite - suite << BlockGivenTest.suite - suite << NonPersistedObjectTest.suite - suite << RefInExternalObjTest.suite - suite << InvalidMethodTest.suite - suite << CircularReferenceTest.suite - suite << BasicThreadSafetyTest.suite - suite << FinalisedTest.suite - suite << DontInterceptTest.suite - suite << AutomaticCustomMarshallerTest.suite -end - -def add_slow_automatic_tests(suite) - suite << ThreadConfidenceTest.suite - suite << ThreadedStartupTest.suite -end - -if __FILE__ == $0 - slowsuite = Test::Unit::TestSuite.new("AutomaticMadeleine (including slow tests)") - add_automatic_tests(slowsuite) - add_slow_automatic_tests(slowsuite) - - require 'test/unit/ui/console/testrunner' - Test::Unit::UI::Console::TestRunner.run(slowsuite) -end diff --git a/vendor/madeleine-0.7.1/test/test_clocked.rb b/vendor/madeleine-0.7.1/test/test_clocked.rb deleted file mode 100755 index fcbd02d1..00000000 --- a/vendor/madeleine-0.7.1/test/test_clocked.rb +++ /dev/null @@ -1,94 +0,0 @@ - -require 'madeleine/clock' - -class ClockedAddingSystem - include Madeleine::Clock::ClockedSystem - - attr_reader :total - - def initialize - @total = 0 - end - - def add(value) - @total += value - @total - end -end - -class TimeTest < Test::Unit::TestCase - - def test_clock - target = Madeleine::Clock::Clock.new - assert_equal(0, target.time.to_i) - assert_equal(0, target.time.usec) - - t1 = Time.at(10000) - target.forward_to(t1) - assert_equal(t1, target.time) - t2 = Time.at(20000) - target.forward_to(t2) - assert_equal(t2, target.time) - - assert_nothing_raised() { - target.forward_to(t2) - } - end - - def test_time_actor - @forward_calls = 0 - @last_time = Time.at(0) - - target = Madeleine::Clock::TimeActor.launch(self, 0.01) - - # When launch() has returned it should have sent - # one synchronous clock-tick before it went to sleep - assert_equal(1, @forward_calls) - - sleep(0.1) - assert(@forward_calls > 1) - target.destroy - - @forward_calls = 0 - sleep(0.1) - assert_equal(0, @forward_calls) - end - - # Self-shunt - def execute_command(command) - mock_system = self - command.execute(mock_system) - end - - # Self-shunt (system) - def clock - self - end - - # Self-shunt (clock) - def forward_to(time) - if time < @last_time - raise "non-monotonous time" - end - @last_time = time - @forward_calls += 1 - end - - def test_clocked_system - target = Object.new - target.extend(Madeleine::Clock::ClockedSystem) - t1 = Time.at(10000) - target.clock.forward_to(t1) - assert_equal(t1, target.clock.time) - t2 = Time.at(20000) - target.clock.forward_to(t2) - assert_equal(t2, target.clock.time) - reloaded_target = Marshal.load(Marshal.dump(target)) - assert_equal(t2, reloaded_target.clock.time) - end -end - - -def add_clocked_tests(suite) - suite << TimeTest.suite -end diff --git a/vendor/madeleine-0.7.1/test/test_command_log.rb b/vendor/madeleine-0.7.1/test/test_command_log.rb deleted file mode 100755 index 9f0961ca..00000000 --- a/vendor/madeleine-0.7.1/test/test_command_log.rb +++ /dev/null @@ -1,110 +0,0 @@ - -unless $LOAD_PATH.include?("lib") - $LOAD_PATH.unshift("lib") -end -unless $LOAD_PATH.include?("test") - $LOAD_PATH.unshift("test") -end - -require 'madeleine' -require 'test/unit' -require 'stringio' - -class ExampleCommand - attr :value - - def initialize(value) - @value = value - end - - def execute(system) - system.add(@value) - end -end - -class CommandLogTest < Test::Unit::TestCase - - class MockFile < StringIO - def fsync - @was_fsynced = true - super - end - - attr :was_fsynced - end - - def test_file_opening - file_service = Object.new - def file_service.exist?(path) - [ - ["some", "path"].join(File::SEPARATOR), - ["some", "path", "000000000000000000001.command_log"].join(File::SEPARATOR), - ["some", "path", "000000000000000000002.command_log"].join(File::SEPARATOR), - ["some", "path", "000000000000000000003.command_log"].join(File::SEPARATOR), - ].include?(path) - end - def file_service.dir_entries(path, &block) - if path != ["some", "path"].join(File::SEPARATOR) - raise "wrong path" - end - [ - "000000000000000000001.command_log", - "000000000000000000003.command_log", - "000000000000000000002.command_log", - ] - end - def file_service.open(path, flags) - @was_open_called = true - if path != ["some", "path", "000000000000000000004.command_log"].join(File::SEPARATOR) - raise "wrong file id" - end - if flags != "wb" - raise "wrong flags" - end - MockFile.new - end - def file_service.was_open_called - @was_open_called - end - - target = Madeleine::CommandLog.new("some/path", file_service) - assert(file_service.was_open_called) - end - - def test_writing_command - file_service = Object.new - def file_service.exist?(path) - [ - ["some", "path"].join(File::SEPARATOR), - ].include?(path) - end - def file_service.dir_entries(path, &block) - if path != ["some", "path"].join(File::SEPARATOR) - raise "wrong path" - end - [] - end - def file_service.open(path, flags) - @file = MockFile.new - @file - end - def file_service.file - @file - end - def file_service.verify - unless @file.was_fsynced - raise "file wasn't fsynced" - end - end - command = ExampleCommand.new(1234) - - target = Madeleine::CommandLog.new("some/path", file_service) - target.store(command) - - file_service.verify - - file_service.file.rewind - assert_equal(Marshal.dump(command), file_service.file.read) - end -end - diff --git a/vendor/madeleine-0.7.1/test/test_executer.rb b/vendor/madeleine-0.7.1/test/test_executer.rb deleted file mode 100755 index 27d2f062..00000000 --- a/vendor/madeleine-0.7.1/test/test_executer.rb +++ /dev/null @@ -1,54 +0,0 @@ - -unless $LOAD_PATH.include?("lib") - $LOAD_PATH.unshift("lib") -end -unless $LOAD_PATH.include?("test") - $LOAD_PATH.unshift("test") -end - -require 'test/unit' -require 'madeleine' - -class ExecuterTest < Test::Unit::TestCase - - def test_executer - system = Object.new - command = self - executer = Madeleine::Executer.new(system) - @executed_with = nil - executer.execute(command) - assert_same(system, @executed_with) - end - - # Self-shunt - def execute(system) - @executed_with = system - end - - def test_execute_with_exception - system = Object.new - command = Object.new - def command.execute(system) - raise "this is an exception from a command" - end - executer = Madeleine::Executer.new(system) - assert_raises(RuntimeError) { - executer.execute(command) - } - end - - def test_exception_in_recovery - system = Object.new - command = Object.new - def command.execute(system) - raise "this is an exception from a command" - end - executer = Madeleine::Executer.new(system) - executer.recovery { - executer.execute(command) - } - assert_raises(RuntimeError) { - executer.execute(command) - } - end -end diff --git a/vendor/madeleine-0.7.1/test/test_persistence.rb b/vendor/madeleine-0.7.1/test/test_persistence.rb deleted file mode 100755 index c0e3a639..00000000 --- a/vendor/madeleine-0.7.1/test/test_persistence.rb +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/local/bin/ruby -w -# -# Copyright(c) 2003 Anders Bengtsson -# -# PersistenceTest is based on the unit tests from Prevayler, -# Copyright(c) 2001-2003 Klaus Wuestefeld. -# - -$LOAD_PATH.unshift("lib") - -require 'madeleine' -require 'test/unit' - -class AddingSystem - attr_reader :total - - def initialize - @total = 0 - end - - def add(value) - @total += value - @total - end -end - - -class Addition - - attr_reader :value - - def initialize(value) - @value = value - end - - def execute(system) - system.add(@value) - end -end - - -class PersistenceTest < Test::Unit::TestCase - - def setup - @madeleine = nil - end - - def teardown - delete_prevalence_files(prevalence_base) - Dir.delete(prevalence_base) - end - - def verify(expected_total) - assert_equal(expected_total, prevalence_system().total(), "Total") - end - - def prevalence_system - @madeleine.system - end - - def prevalence_base - "PrevalenceBase" - end - - def clear_prevalence_base - @madeleine.close unless @madeleine.nil? - delete_prevalence_files(prevalence_base()) - end - - def delete_prevalence_files(directory_name) - return unless File.exist?(directory_name) - Dir.foreach(directory_name) {|file_name| - next if file_name == '.' - next if file_name == '..' - file_name.untaint - assert(File.delete(directory_name + File::SEPARATOR + file_name) == 1, - "Unable to delete #{file_name}") - } - end - - def crash_recover - @madeleine.close unless @madeleine.nil? - @madeleine = create_madeleine() - end - - def create_madeleine - SnapshotMadeleine.new(prevalence_base()) { AddingSystem.new } - end - - def snapshot - @madeleine.take_snapshot - end - - def add(value, expected_total) - total = @madeleine.execute_command(Addition.new(value)) - assert_equal(expected_total, total, "Total") - end - - def verify_snapshots(expected_count) - count = 0 - Dir.foreach(prevalence_base) {|name| - if name =~ /\.snapshot$/ - count += 1 - end - } - assert_equal(expected_count, count, "snapshots") - end - - def test_main - clear_prevalence_base - - # There is nothing to recover at first. - # A new system will be created. - crash_recover - - crash_recover - add(40,40) - add(30,70) - verify(70) - - crash_recover - verify(70) - - add(20,90) - add(15,105) - verify_snapshots(0) - snapshot - verify_snapshots(1) - snapshot - verify_snapshots(2) - verify(105) - - crash_recover - snapshot - add(10,115) - snapshot - add(5,120) - add(4,124) - verify(124) - - crash_recover - add(3,127) - verify(127) - - verify_snapshots(4) - - clear_prevalence_base - snapshot - - crash_recover - add(10,137) - add(2,139) - crash_recover - verify(139) - end - - def test_main_in_safe_level_one - thread = Thread.new { - $SAFE = 1 - test_main - } - thread.join - end -end - - -def add_persistence_tests(suite) - suite << PersistenceTest.suite -end diff --git a/vendor/madeleine-0.7.1/test/test_platforms.rb b/vendor/madeleine-0.7.1/test/test_platforms.rb deleted file mode 100755 index b3ee03b1..00000000 --- a/vendor/madeleine-0.7.1/test/test_platforms.rb +++ /dev/null @@ -1,65 +0,0 @@ - -class AddCommand - def initialize(obj) - @obj = obj - end - - def execute(system) - system[@obj.myid] = @obj - end -end - -class Foo - attr_accessor :myid -end - - -# Checks for a strange marshalling or IO bug observed in the -# native win32-port of Ruby on WinXP. -# -# Test case provided by Steve Conover. - -class WierdWin32CorruptionTest < Test::Unit::TestCase - include TestUtils - - def teardown - (1..5).each {|i| - delete_directory("corruption_test#{i}") - } - end - - def doCorruptionTest(idstr, storagenumber) - m = SnapshotMadeleine.new("corruption_test" + storagenumber) { Hash.new() } - - f = Foo.new() - f.myid = idstr - - m.execute_command(AddCommand.new(f)) - m.close() - m = SnapshotMadeleine.new("corruption_test" + storagenumber) { Hash.new() } - end - - def testErrorOne - doCorruptionTest("123456789012345678901", "1") - end - - def testErrorTwo - doCorruptionTest("aaaaaaaaaaaaaaaaaaaaa", "2") - end - - def testNoErrorOne - doCorruptionTest("12345678901234567890", "3") - end - - def testNoErrorTwo - doCorruptionTest("1234567890123456789012", "4") - end - - def testWhiteSpace - doCorruptionTest("\n\r\t \r\n", "5") - end -end - -def add_platforms_tests(suite) - suite << WierdWin32CorruptionTest.suite -end diff --git a/vendor/madeleine-0.7.1/test/test_zmarshal.rb b/vendor/madeleine-0.7.1/test/test_zmarshal.rb deleted file mode 100755 index 80f46b90..00000000 --- a/vendor/madeleine-0.7.1/test/test_zmarshal.rb +++ /dev/null @@ -1,52 +0,0 @@ - -require 'madeleine/zmarshal' - -require 'stringio' -require 'yaml' - -class ZMarshalTest < Test::Unit::TestCase - - def test_full_circle_marshal - target = Madeleine::ZMarshal.new(Marshal) - object = ["foo", "bar"] - stream = StringIO.new - - target.dump(object, stream) - stream.rewind - result = target.load(stream) - - assert_equal(object, result) - end - - def test_full_circle_yaml - target = Madeleine::ZMarshal.new(YAML) - object = ["foo", "bar"] - stream = StringIO.new - - target.dump(object, stream) - stream.rewind - result = target.load(stream) - - assert_equal(object, result) - end - - def test_compression - target = Madeleine::ZMarshal.new(Marshal) - object = "x" * 1000 - - stream = StringIO.new - Marshal.dump(object, stream) - reference_size = stream.size - - stream = StringIO.new - target.dump(object, stream) - compressed_size = stream.size - - assert(compressed_size < reference_size) - end -end - - -def add_zmarshal_tests(suite) - suite << ZMarshalTest.suite -end diff --git a/vendor/rubyzip-0.5.8/ChangeLog b/vendor/rubyzip-0.5.8/ChangeLog deleted file mode 100644 index 1bb67582..00000000 --- a/vendor/rubyzip-0.5.8/ChangeLog +++ /dev/null @@ -1,1273 +0,0 @@ -2005-03-17 18:11 thomas - - * NEWS, README, lib/zip/zip.rb: [no log message] - -2005-03-17 18:04 thomas - - * install.rb: Fixed install.rb - -2005-03-03 18:38 thomas - - * Rakefile: [no log message] - -2005-02-27 16:23 thomas - - * lib/zip/ziprequire.rb: Added documentation to ziprequire - -2005-02-27 16:17 thomas - - * README, TODO, lib/zip/ziprequire.rb: Added documentation to - ziprequire - -2005-02-27 15:02 thomas - - * Rakefile, test/ziptest.rb: [no log message] - -2005-02-19 21:30 thomas - - * lib/zip/ioextras.rb, lib/zip/stdrubyext.rb, - lib/zip/tempfile_bugfixed.rb, lib/zip/zip.rb, - lib/zip/ziprequire.rb, test/ioextrastest.rb, - test/stdrubyexttest.rb, test/zipfilesystemtest.rb, - test/ziprequiretest.rb, test/ziptest.rb: Added more rdoc and - changed the remaining tests to Test::Unit - -2005-02-19 20:28 thomas - - * lib/zip/: ioextras.rb, zip.rb: Added documentation to - ZipInputStream and ZipOutputStream - -2005-02-18 10:27 thomas - - * README: [no log message] - -2005-02-17 23:21 thomas - - * README, Rakefile: Added ppackage (publish package) task to - Rakefile - -2005-02-17 22:49 thomas - - * README, Rakefile, TODO: Added pdoc (publish doc) task to Rakefile - -2005-02-17 21:27 thomas - - * README, Rakefile, TODO, lib/zip/stdrubyext.rb, lib/zip/zip.rb, - lib/zip/zipfilesystem.rb: Added a bunch of documentation - -2005-02-17 09:47 thomas - - * test/ziptest.rb: [no log message] - -2005-02-16 20:04 thomas - - * NEWS, README, Rakefile: Improved documentation and added rdoc - task to Rakefile - -2005-02-16 19:01 thomas - - * NEWS, Rakefile, lib/zip/zip.rb: [no log message] - -2005-02-16 18:47 thomas - - * Rakefile, samples/example.rb, samples/example_filesystem.rb, - samples/gtkRubyzip.rb, samples/write_simple.rb, - samples/zipfind.rb, test/.cvsignore, test/gentestfiles.rb: - Improvements to Rakefile - -2005-02-15 23:35 thomas - - * NEWS, TODO: [no log message] - -2005-02-15 23:26 thomas - - * Rakefile, rubyzip.gemspec: Now uses Rake to build gem - -2005-02-15 22:52 thomas - - * Rakefile: [no log message] - -2005-02-15 22:39 thomas - - * lib/zip/zip.rb, test/.cvsignore, test/ziptest.rb, NEWS: Fixed - compatibility issue with ruby 1.8.2. Migrated test suite to - Test::Unit - -2005-02-15 22:10 thomas - - * NEWS, lib/zip/ioextras.rb, lib/zip/stdrubyext.rb, - lib/zip/tempfile_bugfixed.rb, lib/zip/zip.rb, - lib/zip/zipfilesystem.rb, lib/zip/ziprequire.rb, test/.cvsignore, - test/file1.txt, test/file1.txt.deflatedData, test/file2.txt, - test/gentestfiles.rb, test/ioextrastest.rb, - test/notzippedruby.rb, test/rubycode.zip, test/rubycode2.zip, - test/stdrubyexttest.rb, test/testDirectory.bin, - test/zipWithDirs.zip, test/zipfilesystemtest.rb, - test/ziprequiretest.rb, test/ziptest.rb, test/data/.cvsignore, - test/data/file1.txt, test/data/file1.txt.deflatedData, - test/data/file2.txt, test/data/notzippedruby.rb, - test/data/rubycode.zip, test/data/rubycode2.zip, - test/data/testDirectory.bin, test/data/zipWithDirs.zip: Changed - directory structure - -2005-02-13 22:44 thomas - - * Rakefile, TODO: [no log message] - -2005-02-13 22:38 thomas - - * rubyzip.gemspec: [no log message] - -2005-02-13 21:53 thomas - - * install.rb: Made install.rb independent of the current path - (fixes bug reported by Drew Robinson) - -2004-12-12 11:22 thomas - - * NEWS, TODO, samples/write_simple.rb: Fixed 'version needed to - extract'-field wrong in local headers - -2004-05-02 15:17 thomas - - * rubyzip.gemspec: Added gemspec contributed by Chad Fowler - -2004-04-02 07:25 thomas - - * NEWS: Fix for FreeBSD 4.9 - -2004-03-29 00:28 thomas - - * NEWS: [no log message] - -2004-03-28 17:59 thomas - - * NEWS: [no log message] - -2004-03-27 16:09 thomas - - * test/stdrubyexttest.rb: Patch for stdrubyext.rb from Nobu Nakada - -2004-03-27 15:30 thomas - - * test/: ioextrastest.rb, stdrubyexttest.rb: converted some files - to unix line-endings - -2004-03-25 16:34 thomas - - * NEWS, install.rb: Significantly reduced memory footprint when - modifying zip files - -2004-03-16 18:20 thomas - - * install.rb, test/alltests.rb, test/ioextrastest.rb, - test/stdrubyexttest.rb, test/ziptest.rb: IO utility classes moved - to new file ioextras.rb. Tests moved to new file ioextrastest.rb - -2004-02-27 13:21 thomas - - * NEWS: Optimization to avoid decompression and recompression - -2004-01-30 16:17 thomas - - * NEWS: [no log message] - -2004-01-30 16:07 thomas - - * README, test/zipfilesystemtest.rb, test/ziptest.rb: Applied - extra-field patch - -2003-12-13 16:57 thomas - - * TODO: [no log message] - -2003-12-10 00:25 thomas - - * test/ziptest.rb: (Temporary) fix to bug reported by Takashi Sano - -2003-08-23 09:42 thomas - - * test/ziptest.rb, NEWS: Fixed ZipFile.get_ouput_stream bug - data - was never written to zip - -2003-08-21 16:05 thomas - - * install.rb: [no log message] - -2003-08-21 16:01 thomas - - * alltests.rb, stdrubyexttest.rb, zipfilesystemtest.rb, - ziprequiretest.rb, ziptest.rb, test/alltests.rb, - test/stdrubyexttest.rb, test/zipfilesystemtest.rb, - test/ziprequiretest.rb, test/ziptest.rb: Moved all test ruby - files to test/ - -2003-08-21 15:54 thomas - - * NEWS, install.rb, stdrubyext.rb, stdrubyexttest.rb, zip.rb, - zipfilesystem.rb, zipfilesystemtest.rb, ziprequire.rb, - ziprequiretest.rb, ziptest.rb, samples/example.rb, - samples/example_filesystem.rb, samples/gtkRubyzip.rb, - samples/zipfind.rb: Moved all production source files to zip/ so - they are in the same dir as when they are installed - -2003-08-21 15:31 thomas - - * NEWS, TODO, alltests.rb: [no log message] - -2003-08-21 15:26 thomas - - * filearchive.rb, filearchivetest.rb, fileutils.rb: Removed - filearchive.rb, filearchivetest.rb and fileutils.rb - -2003-08-21 15:24 thomas - - * samples/.cvsignore, samples/example_filesystem.rb, zip.rb: Added - samples/example_filesystem.rb. Fixed Tempfile creation for - entries created with get_output_stream where entries were in a - subdirectory - -2003-08-21 15:15 thomas - - * zip.rb, ziptest.rb: Fixed mkdir bug. ZipFile.mkdir didn't work if - the zipfile doesn't exist already - -2003-08-21 15:05 thomas - - * ziptest.rb: [no log message] - -2003-08-21 14:53 thomas - - * TODO, zipfilesystemtest.rb: Globbing test placeholder commented - out - -2003-08-21 14:32 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented ZipFsDir.new - and open - -2003-08-21 14:19 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented DirFsIterator - and tests - -2003-08-20 22:50 thomas - - * NEWS, TODO: [no log message] - -2003-08-20 22:45 thomas - - * zipfilesystemtest.rb: [no log message] - -2003-08-20 22:44 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsDir.foreach, ZipFsDir.entries now reimplemented in terms of - it - -2003-08-20 22:25 thomas - - * README: [no log message] - -2003-08-20 18:08 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: [no log message] - -2003-08-20 17:30 thomas - - * zipfilesystem.rb: All access from ZipFsFile and ZipFsDir to - ZipFile is now routed through ZipFileNameMapper which has the - single responsibility of mapping entry/filenames - -2003-08-20 17:18 thomas - - * alltests.rb, stdrubyext.rb, stdrubyexttest.rb: Added - stdrubyexttest.rb and added test test_select_map - -2003-08-20 16:10 thomas - - * zipfilesystem.rb: ZipFsDir was in the wrong module. ZipFileSystem - now has a ctor that creates ZipFsDir and ZipFsFile instances, - instead of creating them lazily. It then passes the dir instance - to the file instance and vice versa - -2003-08-20 15:55 thomas - - * zip.rb, zipfilesystem.rb, zipfilesystemtest.rb: ZipFsFile.open - honours chdir - -2003-08-20 15:39 thomas - - * stdrubyext.rb, zip.rb, zipfilesystem.rb, zipfilesystemtest.rb, - ziptest.rb: Fixed ZipEntry::parent_as_string. Implemented - ZipFsDir.chdir, pwd and entries including test - -2003-08-19 15:44 thomas - - * zip.rb, zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsDir.mkdir - -2003-08-19 15:07 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsDir.delete (and aliases rmdir and unlink) - -2003-08-19 14:33 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Another dummy - implementation and commented out a test for select() which can be - added later - -2003-08-18 20:40 thomas - - * ziptest.rb: Honoured 1.8.0 Object.to_a deprecation warning - -2003-08-18 20:30 thomas - - * zip.rb, ziptest.rb, samples/example.rb, samples/zipfind.rb: - Converted a few more names to ruby underscore style that I missed - with the automated processing the first time around - -2003-08-18 18:39 thomas - - * zip.rb, zipfilesystem.rb, zipfilesystemtest.rb, ziptest.rb: - Implemented Zip::ZipFile.get_output_stream - -2003-08-17 18:28 thomas - - * README, install.rb, stdrubyext.rb, zipfilesystem.rb, - zipfilesystemtest.rb: Updated README with Documentation section. - Updated install.rb. Fixed three tests that failed on 1.8.0. - -2003-08-14 05:40 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Added empty - implementations of atime and ctime - -2003-08-13 17:08 thomas - - * simpledist.rb: Moved simpledist to a separate repository called - 'misc' - -2003-08-13 16:31 thomas - - * NEWS: [no log message] - -2003-08-13 16:29 thomas - - * stdrubyext.rb, zip.rb, zipfilesystem.rb, zipfilesystemtest.rb, - ziprequire.rb, ziprequiretest.rb, ziptest.rb, samples/example.rb, - samples/gtkRubyzip.rb, samples/zipfind.rb: Changed all method - names to the ruby convention underscore style - -2003-08-13 15:18 thomas - - * alltests.rb, zipfilesystem.rb, zipfilesystemtest.rb: Implemented - a lot more of the stat methods. Mostly with dummy implementations - that return values that indicate that these features aren't - supported - -2003-08-13 11:44 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented more methods - and tests in zipfilesystem. Mostly empty methods as permissions - and file types other than files and directories are not supported - -2003-08-13 11:29 thomas - - * install.rb, stdrubyext.rb, zip.rb, zipfilesystem.rb, - zipfilesystemtest.rb: Addd file stdrubyext.rb and moved the - modifications to std ruby classes to it. Refactored the ZipFsStat - tests and ZipFsStat. Added Module.forwardMessages and used it to - implement the forwarding of calls in ZipFsStat - -2003-08-13 10:39 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Added - Zip::ZipFsFile::ZipFsStat and started implementing it and its - methods - -2003-08-13 10:02 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb, ziptest.rb: Updated and - added missing copyright notices - -2003-08-13 10:00 thomas - - * zip.rb, zipfilesystem.rb, zipfilesystemtest.rb: zipfilesystem.rb - is becoming big and not everyone will want to use that code. - Therefore zip.rb no longer requires it. Instead you must require - zipfilesystem.rb itself if you want to use it - -2003-08-13 09:51 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented dummy - permission test methods - -2003-08-13 06:37 thomas - - * TODO, zip.rb, ziptest.rb: Merged from patch from Kristoffer - Lunden. Fixed more 1.8.0 incompatibilites - tests run on 1.8.0 - now - -2003-08-12 19:18 thomas - - * zip.rb: Get rid of 1.8.0 warning - -2003-08-12 19:14 thomas - - * ziptest.rb: ruby 1.8.0 compatibility fix - -2003-08-12 19:13 thomas - - * NEWS, zip.rb: ruby-zlib 0.6.0 compatibility fix - -2002-12-22 20:12 thomas - - * zip.rb: [no log message] - -2002-09-16 22:11 thomas - - * NEWS: [no log message] - -2002-09-15 17:16 thomas - - * samples/zipfind.rb: [no log message] - -2002-09-15 00:02 thomas - - * samples/zipfind.rb: [no log message] - -2002-09-14 22:59 thomas - - * samples/zipfind.rb: Added simple zipfind script - -2002-09-13 23:53 thomas - - * TODO: Added TODO about openmode for zip entries binary/ascii - -2002-09-13 20:54 thomas - - * NEWS: ziptest now runs without errors with ruby-1.7.2-4 (Andy's - latest build) - -2002-09-13 20:51 thomas - - * zip.rb, ziprequiretest.rb, ziptest.rb: ziptest now runs without - errors with ruby-1.7.2-4 (Andy's latest build) - -2002-09-12 00:20 thomas - - * zipfilesystemtest.rb: Improved ZipFsFile.delete/unlink test - -2002-09-12 00:12 thomas - - * test/.cvsignore: [no log message] - -2002-09-12 00:10 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.delete/unlink - -2002-09-11 22:22 thomas - - * alltests.rb: [no log message] - -2002-09-11 22:18 thomas - - * NEWS, zip.rb, zipfilesystem.rb, zipfilesystemtest.rb: Fixed - AbstractInputStream.each_line ignored its aSeparator argument. - Implemented more ZipFsFile methods - -2002-09-11 21:28 thomas - - * zip.rb, zipfilesystem.rb, zipfilesystemtest.rb: ZipFileSystem is - now a module instead of a class, and is mixed into ZipFile, - instead of being made available as a property fileSystem - -2002-09-10 23:45 thomas - - * NEWS: Updated NEWS file - -2002-09-10 23:26 thomas - - * zip.rb: [no log message] - -2002-09-10 22:39 thomas - - * NEWS, zip.rb, ziptest.rb: Fix bug: rewind should reset lineno. - Fix bug: Deflater.read uses separate buffer from produceInput - (feeding gets/readline etc) - -2002-09-09 23:48 thomas - - * .cvsignore: [no log message] - -2002-09-09 22:55 uid26649 - - * zip.rb, ziptest.rb: Implemented ZipInputStream.rewind and - AbstractInputStream.lineno. Tests for both - -2002-09-09 20:31 thomas - - * zip.rb, ziptest.rb: ZipInputStream and ZipOutstream (thru their - AbstractInputStream and AbstractOutputStream now lie about being - kind_of?(IO) - -2002-09-08 16:38 thomas - - * zipfilesystemtest.rb: [no log message] - -2002-09-08 16:07 thomas - - * filearchive.rb, filearchivetest.rb, zip.rb, ziptest.rb: Moved - String additions from filearchive.rb to zip.rb (and moved tests - along too to ziptest.rb). Added ZipEntry.parentAsString and - ZipEntrySet.parent - -2002-09-08 15:28 thomas - - * ziptest.rb: Implemented ZipEntrySetTest.testDup and testCompound - -2002-09-08 15:17 thomas - - * TODO, zip.rb, ziptest.rb: Replaced Array with EntrySet for - keeping entries in a zip file. Tagged repository before this - commit, so this change can be rolled back, if it stinks - -2002-09-07 20:21 thomas - - * zip.rb, ziptest.rb: Implemented ZipEntry.<=> - -2002-09-07 14:48 thomas - - * ziptest.rb: Removed unused code - -2002-08-11 15:14 thomas - - * zip.rb, ziptest.rb: Made some changes to accomodate ruby 1.7.2 - -2002-07-27 15:25 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented ZipFsFile.new - -2002-07-27 00:30 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.pipe - -2002-07-27 00:25 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.link - -2002-07-27 00:23 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.symlink - -2002-07-27 00:20 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.readlink, wrapped ZipFileSystem class in Zip module - -2002-07-27 00:14 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.zero? - -2002-07-27 00:01 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented test for - ZipFsFile.directory? - -2002-07-26 23:56 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.socket? - -2002-07-26 23:50 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.join - -2002-07-26 23:32 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.ftype - -2002-07-26 23:19 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.blockdev? - -2002-07-26 23:12 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.size? (slightly different from size) - -2002-07-26 23:03 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.split - -2002-07-26 23:00 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implemented - ZipFsFile.symlink? - -2002-07-26 22:58 thomas - - * alltests.rb, zip.rb, zipfilesystem.rb, zipfilesystemtest.rb: - Implemented ZipFsFile.mtime - -2002-07-26 17:08 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: Implement ZipFsFile.file? - -2002-07-26 17:06 thomas - - * zip.rb, ziptest.rb: Implemented ZipEntry.file? - -2002-07-26 16:57 thomas - - * alltests.rb, filearchive.rb, filearchivetest.rb, zip.rb, - zipfilesystem.rb, zipfilesystemtest.rb, ziprequire.rb, - ziptest.rb: Implemented ZipFileSystem::ZipFsFile.size - -2002-07-26 16:41 thomas - - * zipfilesystem.rb, zipfilesystemtest.rb: [no log message] - -2002-07-26 16:40 thomas - - * test/zipWithDirs.zip: Changed zipWithDirs.zip so all the entries - in it have unix file endings - -2002-07-26 16:12 thomas - - * alltests.rb, zip.rb, zipfilesystem.rb, zipfilesystemtest.rb: - Started implementing ZipFileSystem - -2002-07-26 15:56 thomas - - * test/zipWithDirs.zip: Added a zip file for testing with a - directory structure - -2002-07-22 21:40 thomas - - * TODO: [no log message] - -2002-07-22 17:49 thomas - - * TODO: [no log message] - -2002-07-21 18:20 thomas - - * NEWS: [no log message] - -2002-07-21 18:12 thomas - - * TODO: Updated TODO with a refactoring idea for FileArchive - -2002-07-21 17:59 thomas - - * filearchive.rb, filearchivetest.rb: Added some FileArchiveAdd - tests and cleaned up some of the FileArchive tests. extract and - add now have individual test fixtures. - -2002-07-21 16:02 thomas - - * filearchive.rb, filearchivetest.rb: Added tests for extract - called with regex src arg and Enumerable src arg - -2002-07-21 15:37 thomas - - * filearchivetest.rb: Added test for continueOnExistsProc when - extracting from a file archive - -2002-07-20 17:13 thomas - - * TODO, filearchivetest.rb, fileutils.rb, ziptest.rb, - test/.cvsignore: Added (failing) tests for FileArchive.add, added - code for creating test files for FileArchive.add tests. Added - fileutils.rb, which is borrowed from ruby 1.7.2 - -2002-07-20 16:07 thomas - - * filearchive.rb, filearchivetest.rb: [no log message] - -2002-07-20 16:05 thomas - - * filearchivetest.rb: Added tests for String extensions - -2002-07-20 02:20 thomas - - * alltests.rb, ziprequiretest.rb, ziptest.rb: [no log message] - -2002-07-20 00:42 thomas - - * install.rb: [no log message] - -2002-07-20 00:42 thomas - - * TODO: Updated TODO - -2002-07-20 00:35 thomas - - * filearchive.rb, filearchivetest.rb: All FileArchive.extract tests - run - -2002-07-19 23:11 thomas - - * filearchive.rb, filearchivetest.rb: [no log message] - -2002-07-19 19:41 thomas - - * filearchivetest.rb: [no log message] - -2002-07-19 19:06 thomas - - * filearchive.rb, filearchivetest.rb: [no log message] - -2002-07-19 18:48 thomas - - * filearchive.rb, filearchivetest.rb, zip.rb: [no log message] - -2002-07-08 13:41 thomas - - * TODO: [no log message] - -2002-06-11 19:47 thomas - - * filearchive.rb, filearchivetest.rb, zip.rb, ziptest.rb: [no log - message] - -2002-05-25 00:41 thomas - - * simpledist.rb: Added hackish script for creating dist files - -2002-04-30 21:22 thomas - - * TODO: [no log message] - -2002-04-30 21:16 thomas - - * filearchive.rb, filearchivetest.rb: [no log message] - -2002-04-30 20:40 thomas - - * filearchive.rb, filearchivetest.rb: Improved testing and wrote - some of the skeleton of extract. Still to do: Fix glob, so it - returns a hashmap instead of a list. The map will need to map the - full entry name to the last part of the name (which is only - really interesting for recursively extracted entries, otherwise - it is just the name). Glob.expandPathList should also output - directories with a trailing slash, which is doesn't right now. - -2002-04-30 19:52 thomas - - * filearchive.rb, filearchivetest.rb: Implemented the first few - tests for FileArchive - -2002-04-24 22:06 thomas - - * ziprequire.rb, ziprequiretest.rb: Appended copyright message to - ziprequire.rb and ziprequiretest.rb - -2002-04-24 20:59 thomas - - * zip.rb: Made ZipEntry tolerate invalid dates - -2002-04-21 00:57 thomas - - * NEWS, TODO, zip.rb, ziptest.rb: Read and write entry modification - date/time correctly - -2002-04-20 02:44 thomas - - * ziprequiretest.rb, test/rubycode2.zip: improved ZipRequireTest - -2002-04-20 02:39 thomas - - * ziprequire.rb: Made a warning go away - -2002-04-20 02:38 thomas - - * ziprequire.rb, ziprequiretest.rb, test/notzippedruby.rb, - test/rubycode.zip: Fixed a bug in ziprequire. Added - ziprequiretest.rb and test data files - -2002-04-19 22:43 thomas - - * zip.rb, ziptest.rb: Added recursion support to Glob module - -2002-04-18 21:37 thomas - - * NEWS, TODO, zip.rb, ziptest.rb: Added Glob module and GlobTest - unit test suite. This module provides the functionality to expand - a 'glob pattern' given a list of files - Next step is to use this - module in ZipFile - -2002-04-01 22:55 thomas - - * NEWS: [no log message] - -2002-04-01 21:16 thomas - - * TODO, zip.rb, ziprequire.rb: Added ziprequire.rb which contains a - proof-of-concept implementation of a require implementation that - can load ruby modules from a zip file. Needs unit tests and - polish. - -2002-03-31 01:13 thomas - - * README: [no log message] - -2002-03-30 16:14 thomas - - * TODO: [no log message] - -2002-03-30 01:52 thomas - - * .cvsignore, README, zip.rb: Added rdoc markup (only #:nodoc:all - modifiers) to zip.rb. Made README 'RDoc compliant' - -2002-03-29 23:29 thomas - - * TODO: [no log message] - -2002-03-29 23:26 thomas - - * example.rb, samples/.cvsignore, samples/example.rb, - samples/gtkRubyzip.rb: Moved example.rb to samples/. Added - another sample gtkRubyzip.rb - -2002-03-29 20:12 thomas - - * NEWS, TODO: [no log message] - -2002-03-29 20:06 thomas - - * .cvsignore, file1.txt, file1.txt.deflatedData, testDirectory.bin, - ziptest.rb, test/.cvsignore, test/file1.txt, - test/file1.txt.deflatedData, test/file2.txt, - test/testDirectory.bin: Added test/ directory and moved the - manually created test data files into it. Changed ziptest.rb so - it runs in test/ directory - -2002-03-29 19:43 thomas - - * TODO: [no log message] - -2002-03-29 18:15 thomas - - * NEWS, zip.rb, ziptest.rb: Don't decompress and recompress zip - entries when changing zip file - -2002-03-29 17:50 thomas - - * zip.rb: Performance optimization: Only write new ZipFile, if it - has been changed. The test suite runs in half the time now. - -2002-03-28 22:12 thomas - - * TODO: [no log message] - -2002-03-23 17:31 thomas - - * TODO: [no log message] - -2002-03-22 22:47 thomas - - * NEWS: [no log message] - -2002-03-22 22:25 thomas - - * NEWS, TODO: [no log message] - -2002-03-22 22:18 thomas - - * ziptest.rb: Found the tests that didn't use blocks to make sure - input streams are closed as soon as they arent used anymore and - got rid of the GC.start - -2002-03-22 22:12 thomas - - * ziptest.rb: All tests run on windows ruby 1.6.6 - -2002-03-22 10:38 thomas - - * zip.rb, ziptest.rb: Windows fixes: Fixed ZipFile.initialize which - needed to open zipfile file in binary mode. Added another - workaround for the return value from File.open(name) where name - is the name of a directory - ruby returns different exceptions in - linux, win/cygwin and windows. A number of tests failed because - in windows you cant delete a file that is open. Fixed by changing - ziptest.rb to use ZipInputStream.getInputStream with blocks a few - places. There is a hack in CommanZipFileFixture.setup where the - GC is explicitly invoked. Should be fixed with blocks instead. - The only currently failing test fails because the test data - creation fails to add a comment to 4entry.zip, because echo eats - the remainder of the line including the pipe character and the - following zip -z 4 entry.zip command - -2002-03-21 22:18 thomas - - * NEWS: [no log message] - -2002-03-21 22:12 thomas - - * NEWS, README, TODO, install.rb: Added install.rb - -2002-03-21 21:45 thomas - - * ziptest.rb: [no log message] - -2002-03-21 20:54 thomas - - * NEWS, TODO: [no log message] - -2002-03-21 20:34 thomas - - * .cvsignore, TODO, zip.rb, ziptest.rb: Added - test_extractDirectoryExistsAsFileOverwrite and fixed to pass - -2002-03-21 20:22 thomas - - * zip.rb, ziptest.rb: Extraction of directory entries is now - supported - -2002-03-20 21:59 thomas - - * NEWS: [no log message] - -2002-03-20 21:24 thomas - - * COPYING, README, README.txt: Removed COPYING, renamed README.txt - to README. Updated README - -2002-03-20 21:18 thomas - - * example.rb: Fixed example.rb added example that shows zip file - manipulation with Zip::ZipFile - -2002-03-20 21:00 thomas - - * .cvsignore: [no log message] - -2002-03-20 20:56 thomas - - * TODO, zip.rb, ziptest.rb: Directories can now be added (not - recursively, the directory entry itself. Directories are - recognized by a empty entries with a trailing /. The purpose of - storing them explicitly in the zip file is to be able to store - permission and ownership information - -2002-03-20 20:08 thomas - - * TODO, zip.rb, ziptest.rb: zip.rb depended on ftools but it was - only included in ziptest.rb - -2002-03-20 19:07 thomas - - * zip.rb, ziptest.rb: ZipError is now a subclass of StandardError - instead of RuntimeError. ZipError now has several subclasses. - -2002-03-19 22:26 thomas - - * TODO: [no log message] - -2002-03-19 22:19 thomas - - * TODO, ziptest.rb: Unit test ZipFile.getInputStream with block - -2002-03-19 22:11 thomas - - * TODO, zip.rb, ziptest.rb: Unit test for adding new entry with - name that already exists in archive, and fixed to pass test - -2002-03-19 21:40 thomas - - * TODO, zip.rb, ziptest.rb: Added unit tests for rename to existing - entry - -2002-03-19 20:42 thomas - - * TODO: [no log message] - -2002-03-19 20:40 thomas - - * TODO, zip.rb, ziptest.rb: Unit test calling ZipFile.extract with - block - -2002-03-18 21:06 thomas - - * TODO: [no log message] - -2002-03-18 21:05 thomas - - * zip.rb, ziptest.rb: ZipFile#commit now reinitializes ZipFile. - -2002-03-18 20:42 thomas - - * TODO, zip.rb, ziptest.rb: Refactoring: - - Collapsed ZipEntry and ZipStreamableZipEntry into ZipEntry. - - Collapsed BasicZipFile and ZipFile into ZipFile. - -2002-03-18 18:05 thomas - - * zip.rb: Removed method that was never called - -2002-03-17 22:33 thomas - - * TODO: [no log message] - -2002-03-17 22:25 thomas - - * ziptest.rb: Run tests with =true as default - -2002-03-17 22:22 thomas - - * NEWS, TODO, zip.rb, ziptest.rb: Now runs with -w switch without - warnings - -2002-03-17 21:10 thomas - - * .cvsignore: [no log message] - -2002-03-17 21:04 thomas - - * zip.rb, ziptest.rb: Down to one failing test - -2002-03-17 20:36 thomas - - * zip.rb, ziptest.rb: [no log message] - -2002-03-17 17:22 thomas - - * TODO, zip.rb, ziptest.rb: [no log message] - -2002-02-25 19:42 thomas - - * TODO: Added more todos - -2002-02-23 15:51 thomas - - * zip.rb: [no log message] - -2002-02-23 15:30 thomas - - * zip.rb, ziptest.rb: [no log message] - -2002-02-23 14:16 thomas - - * zip.rb, ziptest.rb: [no log message] - -2002-02-03 18:47 thomas - - * ziptest.rb: [no log message] - -2002-02-02 15:58 thomas - - * example.rb, zip.rb, ziptest.rb: [no log message] - -2002-02-02 00:16 thomas - - * .cvsignore: [no log message] - -2002-02-02 00:14 thomas - - * example.rb, zip.rb, ziptest.rb: Renamed SimpleZipFile to - BasicZipFile - -2002-02-02 00:09 thomas - - * TODO: [no log message] - -2002-02-02 00:01 thomas - - * ziptest.rb: More test cases - all of them failing, so now there - are 18 failing test cases. Three more test cases to implement, - then it is time for the production code - -2002-02-01 21:49 thomas - - * ziptest.rb: [no log message] - -2002-02-01 21:34 thomas - - * ziptest.rb: Also run SimpleZipFile tests for ZipFile. - -2002-02-01 20:11 thomas - - * example.rb, zip.rb, ziptest.rb: ZipFile renamed to SimpleZipFile. - The new ZipFile will have many more methods that are useful for - managing archives. - -2002-01-29 20:30 thomas - - * TODO: [no log message] - -2002-01-26 00:18 thomas - - * NEWS: [no log message] - -2002-01-26 00:14 thomas - - * ziptest.rb: In unit test: work around ruby/cygwin weirdness. You - get an Errno::EEXISTS instead of an Errno::EISDIR if you try to - open a file for writing that is a directory. - -2002-01-26 00:02 thomas - - * ziptest.rb: Fixed test that failed on windows because of CRLF - line ending - -2002-01-25 23:58 thomas - - * ziptest.rb: [no log message] - -2002-01-25 23:29 thomas - - * .cvsignore, example.rb, zip.rb: Fixed bug reading from empty - deflated entry in zip file - -2002-01-25 23:01 thomas - - * .cvsignore: [no log message] - -2002-01-25 22:56 thomas - - * ziptest.rb: [no log message] - -2002-01-25 22:51 thomas - - * NEWS, README.txt, zip.rb, ziptest.rb: Zip write support is now - fully functional in the form of ZipOutputStream. - -2002-01-25 21:12 thomas - - * zip.rb, ziptest.rb: [no log message] - -2002-01-25 20:37 thomas - - * zip.rb, ziptest.rb: [no log message] - -2002-01-20 16:00 thomas - - * zip.rb, ziptest.rb: Added Deflater and DeflaterTest. - -2002-01-20 00:39 thomas - - * .cvsignore: [no log message] - -2002-01-20 00:23 thomas - - * .cvsignore: Added .cvsignore file - -2002-01-20 00:09 thomas - - * zip.rb, ziptest.rb: Added ZipEntry.writeCDirEntry and misc minor - fixes - -2002-01-19 23:28 thomas - - * example.rb, zip.rb, ziptest.rb: NOTICE: Not all tests run!! - - ZipOutputStream in progress - - Wrapped rubyzip in namespace module Zip. - -2002-01-17 18:52 thomas - - * ziptest.rb: Fail nicely if the user doesn't have info-zip - compatible zip in the path - -2002-01-10 18:02 thomas - - * zip.rb: Adjusted chunk size to 32k after a few perf measurements - -2002-01-09 22:10 thomas - - * README.txt: License now same as rubys, not just GPL - -2002-01-06 00:19 thomas - - * README.txt: [no log message] - -2002-01-05 23:09 thomas - - * NEWS, README.txt: Updated NEWS file - -2002-01-05 23:05 thomas - - * README.txt, zip.rb, ziptest.rb, zlib.c.diff: Added tests for - decompressors and a tests for ZipLocalEntry, - ZipCentralDirectoryEntry and ZipCentralDirectory for handling of - corrupt data - -2002-01-05 22:21 thomas - - * file1.txt.deflatedData: deflated data extracted from a zip file. - contains file1.txt - -2002-01-05 20:05 thomas - - * zip.rb: Changed references to Inflate to Zlib::inflate for - compatibility with ruby-zlib-0.5 - -2002-01-05 19:28 thomas - - * README.txt, zip.rb, ziptest.rb: [no log message] - -2002-01-05 01:52 thomas - - * example.rb, NEWS: [no log message] - -2002-01-05 01:37 thomas - - * COPYING, README.txt: [no log message] - -2002-01-05 01:31 thomas - - * ziptest.rb: Fixed problem with test file creation - -2002-01-05 01:15 thomas - - * README.txt: Updated README.txt - -2002-01-05 01:13 thomas - - * zip.rb, ziptest.rb: ZipFile now works - -2002-01-04 21:51 thomas - - * testDirectory.bin, zip.rb, ziptest.rb: - ZipCentralDirectoryEntryTest now runs - -2002-01-04 18:40 thomas - - * ziptest.rb: Changed - ZIpLocalNEtryTest::test_ReadLocalEntryHeaderOfFirstTestZipEntry - so it works on both unix too. It only worked on windows because - the test made assumptions about the compressed size and crc of an - entry, but that differs depending on the OS because of the CRLF - thing. - -2002-01-04 18:37 thomas - - * README.txt: Added note about zlib.c patch - -2002-01-02 18:48 thomas - - * README.txt, example.rb, file1.txt, zip.rb, ziptest.rb, - zlib.c.diff: Initial revision - -2002-01-02 18:48 thomas - - * README.txt, example.rb, file1.txt, zip.rb, ziptest.rb, - zlib.c.diff: initial - diff --git a/vendor/rubyzip-0.5.8/NEWS b/vendor/rubyzip-0.5.8/NEWS deleted file mode 100644 index 37911fdb..00000000 --- a/vendor/rubyzip-0.5.8/NEWS +++ /dev/null @@ -1,110 +0,0 @@ -= Version 0.5.8 - -Fixed install script. - -= Version 0.5.7 - -install.rb no longer assumes it is being run from the toplevel source -dir. Directory structure changed to reflect common ruby library -project structure. Migrated from RubyUnit to Test::Unit format. Now -uses Rake to build source packages and gems and run unit tests. - -= Version 0.5.6 - -Fix for FreeBSD 4.9 which returns Errno::EFBIG instead of -Errno::EINVAL for some invalid seeks. Fixed 'version needed to -extract'-field incorrect in local headers. - -= Version 0.5.5 - -Fix for a problem with writing zip files that concerns only ruby 1.8.1. - -= Version 0.5.4 - -Significantly reduced memory footprint when modifying zip files. - -= Version 0.5.3 - -Added optimization to avoid decompressing and recompressing individual -entries when modifying a zip archive. - -= Version 0.5.2 - -Fixed ZipFile corruption bug in ZipFile class. Added basic unix -extra-field support. - -= Version 0.5.1 - -Fixed ZipFile.get_output_stream bug. - -= Version 0.5.0 - -List of changes: -* Ruby 1.8.0 and ruby-zlib 0.6.0 compatibility -* Changed method names from camelCase to rubys underscore style. -* Installs to zip/ subdir instead of directly to site_ruby -* Added ZipFile.directory and ZipFile.file - each method return an -object that can be used like Dir and File only for the contents of the -zip file. -* Added sample application zipfind which works like Find.find, only -Zip::ZipFind.find traverses into zip archives too. - -Bug fixes: -* AbstractInputStream.each_line with non-default separator - - -= Version 0.5.0a - -Source reorganized. Added ziprequire, which can be used to load ruby -modules from a zip file, in a fashion similar to jar files in -Java. Added gtkRubyzip, another sample application. Implemented -ZipInputStream.lineno and ZipInputStream.rewind - -Bug fixes: - -* Read and write date and time information correctly for zip entries. -* Fixed read() using separate buffer, causing mix of gets/readline/read to -cause problems. - -= Version 0.4.2 - -Performance optimizations. Test suite runs in half the time. - -= Version 0.4.1 - -Windows compatibility fixes. - -= Version 0.4.0 - -Zip::ZipFile is now mutable and provides a more convenient way of -modifying zip archives than Zip::ZipOutputStream. Operations for -adding, extracting, renaming, replacing and removing entries to zip -archives are now available. - -Runs without warnings with -w switch. - -Install script install.rb added. - - -= Version 0.3.1 - -Rudimentary support for writing zip archives. - - -= Version 0.2.2 - -Fixed and extended unit test suite. Updated to work with ruby/zlib -0.5. It doesn't work with earlier versions of ruby/zlib. - - -= Version 0.2.0 - -Class ZipFile added. Where ZipInputStream is used to read the -individual entries in a zip file, ZipFile reads the central directory -in the zip archive, so you can get to any entry in the zip archive -without having to skipping through all the preceeding entries. - - -= Version 0.1.0 - -First working version of ZipInputStream. diff --git a/vendor/rubyzip-0.5.8/README b/vendor/rubyzip-0.5.8/README deleted file mode 100644 index 6ed15a92..00000000 --- a/vendor/rubyzip-0.5.8/README +++ /dev/null @@ -1,70 +0,0 @@ -= rubyzip - -rubyzip is a ruby library for reading and writing zip files. - -= Install - -If you have rubygems you can install rubyzip directly from the gem -repository - - gem install rubyzip - -Otherwise obtain the source (see below) and run - - ruby install.rb - -To run the unit tests you need to have test::unit installed - - rake test - - -= Documentation - -There is more than one way to access or create a zip archive with -rubyzip. The basic API is modeled after the classes in -java.util.zip from the Java SDK. This means there are classes such -as Zip::ZipInputStream, Zip::ZipOutputStream and -Zip::ZipFile. Zip::ZipInputStream provides a basic interface for -iterating through the entries in a zip archive and reading from the -entries in the same way as from a regular File or IO -object. ZipOutputStream is the corresponding basic output -facility. Zip::ZipFile provides a mean for accessing the archives -central directory and provides means for accessing any entry without -having to iterate through the archive. Unlike Java's -java.util.zip.ZipFile rubyzip's Zip::ZipFile is mutable, which means -it can be used to change zip files as well. - -Another way to access a zip archive with rubyzip is to use rubyzip's -Zip::ZipFileSystem API. Using this API files can be read from and -written to the archive in much the same manner as ruby's builtin -classes allows files to be read from and written to the file system. - -rubyzip also features the -zip/ziprequire.rb[link:files/lib/zip/ziprequire_rb.html] module which -allows ruby to load ruby modules from zip archives. - -For details about the specific behaviour of classes and methods refer -to the test suite. Finally you can generate the rdoc documentation or -visit http://rubyzip.sourceforge.net. - -= License - -rubyzip is distributed under the same license as ruby. See -http://www.ruby-lang.org/en/LICENSE.txt - - -= Website and Project Home - -http://rubyzip.sourceforge.net - -http://sourceforge.net/projects/rubyzip - -== Download (tarballs and gems) - -http://sourceforge.net/project/showfiles.php?group_id=43107&package_id=35377 - -= Authors - -Thomas Sondergaard (thomas at sondergaard.cc) - -extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org) diff --git a/vendor/rubyzip-0.5.8/Rakefile b/vendor/rubyzip-0.5.8/Rakefile deleted file mode 100644 index 03b65c2d..00000000 --- a/vendor/rubyzip-0.5.8/Rakefile +++ /dev/null @@ -1,110 +0,0 @@ -# Rakefile for RubyGems -*- ruby -*- - -require 'rubygems' -require 'rake/clean' -require 'rake/testtask' -require 'rake/packagetask' -require 'rake/gempackagetask' -require 'rake/rdoctask' -require 'rake/contrib/sshpublisher' -require 'net/ftp' - -PKG_NAME = 'rubyzip' -PKG_VERSION = File.read('lib/zip/zip.rb').match(/\s+VERSION\s*=\s*'(.*)'/)[1] - -PKG_FILES = FileList.new - -PKG_FILES.add %w{ README NEWS TODO ChangeLog install.rb Rakefile } -PKG_FILES.add %w{ samples/*.rb } -PKG_FILES.add %w{ test/*.rb } -PKG_FILES.add %w{ test/data/* } -PKG_FILES.exclude "test/data/generated" -PKG_FILES.add %w{ lib/**/*.rb } - -def clobberFromCvsIgnore(path) - CLOBBER.add File.readlines(path+'/.cvsignore').map { - |f| File.join(path, f.chomp) - } -end - -clobberFromCvsIgnore '.' -clobberFromCvsIgnore 'samples' -clobberFromCvsIgnore 'test' -clobberFromCvsIgnore 'test/data' - -task :default => [:test] - -desc "Run unit tests" -task :test do - ruby %{-C test alltests.rb} -end - -# Shortcuts for test targets -task :ut => [:test] - -spec = Gem::Specification.new do |s| - s.name = PKG_NAME - s.version = PKG_VERSION - s.author = "Thomas Sondergaard" - s.email = "thomas(at)sondergaard.cc" - s.homepage = "http://rubyzip.sourceforge.net/" - s.platform = Gem::Platform::RUBY - s.summary = "rubyzip is a ruby module for reading and writing zip files" - s.files = PKG_FILES.to_a #Dir.glob("{samples,lib,test,docs}/**/*").delete_if {|item| item.include?("CVS") || item.include?("rdoc") || item =~ /~$/ } - s.require_path = 'lib' - s.autorequire = 'zip/zip' -end - -Rake::GemPackageTask.new(spec) do |pkg| - pkg.need_zip = true - pkg.need_tar = true -end - -Rake::RDocTask.new do |rd| - rd.main = "README" - rd.rdoc_files.add %W{ lib/zip/*.rb README NEWS TODO ChangeLog } - rd.options << "--title 'rubyzip documentation' --webcvs http://cvs.sourceforge.net/viewcvs.py/rubyzip/rubyzip/" -# rd.options << "--all" -end - -desc "Publish documentation" -task :pdoc => [:rdoc] do - Rake::SshFreshDirPublisher. - new("thomas@rubyzip.sourceforge.net", "rubyzip/htdocs", "html").upload -end - -desc "Publish package" -task :ppackage => [:package] do - Net::FTP.open("upload.sourceforge.net", - "ftp", - ENV['USER']+"@"+ENV['HOSTNAME']) { - |ftpclient| - ftpclient.chdir "incoming" - Dir['pkg/*.{tgz,zip,gem}'].each { - |e| - ftpclient.putbinaryfile(e, File.basename(e)) - } - } -end - -desc "Generate the ChangeLog file" -task :ChangeLog do - puts "Updating ChangeLog" - system %{cvs2cl} -end - -desc "Make a release" -task :release => [:tag_release, :pdoc, :ppackage] do -end - -desc "Make a release tag" -task :tag_release do - tag = "release-#{PKG_VERSION.gsub('.','-')}" - - puts "Checking for tag '#{tag}'" - if (Regexp.new("^\\s+#{tag}") =~ `cvs log README`) - abort "Tag '#{tag}' already exists" - end - puts "Tagging module with '#{tag}'" - system("cvs tag #{tag}") -end diff --git a/vendor/rubyzip-0.5.8/TODO b/vendor/rubyzip-0.5.8/TODO deleted file mode 100644 index 457298c6..00000000 --- a/vendor/rubyzip-0.5.8/TODO +++ /dev/null @@ -1,9 +0,0 @@ - -* Fix problem with mixing AbstractInputStream::gets and AbstractInputStream::read -* Implement ZipFsDir.glob -* ZipFile.checkIntegrity method -* non-MSDOS permission attributes -** See mail from Ned Konz to ruby-talk subj. "Re: SV: [ANN] Archive 0.2" -* Packager version, required unpacker version in zip headers -** See mail from Ned Konz to ruby-talk subj. "Re: SV: [ANN] Archive 0.2" -* implement storing attributes and ownership information diff --git a/vendor/rubyzip-0.5.8/install.rb b/vendor/rubyzip-0.5.8/install.rb deleted file mode 100644 index 405e2b0b..00000000 --- a/vendor/rubyzip-0.5.8/install.rb +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -require 'rbconfig' -require 'find' -require 'ftools' - -include Config - -files = %w{ stdrubyext.rb ioextras.rb zip.rb zipfilesystem.rb ziprequire.rb tempfile_bugfixed.rb } - -INSTALL_DIR = File.join(CONFIG["sitelibdir"], "zip") -File.makedirs(INSTALL_DIR) - -SOURCE_DIR = File.join(File.dirname($0), "lib/zip") - -files.each { - |filename| - installPath = File.join(INSTALL_DIR, filename) - File::install(File.join(SOURCE_DIR, filename), installPath, 0644, true) -} diff --git a/vendor/rubyzip-0.5.8/samples/example.rb b/vendor/rubyzip-0.5.8/samples/example.rb deleted file mode 100644 index 741afa76..00000000 --- a/vendor/rubyzip-0.5.8/samples/example.rb +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env ruby - -$: << "../lib" -system("zip example.zip example.rb gtkRubyzip.rb") - -require 'zip/zip' - -####### Using ZipInputStream alone: ####### - -Zip::ZipInputStream.open("example.zip") { - |zis| - entry = zis.get_next_entry - print "First line of '#{entry.name} (#{entry.size} bytes): " - puts "'#{zis.gets.chomp}'" - entry = zis.get_next_entry - print "First line of '#{entry.name} (#{entry.size} bytes): " - puts "'#{zis.gets.chomp}'" -} - - -####### Using ZipFile to read the directory of a zip file: ####### - -zf = Zip::ZipFile.new("example.zip") -zf.each_with_index { - |entry, index| - - puts "entry #{index} is #{entry.name}, size = #{entry.size}, compressed size = #{entry.compressed_size}" - # use zf.get_input_stream(entry) to get a ZipInputStream for the entry - # entry can be the ZipEntry object or any object which has a to_s method that - # returns the name of the entry. -} - - -####### Using ZipOutputStream to write a zip file: ####### - -Zip::ZipOutputStream.open("exampleout.zip") { - |zos| - zos.put_next_entry("the first little entry") - zos.puts "Hello hello hello hello hello hello hello hello hello" - - zos.put_next_entry("the second little entry") - zos.puts "Hello again" - - # Use rubyzip or your zip client of choice to verify - # the contents of exampleout.zip -} - -####### Using ZipFile to change a zip file: ####### - -Zip::ZipFile.open("exampleout.zip") { - |zf| - zf.add("thisFile.rb", "example.rb") - zf.rename("thisFile.rb", "ILikeThisName.rb") - zf.add("Again", "example.rb") -} - -# Lets check -Zip::ZipFile.open("exampleout.zip") { - |zf| - puts "Changed zip file contains: #{zf.entries.join(', ')}" - zf.remove("Again") - puts "Without 'Again': #{zf.entries.join(', ')}" -} - -# For other examples, look at zip.rb and ziptest.rb - -# Copyright (C) 2002 Thomas Sondergaard -# rubyzip is free software; you can redistribute it and/or -# modify it under the terms of the ruby license. diff --git a/vendor/rubyzip-0.5.8/samples/example_filesystem.rb b/vendor/rubyzip-0.5.8/samples/example_filesystem.rb deleted file mode 100644 index 867e8d4f..00000000 --- a/vendor/rubyzip-0.5.8/samples/example_filesystem.rb +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env ruby - -$: << "../lib" - -require 'zip/zipfilesystem' -require 'ftools' - -EXAMPLE_ZIP = "filesystem.zip" - -File.delete(EXAMPLE_ZIP) if File.exists?(EXAMPLE_ZIP) - -Zip::ZipFile.open(EXAMPLE_ZIP, Zip::ZipFile::CREATE) { - |zf| - zf.file.open("file1.txt", "w") { |os| os.write "first file1.txt" } - zf.dir.mkdir("dir1") - zf.dir.chdir("dir1") - zf.file.open("file1.txt", "w") { |os| os.write "second file1.txt" } - puts zf.file.read("file1.txt") - puts zf.file.read("../file1.txt") - zf.dir.chdir("..") - zf.file.open("file2.txt", "w") { |os| os.write "first file2.txt" } - puts "Entries: #{zf.entries.join(', ')}" -} - -Zip::ZipFile.open(EXAMPLE_ZIP) { - |zf| - puts "Entries from reloaded zip: #{zf.entries.join(', ')}" -} - -# For other examples, look at zip.rb and ziptest.rb - -# Copyright (C) 2003 Thomas Sondergaard -# rubyzip is free software; you can redistribute it and/or -# modify it under the terms of the ruby license. diff --git a/vendor/rubyzip-0.5.8/samples/gtkRubyzip.rb b/vendor/rubyzip-0.5.8/samples/gtkRubyzip.rb deleted file mode 100644 index 5d91829d..00000000 --- a/vendor/rubyzip-0.5.8/samples/gtkRubyzip.rb +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env ruby - -$: << "../lib" - -$VERBOSE = true - -require 'gtk' -require 'zip/zip' - -class MainApp < Gtk::Window - def initialize - super() - set_usize(400, 256) - set_title("rubyzip") - signal_connect(Gtk::Window::SIGNAL_DESTROY) { Gtk.main_quit } - - box = Gtk::VBox.new(false, 0) - add(box) - - @zipfile = nil - @buttonPanel = ButtonPanel.new - @buttonPanel.openButton.signal_connect(Gtk::Button::SIGNAL_CLICKED) { - show_file_selector - } - @buttonPanel.extractButton.signal_connect(Gtk::Button::SIGNAL_CLICKED) { - puts "Not implemented!" - } - box.pack_start(@buttonPanel, false, false, 0) - - sw = Gtk::ScrolledWindow.new - sw.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) - box.pack_start(sw, true, true, 0) - - @clist = Gtk::CList.new(["Name", "Size", "Compression"]) - @clist.set_selection_mode(Gtk::SELECTION_BROWSE) - @clist.set_column_width(0, 120) - @clist.set_column_width(1, 120) - @clist.signal_connect(Gtk::CList::SIGNAL_SELECT_ROW) { - |w, row, column, event| - @selected_row = row - } - sw.add(@clist) - end - - class ButtonPanel < Gtk::HButtonBox - attr_reader :openButton, :extractButton - def initialize - super - set_layout(Gtk::BUTTONBOX_START) - set_spacing(0) - @openButton = Gtk::Button.new("Open archive") - @extractButton = Gtk::Button.new("Extract entry") - pack_start(@openButton) - pack_start(@extractButton) - end - end - - def show_file_selector - @fileSelector = Gtk::FileSelection.new("Open zip file") - @fileSelector.show - @fileSelector.ok_button.signal_connect(Gtk::Button::SIGNAL_CLICKED) { - open_zip(@fileSelector.filename) - @fileSelector.destroy - } - @fileSelector.cancel_button.signal_connect(Gtk::Button::SIGNAL_CLICKED) { - @fileSelector.destroy - } - end - - def open_zip(filename) - @zipfile = Zip::ZipFile.open(filename) - @clist.clear - @zipfile.each { - |entry| - @clist.append([ entry.name, - entry.size.to_s, - (100.0*entry.compressedSize/entry.size).to_s+"%" ]) - } - end -end - -mainApp = MainApp.new() - -mainApp.show_all - -Gtk.main diff --git a/vendor/rubyzip-0.5.8/samples/write_simple.rb b/vendor/rubyzip-0.5.8/samples/write_simple.rb deleted file mode 100644 index 648989a2..00000000 --- a/vendor/rubyzip-0.5.8/samples/write_simple.rb +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env ruby - -$: << "../lib" - -require 'zip/zip' - -include Zip - -ZipOutputStream.open('simple.zip') { - |zos| - ze = zos.put_next_entry 'entry.txt' - zos.puts "Hello world" -} diff --git a/vendor/rubyzip-0.5.8/samples/zipfind.rb b/vendor/rubyzip-0.5.8/samples/zipfind.rb deleted file mode 100644 index 54ad936e..00000000 --- a/vendor/rubyzip-0.5.8/samples/zipfind.rb +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -$: << "../lib" - -require 'zip/zip' -require 'find' - -module Zip - module ZipFind - def self.find(path, zipFilePattern = /\.zip$/i) - Find.find(path) { - |fileName| - yield(fileName) - if zipFilePattern.match(fileName) && File.file?(fileName) - begin - Zip::ZipFile.foreach(fileName) { - |zipEntry| - yield(fileName + File::SEPARATOR + zipEntry.to_s) - } - rescue Errno::EACCES => ex - puts ex - end - end - } - end - - def self.find_file(path, fileNamePattern, zipFilePattern = /\.zip$/i) - self.find(path, zipFilePattern) { - |fileName| - yield(fileName) if fileNamePattern.match(fileName) - } - end - - end -end - -if __FILE__ == $0 - module ZipFindConsoleRunner - - PATH_ARG_INDEX = 0; - FILENAME_PATTERN_ARG_INDEX = 1; - ZIPFILE_PATTERN_ARG_INDEX = 2; - - def self.run(args) - check_args(args) - Zip::ZipFind.find_file(args[PATH_ARG_INDEX], - args[FILENAME_PATTERN_ARG_INDEX], - args[ZIPFILE_PATTERN_ARG_INDEX]) { - |fileName| - report_entry_found fileName - } - end - - def self.check_args(args) - if (args.size != 3) - usage - exit - end - end - - def self.usage - puts "Usage: #{$0} PATH ZIPFILENAME_PATTERN FILNAME_PATTERN" - end - - def self.report_entry_found(fileName) - puts fileName - end - - end - - ZipFindConsoleRunner.run(ARGV) -end diff --git a/vendor/rubyzip-0.5.8/test/alltests.rb b/vendor/rubyzip-0.5.8/test/alltests.rb deleted file mode 100644 index 691349af..00000000 --- a/vendor/rubyzip-0.5.8/test/alltests.rb +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -require 'stdrubyexttest' -require 'ioextrastest' -require 'ziptest' -require 'zipfilesystemtest' -require 'ziprequiretest' diff --git a/vendor/rubyzip-0.5.8/test/data/file1.txt b/vendor/rubyzip-0.5.8/test/data/file1.txt deleted file mode 100644 index 23ea2f73..00000000 --- a/vendor/rubyzip-0.5.8/test/data/file1.txt +++ /dev/null @@ -1,46 +0,0 @@ - -AUTOMAKE_OPTIONS = gnu - -EXTRA_DIST = test.zip - -CXXFLAGS= -g - -noinst_LIBRARIES = libzipios.a - -bin_PROGRAMS = test_zip test_izipfilt test_izipstream -# test_flist - -libzipios_a_SOURCES = backbuffer.h fcol.cpp fcol.h \ - fcol_common.h fcolexceptions.cpp fcolexceptions.h \ - fileentry.cpp fileentry.h flist.cpp \ - flist.h flistentry.cpp flistentry.h \ - flistscanner.h ifiltstreambuf.cpp ifiltstreambuf.h \ - inflatefilt.cpp inflatefilt.h izipfilt.cpp \ - izipfilt.h izipstream.cpp izipstream.h \ - zipfile.cpp zipfile.h ziphead.cpp \ - ziphead.h flistscanner.ll - -# test_flist_SOURCES = test_flist.cpp - -test_izipfilt_SOURCES = test_izipfilt.cpp - -test_izipstream_SOURCES = test_izipstream.cpp - -test_zip_SOURCES = test_zip.cpp - -# Notice that libzipios.a is not specified as -L. -lzipios -# If it was, automake would not include it as a dependency. - -# test_flist_LDADD = libzipios.a - -test_izipfilt_LDADD = libzipios.a -lz - -test_zip_LDADD = libzipios.a -lz - -test_izipstream_LDADD = libzipios.a -lz - - - -flistscanner.cc : flistscanner.ll - $(LEX) -+ -PFListScanner -o$@ $^ - diff --git a/vendor/rubyzip-0.5.8/test/data/file1.txt.deflatedData b/vendor/rubyzip-0.5.8/test/data/file1.txt.deflatedData deleted file mode 100644 index bfbb4f42..00000000 Binary files a/vendor/rubyzip-0.5.8/test/data/file1.txt.deflatedData and /dev/null differ diff --git a/vendor/rubyzip-0.5.8/test/data/file2.txt b/vendor/rubyzip-0.5.8/test/data/file2.txt deleted file mode 100644 index cc9ef6ad..00000000 --- a/vendor/rubyzip-0.5.8/test/data/file2.txt +++ /dev/null @@ -1,1504 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -require 'rubyunit' -require 'zip' - -include Zip - -Dir.chdir "test" - -class AbstractInputStreamTest < RUNIT::TestCase - # AbstractInputStream subclass that provides a read method - - TEST_LINES = [ "Hello world#{$/}", - "this is the second line#{$/}", - "this is the last line"] - TEST_STRING = TEST_LINES.join - class TestAbstractInputStream - include AbstractInputStream - def initialize(aString) - @contents = aString - @readPointer = 0 - end - - def read(charsToRead) - retVal=@contents[@readPointer, charsToRead] - @readPointer+=charsToRead - return retVal - end - - def produceInput - read(100) - end - - def inputFinished? - @contents[@readPointer] == nil - end - end - - def setup - @io = TestAbstractInputStream.new(TEST_STRING) - end - - def test_gets - assert_equals(TEST_LINES[0], @io.gets) - assert_equals(TEST_LINES[1], @io.gets) - assert_equals(TEST_LINES[2], @io.gets) - assert_equals(nil, @io.gets) - end - - def test_getsMultiCharSeperator - assert_equals("Hell", @io.gets("ll")) - assert_equals("o world#{$/}this is the second l", @io.gets("d l")) - end - - def test_each_line - lineNumber=0 - @io.each_line { - |line| - assert_equals(TEST_LINES[lineNumber], line) - lineNumber+=1 - } - end - - def test_readlines - assert_equals(TEST_LINES, @io.readlines) - end - - def test_readline - test_gets - begin - @io.readline - fail "EOFError expected" - rescue EOFError - end - end -end - -class ZipEntryTest < RUNIT::TestCase - TEST_ZIPFILE = "someZipFile.zip" - TEST_COMMENT = "a comment" - TEST_COMPRESSED_SIZE = 1234 - TEST_CRC = 325324 - TEST_EXTRA = "Some data here" - TEST_COMPRESSIONMETHOD = ZipEntry::DEFLATED - TEST_NAME = "entry name" - TEST_SIZE = 8432 - TEST_ISDIRECTORY = false - - def test_constructorAndGetters - entry = ZipEntry.new(TEST_ZIPFILE, - TEST_NAME, - TEST_COMMENT, - TEST_EXTRA, - TEST_COMPRESSED_SIZE, - TEST_CRC, - TEST_COMPRESSIONMETHOD, - TEST_SIZE) - - assert_equals(TEST_COMMENT, entry.comment) - assert_equals(TEST_COMPRESSED_SIZE, entry.compressedSize) - assert_equals(TEST_CRC, entry.crc) - assert_equals(TEST_EXTRA, entry.extra) - assert_equals(TEST_COMPRESSIONMETHOD, entry.compressionMethod) - assert_equals(TEST_NAME, entry.name) - assert_equals(TEST_SIZE, entry.size) - assert_equals(TEST_ISDIRECTORY, entry.isDirectory) - end - - def test_equality - entry1 = ZipEntry.new("file.zip", "name", "isNotCompared", - "something extra", 123, 1234, - ZipEntry::DEFLATED, 10000) - entry2 = ZipEntry.new("file.zip", "name", "isNotComparedXXX", - "something extra", 123, 1234, - ZipEntry::DEFLATED, 10000) - entry3 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extra", 123, 1234, - ZipEntry::DEFLATED, 10000) - entry4 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 123, 1234, - ZipEntry::DEFLATED, 10000) - entry5 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 12, 1234, - ZipEntry::DEFLATED, 10000) - entry6 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 12, 123, - ZipEntry::DEFLATED, 10000) - entry7 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 12, 123, - ZipEntry::STORED, 10000) - entry8 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 12, 123, - ZipEntry::STORED, 100000) - - assert_equals(entry1, entry1) - assert_equals(entry1, entry2) - - assert(entry2 != entry3) - assert(entry3 != entry4) - assert(entry4 != entry5) - assert(entry5 != entry6) - assert(entry6 != entry7) - assert(entry7 != entry8) - - assert(entry7 != "hello") - assert(entry7 != 12) - end -end - -module IOizeString - attr_reader :tell - - def read(count = nil) - @tell ||= 0 - count = size unless count - retVal = slice(@tell, count) - @tell += count - return retVal - end - - def seek(index, offset) - @tell ||= 0 - case offset - when IO::SEEK_END - newPos = size + index - when IO::SEEK_SET - newPos = index - when IO::SEEK_CUR - newPos = @tell + index - else - raise "Error in test method IOizeString::seek" - end - if (newPos < 0 || newPos >= size) - raise Errno::EINVAL - else - @tell=newPos - end - end - - def reset - @tell = 0 - end -end - -class ZipLocalEntryTest < RUNIT::TestCase - def test_readLocalEntryHeaderOfFirstTestZipEntry - File.open(TestZipFile::TEST_ZIP3.zipName) { - |file| - entry = ZipEntry.readLocalEntry(file) - - assert_equal("", entry.comment) - # Differs from windows and unix because of CR LF - # assert_equal(480, entry.compressedSize) - # assert_equal(0x2a27930f, entry.crc) - # extra field is 21 bytes long - # probably contains some unix attrutes or something - # disabled: assert_equal(nil, entry.extra) - assert_equal(ZipEntry::DEFLATED, entry.compressionMethod) - assert_equal(TestZipFile::TEST_ZIP3.entryNames[0], entry.name) - assert_equal(File.size(TestZipFile::TEST_ZIP3.entryNames[0]), entry.size) - assert(! entry.isDirectory) - } - end - - def test_readLocalEntryFromNonZipFile - File.open("ziptest.rb") { - |file| - assert_equals(nil, ZipEntry.readLocalEntry(file)) - } - end - - def test_readLocalEntryFromTruncatedZipFile - zipFragment="" - File.open(TestZipFile::TEST_ZIP2.zipName) { |f| zipFragment = f.read(12) } # local header is at least 30 bytes - zipFragment.extend(IOizeString).reset - entry = ZipEntry.new - entry.readLocalEntry(zipFragment) - fail "ZipError expected" - rescue ZipError - end - - def test_writeEntry - entry = ZipEntry.new("file.zip", "entryName", "my little comment", - "thisIsSomeExtraInformation", 100, 987654, - ZipEntry::DEFLATED, 400) - writeToFile("localEntryHeader.bin", "centralEntryHeader.bin", entry) - entryReadLocal, entryReadCentral = readFromFile("localEntryHeader.bin", "centralEntryHeader.bin") - compareLocalEntryHeaders(entry, entryReadLocal) - compareCDirEntryHeaders(entry, entryReadCentral) - end - - private - def compareLocalEntryHeaders(entry1, entry2) - assert_equals(entry1.compressedSize , entry2.compressedSize) - assert_equals(entry1.crc , entry2.crc) - assert_equals(entry1.extra , entry2.extra) - assert_equals(entry1.compressionMethod, entry2.compressionMethod) - assert_equals(entry1.name , entry2.name) - assert_equals(entry1.size , entry2.size) - assert_equals(entry1.localHeaderOffset, entry2.localHeaderOffset) - end - - def compareCDirEntryHeaders(entry1, entry2) - compareLocalEntryHeaders(entry1, entry2) - assert_equals(entry1.comment, entry2.comment) - end - - def writeToFile(localFileName, centralFileName, entry) - File.open(localFileName, "wb") { |f| entry.writeLocalEntry(f) } - File.open(centralFileName, "wb") { |f| entry.writeCDirEntry(f) } - end - - def readFromFile(localFileName, centralFileName) - localEntry = nil - cdirEntry = nil - File.open(localFileName, "rb") { |f| localEntry = ZipEntry.readLocalEntry(f) } - File.open(centralFileName, "rb") { |f| cdirEntry = ZipEntry.readCDirEntry(f) } - return [localEntry, cdirEntry] - end -end - - -module DecompressorTests - # expects @refText and @decompressor - - def test_readEverything - assert_equals(@refText, @decompressor.read) - end - - def test_readInChunks - chunkSize = 5 - while (decompressedChunk = @decompressor.read(chunkSize)) - assert_equals(@refText.slice!(0, chunkSize), decompressedChunk) - end - assert_equals(0, @refText.size) - end -end - -class InflaterTest < RUNIT::TestCase - include DecompressorTests - - def setup - @file = File.new("file1.txt.deflatedData", "rb") - @refText="" - File.open("file1.txt") { |f| @refText = f.read } - @decompressor = Inflater.new(@file) - end - - def teardown - @file.close - end -end - - -class PassThruDecompressorTest < RUNIT::TestCase - include DecompressorTests - TEST_FILE="file1.txt" - def setup - @file = File.new(TEST_FILE) - @refText="" - File.open(TEST_FILE) { |f| @refText = f.read } - @decompressor = PassThruDecompressor.new(@file, File.size(TEST_FILE)) - end - - def teardown - @file.close - end -end - - -module AssertEntry - def assertNextEntry(filename, zis) - assertEntry(filename, zis, zis.getNextEntry.name) - end - - def assertEntry(filename, zis, entryName) - assert_equals(filename, entryName) - assertEntryContentsForStream(filename, zis, entryName) - end - - def assertEntryContentsForStream(filename, zis, entryName) - File.open(filename, "rb") { - |file| - expected = file.read - actual = zis.read - if (expected != actual) - if (expected.length > 400 || actual.length > 400) - zipEntryFilename=entryName+".zipEntry" - File.open(zipEntryFilename, "wb") { |file| file << actual } - fail("File '#{filename}' is different from '#{zipEntryFilename}'") - else - assert_equals(expected, actual) - end - end - } - end - - def AssertEntry.assertContents(filename, aString) - fileContents = "" - File.open(filename, "rb") { |f| fileContents = f.read } - if (fileContents != aString) - if (expected.length > 400 || actual.length > 400) - stringFile = filename + ".other" - File.open(stringFile, "wb") { |f| f << aString } - fail("File '#{filename}' is different from contents of string stored in '#{stringFile}'") - else - assert_equals(expected, actual) - end - end - end - - def assertStreamContents(zis, testZipFile) - assert(zis != nil) - testZipFile.entryNames.each { - |entryName| - assertNextEntry(entryName, zis) - } - assert_equals(nil, zis.getNextEntry) - end - - def assertTestZipContents(testZipFile) - ZipInputStream.open(testZipFile.zipName) { - |zis| - assertStreamContents(zis, testZipFile) - } - end - - def assertEntryContents(zipFile, entryName, filename = entryName.to_s) - zis = zipFile.getInputStream(entryName) - assertEntryContentsForStream(filename, zis, entryName) - ensure - zis.close if zis - end -end - - - -class ZipInputStreamTest < RUNIT::TestCase - include AssertEntry - - def test_new - zis = ZipInputStream.new(TestZipFile::TEST_ZIP2.zipName) - assertStreamContents(zis, TestZipFile::TEST_ZIP2) - zis.close - end - - def test_openWithBlock - ZipInputStream.open(TestZipFile::TEST_ZIP2.zipName) { - |zis| - assertStreamContents(zis, TestZipFile::TEST_ZIP2) - } - end - - def test_openWithoutBlock - zis = ZipInputStream.open(TestZipFile::TEST_ZIP2.zipName) - assertStreamContents(zis, TestZipFile::TEST_ZIP2) - end - - def test_incompleteReads - ZipInputStream.open(TestZipFile::TEST_ZIP2.zipName) { - |zis| - entry = zis.getNextEntry - assert_equals(TestZipFile::TEST_ZIP2.entryNames[0], entry.name) - assert zis.gets.length > 0 - entry = zis.getNextEntry - assert_equals(TestZipFile::TEST_ZIP2.entryNames[1], entry.name) - assert_equals(0, entry.size) - assert_equals(nil, zis.gets) - entry = zis.getNextEntry - assert_equals(TestZipFile::TEST_ZIP2.entryNames[2], entry.name) - assert zis.gets.length > 0 - entry = zis.getNextEntry - assert_equals(TestZipFile::TEST_ZIP2.entryNames[3], entry.name) - assert zis.gets.length > 0 - } - end - -end - -class TestFiles - RANDOM_ASCII_FILE1 = "randomAscii1.txt" - RANDOM_ASCII_FILE2 = "randomAscii2.txt" - RANDOM_ASCII_FILE3 = "randomAscii3.txt" - RANDOM_BINARY_FILE1 = "randomBinary1.bin" - RANDOM_BINARY_FILE2 = "randomBinary2.bin" - - EMPTY_TEST_DIR = "emptytestdir" - - ASCII_TEST_FILES = [ RANDOM_ASCII_FILE1, RANDOM_ASCII_FILE2, RANDOM_ASCII_FILE3 ] - BINARY_TEST_FILES = [ RANDOM_BINARY_FILE1, RANDOM_BINARY_FILE2 ] - TEST_DIRECTORIES = [ EMPTY_TEST_DIR ] - TEST_FILES = [ ASCII_TEST_FILES, BINARY_TEST_FILES, EMPTY_TEST_DIR ].flatten! - - def TestFiles.createTestFiles(recreate) - if (recreate || - ! (TEST_FILES.inject(true) { |accum, element| accum && File.exists?(element) })) - - ASCII_TEST_FILES.each_with_index { - |filename, index| - createRandomAscii(filename, 1E4 * (index+1)) - } - - BINARY_TEST_FILES.each_with_index { - |filename, index| - createRandomBinary(filename, 1E4 * (index+1)) - } - - ensureDir(EMPTY_TEST_DIR) - end - end - - private - def TestFiles.createRandomAscii(filename, size) - File.open(filename, "wb") { - |file| - while (file.tell < size) - file << rand - end - } - end - - def TestFiles.createRandomBinary(filename, size) - File.open(filename, "wb") { - |file| - while (file.tell < size) - file << rand.to_a.pack("V") - end - } - end - - def TestFiles.ensureDir(name) - if File.exists?(name) - return if File.stat(name).directory? - File.delete(name) - end - Dir.mkdir(name) - end - -end - -# For representation and creation of -# test data -class TestZipFile - attr_accessor :zipName, :entryNames, :comment - - def initialize(zipName, entryNames, comment = "") - @zipName=zipName - @entryNames=entryNames - @comment = comment - end - - def TestZipFile.createTestZips(recreate) - files = Dir.entries(".") - if (recreate || - ! (files.index(TEST_ZIP1.zipName) && - files.index(TEST_ZIP2.zipName) && - files.index(TEST_ZIP3.zipName) && - files.index(TEST_ZIP4.zipName) && - files.index("empty.txt") && - files.index("short.txt") && - files.index("longAscii.txt") && - files.index("longBinary.bin") )) - raise "failed to create test zip '#{TEST_ZIP1.zipName}'" unless - system("zip #{TEST_ZIP1.zipName} ziptest.rb") - raise "failed to remove entry from '#{TEST_ZIP1.zipName}'" unless - system("zip #{TEST_ZIP1.zipName} -d ziptest.rb") - - File.open("empty.txt", "w") {} - - File.open("short.txt", "w") { |file| file << "ABCDEF" } - ziptestTxt="" - File.open("ziptest.rb") { |file| ziptestTxt=file.read } - File.open("longAscii.txt", "w") { - |file| - while (file.tell < 1E5) - file << ziptestTxt - end - } - - testBinaryPattern="" - File.open("empty.zip") { |file| testBinaryPattern=file.read } - testBinaryPattern *= 4 - - File.open("longBinary.bin", "wb") { - |file| - while (file.tell < 3E5) - file << testBinaryPattern << rand - end - } - raise "failed to create test zip '#{TEST_ZIP2.zipName}'" unless - system("zip #{TEST_ZIP2.zipName} #{TEST_ZIP2.entryNames.join(' ')}") - - # without bash system interprets everything after echo as parameters to - # echo including | zip -z ... - raise "failed to add comment to test zip '#{TEST_ZIP2.zipName}'" unless - system("bash -c \"echo #{TEST_ZIP2.comment} | zip -z #{TEST_ZIP2.zipName}\"") - - raise "failed to create test zip '#{TEST_ZIP3.zipName}'" unless - system("zip #{TEST_ZIP3.zipName} #{TEST_ZIP3.entryNames.join(' ')}") - - raise "failed to create test zip '#{TEST_ZIP4.zipName}'" unless - system("zip #{TEST_ZIP4.zipName} #{TEST_ZIP4.entryNames.join(' ')}") - end - rescue - raise $!.to_s + - "\n\nziptest.rb requires the Info-ZIP program 'zip' in the path\n" + - "to create test data. If you don't have it you can download\n" + - "the necessary test files at http://sf.net/projects/rubyzip." - end - - TEST_ZIP1 = TestZipFile.new("empty.zip", []) - TEST_ZIP2 = TestZipFile.new("4entry.zip", %w{ longAscii.txt empty.txt short.txt longBinary.bin}, - "my zip comment") - TEST_ZIP3 = TestZipFile.new("test1.zip", %w{ file1.txt }) - TEST_ZIP4 = TestZipFile.new("zipWithDir.zip", [ "file1.txt", - TestFiles::EMPTY_TEST_DIR]) -end - - -class AbstractOutputStreamTest < RUNIT::TestCase - class TestOutputStream - include AbstractOutputStream - - attr_accessor :buffer - - def initialize - @buffer = "" - end - - def << (data) - @buffer << data - self - end - end - - def setup - @outputStream = TestOutputStream.new - - @origCommaSep = $, - @origOutputSep = $\ - end - - def teardown - $, = @origCommaSep - $\ = @origOutputSep - end - - def test_write - count = @outputStream.write("a little string") - assert_equals("a little string", @outputStream.buffer) - assert_equals("a little string".length, count) - - count = @outputStream.write(". a little more") - assert_equals("a little string. a little more", @outputStream.buffer) - assert_equals(". a little more".length, count) - end - - def test_print - $\ = nil # record separator set to nil - @outputStream.print("hello") - assert_equals("hello", @outputStream.buffer) - - @outputStream.print(" world.") - assert_equals("hello world.", @outputStream.buffer) - - @outputStream.print(" You ok ", "out ", "there?") - assert_equals("hello world. You ok out there?", @outputStream.buffer) - - $\ = "\n" - @outputStream.print - assert_equals("hello world. You ok out there?\n", @outputStream.buffer) - - @outputStream.print("I sure hope so!") - assert_equals("hello world. You ok out there?\nI sure hope so!\n", @outputStream.buffer) - - $, = "X" - @outputStream.buffer = "" - @outputStream.print("monkey", "duck", "zebra") - assert_equals("monkeyXduckXzebra\n", @outputStream.buffer) - - $\ = nil - @outputStream.buffer = "" - @outputStream.print(20) - assert_equals("20", @outputStream.buffer) - end - - def test_printf - @outputStream.printf("%d %04x", 123, 123) - assert_equals("123 007b", @outputStream.buffer) - end - - def test_putc - @outputStream.putc("A") - assert_equals("A", @outputStream.buffer) - @outputStream.putc(65) - assert_equals("AA", @outputStream.buffer) - end - - def test_puts - @outputStream.puts - assert_equals("\n", @outputStream.buffer) - - @outputStream.puts("hello", "world") - assert_equals("\nhello\nworld\n", @outputStream.buffer) - - @outputStream.buffer = "" - @outputStream.puts("hello\n", "world\n") - assert_equals("hello\nworld\n", @outputStream.buffer) - - @outputStream.buffer = "" - @outputStream.puts(["hello\n", "world\n"]) - assert_equals("hello\nworld\n", @outputStream.buffer) - - @outputStream.buffer = "" - @outputStream.puts(["hello\n", "world\n"], "bingo") - assert_equals("hello\nworld\nbingo\n", @outputStream.buffer) - - @outputStream.buffer = "" - @outputStream.puts(16, 20, 50, "hello") - assert_equals("16\n20\n50\nhello\n", @outputStream.buffer) - end -end - - -module CrcTest - def runCrcTest(compressorClass) - str = "Here's a nice little text to compute the crc for! Ho hum, it is nice nice nice nice indeed." - fakeOut = AbstractOutputStreamTest::TestOutputStream.new - - deflater = compressorClass.new(fakeOut) - deflater << str - assert_equals(0x919920fc, deflater.crc) - end -end - - - -class PassThruCompressorTest < RUNIT::TestCase - include CrcTest - - def test_size - File.open("dummy.txt", "wb") { - |file| - compressor = PassThruCompressor.new(file) - - assert_equals(0, compressor.size) - - t1 = "hello world" - t2 = "" - t3 = "bingo" - - compressor << t1 - assert_equals(compressor.size, t1.size) - - compressor << t2 - assert_equals(compressor.size, t1.size + t2.size) - - compressor << t3 - assert_equals(compressor.size, t1.size + t2.size + t3.size) - } - end - - def test_crc - runCrcTest(PassThruCompressor) - end -end - -class DeflaterTest < RUNIT::TestCase - include CrcTest - - def test_outputOperator - txt = loadFile("ziptest.rb") - deflate(txt, "deflatertest.bin") - inflatedTxt = inflate("deflatertest.bin") - assert_equals(txt, inflatedTxt) - end - - private - def loadFile(fileName) - txt = nil - File.open(fileName, "rb") { |f| txt = f.read } - end - - def deflate(data, fileName) - File.open(fileName, "wb") { - |file| - deflater = Deflater.new(file) - deflater << data - deflater.finish - assert_equals(deflater.size, data.size) - file << "trailing data for zlib with -MAX_WBITS" - } - end - - def inflate(fileName) - txt = nil - File.open(fileName, "rb") { - |file| - inflater = Inflater.new(file) - txt = inflater.read - } - end - - def test_crc - runCrcTest(Deflater) - end -end - -class ZipOutputStreamTest < RUNIT::TestCase - include AssertEntry - - TEST_ZIP = TestZipFile::TEST_ZIP2.clone - TEST_ZIP.zipName = "output.zip" - - def test_new - zos = ZipOutputStream.new(TEST_ZIP.zipName) - zos.comment = TEST_ZIP.comment - writeTestZip(zos) - zos.close - assertTestZipContents(TEST_ZIP) - end - - def test_open - ZipOutputStream.open(TEST_ZIP.zipName) { - |zos| - zos.comment = TEST_ZIP.comment - writeTestZip(zos) - } - assertTestZipContents(TEST_ZIP) - end - - def test_writingToClosedStream - assertIOErrorInClosedStream { |zos| zos << "hello world" } - assertIOErrorInClosedStream { |zos| zos.puts "hello world" } - assertIOErrorInClosedStream { |zos| zos.write "hello world" } - end - - def test_cannotOpenFile - name = TestFiles::EMPTY_TEST_DIR - begin - zos = ZipOutputStream.open(name) - rescue Exception - assert($!.kind_of?(Errno::EISDIR) || # Linux - $!.kind_of?(Errno::EEXIST) || # Windows/cygwin - $!.kind_of?(Errno::EACCES), # Windows - "Expected Errno::EISDIR (or on win/cygwin: Errno::EEXIST), but was: #{$!.type}") - end - end - - def assertIOErrorInClosedStream - assert_exception(IOError) { - zos = ZipOutputStream.new("test_putOnClosedStream.zip") - zos.close - yield zos - } - end - - def writeTestZip(zos) - TEST_ZIP.entryNames.each { - |entryName| - zos.putNextEntry(entryName) - File.open(entryName, "rb") { |f| zos.write(f.read) } - } - end -end - - - -module Enumerable - def compareEnumerables(otherEnumerable) - otherAsArray = otherEnumerable.to_a - index=0 - each_with_index { - |element, index| - return false unless yield(element, otherAsArray[index]) - } - return index+1 == otherAsArray.size - end -end - - -class ZipCentralDirectoryEntryTest < RUNIT::TestCase - - def test_readFromStream - File.open("testDirectory.bin", "rb") { - |file| - entry = ZipEntry.readCDirEntry(file) - - assert_equals("longAscii.txt", entry.name) - assert_equals(ZipEntry::DEFLATED, entry.compressionMethod) - assert_equals(106490, entry.size) - assert_equals(3784, entry.compressedSize) - assert_equals(0xfcd1799c, entry.crc) - assert_equals("", entry.comment) - - entry = ZipEntry.readCDirEntry(file) - assert_equals("empty.txt", entry.name) - assert_equals(ZipEntry::STORED, entry.compressionMethod) - assert_equals(0, entry.size) - assert_equals(0, entry.compressedSize) - assert_equals(0x0, entry.crc) - assert_equals("", entry.comment) - - entry = ZipEntry.readCDirEntry(file) - assert_equals("short.txt", entry.name) - assert_equals(ZipEntry::STORED, entry.compressionMethod) - assert_equals(6, entry.size) - assert_equals(6, entry.compressedSize) - assert_equals(0xbb76fe69, entry.crc) - assert_equals("", entry.comment) - - entry = ZipEntry.readCDirEntry(file) - assert_equals("longBinary.bin", entry.name) - assert_equals(ZipEntry::DEFLATED, entry.compressionMethod) - assert_equals(1000024, entry.size) - assert_equals(70847, entry.compressedSize) - assert_equals(0x10da7d59, entry.crc) - assert_equals("", entry.comment) - - entry = ZipEntry.readCDirEntry(file) - assert_equals(nil, entry) -# Fields that are not check by this test: -# version made by 2 bytes -# version needed to extract 2 bytes -# general purpose bit flag 2 bytes -# last mod file time 2 bytes -# last mod file date 2 bytes -# compressed size 4 bytes -# uncompressed size 4 bytes -# disk number start 2 bytes -# internal file attributes 2 bytes -# external file attributes 4 bytes -# relative offset of local header 4 bytes - -# file name (variable size) -# extra field (variable size) -# file comment (variable size) - - } - end - - def test_ReadEntryFromTruncatedZipFile - fragment="" - File.open("testDirectory.bin") { |f| fragment = f.read(12) } # cdir entry header is at least 46 bytes - fragment.extend(IOizeString) - entry = ZipEntry.new - entry.readCDirEntry(fragment) - fail "ZipError expected" - rescue ZipError - end - -end - -class ZipCentralDirectoryTest < RUNIT::TestCase - - def test_readFromStream - File.open(TestZipFile::TEST_ZIP2.zipName, "rb") { - |zipFile| - cdir = ZipCentralDirectory.readFromStream(zipFile) - - assert_equals(TestZipFile::TEST_ZIP2.entryNames.size, cdir.size) - assert(cdir.compareEnumerables(TestZipFile::TEST_ZIP2.entryNames) { - |cdirEntry, testEntryName| - cdirEntry.name == testEntryName - }) - assert_equals(TestZipFile::TEST_ZIP2.comment, cdir.comment) - } - end - - def test_readFromInvalidStream - File.open("ziptest.rb", "rb") { - |zipFile| - cdir = ZipCentralDirectory.new - cdir.readFromStream(zipFile) - } - fail "ZipError expected!" - rescue ZipError - end - - def test_ReadFromTruncatedZipFile - fragment="" - File.open("testDirectory.bin") { |f| fragment = f.read } - fragment.slice!(12) # removed part of first cdir entry. eocd structure still complete - fragment.extend(IOizeString) - entry = ZipCentralDirectory.new - entry.readFromStream(fragment) - fail "ZipError expected" - rescue ZipError - end - - def test_writeToStream - entries = [ ZipEntry.new("file.zip", "flimse", "myComment", "somethingExtra"), - ZipEntry.new("file.zip", "secondEntryName"), - ZipEntry.new("file.zip", "lastEntry.txt", "Has a comment too") ] - cdir = ZipCentralDirectory.new(entries, "my zip comment") - File.open("cdirtest.bin", "wb") { |f| cdir.writeToStream(f) } - cdirReadback = ZipCentralDirectory.new - File.open("cdirtest.bin", "rb") { |f| cdirReadback.readFromStream(f) } - - assert_equals(cdir.entries, cdirReadback.entries) - end - - def test_equality - cdir1 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil, - "somethingExtra"), - ZipEntry.new("file.zip", "secondEntryName"), - ZipEntry.new("file.zip", "lastEntry.txt") ], - "my zip comment") - cdir2 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil, - "somethingExtra"), - ZipEntry.new("file.zip", "secondEntryName"), - ZipEntry.new("file.zip", "lastEntry.txt") ], - "my zip comment") - cdir3 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil, - "somethingExtra"), - ZipEntry.new("file.zip", "secondEntryName"), - ZipEntry.new("file.zip", "lastEntry.txt") ], - "comment?") - cdir4 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil, - "somethingExtra"), - ZipEntry.new("file.zip", "lastEntry.txt") ], - "comment?") - assert_equals(cdir1, cdir1) - assert_equals(cdir1, cdir2) - - assert(cdir1 != cdir3) - assert(cdir2 != cdir3) - assert(cdir2 != cdir3) - assert(cdir3 != cdir4) - - assert(cdir3 != "hello") - end -end - - -class BasicZipFileTest < RUNIT::TestCase - include AssertEntry - - def setup - @zipFile = ZipFile.new(TestZipFile::TEST_ZIP2.zipName) - @testEntryNameIndex=0 - end - - def nextTestEntryName - retVal=TestZipFile::TEST_ZIP2.entryNames[@testEntryNameIndex] - @testEntryNameIndex+=1 - return retVal - end - - def test_entries - assert_equals(TestZipFile::TEST_ZIP2.entryNames, @zipFile.entries.map {|e| e.name} ) - end - - def test_each - @zipFile.each { - |entry| - assert_equals(nextTestEntryName, entry.name) - } - assert_equals(4, @testEntryNameIndex) - end - - def test_foreach - ZipFile.foreach(TestZipFile::TEST_ZIP2.zipName) { - |entry| - assert_equals(nextTestEntryName, entry.name) - } - assert_equals(4, @testEntryNameIndex) - end - - def test_getInputStream - @zipFile.each { - |entry| - assertEntry(nextTestEntryName, @zipFile.getInputStream(entry), - entry.name) - } - assert_equals(4, @testEntryNameIndex) - end - - def test_getInputStreamBlock - fileAndEntryName = @zipFile.entries.first.name - @zipFile.getInputStream(fileAndEntryName) { - |zis| - assertEntryContentsForStream(fileAndEntryName, - zis, - fileAndEntryName) - } - end -end - -class CommonZipFileFixture < RUNIT::TestCase - include AssertEntry - - EMPTY_FILENAME = "emptyZipFile.zip" - - TEST_ZIP = TestZipFile::TEST_ZIP2.clone - TEST_ZIP.zipName = "4entry_copy.zip" - - def setup - File.delete(EMPTY_FILENAME) if File.exists?(EMPTY_FILENAME) - File.copy(TestZipFile::TEST_ZIP2.zipName, TEST_ZIP.zipName) - end -end - -class ZipFileTest < CommonZipFileFixture - - def test_createFromScratch - comment = "a short comment" - - zf = ZipFile.new(EMPTY_FILENAME, ZipFile::CREATE) - zf.comment = comment - zf.close - - zfRead = ZipFile.new(EMPTY_FILENAME) - assert_equals(comment, zfRead.comment) - assert_equals(0, zfRead.entries.length) - end - - def test_add - srcFile = "ziptest.rb" - entryName = "newEntryName.rb" - assert(File.exists? srcFile) - zf = ZipFile.new(EMPTY_FILENAME, ZipFile::CREATE) - zf.add(entryName, srcFile) - zf.close - - zfRead = ZipFile.new(EMPTY_FILENAME) - assert_equals("", zfRead.comment) - assert_equals(1, zfRead.entries.length) - assert_equals(entryName, zfRead.entries.first.name) - AssertEntry.assertContents(srcFile, - zfRead.getInputStream(entryName) { |zis| zis.read }) - end - - def test_addExistingEntryName - assert_exception(ZipEntryExistsError) { - ZipFile.open(TEST_ZIP.zipName) { - |zf| - zf.add(zf.entries.first.name, "ziptest.rb") - } - } - end - - def test_addExistingEntryNameReplace - gotCalled = false - replacedEntry = nil - ZipFile.open(TEST_ZIP.zipName) { - |zf| - replacedEntry = zf.entries.first.name - zf.add(replacedEntry, "ziptest.rb") { gotCalled = true; true } - } - assert(gotCalled) - ZipFile.open(TEST_ZIP.zipName) { - |zf| - assertContains(zf, replacedEntry, "ziptest.rb") - } - end - - def test_addDirectory - ZipFile.open(TEST_ZIP.zipName) { - |zf| - zf.add(TestFiles::EMPTY_TEST_DIR, TestFiles::EMPTY_TEST_DIR) - } - ZipFile.open(TEST_ZIP.zipName) { - |zf| - dirEntry = zf.entries.detect { |e| e.name == TestFiles::EMPTY_TEST_DIR+"/" } - assert(dirEntry.isDirectory) - } - end - - def test_remove - entryToRemove, *remainingEntries = TEST_ZIP.entryNames - - File.copy(TestZipFile::TEST_ZIP2.zipName, TEST_ZIP.zipName) - - zf = ZipFile.new(TEST_ZIP.zipName) - assert(zf.entries.map { |e| e.name }.include?(entryToRemove)) - zf.remove(entryToRemove) - assert(! zf.entries.map { |e| e.name }.include?(entryToRemove)) - assert_equals(zf.entries.map {|x| x.name }.sort, remainingEntries.sort) - zf.close - - zfRead = ZipFile.new(TEST_ZIP.zipName) - assert(! zfRead.entries.map { |e| e.name }.include?(entryToRemove)) - assert_equals(zfRead.entries.map {|x| x.name }.sort, remainingEntries.sort) - zfRead.close - end - - - def test_rename - entryToRename, *remainingEntries = TEST_ZIP.entryNames - - zf = ZipFile.new(TEST_ZIP.zipName) - assert(zf.entries.map { |e| e.name }.include? entryToRename) - - newName = "changed name" - assert(! zf.entries.map { |e| e.name }.include?(newName)) - - zf.rename(entryToRename, newName) - assert(zf.entries.map { |e| e.name }.include? newName) - - zf.close - - zfRead = ZipFile.new(TEST_ZIP.zipName) - assert(zfRead.entries.map { |e| e.name }.include? newName) - zfRead.close - end - - def test_renameToExistingEntry - oldEntries = nil - ZipFile.open(TEST_ZIP.zipName) { |zf| oldEntries = zf.entries } - - assert_exception(ZipEntryExistsError) { - ZipFile.open(TEST_ZIP.zipName) { - |zf| - zf.rename(zf.entries[0], zf.entries[1].name) - } - } - - ZipFile.open(TEST_ZIP.zipName) { - |zf| - assert_equals(oldEntries.map{ |e| e.name }, zf.entries.map{ |e| e.name }) - } - end - - def test_renameToExistingEntryOverwrite - oldEntries = nil - ZipFile.open(TEST_ZIP.zipName) { |zf| oldEntries = zf.entries } - - gotCalled = false - ZipFile.open(TEST_ZIP.zipName) { - |zf| - zf.rename(zf.entries[0], zf.entries[1].name) { gotCalled = true; true } - } - - assert(gotCalled) - oldEntries.delete_at(0) - ZipFile.open(TEST_ZIP.zipName) { - |zf| - assert_equals(oldEntries.map{ |e| e.name }, - zf.entries.map{ |e| e.name }) - } - end - - def test_renameNonEntry - nonEntry = "bogusEntry" - targetEntry = "targetEntryName" - zf = ZipFile.new(TEST_ZIP.zipName) - assert(! zf.entries.include?(nonEntry)) - assert_exception(ZipNoSuchEntryError) { - zf.rename(nonEntry, targetEntry) - } - zf.commit - assert(! zf.entries.include?(targetEntry)) - ensure - zf.close - end - - def test_renameEntryToExistingEntry - entry1, entry2, *remaining = TEST_ZIP.entryNames - zf = ZipFile.new(TEST_ZIP.zipName) - assert_exception(ZipEntryExistsError) { - zf.rename(entry1, entry2) - } - ensure - zf.close - end - - def test_replace - unchangedEntries = TEST_ZIP.entryNames.dup - entryToReplace = unchangedEntries.delete_at(2) - newEntrySrcFilename = "ziptest.rb" - - zf = ZipFile.new(TEST_ZIP.zipName) - zf.replace(entryToReplace, newEntrySrcFilename) - - zf.close - - zfRead = ZipFile.new(TEST_ZIP.zipName) - AssertEntry::assertContents(newEntrySrcFilename, - zfRead.getInputStream(entryToReplace) { |is| is.read }) - zfRead.close - end - - def test_replaceNonEntry - entryToReplace = "nonExistingEntryname" - ZipFile.open(TEST_ZIP.zipName) { - |zf| - assert_exception(ZipNoSuchEntryError) { - zf.replace(entryToReplace, "ziptest.rb") - } - } - end - - def test_commit - newName = "renamedFirst" - zf = ZipFile.new(TEST_ZIP.zipName) - oldName = zf.entries.first - zf.rename(oldName, newName) - zf.commit - - zfRead = ZipFile.new(TEST_ZIP.zipName) - assert(zfRead.entries.detect { |e| e.name == newName } != nil) - assert(zfRead.entries.detect { |e| e.name == oldName } == nil) - zfRead.close - - zf.close - end - - # This test tests that after commit, you - # can delete the file you used to add the entry to the zip file - # with - def test_commitUseZipEntry - File.copy(TestFiles::RANDOM_ASCII_FILE1, "okToDelete.txt") - zf = ZipFile.open(TEST_ZIP.zipName) - zf.add("okToDelete.txt", "okToDelete.txt") - assertContains(zf, "okToDelete.txt") - zf.commit - File.move("okToDelete.txt", "okToDeleteMoved.txt") - assertContains(zf, "okToDelete.txt", "okToDeleteMoved.txt") - end - -# def test_close -# zf = ZipFile.new(TEST_ZIP.zipName) -# zf.close -# assert_exception(IOError) { -# zf.extract(TEST_ZIP.entryNames.first, "hullubullu") -# } -# end - - def test_compound1 - renamedName = "renamedName" - originalEntries = [] - begin - zf = ZipFile.new(TEST_ZIP.zipName) - originalEntries = zf.entries.dup - - assertNotContains(zf, TestFiles::RANDOM_ASCII_FILE1) - zf.add(TestFiles::RANDOM_ASCII_FILE1, - TestFiles::RANDOM_ASCII_FILE1) - assertContains(zf, TestFiles::RANDOM_ASCII_FILE1) - - zf.rename(zf.entries[0], renamedName) - assertContains(zf, renamedName) - - TestFiles::BINARY_TEST_FILES.each { - |filename| - zf.add(filename, filename) - assertContains(zf, filename) - } - - assertContains(zf, originalEntries.last.to_s) - zf.remove(originalEntries.last.to_s) - assertNotContains(zf, originalEntries.last.to_s) - - ensure - zf.close - end - begin - zfRead = ZipFile.new(TEST_ZIP.zipName) - assertContains(zfRead, TestFiles::RANDOM_ASCII_FILE1) - assertContains(zfRead, renamedName) - TestFiles::BINARY_TEST_FILES.each { - |filename| - assertContains(zfRead, filename) - } - assertNotContains(zfRead, originalEntries.last.to_s) - ensure - zfRead.close - end - end - - def test_compound2 - begin - zf = ZipFile.new(TEST_ZIP.zipName) - originalEntries = zf.entries.dup - - originalEntries.each { - |entry| - zf.remove(entry) - assertNotContains(zf, entry) - } - assert(zf.entries.empty?) - - TestFiles::ASCII_TEST_FILES.each { - |filename| - zf.add(filename, filename) - assertContains(zf, filename) - } - assert_equals(zf.entries.map { |e| e.name }, TestFiles::ASCII_TEST_FILES) - - zf.rename(TestFiles::ASCII_TEST_FILES[0], "newName") - assertNotContains(zf, TestFiles::ASCII_TEST_FILES[0]) - assertContains(zf, "newName") - ensure - zf.close - end - begin - zfRead = ZipFile.new(TEST_ZIP.zipName) - asciiTestFiles = TestFiles::ASCII_TEST_FILES.dup - asciiTestFiles.shift - asciiTestFiles.each { - |filename| - assertContains(zf, filename) - } - - assertContains(zf, "newName") - ensure - zfRead.close - end - end - - private - def assertContains(zf, entryName, filename = entryName) - assert(zf.entries.detect { |e| e.name == entryName} != nil, "entry #{entryName} not in #{zf.entries.join(', ')} in zip file #{zf}") - assertEntryContents(zf, entryName, filename) if File.exists?(filename) - end - - def assertNotContains(zf, entryName) - assert(zf.entries.detect { |e| e.name == entryName} == nil, "entry #{entryName} in #{zf.entries.join(', ')} in zip file #{zf}") - end -end - -class ZipFileExtractTest < CommonZipFileFixture - EXTRACTED_FILENAME = "extEntry" - ENTRY_TO_EXTRACT, *REMAINING_ENTRIES = TEST_ZIP.entryNames.reverse - - def setup - super - File.delete(EXTRACTED_FILENAME) if File.exists?(EXTRACTED_FILENAME) - end - - def test_extract - ZipFile.open(TEST_ZIP.zipName) { - |zf| - zf.extract(ENTRY_TO_EXTRACT, EXTRACTED_FILENAME) - - assert(File.exists? EXTRACTED_FILENAME) - AssertEntry::assertContents(EXTRACTED_FILENAME, - zf.getInputStream(ENTRY_TO_EXTRACT) { |is| is.read }) - } - end - - def test_extractExists - writtenText = "written text" - File.open(EXTRACTED_FILENAME, "w") { |f| f.write(writtenText) } - - assert_exception(ZipDestinationFileExistsError) { - ZipFile.open(TEST_ZIP.zipName) { - |zf| - zf.extract(zf.entries.first, EXTRACTED_FILENAME) - } - } - File.open(EXTRACTED_FILENAME, "r") { - |f| - assert_equals(writtenText, f.read) - } - end - - def test_extractExistsOverwrite - writtenText = "written text" - File.open(EXTRACTED_FILENAME, "w") { |f| f.write(writtenText) } - - gotCalled = false - ZipFile.open(TEST_ZIP.zipName) { - |zf| - zf.extract(zf.entries.first, EXTRACTED_FILENAME) { gotCalled = true; true } - } - - assert(gotCalled) - File.open(EXTRACTED_FILENAME, "r") { - |f| - assert(writtenText != f.read) - } - end - - def test_extractNonEntry - zf = ZipFile.new(TEST_ZIP.zipName) - assert_exception(ZipNoSuchEntryError) { zf.extract("nonExistingEntry", "nonExistingEntry") } - ensure - zf.close if zf - end - - def test_extractNonEntry2 - outFile = "outfile" - assert_exception(ZipNoSuchEntryError) { - zf = ZipFile.new(TEST_ZIP.zipName) - nonEntry = "hotdog-diddelidoo" - assert(! zf.entries.include?(nonEntry)) - zf.extract(nonEntry, outFile) - zf.close - } - assert(! File.exists?(outFile)) - end - -end - -class ZipFileExtractDirectoryTest < CommonZipFileFixture - TEST_OUT_NAME = "emptyOutDir" - - def openZip(&aProc) - assert(aProc != nil) - ZipFile.open(TestZipFile::TEST_ZIP4.zipName, &aProc) - end - - def extractTestDir(&aProc) - openZip { - |zf| - zf.extract(TestFiles::EMPTY_TEST_DIR, TEST_OUT_NAME, &aProc) - } - end - - def setup - super - - Dir.rmdir(TEST_OUT_NAME) if File.directory? TEST_OUT_NAME - File.delete(TEST_OUT_NAME) if File.exists? TEST_OUT_NAME - end - - def test_extractDirectory - extractTestDir - assert(File.directory? TEST_OUT_NAME) - end - - def test_extractDirectoryExistsAsDir - Dir.mkdir TEST_OUT_NAME - extractTestDir - assert(File.directory? TEST_OUT_NAME) - end - - def test_extractDirectoryExistsAsFile - File.open(TEST_OUT_NAME, "w") { |f| f.puts "something" } - assert_exception(ZipDestinationFileExistsError) { extractTestDir } - end - - def test_extractDirectoryExistsAsFileOverwrite - File.open(TEST_OUT_NAME, "w") { |f| f.puts "something" } - gotCalled = false - extractTestDir { - |entry, destPath| - gotCalled = true - assert_equals(TEST_OUT_NAME, destPath) - assert(entry.isDirectory) - true - } - assert(gotCalled) - assert(File.directory? TEST_OUT_NAME) - end -end - - -TestFiles::createTestFiles(ARGV.index("recreate") != nil || - ARGV.index("recreateonly") != nil) -TestZipFile::createTestZips(ARGV.index("recreate") != nil || - ARGV.index("recreateonly") != nil) -exit if ARGV.index("recreateonly") != nil - -#require 'runit/cui/testrunner' -#RUNIT::CUI::TestRunner.run(ZipFileTest.suite) - -# Copyright (C) 2002 Thomas Sondergaard -# rubyzip is free software; you can redistribute it and/or -# modify it under the terms of the ruby license. diff --git a/vendor/rubyzip-0.5.8/test/data/notzippedruby.rb b/vendor/rubyzip-0.5.8/test/data/notzippedruby.rb deleted file mode 100644 index 036d25e9..00000000 --- a/vendor/rubyzip-0.5.8/test/data/notzippedruby.rb +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env ruby - -class NotZippedRuby - def returnTrue - true - end -end diff --git a/vendor/rubyzip-0.5.8/test/data/rubycode.zip b/vendor/rubyzip-0.5.8/test/data/rubycode.zip deleted file mode 100644 index 8a68560e..00000000 Binary files a/vendor/rubyzip-0.5.8/test/data/rubycode.zip and /dev/null differ diff --git a/vendor/rubyzip-0.5.8/test/data/rubycode2.zip b/vendor/rubyzip-0.5.8/test/data/rubycode2.zip deleted file mode 100644 index 8e1cd08f..00000000 Binary files a/vendor/rubyzip-0.5.8/test/data/rubycode2.zip and /dev/null differ diff --git a/vendor/rubyzip-0.5.8/test/data/testDirectory.bin b/vendor/rubyzip-0.5.8/test/data/testDirectory.bin deleted file mode 100644 index cbdb9f7d..00000000 Binary files a/vendor/rubyzip-0.5.8/test/data/testDirectory.bin and /dev/null differ diff --git a/vendor/rubyzip-0.5.8/test/data/zipWithDirs.zip b/vendor/rubyzip-0.5.8/test/data/zipWithDirs.zip deleted file mode 100644 index 4b01f011..00000000 Binary files a/vendor/rubyzip-0.5.8/test/data/zipWithDirs.zip and /dev/null differ diff --git a/vendor/rubyzip-0.5.8/test/gentestfiles.rb b/vendor/rubyzip-0.5.8/test/gentestfiles.rb deleted file mode 100644 index 1b579702..00000000 --- a/vendor/rubyzip-0.5.8/test/gentestfiles.rb +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -class TestFiles - RANDOM_ASCII_FILE1 = "data/generated/randomAscii1.txt" - RANDOM_ASCII_FILE2 = "data/generated/randomAscii2.txt" - RANDOM_ASCII_FILE3 = "data/generated/randomAscii3.txt" - RANDOM_BINARY_FILE1 = "data/generated/randomBinary1.bin" - RANDOM_BINARY_FILE2 = "data/generated/randomBinary2.bin" - - EMPTY_TEST_DIR = "data/generated/emptytestdir" - - ASCII_TEST_FILES = [ RANDOM_ASCII_FILE1, RANDOM_ASCII_FILE2, RANDOM_ASCII_FILE3 ] - BINARY_TEST_FILES = [ RANDOM_BINARY_FILE1, RANDOM_BINARY_FILE2 ] - TEST_DIRECTORIES = [ EMPTY_TEST_DIR ] - TEST_FILES = [ ASCII_TEST_FILES, BINARY_TEST_FILES, EMPTY_TEST_DIR ].flatten! - - def TestFiles.create_test_files(recreate) - if (recreate || - ! (TEST_FILES.inject(true) { |accum, element| accum && File.exists?(element) })) - - Dir.mkdir "data/generated" rescue Errno::EEXIST - - ASCII_TEST_FILES.each_with_index { - |filename, index| - create_random_ascii(filename, 1E4 * (index+1)) - } - - BINARY_TEST_FILES.each_with_index { - |filename, index| - create_random_binary(filename, 1E4 * (index+1)) - } - - ensure_dir(EMPTY_TEST_DIR) - end - end - - private - def TestFiles.create_random_ascii(filename, size) - File.open(filename, "wb") { - |file| - while (file.tell < size) - file << rand - end - } - end - - def TestFiles.create_random_binary(filename, size) - File.open(filename, "wb") { - |file| - while (file.tell < size) - file << [rand].pack("V") - end - } - end - - def TestFiles.ensure_dir(name) - if File.exists?(name) - return if File.stat(name).directory? - File.delete(name) - end - Dir.mkdir(name) - end - -end - - - -# For representation and creation of -# test data -class TestZipFile - attr_accessor :zip_name, :entry_names, :comment - - def initialize(zip_name, entry_names, comment = "") - @zip_name=zip_name - @entry_names=entry_names - @comment = comment - end - - def TestZipFile.create_test_zips(recreate) - files = Dir.entries("data/generated") - if (recreate || - ! (files.index(File.basename(TEST_ZIP1.zip_name)) && - files.index(File.basename(TEST_ZIP2.zip_name)) && - files.index(File.basename(TEST_ZIP3.zip_name)) && - files.index(File.basename(TEST_ZIP4.zip_name)) && - files.index("empty.txt") && - files.index("short.txt") && - files.index("longAscii.txt") && - files.index("longBinary.bin") )) - raise "failed to create test zip '#{TEST_ZIP1.zip_name}'" unless - system("zip #{TEST_ZIP1.zip_name} data/file2.txt") - raise "failed to remove entry from '#{TEST_ZIP1.zip_name}'" unless - system("zip #{TEST_ZIP1.zip_name} -d data/file2.txt") - - File.open("data/generated/empty.txt", "w") {} - - File.open("data/generated/short.txt", "w") { |file| file << "ABCDEF" } - ziptestTxt="" - File.open("data/file2.txt") { |file| ziptestTxt=file.read } - File.open("data/generated/longAscii.txt", "w") { - |file| - while (file.tell < 1E5) - file << ziptestTxt - end - } - - testBinaryPattern="" - File.open("data/generated/empty.zip") { |file| testBinaryPattern=file.read } - testBinaryPattern *= 4 - - File.open("data/generated/longBinary.bin", "wb") { - |file| - while (file.tell < 3E5) - file << testBinaryPattern << rand - end - } - raise "failed to create test zip '#{TEST_ZIP2.zip_name}'" unless - system("zip #{TEST_ZIP2.zip_name} #{TEST_ZIP2.entry_names.join(' ')}") - - # without bash system interprets everything after echo as parameters to - # echo including | zip -z ... - raise "failed to add comment to test zip '#{TEST_ZIP2.zip_name}'" unless - system("bash -c \"echo #{TEST_ZIP2.comment} | zip -z #{TEST_ZIP2.zip_name}\"") - - raise "failed to create test zip '#{TEST_ZIP3.zip_name}'" unless - system("zip #{TEST_ZIP3.zip_name} #{TEST_ZIP3.entry_names.join(' ')}") - - raise "failed to create test zip '#{TEST_ZIP4.zip_name}'" unless - system("zip #{TEST_ZIP4.zip_name} #{TEST_ZIP4.entry_names.join(' ')}") - end - rescue - raise $!.to_s + - "\n\nziptest.rb requires the Info-ZIP program 'zip' in the path\n" + - "to create test data. If you don't have it you can download\n" + - "the necessary test files at http://sf.net/projects/rubyzip." - end - - TEST_ZIP1 = TestZipFile.new("data/generated/empty.zip", []) - TEST_ZIP2 = TestZipFile.new("data/generated/4entry.zip", %w{ data/generated/longAscii.txt data/generated/empty.txt data/generated/short.txt data/generated/longBinary.bin}, - "my zip comment") - TEST_ZIP3 = TestZipFile.new("data/generated/test1.zip", %w{ data/file1.txt }) - TEST_ZIP4 = TestZipFile.new("data/generated/zipWithDir.zip", [ "data/file1.txt", - TestFiles::EMPTY_TEST_DIR]) -end - - -END { - TestFiles::create_test_files(ARGV.index("recreate") != nil || - ARGV.index("recreateonly") != nil) - TestZipFile::create_test_zips(ARGV.index("recreate") != nil || - ARGV.index("recreateonly") != nil) - exit if ARGV.index("recreateonly") != nil -} diff --git a/vendor/rubyzip-0.5.8/test/ioextrastest.rb b/vendor/rubyzip-0.5.8/test/ioextrastest.rb deleted file mode 100644 index b18e9db9..00000000 --- a/vendor/rubyzip-0.5.8/test/ioextrastest.rb +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -$: << "../lib" - -require 'test/unit' -require 'zip/ioextras' - -include IOExtras - -class FakeIOTest < Test::Unit::TestCase - class FakeIOUsingClass - include FakeIO - end - - def test_kind_of? - obj = FakeIOUsingClass.new - - assert(obj.kind_of?(Object)) - assert(obj.kind_of?(FakeIOUsingClass)) - assert(obj.kind_of?(IO)) - assert(!obj.kind_of?(Fixnum)) - assert(!obj.kind_of?(String)) - end -end - -class AbstractInputStreamTest < Test::Unit::TestCase - # AbstractInputStream subclass that provides a read method - - TEST_LINES = [ "Hello world#{$/}", - "this is the second line#{$/}", - "this is the last line"] - TEST_STRING = TEST_LINES.join - class TestAbstractInputStream - include AbstractInputStream - def initialize(aString) - super() - @contents = aString - @readPointer = 0 - end - - def read(charsToRead) - retVal=@contents[@readPointer, charsToRead] - @readPointer+=charsToRead - return retVal - end - - def produce_input - read(100) - end - - def input_finished? - @contents[@readPointer] == nil - end - end - - def setup - @io = TestAbstractInputStream.new(TEST_STRING) - end - - def test_gets - assert_equal(TEST_LINES[0], @io.gets) - assert_equal(1, @io.lineno) - assert_equal(TEST_LINES[1], @io.gets) - assert_equal(2, @io.lineno) - assert_equal(TEST_LINES[2], @io.gets) - assert_equal(3, @io.lineno) - assert_equal(nil, @io.gets) - assert_equal(4, @io.lineno) - end - - def test_getsMultiCharSeperator - assert_equal("Hell", @io.gets("ll")) - assert_equal("o world#{$/}this is the second l", @io.gets("d l")) - end - - def test_each_line - lineNumber=0 - @io.each_line { - |line| - assert_equal(TEST_LINES[lineNumber], line) - lineNumber+=1 - } - end - - def test_readlines - assert_equal(TEST_LINES, @io.readlines) - end - - def test_readline - test_gets - begin - @io.readline - fail "EOFError expected" - rescue EOFError - end - end -end - -class AbstractOutputStreamTest < Test::Unit::TestCase - class TestOutputStream - include AbstractOutputStream - - attr_accessor :buffer - - def initialize - @buffer = "" - end - - def << (data) - @buffer << data - self - end - end - - def setup - @outputStream = TestOutputStream.new - - @origCommaSep = $, - @origOutputSep = $\ - end - - def teardown - $, = @origCommaSep - $\ = @origOutputSep - end - - def test_write - count = @outputStream.write("a little string") - assert_equal("a little string", @outputStream.buffer) - assert_equal("a little string".length, count) - - count = @outputStream.write(". a little more") - assert_equal("a little string. a little more", @outputStream.buffer) - assert_equal(". a little more".length, count) - end - - def test_print - $\ = nil # record separator set to nil - @outputStream.print("hello") - assert_equal("hello", @outputStream.buffer) - - @outputStream.print(" world.") - assert_equal("hello world.", @outputStream.buffer) - - @outputStream.print(" You ok ", "out ", "there?") - assert_equal("hello world. You ok out there?", @outputStream.buffer) - - $\ = "\n" - @outputStream.print - assert_equal("hello world. You ok out there?\n", @outputStream.buffer) - - @outputStream.print("I sure hope so!") - assert_equal("hello world. You ok out there?\nI sure hope so!\n", @outputStream.buffer) - - $, = "X" - @outputStream.buffer = "" - @outputStream.print("monkey", "duck", "zebra") - assert_equal("monkeyXduckXzebra\n", @outputStream.buffer) - - $\ = nil - @outputStream.buffer = "" - @outputStream.print(20) - assert_equal("20", @outputStream.buffer) - end - - def test_printf - @outputStream.printf("%d %04x", 123, 123) - assert_equal("123 007b", @outputStream.buffer) - end - - def test_putc - @outputStream.putc("A") - assert_equal("A", @outputStream.buffer) - @outputStream.putc(65) - assert_equal("AA", @outputStream.buffer) - end - - def test_puts - @outputStream.puts - assert_equal("\n", @outputStream.buffer) - - @outputStream.puts("hello", "world") - assert_equal("\nhello\nworld\n", @outputStream.buffer) - - @outputStream.buffer = "" - @outputStream.puts("hello\n", "world\n") - assert_equal("hello\nworld\n", @outputStream.buffer) - - @outputStream.buffer = "" - @outputStream.puts(["hello\n", "world\n"]) - assert_equal("hello\nworld\n", @outputStream.buffer) - - @outputStream.buffer = "" - @outputStream.puts(["hello\n", "world\n"], "bingo") - assert_equal("hello\nworld\nbingo\n", @outputStream.buffer) - - @outputStream.buffer = "" - @outputStream.puts(16, 20, 50, "hello") - assert_equal("16\n20\n50\nhello\n", @outputStream.buffer) - end -end - - -# Copyright (C) 2002-2004 Thomas Sondergaard -# rubyzip is free software; you can redistribute it and/or -# modify it under the terms of the ruby license. diff --git a/vendor/rubyzip-0.5.8/test/stdrubyexttest.rb b/vendor/rubyzip-0.5.8/test/stdrubyexttest.rb deleted file mode 100644 index f11608f7..00000000 --- a/vendor/rubyzip-0.5.8/test/stdrubyexttest.rb +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -$: << "../lib" - -require 'test/unit' -require 'zip/stdrubyext' - -class ModuleTest < Test::Unit::TestCase - - def test_select_map - assert_equal([2, 4, 8, 10], [1, 2, 3, 4, 5].select_map { |e| e == 3 ? nil : 2*e }) - end - -end - -class StringExtensionsTest < Test::Unit::TestCase - - def test_starts_with - assert("hello".starts_with("")) - assert("hello".starts_with("h")) - assert("hello".starts_with("he")) - assert(! "hello".starts_with("hello there")) - assert(! "hello".starts_with(" he")) - - assert_raise(TypeError, "type mismatch: NilClass given") { - "hello".starts_with(nil) - } - end - - def test_ends_with - assert("hello".ends_with("o")) - assert("hello".ends_with("lo")) - assert("hello".ends_with("hello")) - assert(!"howdy".ends_with("o")) - assert(!"howdy".ends_with("oy")) - assert(!"howdy".ends_with("howdy doody")) - assert(!"howdy".ends_with("doody howdy")) - end - - def test_ensure_end - assert_equal("hello!", "hello!".ensure_end("!")) - assert_equal("hello!", "hello!".ensure_end("o!")) - assert_equal("hello!", "hello".ensure_end("!")) - assert_equal("hello!", "hel".ensure_end("lo!")) - end -end - -# Copyright (C) 2002, 2003 Thomas Sondergaard -# rubyzip is free software; you can redistribute it and/or -# modify it under the terms of the ruby license. diff --git a/vendor/rubyzip-0.5.8/test/zipfilesystemtest.rb b/vendor/rubyzip-0.5.8/test/zipfilesystemtest.rb deleted file mode 100644 index 10140e10..00000000 --- a/vendor/rubyzip-0.5.8/test/zipfilesystemtest.rb +++ /dev/null @@ -1,829 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -$: << "../lib" - -require 'zip/zipfilesystem' -require 'test/unit' - -module ExtraAssertions - - def assert_forwarded(anObject, method, retVal, *expectedArgs) - callArgs = nil - setCallArgsProc = proc { |args| callArgs = args } - anObject.instance_eval <<-"end_eval" - alias #{method}_org #{method} - def #{method}(*args) - ObjectSpace._id2ref(#{setCallArgsProc.object_id}).call(args) - ObjectSpace._id2ref(#{retVal.object_id}) - end - end_eval - - assert_equal(retVal, yield) # Invoke test - assert_equal(expectedArgs, callArgs) - ensure - anObject.instance_eval "alias #{method} #{method}_org" - end - -end - -include Zip - -class ZipFsFileNonmutatingTest < Test::Unit::TestCase - def setup - @zipFile = ZipFile.new("data/zipWithDirs.zip") - end - - def teardown - @zipFile.close if @zipFile - end - - def test_umask - assert_equal(File.umask, @zipFile.file.umask) - @zipFile.file.umask(0006) - end - - def test_exists? - assert(! @zipFile.file.exists?("notAFile")) - assert(@zipFile.file.exists?("file1")) - assert(@zipFile.file.exists?("dir1")) - assert(@zipFile.file.exists?("dir1/")) - assert(@zipFile.file.exists?("dir1/file12")) - assert(@zipFile.file.exist?("dir1/file12")) # notice, tests exist? alias of exists? ! - - @zipFile.dir.chdir "dir1/" - assert(!@zipFile.file.exists?("file1")) - assert(@zipFile.file.exists?("file12")) - end - - def test_open_read - blockCalled = false - @zipFile.file.open("file1", "r") { - |f| - blockCalled = true - assert_equal("this is the entry 'file1' in my test archive!", - f.readline.chomp) - } - assert(blockCalled) - - blockCalled = false - @zipFile.dir.chdir "dir2" - @zipFile.file.open("file21", "r") { - |f| - blockCalled = true - assert_equal("this is the entry 'dir2/file21' in my test archive!", - f.readline.chomp) - } - assert(blockCalled) - @zipFile.dir.chdir "/" - - assert_raise(Errno::ENOENT) { - @zipFile.file.open("noSuchEntry") - } - - begin - is = @zipFile.file.open("file1") - assert_equal("this is the entry 'file1' in my test archive!", - is.readline.chomp) - ensure - is.close if is - end - end - - def test_new - begin - is = @zipFile.file.new("file1") - assert_equal("this is the entry 'file1' in my test archive!", - is.readline.chomp) - ensure - is.close if is - end - begin - is = @zipFile.file.new("file1") { - fail "should not call block" - } - ensure - is.close if is - end - end - - def test_symlink - assert_raise(NotImplementedError) { - @zipFile.file.symlink("file1", "aSymlink") - } - end - - def test_size - assert_raise(Errno::ENOENT) { @zipFile.file.size("notAFile") } - assert_equal(72, @zipFile.file.size("file1")) - assert_equal(0, @zipFile.file.size("dir2/dir21")) - - assert_equal(72, @zipFile.file.stat("file1").size) - assert_equal(0, @zipFile.file.stat("dir2/dir21").size) - end - - def test_size? - assert_equal(nil, @zipFile.file.size?("notAFile")) - assert_equal(72, @zipFile.file.size?("file1")) - assert_equal(nil, @zipFile.file.size?("dir2/dir21")) - - assert_equal(72, @zipFile.file.stat("file1").size?) - assert_equal(nil, @zipFile.file.stat("dir2/dir21").size?) - end - - - def test_file? - assert(@zipFile.file.file?("file1")) - assert(@zipFile.file.file?("dir2/file21")) - assert(! @zipFile.file.file?("dir1")) - assert(! @zipFile.file.file?("dir1/dir11")) - - assert(@zipFile.file.stat("file1").file?) - assert(@zipFile.file.stat("dir2/file21").file?) - assert(! @zipFile.file.stat("dir1").file?) - assert(! @zipFile.file.stat("dir1/dir11").file?) - end - - include ExtraAssertions - - def test_dirname - assert_forwarded(File, :dirname, "retVal", "a/b/c/d") { - @zipFile.file.dirname("a/b/c/d") - } - end - - def test_basename - assert_forwarded(File, :basename, "retVal", "a/b/c/d") { - @zipFile.file.basename("a/b/c/d") - } - end - - def test_split - assert_forwarded(File, :split, "retVal", "a/b/c/d") { - @zipFile.file.split("a/b/c/d") - } - end - - def test_join - assert_equal("a/b/c", @zipFile.file.join("a/b", "c")) - assert_equal("a/b/c/d", @zipFile.file.join("a/b", "c/d")) - assert_equal("/c/d", @zipFile.file.join("", "c/d")) - assert_equal("a/b/c/d", @zipFile.file.join("a", "b", "c", "d")) - end - - def test_utime - t_now = Time.now - t_bak = @zipFile.file.mtime("file1") - @zipFile.file.utime(t_now, "file1") - assert_equal(t_now, @zipFile.file.mtime("file1")) - @zipFile.file.utime(t_bak, "file1") - assert_equal(t_bak, @zipFile.file.mtime("file1")) - end - - - def assert_always_false(operation) - assert(! @zipFile.file.send(operation, "noSuchFile")) - assert(! @zipFile.file.send(operation, "file1")) - assert(! @zipFile.file.send(operation, "dir1")) - assert(! @zipFile.file.stat("file1").send(operation)) - assert(! @zipFile.file.stat("dir1").send(operation)) - end - - def assert_true_if_entry_exists(operation) - assert(! @zipFile.file.send(operation, "noSuchFile")) - assert(@zipFile.file.send(operation, "file1")) - assert(@zipFile.file.send(operation, "dir1")) - assert(@zipFile.file.stat("file1").send(operation)) - assert(@zipFile.file.stat("dir1").send(operation)) - end - - def test_pipe? - assert_always_false(:pipe?) - end - - def test_blockdev? - assert_always_false(:blockdev?) - end - - def test_symlink? - assert_always_false(:symlink?) - end - - def test_socket? - assert_always_false(:socket?) - end - - def test_chardev? - assert_always_false(:chardev?) - end - - def test_truncate - assert_raise(StandardError, "truncate not supported") { - @zipFile.file.truncate("file1", 100) - } - end - - def assert_e_n_o_e_n_t(operation, args = ["NoSuchFile"]) - assert_raise(Errno::ENOENT) { - @zipFile.file.send(operation, *args) - } - end - - def test_ftype - assert_e_n_o_e_n_t(:ftype) - assert_equal("file", @zipFile.file.ftype("file1")) - assert_equal("directory", @zipFile.file.ftype("dir1/dir11")) - assert_equal("directory", @zipFile.file.ftype("dir1/dir11/")) - end - - def test_link - assert_raise(NotImplementedError) { - @zipFile.file.link("file1", "someOtherString") - } - end - - def test_directory? - assert(! @zipFile.file.directory?("notAFile")) - assert(! @zipFile.file.directory?("file1")) - assert(! @zipFile.file.directory?("dir1/file11")) - assert(@zipFile.file.directory?("dir1")) - assert(@zipFile.file.directory?("dir1/")) - assert(@zipFile.file.directory?("dir2/dir21")) - - assert(! @zipFile.file.stat("file1").directory?) - assert(! @zipFile.file.stat("dir1/file11").directory?) - assert(@zipFile.file.stat("dir1").directory?) - assert(@zipFile.file.stat("dir1/").directory?) - assert(@zipFile.file.stat("dir2/dir21").directory?) - end - - def test_chown - assert_equal(2, @zipFile.file.chown(1,2, "dir1", "file1")) - assert_equal(1, @zipFile.file.stat("dir1").uid) - assert_equal(2, @zipFile.file.stat("dir1").gid) - assert_equal(2, @zipFile.file.chown(nil, nil, "dir1", "file1")) - end - - def test_zero? - assert(! @zipFile.file.zero?("notAFile")) - assert(! @zipFile.file.zero?("file1")) - assert(@zipFile.file.zero?("dir1")) - blockCalled = false - ZipFile.open("data/generated/4entry.zip") { - |zf| - blockCalled = true - assert(zf.file.zero?("data/generated/empty.txt")) - } - assert(blockCalled) - - assert(! @zipFile.file.stat("file1").zero?) - assert(@zipFile.file.stat("dir1").zero?) - blockCalled = false - ZipFile.open("data/generated/4entry.zip") { - |zf| - blockCalled = true - assert(zf.file.stat("data/generated/empty.txt").zero?) - } - assert(blockCalled) - end - - def test_expand_path - ZipFile.open("data/zipWithDirs.zip") { - |zf| - assert_equal("/", zf.file.expand_path(".")) - zf.dir.chdir "dir1" - assert_equal("/dir1", zf.file.expand_path(".")) - assert_equal("/dir1/file12", zf.file.expand_path("file12")) - assert_equal("/", zf.file.expand_path("..")) - assert_equal("/dir2/dir21", zf.file.expand_path("../dir2/dir21")) - } - end - - def test_mtime - assert_equal(Time.at(1027694306), - @zipFile.file.mtime("dir2/file21")) - assert_equal(Time.at(1027690863), - @zipFile.file.mtime("dir2/dir21")) - assert_raise(Errno::ENOENT) { - @zipFile.file.mtime("noSuchEntry") - } - - assert_equal(Time.at(1027694306), - @zipFile.file.stat("dir2/file21").mtime) - assert_equal(Time.at(1027690863), - @zipFile.file.stat("dir2/dir21").mtime) - end - - def test_ctime - assert_nil(@zipFile.file.ctime("file1")) - assert_nil(@zipFile.file.stat("file1").ctime) - end - - def test_atime - assert_nil(@zipFile.file.atime("file1")) - assert_nil(@zipFile.file.stat("file1").atime) - end - - def test_readable? - assert(! @zipFile.file.readable?("noSuchFile")) - assert(@zipFile.file.readable?("file1")) - assert(@zipFile.file.readable?("dir1")) - assert(@zipFile.file.stat("file1").readable?) - assert(@zipFile.file.stat("dir1").readable?) - end - - def test_readable_real? - assert(! @zipFile.file.readable_real?("noSuchFile")) - assert(@zipFile.file.readable_real?("file1")) - assert(@zipFile.file.readable_real?("dir1")) - assert(@zipFile.file.stat("file1").readable_real?) - assert(@zipFile.file.stat("dir1").readable_real?) - end - - def test_writable? - assert(! @zipFile.file.writable?("noSuchFile")) - assert(@zipFile.file.writable?("file1")) - assert(@zipFile.file.writable?("dir1")) - assert(@zipFile.file.stat("file1").writable?) - assert(@zipFile.file.stat("dir1").writable?) - end - - def test_writable_real? - assert(! @zipFile.file.writable_real?("noSuchFile")) - assert(@zipFile.file.writable_real?("file1")) - assert(@zipFile.file.writable_real?("dir1")) - assert(@zipFile.file.stat("file1").writable_real?) - assert(@zipFile.file.stat("dir1").writable_real?) - end - - def test_executable? - assert(! @zipFile.file.executable?("noSuchFile")) - assert(! @zipFile.file.executable?("file1")) - assert(@zipFile.file.executable?("dir1")) - assert(! @zipFile.file.stat("file1").executable?) - assert(@zipFile.file.stat("dir1").executable?) - end - - def test_executable_real? - assert(! @zipFile.file.executable_real?("noSuchFile")) - assert(! @zipFile.file.executable_real?("file1")) - assert(@zipFile.file.executable_real?("dir1")) - assert(! @zipFile.file.stat("file1").executable_real?) - assert(@zipFile.file.stat("dir1").executable_real?) - end - - def test_owned? - assert_true_if_entry_exists(:owned?) - end - - def test_grpowned? - assert_true_if_entry_exists(:grpowned?) - end - - def test_setgid? - assert_always_false(:setgid?) - end - - def test_setuid? - assert_always_false(:setgid?) - end - - def test_sticky? - assert_always_false(:sticky?) - end - - def test_readlink - assert_raise(NotImplementedError) { - @zipFile.file.readlink("someString") - } - end - - def test_stat - s = @zipFile.file.stat("file1") - assert(s.kind_of?(File::Stat)) # It pretends - assert_raise(Errno::ENOENT, "No such file or directory - noSuchFile") { - @zipFile.file.stat("noSuchFile") - } - end - - def test_lstat - assert(@zipFile.file.lstat("file1").file?) - end - - - def test_chmod - assert_raise(Errno::ENOENT, "No such file or directory - noSuchFile") { - @zipFile.file.chmod(0644, "file1", "NoSuchFile") - } - assert_equal(2, @zipFile.file.chmod(0644, "file1", "dir1")) - end - - def test_pipe - assert_raise(NotImplementedError) { - @zipFile.file.pipe - } - end - - def test_foreach - ZipFile.open("data/generated/zipWithDir.zip") { - |zf| - ref = [] - File.foreach("data/file1.txt") { |e| ref << e } - - index = 0 - zf.file.foreach("data/file1.txt") { - |l| - assert_equal(ref[index], l) - index = index.next - } - assert_equal(ref.size, index) - } - - ZipFile.open("data/generated/zipWithDir.zip") { - |zf| - ref = [] - File.foreach("data/file1.txt", " ") { |e| ref << e } - - index = 0 - zf.file.foreach("data/file1.txt", " ") { - |l| - assert_equal(ref[index], l) - index = index.next - } - assert_equal(ref.size, index) - } - end - - def test_popen - assert_equal(File.popen("ls") { |f| f.read }, - @zipFile.file.popen("ls") { |f| f.read }) - end - -# Can be added later -# def test_select -# fail "implement test" -# end - - def test_readlines - ZipFile.open("data/generated/zipWithDir.zip") { - |zf| - assert_equal(File.readlines("data/file1.txt"), - zf.file.readlines("data/file1.txt")) - } - end - - def test_read - ZipFile.open("data/generated/zipWithDir.zip") { - |zf| - assert_equal(File.read("data/file1.txt"), - zf.file.read("data/file1.txt")) - } - end - -end - -class ZipFsFileStatTest < Test::Unit::TestCase - - def setup - @zipFile = ZipFile.new("data/zipWithDirs.zip") - end - - def teardown - @zipFile.close if @zipFile - end - - def test_blocks - assert_equal(nil, @zipFile.file.stat("file1").blocks) - end - - def test_ino - assert_equal(0, @zipFile.file.stat("file1").ino) - end - - def test_uid - assert_equal(0, @zipFile.file.stat("file1").uid) - end - - def test_gid - assert_equal(0, @zipFile.file.stat("file1").gid) - end - - def test_ftype - assert_equal("file", @zipFile.file.stat("file1").ftype) - assert_equal("directory", @zipFile.file.stat("dir1").ftype) - end - - def test_mode - assert_equal(0600, @zipFile.file.stat("file1").mode & 0777) - assert_equal(0600, @zipFile.file.stat("file1").mode & 0777) - assert_equal(0755, @zipFile.file.stat("dir1").mode & 0777) - assert_equal(0755, @zipFile.file.stat("dir1").mode & 0777) - end - - def test_dev - assert_equal(0, @zipFile.file.stat("file1").dev) - end - - def test_rdev - assert_equal(0, @zipFile.file.stat("file1").rdev) - end - - def test_rdev_major - assert_equal(0, @zipFile.file.stat("file1").rdev_major) - end - - def test_rdev_minor - assert_equal(0, @zipFile.file.stat("file1").rdev_minor) - end - - def test_nlink - assert_equal(1, @zipFile.file.stat("file1").nlink) - end - - def test_blksize - assert_nil(@zipFile.file.stat("file1").blksize) - end - -end - -class ZipFsFileMutatingTest < Test::Unit::TestCase - TEST_ZIP = "zipWithDirs_copy.zip" - def setup - File.copy("data/zipWithDirs.zip", TEST_ZIP) - end - - def teardown - end - - def test_delete - do_test_delete_or_unlink(:delete) - end - - def test_unlink - do_test_delete_or_unlink(:unlink) - end - - def test_open_write - ZipFile.open(TEST_ZIP) { - |zf| - - zf.file.open("test_open_write_entry", "w") { - |f| - blockCalled = true - f.write "This is what I'm writing" - } - assert_equal("This is what I'm writing", - zf.file.read("test_open_write_entry")) - - # Test with existing entry - zf.file.open("file1", "w") { - |f| - blockCalled = true - f.write "This is what I'm writing too" - } - assert_equal("This is what I'm writing too", - zf.file.read("file1")) - } - end - - def test_rename - ZipFile.open(TEST_ZIP) { - |zf| - assert_raise(Errno::ENOENT, "") { - zf.file.rename("NoSuchFile", "bimse") - } - zf.file.rename("file1", "newNameForFile1") - } - - ZipFile.open(TEST_ZIP) { - |zf| - assert(! zf.file.exists?("file1")) - assert(zf.file.exists?("newNameForFile1")) - } - end - - def do_test_delete_or_unlink(symbol) - ZipFile.open(TEST_ZIP) { - |zf| - assert(zf.file.exists?("dir2/dir21/dir221/file2221")) - zf.file.send(symbol, "dir2/dir21/dir221/file2221") - assert(! zf.file.exists?("dir2/dir21/dir221/file2221")) - - assert(zf.file.exists?("dir1/file11")) - assert(zf.file.exists?("dir1/file12")) - zf.file.send(symbol, "dir1/file11", "dir1/file12") - assert(! zf.file.exists?("dir1/file11")) - assert(! zf.file.exists?("dir1/file12")) - - assert_raise(Errno::ENOENT) { zf.file.send(symbol, "noSuchFile") } - assert_raise(Errno::EISDIR) { zf.file.send(symbol, "dir1/dir11") } - assert_raise(Errno::EISDIR) { zf.file.send(symbol, "dir1/dir11/") } - } - - ZipFile.open(TEST_ZIP) { - |zf| - assert(! zf.file.exists?("dir2/dir21/dir221/file2221")) - assert(! zf.file.exists?("dir1/file11")) - assert(! zf.file.exists?("dir1/file12")) - - assert(zf.file.exists?("dir1/dir11")) - assert(zf.file.exists?("dir1/dir11/")) - } - end - -end - -class ZipFsDirectoryTest < Test::Unit::TestCase - TEST_ZIP = "zipWithDirs_copy.zip" - - def setup - File.copy("data/zipWithDirs.zip", TEST_ZIP) - end - - def test_delete - ZipFile.open(TEST_ZIP) { - |zf| - assert_raise(Errno::ENOENT, "No such file or directory - NoSuchFile.txt") { - zf.dir.delete("NoSuchFile.txt") - } - assert_raise(Errno::EINVAL, "Invalid argument - file1") { - zf.dir.delete("file1") - } - assert(zf.file.exists?("dir1")) - zf.dir.delete("dir1") - assert(! zf.file.exists?("dir1")) - } - end - - def test_mkdir - ZipFile.open(TEST_ZIP) { - |zf| - assert_raise(Errno::EEXIST, "File exists - dir1") { - zf.dir.mkdir("file1") - } - assert_raise(Errno::EEXIST, "File exists - dir1") { - zf.dir.mkdir("dir1") - } - assert(!zf.file.exists?("newDir")) - zf.dir.mkdir("newDir") - assert(zf.file.directory?("newDir")) - assert(!zf.file.exists?("newDir2")) - zf.dir.mkdir("newDir2", 3485) - assert(zf.file.directory?("newDir2")) - } - end - - def test_pwd_chdir_entries - ZipFile.open(TEST_ZIP) { - |zf| - assert_equal("/", zf.dir.pwd) - - assert_raise(Errno::ENOENT, "No such file or directory - no such dir") { - zf.dir.chdir "no such dir" - } - - assert_raise(Errno::EINVAL, "Invalid argument - file1") { - zf.dir.chdir "file1" - } - - assert_equal(["dir1", "dir2", "file1"].sort, zf.dir.entries(".").sort) - zf.dir.chdir "dir1" - assert_equal("/dir1", zf.dir.pwd) - assert_equal(["dir11", "file11", "file12"], zf.dir.entries(".").sort) - - zf.dir.chdir "../dir2/dir21" - assert_equal("/dir2/dir21", zf.dir.pwd) - assert_equal(["dir221"].sort, zf.dir.entries(".").sort) - } - end - - def test_foreach - ZipFile.open(TEST_ZIP) { - |zf| - - blockCalled = false - assert_raise(Errno::ENOENT, "No such file or directory - noSuchDir") { - zf.dir.foreach("noSuchDir") { |e| blockCalled = true } - } - assert(! blockCalled) - - assert_raise(Errno::ENOTDIR, "Not a directory - file1") { - zf.dir.foreach("file1") { |e| blockCalled = true } - } - assert(! blockCalled) - - entries = [] - zf.dir.foreach(".") { |e| entries << e } - assert_equal(["dir1", "dir2", "file1"].sort, entries.sort) - - entries = [] - zf.dir.foreach("dir1") { |e| entries << e } - assert_equal(["dir11", "file11", "file12"], entries.sort) - } - end - - def test_chroot - ZipFile.open(TEST_ZIP) { - |zf| - assert_raise(NotImplementedError) { - zf.dir.chroot - } - } - end - - # Globbing not supported yet - #def test_glob - # # test alias []-operator too - # fail "implement test" - #end - - def test_open_new - ZipFile.open(TEST_ZIP) { - |zf| - - assert_raise(Errno::ENOTDIR, "Not a directory - file1") { - zf.dir.new("file1") - } - - assert_raise(Errno::ENOENT, "No such file or directory - noSuchFile") { - zf.dir.new("noSuchFile") - } - - d = zf.dir.new(".") - assert_equal(["file1", "dir1", "dir2"].sort, d.entries.sort) - d.close - - zf.dir.open("dir1") { - |d| - assert_equal(["dir11", "file11", "file12"].sort, d.entries.sort) - } - } - end - -end - -class ZipFsDirIteratorTest < Test::Unit::TestCase - - FILENAME_ARRAY = [ "f1", "f2", "f3", "f4", "f5", "f6" ] - - def setup - @dirIt = ZipFileSystem::ZipFsDirIterator.new(FILENAME_ARRAY) - end - - def test_close - @dirIt.close - assert_raise(IOError, "closed directory") { - @dirIt.each { |e| p e } - } - assert_raise(IOError, "closed directory") { - @dirIt.read - } - assert_raise(IOError, "closed directory") { - @dirIt.rewind - } - assert_raise(IOError, "closed directory") { - @dirIt.seek(0) - } - assert_raise(IOError, "closed directory") { - @dirIt.tell - } - - end - - def test_each - # Tested through Enumerable.entries - assert_equal(FILENAME_ARRAY, @dirIt.entries) - end - - def test_read - FILENAME_ARRAY.size.times { - |i| - assert_equal(FILENAME_ARRAY[i], @dirIt.read) - } - end - - def test_rewind - @dirIt.read - @dirIt.read - assert_equal(FILENAME_ARRAY[2], @dirIt.read) - @dirIt.rewind - assert_equal(FILENAME_ARRAY[0], @dirIt.read) - end - - def test_tell_seek - @dirIt.read - @dirIt.read - pos = @dirIt.tell - valAtPos = @dirIt.read - @dirIt.read - @dirIt.seek(pos) - assert_equal(valAtPos, @dirIt.read) - end - -end - - -# Copyright (C) 2002, 2003 Thomas Sondergaard -# rubyzip is free software; you can redistribute it and/or -# modify it under the terms of the ruby license. diff --git a/vendor/rubyzip-0.5.8/test/ziprequiretest.rb b/vendor/rubyzip-0.5.8/test/ziprequiretest.rb deleted file mode 100644 index 68d2c714..00000000 --- a/vendor/rubyzip-0.5.8/test/ziprequiretest.rb +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -$: << "../lib" - -require 'test/unit' -require 'zip/ziprequire' - -$: << 'data/rubycode.zip' << 'data/rubycode2.zip' - -class ZipRequireTest < Test::Unit::TestCase - def test_require - assert(require('data/notzippedruby')) - assert(!require('data/notzippedruby')) - - assert(require('zippedruby1')) - assert(!require('zippedruby1')) - - assert(require('zippedruby2')) - assert(!require('zippedruby2')) - - assert(require('zippedruby3')) - assert(!require('zippedruby3')) - - c1 = NotZippedRuby.new - assert(c1.returnTrue) - assert(ZippedRuby1.returnTrue) - assert(!ZippedRuby2.returnFalse) - assert_equal(4, ZippedRuby3.multiplyValues(2, 2)) - end - - def test_get_resource - get_resource("aResource.txt") { - |f| - assert_equal("Nothing exciting in this file!", f.read) - } - end -end - -# Copyright (C) 2002 Thomas Sondergaard -# rubyzip is free software; you can redistribute it and/or -# modify it under the terms of the ruby license. diff --git a/vendor/rubyzip-0.5.8/test/ziptest.rb b/vendor/rubyzip-0.5.8/test/ziptest.rb deleted file mode 100644 index cd5c7c2b..00000000 --- a/vendor/rubyzip-0.5.8/test/ziptest.rb +++ /dev/null @@ -1,1557 +0,0 @@ -#!/usr/bin/env ruby - -$VERBOSE = true - -$: << "../lib" - -require 'test/unit' -require 'zip/zip' -require 'gentestfiles' - -include Zip - - -class ZipEntryTest < Test::Unit::TestCase - TEST_ZIPFILE = "someZipFile.zip" - TEST_COMMENT = "a comment" - TEST_COMPRESSED_SIZE = 1234 - TEST_CRC = 325324 - TEST_EXTRA = "Some data here" - TEST_COMPRESSIONMETHOD = ZipEntry::DEFLATED - TEST_NAME = "entry name" - TEST_SIZE = 8432 - TEST_ISDIRECTORY = false - - def test_constructorAndGetters - entry = ZipEntry.new(TEST_ZIPFILE, - TEST_NAME, - TEST_COMMENT, - TEST_EXTRA, - TEST_COMPRESSED_SIZE, - TEST_CRC, - TEST_COMPRESSIONMETHOD, - TEST_SIZE) - - assert_equal(TEST_COMMENT, entry.comment) - assert_equal(TEST_COMPRESSED_SIZE, entry.compressed_size) - assert_equal(TEST_CRC, entry.crc) - assert_instance_of(Zip::ZipExtraField, entry.extra) - assert_equal(TEST_COMPRESSIONMETHOD, entry.compression_method) - assert_equal(TEST_NAME, entry.name) - assert_equal(TEST_SIZE, entry.size) - assert_equal(TEST_ISDIRECTORY, entry.is_directory) - end - - def test_is_directoryAndIsFile - assert(ZipEntry.new(TEST_ZIPFILE, "hello").file?) - assert(! ZipEntry.new(TEST_ZIPFILE, "hello").directory?) - - assert(ZipEntry.new(TEST_ZIPFILE, "dir/hello").file?) - assert(! ZipEntry.new(TEST_ZIPFILE, "dir/hello").directory?) - - assert(ZipEntry.new(TEST_ZIPFILE, "hello/").directory?) - assert(! ZipEntry.new(TEST_ZIPFILE, "hello/").file?) - - assert(ZipEntry.new(TEST_ZIPFILE, "dir/hello/").directory?) - assert(! ZipEntry.new(TEST_ZIPFILE, "dir/hello/").file?) - end - - def test_equality - entry1 = ZipEntry.new("file.zip", "name", "isNotCompared", - "something extra", 123, 1234, - ZipEntry::DEFLATED, 10000) - entry2 = ZipEntry.new("file.zip", "name", "isNotComparedXXX", - "something extra", 123, 1234, - ZipEntry::DEFLATED, 10000) - entry3 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extra", 123, 1234, - ZipEntry::DEFLATED, 10000) - entry4 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 123, 1234, - ZipEntry::DEFLATED, 10000) - entry5 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 12, 1234, - ZipEntry::DEFLATED, 10000) - entry6 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 12, 123, - ZipEntry::DEFLATED, 10000) - entry7 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 12, 123, - ZipEntry::STORED, 10000) - entry8 = ZipEntry.new("file.zip", "name2", "isNotComparedXXX", - "something extraXX", 12, 123, - ZipEntry::STORED, 100000) - - assert_equal(entry1, entry1) - assert_equal(entry1, entry2) - - assert(entry2 != entry3) - assert(entry3 != entry4) - assert(entry4 != entry5) - assert(entry5 != entry6) - assert(entry6 != entry7) - assert(entry7 != entry8) - - assert(entry7 != "hello") - assert(entry7 != 12) - - assert(entry7 != ZipStreamableFile.new(entry7, "aPath")) - end - - def test_compare - assert_equal(0, (ZipEntry.new("zf.zip", "a") <=> ZipEntry.new("zf.zip", "a"))) - assert_equal(1, (ZipEntry.new("zf.zip", "b") <=> ZipEntry.new("zf.zip", "a"))) - assert_equal(-1, (ZipEntry.new("zf.zip", "a") <=> ZipEntry.new("zf.zip", "b"))) - - entries = [ - ZipEntry.new("zf.zip", "5"), - ZipEntry.new("zf.zip", "1"), - ZipEntry.new("zf.zip", "3"), - ZipEntry.new("zf.zip", "4"), - ZipEntry.new("zf.zip", "0"), - ZipEntry.new("zf.zip", "2") - ] - - entries.sort! - assert_equal("0", entries[0].to_s) - assert_equal("1", entries[1].to_s) - assert_equal("2", entries[2].to_s) - assert_equal("3", entries[3].to_s) - assert_equal("4", entries[4].to_s) - assert_equal("5", entries[5].to_s) - end - - def test_parentAsString - entry1 = ZipEntry.new("zf.zip", "aa") - entry2 = ZipEntry.new("zf.zip", "aa/") - entry3 = ZipEntry.new("zf.zip", "aa/bb") - entry4 = ZipEntry.new("zf.zip", "aa/bb/") - entry5 = ZipEntry.new("zf.zip", "aa/bb/cc") - entry6 = ZipEntry.new("zf.zip", "aa/bb/cc/") - - assert_equal(nil, entry1.parent_as_string) - assert_equal(nil, entry2.parent_as_string) - assert_equal("aa/", entry3.parent_as_string) - assert_equal("aa/", entry4.parent_as_string) - assert_equal("aa/bb/", entry5.parent_as_string) - assert_equal("aa/bb/", entry6.parent_as_string) - end - - def test_entry_name_cannot_start_with_slash - assert_raise(ZipEntryNameError) { ZipEntry.new("zf.zip", "/hej/der") } - end -end - -module IOizeString - attr_reader :tell - - def read(count = nil) - @tell ||= 0 - count = size unless count - retVal = slice(@tell, count) - @tell += count - return retVal - end - - def seek(index, offset) - @tell ||= 0 - case offset - when IO::SEEK_END - newPos = size + index - when IO::SEEK_SET - newPos = index - when IO::SEEK_CUR - newPos = @tell + index - else - raise "Error in test method IOizeString::seek" - end - if (newPos < 0 || newPos >= size) - raise Errno::EINVAL - else - @tell=newPos - end - end - - def reset - @tell = 0 - end -end - -class ZipLocalEntryTest < Test::Unit::TestCase - def test_read_local_entryHeaderOfFirstTestZipEntry - File.open(TestZipFile::TEST_ZIP3.zip_name, "rb") { - |file| - entry = ZipEntry.read_local_entry(file) - - assert_equal("", entry.comment) - # Differs from windows and unix because of CR LF - # assert_equal(480, entry.compressed_size) - # assert_equal(0x2a27930f, entry.crc) - # extra field is 21 bytes long - # probably contains some unix attrutes or something - # disabled: assert_equal(nil, entry.extra) - assert_equal(ZipEntry::DEFLATED, entry.compression_method) - assert_equal(TestZipFile::TEST_ZIP3.entry_names[0], entry.name) - assert_equal(File.size(TestZipFile::TEST_ZIP3.entry_names[0]), entry.size) - assert(! entry.is_directory) - } - end - - def test_readDateTime - File.open("data/rubycode.zip", "rb") { - |file| - entry = ZipEntry.read_local_entry(file) - assert_equal("zippedruby1.rb", entry.name) - assert_equal(Time.at(1019261638), entry.time) - } - end - - def test_read_local_entryFromNonZipFile - File.open("data/file2.txt") { - |file| - assert_equal(nil, ZipEntry.read_local_entry(file)) - } - end - - def test_read_local_entryFromTruncatedZipFile - zipFragment="" - File.open(TestZipFile::TEST_ZIP2.zip_name) { |f| zipFragment = f.read(12) } # local header is at least 30 bytes - zipFragment.extend(IOizeString).reset - entry = ZipEntry.new - entry.read_local_entry(zipFragment) - fail "ZipError expected" - rescue ZipError - end - - def test_writeEntry - entry = ZipEntry.new("file.zip", "entryName", "my little comment", - "thisIsSomeExtraInformation", 100, 987654, - ZipEntry::DEFLATED, 400) - write_to_file("localEntryHeader.bin", "centralEntryHeader.bin", entry) - entryReadLocal, entryReadCentral = read_from_file("localEntryHeader.bin", "centralEntryHeader.bin") - compare_local_entry_headers(entry, entryReadLocal) - compare_c_dir_entry_headers(entry, entryReadCentral) - end - - private - def compare_local_entry_headers(entry1, entry2) - assert_equal(entry1.compressed_size , entry2.compressed_size) - assert_equal(entry1.crc , entry2.crc) - assert_equal(entry1.extra , entry2.extra) - assert_equal(entry1.compression_method, entry2.compression_method) - assert_equal(entry1.name , entry2.name) - assert_equal(entry1.size , entry2.size) - assert_equal(entry1.localHeaderOffset, entry2.localHeaderOffset) - end - - def compare_c_dir_entry_headers(entry1, entry2) - compare_local_entry_headers(entry1, entry2) - assert_equal(entry1.comment, entry2.comment) - end - - def write_to_file(localFileName, centralFileName, entry) - File.open(localFileName, "wb") { |f| entry.write_local_entry(f) } - File.open(centralFileName, "wb") { |f| entry.write_c_dir_entry(f) } - end - - def read_from_file(localFileName, centralFileName) - localEntry = nil - cdirEntry = nil - File.open(localFileName, "rb") { |f| localEntry = ZipEntry.read_local_entry(f) } - File.open(centralFileName, "rb") { |f| cdirEntry = ZipEntry.read_c_dir_entry(f) } - return [localEntry, cdirEntry] - end -end - - -module DecompressorTests - # expects @refText, @refLines and @decompressor - - TEST_FILE="data/file1.txt" - - def setup - @refText="" - File.open(TEST_FILE) { |f| @refText = f.read } - @refLines = @refText.split($/) - end - - def test_readEverything - assert_equal(@refText, @decompressor.read) - end - - def test_readInChunks - chunkSize = 5 - while (decompressedChunk = @decompressor.read(chunkSize)) - assert_equal(@refText.slice!(0, chunkSize), decompressedChunk) - end - assert_equal(0, @refText.size) - end - - def test_mixingReadsAndProduceInput - # Just some preconditions to make sure we have enough data for this test - assert(@refText.length > 1000) - assert(@refLines.length > 40) - - - assert_equal(@refText[0...100], @decompressor.read(100)) - - assert(! @decompressor.input_finished?) - buf = @decompressor.produce_input - assert_equal(@refText[100...(100+buf.length)], buf) - end -end - -class InflaterTest < Test::Unit::TestCase - include DecompressorTests - - def setup - super - @file = File.new("data/file1.txt.deflatedData", "rb") - @decompressor = Inflater.new(@file) - end - - def teardown - @file.close - end -end - - -class PassThruDecompressorTest < Test::Unit::TestCase - include DecompressorTests - def setup - super - @file = File.new(TEST_FILE) - @decompressor = PassThruDecompressor.new(@file, File.size(TEST_FILE)) - end - - def teardown - @file.close - end -end - - -module AssertEntry - def assert_next_entry(filename, zis) - assert_entry(filename, zis, zis.get_next_entry.name) - end - - def assert_entry(filename, zis, entryName) - assert_equal(filename, entryName) - assert_entryContentsForStream(filename, zis, entryName) - end - - def assert_entryContentsForStream(filename, zis, entryName) - File.open(filename, "rb") { - |file| - expected = file.read - actual = zis.read - if (expected != actual) - if ((expected && actual) && (expected.length > 400 || actual.length > 400)) - zipEntryFilename=entryName+".zipEntry" - File.open(zipEntryFilename, "wb") { |file| file << actual } - fail("File '#{filename}' is different from '#{zipEntryFilename}'") - else - assert_equal(expected, actual) - end - end - } - end - - def AssertEntry.assert_contents(filename, aString) - fileContents = "" - File.open(filename, "rb") { |f| fileContents = f.read } - if (fileContents != aString) - if (fileContents.length > 400 || aString.length > 400) - stringFile = filename + ".other" - File.open(stringFile, "wb") { |f| f << aString } - fail("File '#{filename}' is different from contents of string stored in '#{stringFile}'") - else - assert_equal(fileContents, aString) - end - end - end - - def assert_stream_contents(zis, testZipFile) - assert(zis != nil) - testZipFile.entry_names.each { - |entryName| - assert_next_entry(entryName, zis) - } - assert_equal(nil, zis.get_next_entry) - end - - def assert_test_zip_contents(testZipFile) - ZipInputStream.open(testZipFile.zip_name) { - |zis| - assert_stream_contents(zis, testZipFile) - } - end - - def assert_entryContents(zipFile, entryName, filename = entryName.to_s) - zis = zipFile.get_input_stream(entryName) - assert_entryContentsForStream(filename, zis, entryName) - ensure - zis.close if zis - end -end - - - -class ZipInputStreamTest < Test::Unit::TestCase - include AssertEntry - - def test_new - zis = ZipInputStream.new(TestZipFile::TEST_ZIP2.zip_name) - assert_stream_contents(zis, TestZipFile::TEST_ZIP2) - zis.close - end - - def test_openWithBlock - ZipInputStream.open(TestZipFile::TEST_ZIP2.zip_name) { - |zis| - assert_stream_contents(zis, TestZipFile::TEST_ZIP2) - } - end - - def test_openWithoutBlock - zis = ZipInputStream.open(TestZipFile::TEST_ZIP2.zip_name) - assert_stream_contents(zis, TestZipFile::TEST_ZIP2) - end - - def test_incompleteReads - ZipInputStream.open(TestZipFile::TEST_ZIP2.zip_name) { - |zis| - entry = zis.get_next_entry - assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], entry.name) - assert zis.gets.length > 0 - entry = zis.get_next_entry - assert_equal(TestZipFile::TEST_ZIP2.entry_names[1], entry.name) - assert_equal(0, entry.size) - assert_equal(nil, zis.gets) - entry = zis.get_next_entry - assert_equal(TestZipFile::TEST_ZIP2.entry_names[2], entry.name) - assert zis.gets.length > 0 - entry = zis.get_next_entry - assert_equal(TestZipFile::TEST_ZIP2.entry_names[3], entry.name) - assert zis.gets.length > 0 - } - end - - def test_rewind - ZipInputStream.open(TestZipFile::TEST_ZIP2.zip_name) { - |zis| - e = zis.get_next_entry - assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], e.name) - - # Do a little reading - buf = "" - buf << zis.read(100) - buf << (zis.gets || "") - buf << (zis.gets || "") - - zis.rewind - - buf2 = "" - buf2 << zis.read(100) - buf2 << (zis.gets || "") - buf2 << (zis.gets || "") - - assert_equal(buf, buf2) - - zis.rewind - - assert_entry(e.name, zis, e.name) - } - end - -end - - -module CrcTest - - class TestOutputStream - include IOExtras::AbstractOutputStream - - attr_accessor :buffer - - def initialize - @buffer = "" - end - - def << (data) - @buffer << data - self - end - end - - def run_crc_test(compressorClass) - str = "Here's a nice little text to compute the crc for! Ho hum, it is nice nice nice nice indeed." - fakeOut = TestOutputStream.new - - deflater = compressorClass.new(fakeOut) - deflater << str - assert_equal(0x919920fc, deflater.crc) - end -end - - - -class PassThruCompressorTest < Test::Unit::TestCase - include CrcTest - - def test_size - File.open("dummy.txt", "wb") { - |file| - compressor = PassThruCompressor.new(file) - - assert_equal(0, compressor.size) - - t1 = "hello world" - t2 = "" - t3 = "bingo" - - compressor << t1 - assert_equal(compressor.size, t1.size) - - compressor << t2 - assert_equal(compressor.size, t1.size + t2.size) - - compressor << t3 - assert_equal(compressor.size, t1.size + t2.size + t3.size) - } - end - - def test_crc - run_crc_test(PassThruCompressor) - end -end - -class DeflaterTest < Test::Unit::TestCase - include CrcTest - - def test_outputOperator - txt = load_file("data/file2.txt") - deflate(txt, "deflatertest.bin") - inflatedTxt = inflate("deflatertest.bin") - assert_equal(txt, inflatedTxt) - end - - private - def load_file(fileName) - txt = nil - File.open(fileName, "rb") { |f| txt = f.read } - end - - def deflate(data, fileName) - File.open(fileName, "wb") { - |file| - deflater = Deflater.new(file) - deflater << data - deflater.finish - assert_equal(deflater.size, data.size) - file << "trailing data for zlib with -MAX_WBITS" - } - end - - def inflate(fileName) - txt = nil - File.open(fileName, "rb") { - |file| - inflater = Inflater.new(file) - txt = inflater.read - } - end - - def test_crc - run_crc_test(Deflater) - end -end - -class ZipOutputStreamTest < Test::Unit::TestCase - include AssertEntry - - TEST_ZIP = TestZipFile::TEST_ZIP2.clone - TEST_ZIP.zip_name = "output.zip" - - def test_new - zos = ZipOutputStream.new(TEST_ZIP.zip_name) - zos.comment = TEST_ZIP.comment - write_test_zip(zos) - zos.close - assert_test_zip_contents(TEST_ZIP) - end - - def test_open - ZipOutputStream.open(TEST_ZIP.zip_name) { - |zos| - zos.comment = TEST_ZIP.comment - write_test_zip(zos) - } - assert_test_zip_contents(TEST_ZIP) - end - - def test_writingToClosedStream - assert_i_o_error_in_closed_stream { |zos| zos << "hello world" } - assert_i_o_error_in_closed_stream { |zos| zos.puts "hello world" } - assert_i_o_error_in_closed_stream { |zos| zos.write "hello world" } - end - - def test_cannotOpenFile - name = TestFiles::EMPTY_TEST_DIR - begin - zos = ZipOutputStream.open(name) - rescue Exception - assert($!.kind_of?(Errno::EISDIR) || # Linux - $!.kind_of?(Errno::EEXIST) || # Windows/cygwin - $!.kind_of?(Errno::EACCES), # Windows - "Expected Errno::EISDIR (or on win/cygwin: Errno::EEXIST), but was: #{$!.class}") - end - end - - def assert_i_o_error_in_closed_stream - assert_raise(IOError) { - zos = ZipOutputStream.new("test_putOnClosedStream.zip") - zos.close - yield zos - } - end - - def write_test_zip(zos) - TEST_ZIP.entry_names.each { - |entryName| - zos.put_next_entry(entryName) - File.open(entryName, "rb") { |f| zos.write(f.read) } - } - end -end - - - -module Enumerable - def compare_enumerables(otherEnumerable) - otherAsArray = otherEnumerable.to_a - index=0 - each_with_index { - |element, index| - return false unless yield(element, otherAsArray[index]) - } - return index+1 == otherAsArray.size - end -end - - -class ZipCentralDirectoryEntryTest < Test::Unit::TestCase - - def test_read_from_stream - File.open("data/testDirectory.bin", "rb") { - |file| - entry = ZipEntry.read_c_dir_entry(file) - - assert_equal("longAscii.txt", entry.name) - assert_equal(ZipEntry::DEFLATED, entry.compression_method) - assert_equal(106490, entry.size) - assert_equal(3784, entry.compressed_size) - assert_equal(0xfcd1799c, entry.crc) - assert_equal("", entry.comment) - - entry = ZipEntry.read_c_dir_entry(file) - assert_equal("empty.txt", entry.name) - assert_equal(ZipEntry::STORED, entry.compression_method) - assert_equal(0, entry.size) - assert_equal(0, entry.compressed_size) - assert_equal(0x0, entry.crc) - assert_equal("", entry.comment) - - entry = ZipEntry.read_c_dir_entry(file) - assert_equal("short.txt", entry.name) - assert_equal(ZipEntry::STORED, entry.compression_method) - assert_equal(6, entry.size) - assert_equal(6, entry.compressed_size) - assert_equal(0xbb76fe69, entry.crc) - assert_equal("", entry.comment) - - entry = ZipEntry.read_c_dir_entry(file) - assert_equal("longBinary.bin", entry.name) - assert_equal(ZipEntry::DEFLATED, entry.compression_method) - assert_equal(1000024, entry.size) - assert_equal(70847, entry.compressed_size) - assert_equal(0x10da7d59, entry.crc) - assert_equal("", entry.comment) - - entry = ZipEntry.read_c_dir_entry(file) - assert_equal(nil, entry) -# Fields that are not check by this test: -# version made by 2 bytes -# version needed to extract 2 bytes -# general purpose bit flag 2 bytes -# last mod file time 2 bytes -# last mod file date 2 bytes -# compressed size 4 bytes -# uncompressed size 4 bytes -# disk number start 2 bytes -# internal file attributes 2 bytes -# external file attributes 4 bytes -# relative offset of local header 4 bytes - -# file name (variable size) -# extra field (variable size) -# file comment (variable size) - - } - end - - def test_ReadEntryFromTruncatedZipFile - fragment="" - File.open("data/testDirectory.bin") { |f| fragment = f.read(12) } # cdir entry header is at least 46 bytes - fragment.extend(IOizeString) - entry = ZipEntry.new - entry.read_c_dir_entry(fragment) - fail "ZipError expected" - rescue ZipError - end - -end - - -class ZipEntrySetTest < Test::Unit::TestCase - ZIP_ENTRIES = [ - ZipEntry.new("zipfile.zip", "name1", "comment1"), - ZipEntry.new("zipfile.zip", "name2", "comment1"), - ZipEntry.new("zipfile.zip", "name3", "comment1"), - ZipEntry.new("zipfile.zip", "name4", "comment1"), - ZipEntry.new("zipfile.zip", "name5", "comment1"), - ZipEntry.new("zipfile.zip", "name6", "comment1") - ] - - def setup - @zipEntrySet = ZipEntrySet.new(ZIP_ENTRIES) - end - - def test_include - assert(@zipEntrySet.include?(ZIP_ENTRIES.first)) - assert(! @zipEntrySet.include?(ZipEntry.new("different.zip", "different", "aComment"))) - end - - def test_size - assert_equal(ZIP_ENTRIES.size, @zipEntrySet.size) - assert_equal(ZIP_ENTRIES.size, @zipEntrySet.length) - @zipEntrySet << ZipEntry.new("a", "b", "c") - assert_equal(ZIP_ENTRIES.size + 1, @zipEntrySet.length) - end - - def test_add - zes = ZipEntrySet.new - entry1 = ZipEntry.new("zf.zip", "name1") - entry2 = ZipEntry.new("zf.zip", "name2") - zes << entry1 - assert(zes.include?(entry1)) - zes.push(entry2) - assert(zes.include?(entry2)) - end - - def test_delete - assert_equal(ZIP_ENTRIES.size, @zipEntrySet.size) - entry = @zipEntrySet.delete(ZIP_ENTRIES.first) - assert_equal(ZIP_ENTRIES.size - 1, @zipEntrySet.size) - assert_equal(ZIP_ENTRIES.first, entry) - - entry = @zipEntrySet.delete(ZIP_ENTRIES.first) - assert_equal(ZIP_ENTRIES.size - 1, @zipEntrySet.size) - assert_nil(entry) - end - - def test_each - # Tested indirectly via each_with_index - count = 0 - @zipEntrySet.each_with_index { - |entry, index| - assert(ZIP_ENTRIES.include?(entry)) - count = count.succ - } - assert_equal(ZIP_ENTRIES.size, count) - end - - def test_entries - assert_equal(ZIP_ENTRIES.sort, @zipEntrySet.entries.sort) - end - - def test_compound - newEntry = ZipEntry.new("zf.zip", "new entry", "new entry's comment") - assert_equal(ZIP_ENTRIES.size, @zipEntrySet.size) - @zipEntrySet << newEntry - assert_equal(ZIP_ENTRIES.size + 1, @zipEntrySet.size) - assert(@zipEntrySet.include?(newEntry)) - - @zipEntrySet.delete(newEntry) - assert_equal(ZIP_ENTRIES.size, @zipEntrySet.size) - end - - def test_dup - copy = @zipEntrySet.dup - assert_equal(@zipEntrySet, copy) - - # demonstrate that this is a deep copy - copy.entries[0].name = "a totally different name" - assert(@zipEntrySet != copy) - end - - def test_parent - entries = [ - ZipEntry.new("zf.zip", "a"), - ZipEntry.new("zf.zip", "a/"), - ZipEntry.new("zf.zip", "a/b"), - ZipEntry.new("zf.zip", "a/b/"), - ZipEntry.new("zf.zip", "a/b/c"), - ZipEntry.new("zf.zip", "a/b/c/") - ] - entrySet = ZipEntrySet.new(entries) - - assert_equal(nil, entrySet.parent(entries[0])) - assert_equal(nil, entrySet.parent(entries[1])) - assert_equal(entries[1], entrySet.parent(entries[2])) - assert_equal(entries[1], entrySet.parent(entries[3])) - assert_equal(entries[3], entrySet.parent(entries[4])) - assert_equal(entries[3], entrySet.parent(entries[5])) - end -end - - -class ZipCentralDirectoryTest < Test::Unit::TestCase - - def test_read_from_stream - File.open(TestZipFile::TEST_ZIP2.zip_name, "rb") { - |zipFile| - cdir = ZipCentralDirectory.read_from_stream(zipFile) - - assert_equal(TestZipFile::TEST_ZIP2.entry_names.size, cdir.size) - assert(cdir.entries.sort.compare_enumerables(TestZipFile::TEST_ZIP2.entry_names.sort) { - |cdirEntry, testEntryName| - cdirEntry.name == testEntryName - }) - assert_equal(TestZipFile::TEST_ZIP2.comment, cdir.comment) - } - end - - def test_readFromInvalidStream - File.open("data/file2.txt", "rb") { - |zipFile| - cdir = ZipCentralDirectory.new - cdir.read_from_stream(zipFile) - } - fail "ZipError expected!" - rescue ZipError - end - - def test_ReadFromTruncatedZipFile - fragment="" - File.open("data/testDirectory.bin") { |f| fragment = f.read } - fragment.slice!(12) # removed part of first cdir entry. eocd structure still complete - fragment.extend(IOizeString) - entry = ZipCentralDirectory.new - entry.read_from_stream(fragment) - fail "ZipError expected" - rescue ZipError - end - - def test_write_to_stream - entries = [ ZipEntry.new("file.zip", "flimse", "myComment", "somethingExtra"), - ZipEntry.new("file.zip", "secondEntryName"), - ZipEntry.new("file.zip", "lastEntry.txt", "Has a comment too") ] - cdir = ZipCentralDirectory.new(entries, "my zip comment") - File.open("cdirtest.bin", "wb") { |f| cdir.write_to_stream(f) } - cdirReadback = ZipCentralDirectory.new - File.open("cdirtest.bin", "rb") { |f| cdirReadback.read_from_stream(f) } - - assert_equal(cdir.entries.sort, cdirReadback.entries.sort) - end - - def test_equality - cdir1 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil, - "somethingExtra"), - ZipEntry.new("file.zip", "secondEntryName"), - ZipEntry.new("file.zip", "lastEntry.txt") ], - "my zip comment") - cdir2 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil, - "somethingExtra"), - ZipEntry.new("file.zip", "secondEntryName"), - ZipEntry.new("file.zip", "lastEntry.txt") ], - "my zip comment") - cdir3 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil, - "somethingExtra"), - ZipEntry.new("file.zip", "secondEntryName"), - ZipEntry.new("file.zip", "lastEntry.txt") ], - "comment?") - cdir4 = ZipCentralDirectory.new([ ZipEntry.new("file.zip", "flimse", nil, - "somethingExtra"), - ZipEntry.new("file.zip", "lastEntry.txt") ], - "comment?") - assert_equal(cdir1, cdir1) - assert_equal(cdir1, cdir2) - - assert(cdir1 != cdir3) - assert(cdir2 != cdir3) - assert(cdir2 != cdir3) - assert(cdir3 != cdir4) - - assert(cdir3 != "hello") - end -end - - -class BasicZipFileTest < Test::Unit::TestCase - include AssertEntry - - def setup - @zipFile = ZipFile.new(TestZipFile::TEST_ZIP2.zip_name) - @testEntryNameIndex=0 - end - - def test_entries - assert_equal(TestZipFile::TEST_ZIP2.entry_names.sort, - @zipFile.entries.entries.sort.map {|e| e.name} ) - end - - def test_each - count = 0 - visited = {} - @zipFile.each { - |entry| - assert(TestZipFile::TEST_ZIP2.entry_names.include?(entry.name)) - assert(! visited.include?(entry.name)) - visited[entry.name] = nil - count = count.succ - } - assert_equal(TestZipFile::TEST_ZIP2.entry_names.length, count) - end - - def test_foreach - count = 0 - visited = {} - ZipFile.foreach(TestZipFile::TEST_ZIP2.zip_name) { - |entry| - assert(TestZipFile::TEST_ZIP2.entry_names.include?(entry.name)) - assert(! visited.include?(entry.name)) - visited[entry.name] = nil - count = count.succ - } - assert_equal(TestZipFile::TEST_ZIP2.entry_names.length, count) - end - - def test_get_input_stream - count = 0 - visited = {} - @zipFile.each { - |entry| - assert_entry(entry.name, @zipFile.get_input_stream(entry), entry.name) - assert(! visited.include?(entry.name)) - visited[entry.name] = nil - count = count.succ - } - assert_equal(TestZipFile::TEST_ZIP2.entry_names.length, count) - end - - def test_get_input_streamBlock - fileAndEntryName = @zipFile.entries.first.name - @zipFile.get_input_stream(fileAndEntryName) { - |zis| - assert_entryContentsForStream(fileAndEntryName, - zis, - fileAndEntryName) - } - end -end - -module CommonZipFileFixture - include AssertEntry - - EMPTY_FILENAME = "emptyZipFile.zip" - - TEST_ZIP = TestZipFile::TEST_ZIP2.clone - TEST_ZIP.zip_name = "4entry_copy.zip" - - def setup - File.delete(EMPTY_FILENAME) if File.exists?(EMPTY_FILENAME) - File.copy(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name) - end -end - -class ZipFileTest < Test::Unit::TestCase - include CommonZipFileFixture - - def test_createFromScratch - comment = "a short comment" - - zf = ZipFile.new(EMPTY_FILENAME, ZipFile::CREATE) - zf.get_output_stream("myFile") { |os| os.write "myFile contains just this" } - zf.mkdir("dir1") - zf.comment = comment - zf.close - - zfRead = ZipFile.new(EMPTY_FILENAME) - assert_equal(comment, zfRead.comment) - assert_equal(2, zfRead.entries.length) - end - - def test_get_output_stream - entryCount = nil - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - entryCount = zf.size - zf.get_output_stream('newEntry.txt') { - |os| - os.write "Putting stuff in newEntry.txt" - } - assert_equal(entryCount+1, zf.size) - assert_equal("Putting stuff in newEntry.txt", zf.read("newEntry.txt")) - - zf.get_output_stream(zf.get_entry('data/generated/empty.txt')) { - |os| - os.write "Putting stuff in data/generated/empty.txt" - } - assert_equal(entryCount+1, zf.size) - assert_equal("Putting stuff in data/generated/empty.txt", zf.read("data/generated/empty.txt")) - - } - - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - assert_equal(entryCount+1, zf.size) - assert_equal("Putting stuff in newEntry.txt", zf.read("newEntry.txt")) - assert_equal("Putting stuff in data/generated/empty.txt", zf.read("data/generated/empty.txt")) - } - end - - def test_add - srcFile = "data/file2.txt" - entryName = "newEntryName.rb" - assert(File.exists?(srcFile)) - zf = ZipFile.new(EMPTY_FILENAME, ZipFile::CREATE) - zf.add(entryName, srcFile) - zf.close - - zfRead = ZipFile.new(EMPTY_FILENAME) - assert_equal("", zfRead.comment) - assert_equal(1, zfRead.entries.length) - assert_equal(entryName, zfRead.entries.first.name) - AssertEntry.assert_contents(srcFile, - zfRead.get_input_stream(entryName) { |zis| zis.read }) - end - - def test_addExistingEntryName - assert_raise(ZipEntryExistsError) { - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - zf.add(zf.entries.first.name, "data/file2.txt") - } - } - end - - def test_addExistingEntryNameReplace - gotCalled = false - replacedEntry = nil - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - replacedEntry = zf.entries.first.name - zf.add(replacedEntry, "data/file2.txt") { gotCalled = true; true } - } - assert(gotCalled) - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - assert_contains(zf, replacedEntry, "data/file2.txt") - } - end - - def test_addDirectory - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - zf.add(TestFiles::EMPTY_TEST_DIR, TestFiles::EMPTY_TEST_DIR) - } - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - dirEntry = zf.entries.detect { |e| e.name == TestFiles::EMPTY_TEST_DIR+"/" } - assert(dirEntry.is_directory) - } - end - - def test_remove - entryToRemove, *remainingEntries = TEST_ZIP.entry_names - - File.copy(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name) - - zf = ZipFile.new(TEST_ZIP.zip_name) - assert(zf.entries.map { |e| e.name }.include?(entryToRemove)) - zf.remove(entryToRemove) - assert(! zf.entries.map { |e| e.name }.include?(entryToRemove)) - assert_equal(zf.entries.map {|x| x.name }.sort, remainingEntries.sort) - zf.close - - zfRead = ZipFile.new(TEST_ZIP.zip_name) - assert(! zfRead.entries.map { |e| e.name }.include?(entryToRemove)) - assert_equal(zfRead.entries.map {|x| x.name }.sort, remainingEntries.sort) - zfRead.close - end - - - def test_rename - entryToRename, *remainingEntries = TEST_ZIP.entry_names - - zf = ZipFile.new(TEST_ZIP.zip_name) - assert(zf.entries.map { |e| e.name }.include?(entryToRename)) - - newName = "changed name" - assert(! zf.entries.map { |e| e.name }.include?(newName)) - - zf.rename(entryToRename, newName) - assert(zf.entries.map { |e| e.name }.include?(newName)) - - zf.close - - zfRead = ZipFile.new(TEST_ZIP.zip_name) - assert(zfRead.entries.map { |e| e.name }.include?(newName)) - zfRead.close - end - - def test_renameToExistingEntry - oldEntries = nil - ZipFile.open(TEST_ZIP.zip_name) { |zf| oldEntries = zf.entries } - - assert_raise(ZipEntryExistsError) { - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - zf.rename(zf.entries[0], zf.entries[1].name) - } - } - - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - assert_equal(oldEntries.sort.map{ |e| e.name }, zf.entries.sort.map{ |e| e.name }) - } - end - - def test_renameToExistingEntryOverwrite - oldEntries = nil - ZipFile.open(TEST_ZIP.zip_name) { |zf| oldEntries = zf.entries } - - gotCalled = false - renamedEntryName = nil - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - renamedEntryName = zf.entries[0].name - zf.rename(zf.entries[0], zf.entries[1].name) { gotCalled = true; true } - } - - assert(gotCalled) - oldEntries.delete_if { |e| e.name == renamedEntryName } - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - assert_equal(oldEntries.sort.map{ |e| e.name }, - zf.entries.sort.map{ |e| e.name }) - } - end - - def test_renameNonEntry - nonEntry = "bogusEntry" - target_entry = "target_entryName" - zf = ZipFile.new(TEST_ZIP.zip_name) - assert(! zf.entries.include?(nonEntry)) - assert_raise(Errno::ENOENT) { - zf.rename(nonEntry, target_entry) - } - zf.commit - assert(! zf.entries.include?(target_entry)) - ensure - zf.close - end - - def test_renameEntryToExistingEntry - entry1, entry2, *remaining = TEST_ZIP.entry_names - zf = ZipFile.new(TEST_ZIP.zip_name) - assert_raise(ZipEntryExistsError) { - zf.rename(entry1, entry2) - } - ensure - zf.close - end - - def test_replace - entryToReplace = TEST_ZIP.entry_names[2] - newEntrySrcFilename = "data/file2.txt" - zf = ZipFile.new(TEST_ZIP.zip_name) - zf.replace(entryToReplace, newEntrySrcFilename) - - zf.close - zfRead = ZipFile.new(TEST_ZIP.zip_name) - AssertEntry::assert_contents(newEntrySrcFilename, - zfRead.get_input_stream(entryToReplace) { |is| is.read }) - AssertEntry::assert_contents(TEST_ZIP.entry_names[0], - zfRead.get_input_stream(TEST_ZIP.entry_names[0]) { |is| is.read }) - AssertEntry::assert_contents(TEST_ZIP.entry_names[1], - zfRead.get_input_stream(TEST_ZIP.entry_names[1]) { |is| is.read }) - AssertEntry::assert_contents(TEST_ZIP.entry_names[3], - zfRead.get_input_stream(TEST_ZIP.entry_names[3]) { |is| is.read }) - zfRead.close - end - - def test_replaceNonEntry - entryToReplace = "nonExistingEntryname" - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - assert_raise(Errno::ENOENT) { - zf.replace(entryToReplace, "data/file2.txt") - } - } - end - - def test_commit - newName = "renamedFirst" - zf = ZipFile.new(TEST_ZIP.zip_name) - oldName = zf.entries.first - zf.rename(oldName, newName) - zf.commit - - zfRead = ZipFile.new(TEST_ZIP.zip_name) - assert(zfRead.entries.detect { |e| e.name == newName } != nil) - assert(zfRead.entries.detect { |e| e.name == oldName } == nil) - zfRead.close - - zf.close - end - - # This test tests that after commit, you - # can delete the file you used to add the entry to the zip file - # with - def test_commitUseZipEntry - File.copy(TestFiles::RANDOM_ASCII_FILE1, "okToDelete.txt") - zf = ZipFile.open(TEST_ZIP.zip_name) - zf.add("okToDelete.txt", "okToDelete.txt") - assert_contains(zf, "okToDelete.txt") - zf.commit - File.move("okToDelete.txt", "okToDeleteMoved.txt") - assert_contains(zf, "okToDelete.txt", "okToDeleteMoved.txt") - end - -# def test_close -# zf = ZipFile.new(TEST_ZIP.zip_name) -# zf.close -# assert_raise(IOError) { -# zf.extract(TEST_ZIP.entry_names.first, "hullubullu") -# } -# end - - def test_compound1 - renamedName = "renamedName" - originalEntries = [] - begin - zf = ZipFile.new(TEST_ZIP.zip_name) - originalEntries = zf.entries.dup - - assert_not_contains(zf, TestFiles::RANDOM_ASCII_FILE1) - zf.add(TestFiles::RANDOM_ASCII_FILE1, - TestFiles::RANDOM_ASCII_FILE1) - assert_contains(zf, TestFiles::RANDOM_ASCII_FILE1) - - zf.rename(zf.entries[0], renamedName) - assert_contains(zf, renamedName) - - TestFiles::BINARY_TEST_FILES.each { - |filename| - zf.add(filename, filename) - assert_contains(zf, filename) - } - - assert_contains(zf, originalEntries.last.to_s) - zf.remove(originalEntries.last.to_s) - assert_not_contains(zf, originalEntries.last.to_s) - - ensure - zf.close - end - begin - zfRead = ZipFile.new(TEST_ZIP.zip_name) - assert_contains(zfRead, TestFiles::RANDOM_ASCII_FILE1) - assert_contains(zfRead, renamedName) - TestFiles::BINARY_TEST_FILES.each { - |filename| - assert_contains(zfRead, filename) - } - assert_not_contains(zfRead, originalEntries.last.to_s) - ensure - zfRead.close - end - end - - def test_compound2 - begin - zf = ZipFile.new(TEST_ZIP.zip_name) - originalEntries = zf.entries.dup - - originalEntries.each { - |entry| - zf.remove(entry) - assert_not_contains(zf, entry) - } - assert(zf.entries.empty?) - - TestFiles::ASCII_TEST_FILES.each { - |filename| - zf.add(filename, filename) - assert_contains(zf, filename) - } - assert_equal(zf.entries.sort.map { |e| e.name }, TestFiles::ASCII_TEST_FILES) - - zf.rename(TestFiles::ASCII_TEST_FILES[0], "newName") - assert_not_contains(zf, TestFiles::ASCII_TEST_FILES[0]) - assert_contains(zf, "newName") - ensure - zf.close - end - begin - zfRead = ZipFile.new(TEST_ZIP.zip_name) - asciiTestFiles = TestFiles::ASCII_TEST_FILES.dup - asciiTestFiles.shift - asciiTestFiles.each { - |filename| - assert_contains(zf, filename) - } - - assert_contains(zf, "newName") - ensure - zfRead.close - end - end - - private - def assert_contains(zf, entryName, filename = entryName) - assert(zf.entries.detect { |e| e.name == entryName} != nil, "entry #{entryName} not in #{zf.entries.join(', ')} in zip file #{zf}") - assert_entryContents(zf, entryName, filename) if File.exists?(filename) - end - - def assert_not_contains(zf, entryName) - assert(zf.entries.detect { |e| e.name == entryName} == nil, "entry #{entryName} in #{zf.entries.join(', ')} in zip file #{zf}") - end -end - -class ZipFileExtractTest < Test::Unit::TestCase - include CommonZipFileFixture - EXTRACTED_FILENAME = "extEntry" - ENTRY_TO_EXTRACT, *REMAINING_ENTRIES = TEST_ZIP.entry_names.reverse - - def setup - super - File.delete(EXTRACTED_FILENAME) if File.exists?(EXTRACTED_FILENAME) - end - - def test_extract - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - zf.extract(ENTRY_TO_EXTRACT, EXTRACTED_FILENAME) - - assert(File.exists?(EXTRACTED_FILENAME)) - AssertEntry::assert_contents(EXTRACTED_FILENAME, - zf.get_input_stream(ENTRY_TO_EXTRACT) { |is| is.read }) - } - end - - def test_extractExists - writtenText = "written text" - File.open(EXTRACTED_FILENAME, "w") { |f| f.write(writtenText) } - - assert_raise(ZipDestinationFileExistsError) { - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - zf.extract(zf.entries.first, EXTRACTED_FILENAME) - } - } - File.open(EXTRACTED_FILENAME, "r") { - |f| - assert_equal(writtenText, f.read) - } - end - - def test_extractExistsOverwrite - writtenText = "written text" - File.open(EXTRACTED_FILENAME, "w") { |f| f.write(writtenText) } - - gotCalledCorrectly = false - ZipFile.open(TEST_ZIP.zip_name) { - |zf| - zf.extract(zf.entries.first, EXTRACTED_FILENAME) { - |entry, extractLoc| - gotCalledCorrectly = zf.entries.first == entry && - extractLoc == EXTRACTED_FILENAME - true - } - } - - assert(gotCalledCorrectly) - File.open(EXTRACTED_FILENAME, "r") { - |f| - assert(writtenText != f.read) - } - end - - def test_extractNonEntry - zf = ZipFile.new(TEST_ZIP.zip_name) - assert_raise(Errno::ENOENT) { zf.extract("nonExistingEntry", "nonExistingEntry") } - ensure - zf.close if zf - end - - def test_extractNonEntry2 - outFile = "outfile" - assert_raise(Errno::ENOENT) { - zf = ZipFile.new(TEST_ZIP.zip_name) - nonEntry = "hotdog-diddelidoo" - assert(! zf.entries.include?(nonEntry)) - zf.extract(nonEntry, outFile) - zf.close - } - assert(! File.exists?(outFile)) - end - -end - -class ZipFileExtractDirectoryTest < Test::Unit::TestCase - include CommonZipFileFixture - TEST_OUT_NAME = "emptyOutDir" - - def open_zip(&aProc) - assert(aProc != nil) - ZipFile.open(TestZipFile::TEST_ZIP4.zip_name, &aProc) - end - - def extract_test_dir(&aProc) - open_zip { - |zf| - zf.extract(TestFiles::EMPTY_TEST_DIR, TEST_OUT_NAME, &aProc) - } - end - - def setup - super - - Dir.rmdir(TEST_OUT_NAME) if File.directory? TEST_OUT_NAME - File.delete(TEST_OUT_NAME) if File.exists? TEST_OUT_NAME - end - - def test_extractDirectory - extract_test_dir - assert(File.directory?(TEST_OUT_NAME)) - end - - def test_extractDirectoryExistsAsDir - Dir.mkdir TEST_OUT_NAME - extract_test_dir - assert(File.directory?(TEST_OUT_NAME)) - end - - def test_extractDirectoryExistsAsFile - File.open(TEST_OUT_NAME, "w") { |f| f.puts "something" } - assert_raise(ZipDestinationFileExistsError) { extract_test_dir } - end - - def test_extractDirectoryExistsAsFileOverwrite - File.open(TEST_OUT_NAME, "w") { |f| f.puts "something" } - gotCalled = false - extract_test_dir { - |entry, destPath| - gotCalled = true - assert_equal(TEST_OUT_NAME, destPath) - assert(entry.is_directory) - true - } - assert(gotCalled) - assert(File.directory?(TEST_OUT_NAME)) - end -end - -class ZipStreamableFileTest < Test::Unit::TestCase - def test_equality - zipEntry1 = ZipEntry.new("zf.zip", "entryname1", "comment") - zipEntry2 = ZipEntry.new("zf.zip", "entryname2", "comment") - - zipStreamableFile1 = ZipStreamableFile.new(zipEntry1, "path") - zipStreamableFile2 = ZipStreamableFile.new(zipEntry1, "path") - zipStreamableFile3 = ZipStreamableFile.new(zipEntry1, "anotherPath") - zipStreamableFile4 = ZipStreamableFile.new(zipEntry2, "path") - - assert_equal(zipStreamableFile1, zipStreamableFile1) - assert_equal(zipStreamableFile1, zipStreamableFile2) - assert(zipStreamableFile1 != zipStreamableFile3) - assert(zipStreamableFile1 != zipStreamableFile4) - assert(zipStreamableFile1 != zipEntry1) - assert(zipStreamableFile1 != "hej") - end -end - -class ZipExtraFieldTest < Test::Unit::TestCase - def test_new - extra_pure = ZipExtraField.new("") - extra_withstr = ZipExtraField.new("foo") - assert_instance_of(ZipExtraField, extra_pure) - assert_instance_of(ZipExtraField, extra_withstr) - end - - def test_unknownfield - extra = ZipExtraField.new("foo") - assert_equal(extra["Unknown"], "foo") - extra.merge("a") - assert_equal(extra["Unknown"], "fooa") - extra.merge("barbaz") - assert_equal(extra.to_s, "fooabarbaz") - end - - - def test_merge - str = "UT\x5\0\x3\250$\r@Ux\0\0" - extra1 = ZipExtraField.new("") - extra2 = ZipExtraField.new(str) - assert(! extra1.member?("UniversalTime")) - assert(extra2.member?("UniversalTime")) - extra1.merge(str) - assert_equal(extra1["UniversalTime"].mtime, extra2["UniversalTime"].mtime) - end - - def test_length - str = "UT\x5\0\x3\250$\r@Ux\0\0Te\0\0testit" - extra = ZipExtraField.new(str) - assert_equal(extra.local_length, extra.to_local_bin.length) - assert_equal(extra.c_dir_length, extra.to_c_dir_bin.length) - extra.merge("foo") - assert_equal(extra.local_length, extra.to_local_bin.length) - assert_equal(extra.c_dir_length, extra.to_c_dir_bin.length) - end - - - def test_to_s - str = "UT\x5\0\x3\250$\r@Ux\0\0Te\0\0testit" - extra = ZipExtraField.new(str) - assert_instance_of(String, extra.to_s) - - s = extra.to_s - extra.merge("foo") - assert_equal(s.length + 3, extra.to_s.length) - end - - def test_equality - str = "UT\x5\0\x3\250$\r@" - extra1 = ZipExtraField.new(str) - extra2 = ZipExtraField.new(str) - extra3 = ZipExtraField.new(str) - assert_equal(extra1, extra2) - - extra2["UniversalTime"].mtime = Time.now - assert(extra1 != extra2) - - extra3.create("IUnix") - assert(extra1 != extra3) - - extra1.create("IUnix") - assert_equal(extra1, extra3) - end - -end - -# Copyright (C) 2002, 2003 Thomas Sondergaard -# rubyzip is free software; you can redistribute it and/or -# modify it under the terms of the ruby license.