[macruby-changes] [4114] MacRuby/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Mon May 17 18:40:53 PDT 2010
Revision: 4114
http://trac.macosforge.org/projects/ruby/changeset/4114
Author: martinlagardette at apple.com
Date: 2010-05-17 18:40:51 -0700 (Mon, 17 May 2010)
Log Message:
-----------
Update library and removing working tags
Modified Paths:
--------------
MacRuby/trunk/lib/English.rb
MacRuby/trunk/lib/cgi/cookie.rb
MacRuby/trunk/lib/cgi/core.rb
MacRuby/trunk/lib/cgi/html.rb
MacRuby/trunk/lib/cgi/session/pstore.rb
MacRuby/trunk/lib/cgi/session.rb
MacRuby/trunk/lib/cgi/util.rb
MacRuby/trunk/lib/cgi.rb
MacRuby/trunk/lib/cmath.rb
MacRuby/trunk/lib/complex.rb
MacRuby/trunk/lib/csv.rb
MacRuby/trunk/lib/date/format.rb
MacRuby/trunk/lib/date.rb
MacRuby/trunk/lib/drb/drb.rb
MacRuby/trunk/lib/drb/eq.rb
MacRuby/trunk/lib/drb/extserv.rb
MacRuby/trunk/lib/drb/extservm.rb
MacRuby/trunk/lib/drb/invokemethod.rb
MacRuby/trunk/lib/drb/observer.rb
MacRuby/trunk/lib/drb/ssl.rb
MacRuby/trunk/lib/drb/timeridconv.rb
MacRuby/trunk/lib/drb/unix.rb
MacRuby/trunk/lib/e2mmap.rb
MacRuby/trunk/lib/erb.rb
MacRuby/trunk/lib/fileutils.rb
MacRuby/trunk/lib/find.rb
MacRuby/trunk/lib/forwardable.rb
MacRuby/trunk/lib/getoptlong.rb
MacRuby/trunk/lib/gserver.rb
MacRuby/trunk/lib/ipaddr.rb
MacRuby/trunk/lib/logger.rb
MacRuby/trunk/lib/mathn.rb
MacRuby/trunk/lib/matrix.rb
MacRuby/trunk/lib/minitest/autorun.rb
MacRuby/trunk/lib/minitest/mock.rb
MacRuby/trunk/lib/minitest/spec.rb
MacRuby/trunk/lib/minitest/unit.rb
MacRuby/trunk/lib/mkmf.rb
MacRuby/trunk/lib/monitor.rb
MacRuby/trunk/lib/mutex_m.rb
MacRuby/trunk/lib/net/ftp.rb
MacRuby/trunk/lib/net/http.rb
MacRuby/trunk/lib/net/https.rb
MacRuby/trunk/lib/net/imap.rb
MacRuby/trunk/lib/net/pop.rb
MacRuby/trunk/lib/net/protocol.rb
MacRuby/trunk/lib/net/smtp.rb
MacRuby/trunk/lib/net/telnet.rb
MacRuby/trunk/lib/observer.rb
MacRuby/trunk/lib/open-uri.rb
MacRuby/trunk/lib/open3.rb
MacRuby/trunk/lib/optparse.rb
MacRuby/trunk/lib/pathname.rb
MacRuby/trunk/lib/pp.rb
MacRuby/trunk/lib/prettyprint.rb
MacRuby/trunk/lib/pstore.rb
MacRuby/trunk/lib/rake/clean.rb
MacRuby/trunk/lib/rake/gempackagetask.rb
MacRuby/trunk/lib/rake/loaders/makefile.rb
MacRuby/trunk/lib/rake/packagetask.rb
MacRuby/trunk/lib/rake/rdoctask.rb
MacRuby/trunk/lib/rake/runtest.rb
MacRuby/trunk/lib/rake/tasklib.rb
MacRuby/trunk/lib/rake/testtask.rb
MacRuby/trunk/lib/rake/win32.rb
MacRuby/trunk/lib/rake.rb
MacRuby/trunk/lib/rational.rb
MacRuby/trunk/lib/resolv.rb
MacRuby/trunk/lib/rexml/attlistdecl.rb
MacRuby/trunk/lib/rexml/attribute.rb
MacRuby/trunk/lib/rexml/cdata.rb
MacRuby/trunk/lib/rexml/child.rb
MacRuby/trunk/lib/rexml/comment.rb
MacRuby/trunk/lib/rexml/doctype.rb
MacRuby/trunk/lib/rexml/document.rb
MacRuby/trunk/lib/rexml/dtd/entitydecl.rb
MacRuby/trunk/lib/rexml/dtd/notationdecl.rb
MacRuby/trunk/lib/rexml/element.rb
MacRuby/trunk/lib/rexml/encoding.rb
MacRuby/trunk/lib/rexml/encodings/CP-1252.rb
MacRuby/trunk/lib/rexml/encodings/ISO-8859-15.rb
MacRuby/trunk/lib/rexml/encodings/UNILE.rb
MacRuby/trunk/lib/rexml/encodings/UTF-16.rb
MacRuby/trunk/lib/rexml/entity.rb
MacRuby/trunk/lib/rexml/formatters/default.rb
MacRuby/trunk/lib/rexml/formatters/pretty.rb
MacRuby/trunk/lib/rexml/formatters/transitive.rb
MacRuby/trunk/lib/rexml/functions.rb
MacRuby/trunk/lib/rexml/instruction.rb
MacRuby/trunk/lib/rexml/namespace.rb
MacRuby/trunk/lib/rexml/node.rb
MacRuby/trunk/lib/rexml/output.rb
MacRuby/trunk/lib/rexml/parent.rb
MacRuby/trunk/lib/rexml/parseexception.rb
MacRuby/trunk/lib/rexml/parsers/baseparser.rb
MacRuby/trunk/lib/rexml/parsers/pullparser.rb
MacRuby/trunk/lib/rexml/parsers/sax2parser.rb
MacRuby/trunk/lib/rexml/parsers/streamparser.rb
MacRuby/trunk/lib/rexml/parsers/treeparser.rb
MacRuby/trunk/lib/rexml/parsers/xpathparser.rb
MacRuby/trunk/lib/rexml/quickpath.rb
MacRuby/trunk/lib/rexml/rexml.rb
MacRuby/trunk/lib/rexml/sax2listener.rb
MacRuby/trunk/lib/rexml/source.rb
MacRuby/trunk/lib/rexml/streamlistener.rb
MacRuby/trunk/lib/rexml/text.rb
MacRuby/trunk/lib/rexml/validation/relaxng.rb
MacRuby/trunk/lib/rexml/validation/validation.rb
MacRuby/trunk/lib/rexml/xmltokens.rb
MacRuby/trunk/lib/rexml/xpath.rb
MacRuby/trunk/lib/rexml/xpath_parser.rb
MacRuby/trunk/lib/rinda/rinda.rb
MacRuby/trunk/lib/rinda/ring.rb
MacRuby/trunk/lib/rinda/tuplespace.rb
MacRuby/trunk/lib/rss/0.9.rb
MacRuby/trunk/lib/rss/1.0.rb
MacRuby/trunk/lib/rss/2.0.rb
MacRuby/trunk/lib/rss/atom.rb
MacRuby/trunk/lib/rss/content/1.0.rb
MacRuby/trunk/lib/rss/content/2.0.rb
MacRuby/trunk/lib/rss/converter.rb
MacRuby/trunk/lib/rss/dublincore/1.0.rb
MacRuby/trunk/lib/rss/dublincore/2.0.rb
MacRuby/trunk/lib/rss/dublincore/atom.rb
MacRuby/trunk/lib/rss/dublincore.rb
MacRuby/trunk/lib/rss/image.rb
MacRuby/trunk/lib/rss/maker/0.9.rb
MacRuby/trunk/lib/rss/maker/1.0.rb
MacRuby/trunk/lib/rss/maker/2.0.rb
MacRuby/trunk/lib/rss/maker/base.rb
MacRuby/trunk/lib/rss/maker/dublincore.rb
MacRuby/trunk/lib/rss/maker/entry.rb
MacRuby/trunk/lib/rss/maker/feed.rb
MacRuby/trunk/lib/rss/maker/image.rb
MacRuby/trunk/lib/rss/maker/taxonomy.rb
MacRuby/trunk/lib/rss/maker/trackback.rb
MacRuby/trunk/lib/rss/maker.rb
MacRuby/trunk/lib/rss/parser.rb
MacRuby/trunk/lib/rss/rexmlparser.rb
MacRuby/trunk/lib/rss/rss.rb
MacRuby/trunk/lib/rss/syndication.rb
MacRuby/trunk/lib/rss/taxonomy.rb
MacRuby/trunk/lib/rss/trackback.rb
MacRuby/trunk/lib/rss/utils.rb
MacRuby/trunk/lib/rss/xml-stylesheet.rb
MacRuby/trunk/lib/rss/xmlparser.rb
MacRuby/trunk/lib/rss/xmlscanner.rb
MacRuby/trunk/lib/securerandom.rb
MacRuby/trunk/lib/set.rb
MacRuby/trunk/lib/shell/builtin-command.rb
MacRuby/trunk/lib/shell/command-processor.rb
MacRuby/trunk/lib/shell/error.rb
MacRuby/trunk/lib/shell/filter.rb
MacRuby/trunk/lib/shell/process-controller.rb
MacRuby/trunk/lib/shell/system-command.rb
MacRuby/trunk/lib/shell/version.rb
MacRuby/trunk/lib/shell.rb
MacRuby/trunk/lib/sync.rb
MacRuby/trunk/lib/tempfile.rb
MacRuby/trunk/lib/test/unit/assertions.rb
MacRuby/trunk/lib/test/unit/testcase.rb
MacRuby/trunk/lib/test/unit.rb
MacRuby/trunk/lib/thread.rb
MacRuby/trunk/lib/thwait.rb
MacRuby/trunk/lib/time.rb
MacRuby/trunk/lib/timeout.rb
MacRuby/trunk/lib/tmpdir.rb
MacRuby/trunk/lib/tracer.rb
MacRuby/trunk/lib/tsort.rb
MacRuby/trunk/lib/un.rb
MacRuby/trunk/lib/uri/common.rb
MacRuby/trunk/lib/uri/ftp.rb
MacRuby/trunk/lib/uri/generic.rb
MacRuby/trunk/lib/uri/http.rb
MacRuby/trunk/lib/uri/https.rb
MacRuby/trunk/lib/uri/ldap.rb
MacRuby/trunk/lib/uri/mailto.rb
MacRuby/trunk/lib/uri.rb
MacRuby/trunk/lib/xmlrpc/base64.rb
MacRuby/trunk/lib/xmlrpc/client.rb
MacRuby/trunk/lib/xmlrpc/config.rb
MacRuby/trunk/lib/xmlrpc/create.rb
MacRuby/trunk/lib/xmlrpc/datetime.rb
MacRuby/trunk/lib/xmlrpc/httpserver.rb
MacRuby/trunk/lib/xmlrpc/marshal.rb
MacRuby/trunk/lib/xmlrpc/parser.rb
MacRuby/trunk/lib/xmlrpc/server.rb
MacRuby/trunk/lib/xmlrpc/utils.rb
MacRuby/trunk/numeric.c
MacRuby/trunk/rakelib/builder/builder.rb
MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/cookie/value_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/initialize_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/unescape_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/csv/parse_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/date/strptime_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/getoptlong/set_options_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/logger/device/close_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/logger/device/write_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/logger/logger/close_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/build_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/collect_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_size_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_vector_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/columns_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/conj_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/conjugate_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/constructor_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/det_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/determinant_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/divide_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/each_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/each_with_index_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/element_reference_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/empty_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/exponent_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/imag_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/imaginary_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/inspect_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/map_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/minor_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/minus_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/multiply_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/plus_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rank_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/real_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rect_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rectangular_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/regular_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/row_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/singular_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/square_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/t_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/tr_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/trace_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/transpose_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/vector/each2_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/library/uri/eql_tags.txt
Modified: MacRuby/trunk/lib/English.rb
===================================================================
--- MacRuby/trunk/lib/English.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/English.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -11,7 +11,7 @@
# With English:
#
# require "English"
-#
+#
# $OUTPUT_FIELD_SEPARATOR = ' -- '
# "waterbuffalo" =~ /buff/
# print $LOADED_FEATURES, $POSTMATCH, $PID, "\n"
@@ -83,7 +83,7 @@
# of the contents of all the files
# given as command-line arguments, or <tt>$stdin</tt>
# (in the case where there are no
-# arguments). <tt>$<</tt> supports methods similar to a
+# arguments). <tt>$<</tt> supports methods similar to a
# +File+ object:
# +inmode+, +close+,
# <tt>closed?</tt>, +each+,
@@ -91,7 +91,7 @@
# +eof+, <tt>eof?</tt>, +file+,
# +filename+, +fileno+,
# +getc+, +gets+, +lineno+,
-# <tt>lineno=</tt>, +path+,
+# <tt>lineno=</tt>, +path+,
# +pos+, <tt>pos=</tt>,
# +read+, +readchar+,
# +readline+, +readlines+,
@@ -139,12 +139,12 @@
alias $MATCH $&
# The string preceding the match in the last
-# successful pattern match. This variable is local to
+# successful pattern match. This variable is local to
# the current scope. Read only. Thread local.
alias $PREMATCH $`
# The string following the match in the last
-# successful pattern match. This variable is local to
+# successful pattern match. This variable is local to
# the current scope. Read only. Thread local.
alias $POSTMATCH $'
Modified: MacRuby/trunk/lib/cgi/cookie.rb
===================================================================
--- MacRuby/trunk/lib/cgi/cookie.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/cgi/cookie.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,37 +1,38 @@
- # Class representing an HTTP cookie.
- #
- # In addition to its specific fields and methods, a Cookie instance
- # is a delegator to the array of its values.
- #
- # See RFC 2965.
- #
- # == Examples of use
- # cookie1 = CGI::Cookie::new("name", "value1", "value2", ...)
- # cookie1 = CGI::Cookie::new("name" => "name", "value" => "value")
- # cookie1 = CGI::Cookie::new('name' => 'name',
- # 'value' => ['value1', 'value2', ...],
- # 'path' => 'path', # optional
- # 'domain' => 'domain', # optional
- # 'expires' => Time.now, # optional
- # 'secure' => true # optional
- # )
- #
- # cgi.out("cookie" => [cookie1, cookie2]) { "string" }
- #
- # name = cookie1.name
- # values = cookie1.value
- # path = cookie1.path
- # domain = cookie1.domain
- # expires = cookie1.expires
- # secure = cookie1.secure
- #
- # cookie1.name = 'name'
- # cookie1.value = ['value1', 'value2', ...]
- # cookie1.path = 'path'
- # cookie1.domain = 'domain'
- # cookie1.expires = Time.now + 30
- # cookie1.secure = true
+# Class representing an HTTP cookie.
+#
+# In addition to its specific fields and methods, a Cookie instance
+# is a delegator to the array of its values.
+#
+# See RFC 2965.
+#
+# == Examples of use
+# cookie1 = CGI::Cookie::new("name", "value1", "value2", ...)
+# cookie1 = CGI::Cookie::new("name" => "name", "value" => "value")
+# cookie1 = CGI::Cookie::new('name' => 'name',
+# 'value' => ['value1', 'value2', ...],
+# 'path' => 'path', # optional
+# 'domain' => 'domain', # optional
+# 'expires' => Time.now, # optional
+# 'secure' => true # optional
+# )
+#
+# cgi.out("cookie" => [cookie1, cookie2]) { "string" }
+#
+# name = cookie1.name
+# values = cookie1.value
+# path = cookie1.path
+# domain = cookie1.domain
+# expires = cookie1.expires
+# secure = cookie1.secure
+#
+# cookie1.name = 'name'
+# cookie1.value = ['value1', 'value2', ...]
+# cookie1.path = 'path'
+# cookie1.domain = 'domain'
+# cookie1.expires = Time.now + 30
+# cookie1.secure = true
class CGI
+ @@accept_charset="UTF-8" unless defined?(@@accept_charset)
class Cookie < Array
# Create a new CGI::Cookie object.
@@ -48,18 +49,19 @@
# domain:: the domain for which this cookie applies.
# expires:: the time at which this cookie expires, as a +Time+ object.
# secure:: whether this cookie is a secure cookie or not (default to
- # false). Secure cookies are only transmitted to HTTPS
+ # false). Secure cookies are only transmitted to HTTPS
# servers.
#
# These keywords correspond to attributes of the cookie object.
def initialize(name = "", *value)
+ @domain = nil
+ @expires = nil
if name.kind_of?(String)
@name = name
- @value = value
%r|^(.*/)|.match(ENV["SCRIPT_NAME"])
@path = ($1 or "")
@secure = false
- return super(@value)
+ return super(value)
end
options = name
@@ -68,7 +70,7 @@
end
@name = options["name"]
- @value = Array(options["value"])
+ value = Array(options["value"])
# simple support for IE
if options["path"]
@path = options["path"]
@@ -80,12 +82,20 @@
@expires = options["expires"]
@secure = options["secure"] == true ? true : false
- super(@value)
+ super(value)
end
- attr_accessor("name", "value", "path", "domain", "expires")
+ attr_accessor("name", "path", "domain", "expires")
attr_reader("secure")
+ def value
+ self
+ end
+
+ def value=(val)
+ replace(Array(val))
+ end
+
# Set whether the Cookie is a secure cookie or not.
#
# +val+ must be a boolean.
@@ -96,7 +106,7 @@
# Convert the Cookie to its string representation.
def to_s
- val = @value.kind_of?(String) ? CGI::escape(@value) : @value.collect{|v| CGI::escape(v) }.join("&")
+ val = collect{|v| CGI::escape(v) }.join("&")
buf = "#{@name}=#{val}"
buf << "; domain=#{@domain}" if @domain
buf << "; path=#{@path}" if @path
@@ -123,7 +133,7 @@
next unless name and values
name = CGI::unescape(name)
values ||= ""
- values = values.split('&').collect{|v| CGI::unescape(v) }
+ values = values.split('&').collect{|v| CGI::unescape(v,@@accept_charset) }
if cookies.has_key?(name)
values = cookies[name].value + values
end
Modified: MacRuby/trunk/lib/cgi/core.rb
===================================================================
--- MacRuby/trunk/lib/cgi/core.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/cgi/core.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -11,9 +11,9 @@
# Standard internet newline sequence
EOL = CR + LF
- REVISION = '$Id: core.rb 21825 2009-01-28 09:21:49Z yugui $' #:nodoc:
+ REVISION = '$Id: core.rb 27581 2010-05-01 23:54:39Z nobu $' #:nodoc:
- NEEDS_BINMODE = true if /WIN/i.match(RUBY_PLATFORM)
+ NEEDS_BINMODE = File::BINARY != 0
# Path separators in different environments.
PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
@@ -33,22 +33,16 @@
"METHOD_NOT_ALLOWED" => "405 Method Not Allowed",
"NOT_ACCEPTABLE" => "406 Not Acceptable",
"LENGTH_REQUIRED" => "411 Length Required",
- "PRECONDITION_FAILED" => "412 Rrecondition Failed",
+ "PRECONDITION_FAILED" => "412 Precondition Failed",
"SERVER_ERROR" => "500 Internal Server Error",
"NOT_IMPLEMENTED" => "501 Method Not Implemented",
"BAD_GATEWAY" => "502 Bad Gateway",
"VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates"
}
- # Abbreviated day-of-week names specified by RFC 822
- RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
-
- # Abbreviated month names specified by RFC 822
- RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
-
# :startdoc:
- def env_table
+ def env_table
ENV
end
@@ -79,7 +73,7 @@
# status:: the HTTP status code, returned as the Status header. See the
# list of available status codes below.
# server:: the server software, returned as the Server header.
- # connection:: the connection type, returned as the Connection header (for
+ # connection:: the connection type, returned as the Connection header (for
# instance, "close".
# length:: the length of the content that will be sent, returned as the
# Content-Length header.
@@ -89,19 +83,19 @@
# object, returned as the Expires header.
# cookie:: a cookie or cookies, returned as one or more Set-Cookie headers.
# The value can be the literal string of the cookie; a CGI::Cookie
- # object; an Array of literal cookie strings or Cookie objects; or a
+ # object; an Array of literal cookie strings or Cookie objects; or a
# hash all of whose values are literal cookie strings or Cookie objects.
# These cookies are in addition to the cookies held in the
# @output_cookies field.
#
# Other header lines can also be set; they are appended as key: value.
- #
+ #
# header
# # Content-Type: text/html
- #
+ #
# header("text/plain")
# # Content-Type: text/plain
- #
+ #
# header("nph" => true,
# "status" => "OK", # == "200 OK"
# # "status" => "200 GOOD",
@@ -116,9 +110,9 @@
# "cookie" => [cookie1, cookie2],
# "my_header1" => "my_value"
# "my_header2" => "my_value")
- #
+ #
# The status codes are:
- #
+ #
# "OK" --> "200 OK"
# "PARTIAL_CONTENT" --> "206 Partial Content"
# "MULTIPLE_CHOICES" --> "300 Multiple Choices"
@@ -137,8 +131,8 @@
# "NOT_IMPLEMENTED" --> "501 Method Not Implemented"
# "BAD_GATEWAY" --> "502 Bad Gateway"
# "VARIANT_ALSO_VARIES" --> "506 Variant Also Negotiates"
- #
- # This method does not perform charset conversion.
+ #
+ # This method does not perform charset conversion.
def header(options='text/html')
if options.is_a?(String)
content_type = options
@@ -277,13 +271,13 @@
# # Content-Length: 6
# #
# # string
- #
+ #
# cgi.out("text/plain") { "string" }
# # Content-Type: text/plain
# # Content-Length: 6
# #
# # string
- #
+ #
# cgi.out("nph" => true,
# "status" => "OK", # == "200 OK"
# "server" => ENV['SERVER_SOFTWARE'],
@@ -296,16 +290,16 @@
# "cookie" => [cookie1, cookie2],
# "my_header1" => "my_value",
# "my_header2" => "my_value") { "string" }
- #
+ #
# Content-Length is automatically calculated from the size of
# the String returned by the content block.
#
# If ENV['REQUEST_METHOD'] == "HEAD", then only the header
# is outputted (the content block is still required, but it
# is ignored).
- #
+ #
# If the charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then
- # the content is converted to this charset, and the language is set
+ # the content is converted to this charset, and the language is set
# to "ja".
def out(options = "text/html") # :yield:
@@ -358,7 +352,7 @@
# Mixin module. It provides the follow functionality groups:
#
- # 1. Access to CGI environment variables as methods. See
+ # 1. Access to CGI environment variables as methods. See
# documentation to the CGI class for a list of these variables.
#
# 2. Access to cookies, including the cookies attribute.
@@ -408,7 +402,7 @@
# values is an Array.
attr_reader :params
- # Get the uploaed files as a hash of name=>values pairs
+ # Get the uploaded files as a hash of name=>values pairs
attr_reader :files
# Set all the parameters.
@@ -440,7 +434,13 @@
## create body (StringIO or Tempfile)
body = create_body(bufsize < content_length)
class << body
- alias local_path path
+ if method_defined?(:path)
+ alias local_path path
+ else
+ def local_path
+ nil
+ end
+ end
attr_reader :original_filename, :content_type
end
## find head and boundary
@@ -549,12 +549,17 @@
%|(offline mode: enter name=value pairs on standard input)\n|
)
end
- readlines.join(' ').gsub(/\n/, '')
- end.gsub(/\\=/, '%3D').gsub(/\\&/, '%26')
+ array = readlines rescue nil
+ if not array.nil?
+ array.join(' ').gsub(/\n/n, '')
+ else
+ ""
+ end
+ end.gsub(/\\=/n, '%3D').gsub(/\\&/n, '%26')
words = Shellwords.shellwords(string)
- if words.find{|x| /=/.match(x) }
+ if words.find{|x| /=/n.match(x) }
words.join('&')
else
words.join('+')
@@ -617,7 +622,7 @@
# Get the value for the parameter with a given key.
#
- # If the parameter has multiple values, only the first will be
+ # If the parameter has multiple values, only the first will be
# retrieved; use #params() to get the array of values.
def [](key)
params = @params[key]
@@ -658,7 +663,7 @@
# This default value default is "UTF-8"
# If you want to change the default accept character set
# when create a new CGI instance, set this:
- #
+ #
# CGI.accept_charset = "EUC-JP"
#
@@ -700,11 +705,11 @@
#
# == block
#
- # When you use a block, you can write a process
+ # When you use a block, you can write a process
# that query encoding is invalid. Example:
#
# encoding_error={}
- # cgi=CGI.new(:accept_charset=>"EUC-JP") do |name,value|
+ # cgi=CGI.new(:accept_charset=>"EUC-JP") do |name,value|
# encoding_error[key] = value
# end
#
Modified: MacRuby/trunk/lib/cgi/html.rb
===================================================================
--- MacRuby/trunk/lib/cgi/html.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/cgi/html.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -66,7 +66,7 @@
# Modules Http3, Http4, etc., contain more basic HTML-generation methods
# (:title, :center, etc.).
#
- # See class CGI for a detailed example.
+ # See class CGI for a detailed example.
#
module HtmlExtension
@@ -99,7 +99,7 @@
end
end
- # Generate a Document Base URI element as a String.
+ # Generate a Document Base URI element as a String.
#
# +href+ can either by a string, giving the base URL for the HREF
# attribute, or it can be a has of the element's attributes.
@@ -179,10 +179,10 @@
#
# checkbox("name")
# # = checkbox("NAME" => "name")
- #
+ #
# checkbox("name", "value")
# # = checkbox("NAME" => "name", "VALUE" => "value")
- #
+ #
# checkbox("name", "value", true)
# # = checkbox("NAME" => "name", "VALUE" => "value", "CHECKED" => true)
def checkbox(name = "", value = nil, checked = nil)
@@ -220,23 +220,23 @@
# # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
# # <INPUT TYPE="checkbox" NAME="name" VALUE="bar">bar
# # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
- #
+ #
# checkbox_group("name", ["foo"], ["bar", true], "baz")
# # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
# # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="bar">bar
# # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
- #
+ #
# checkbox_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
# # <INPUT TYPE="checkbox" NAME="name" VALUE="1">Foo
# # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="2">Bar
# # <INPUT TYPE="checkbox" NAME="name" VALUE="Baz">Baz
- #
+ #
# checkbox_group("NAME" => "name",
# "VALUES" => ["foo", "bar", "baz"])
- #
+ #
# checkbox_group("NAME" => "name",
# "VALUES" => [["foo"], ["bar", true], "baz"])
- #
+ #
# checkbox_group("NAME" => "name",
# "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
def checkbox_group(name = "", *values)
@@ -272,13 +272,13 @@
#
# file_field("name")
# # <INPUT TYPE="file" NAME="name" SIZE="20">
- #
+ #
# file_field("name", 40)
# # <INPUT TYPE="file" NAME="name" SIZE="40">
- #
+ #
# file_field("name", 40, 100)
# # <INPUT TYPE="file" NAME="name" SIZE="40" MAXLENGTH="100">
- #
+ #
# file_field("NAME" => "name", "SIZE" => 40)
# # <INPUT TYPE="file" NAME="name" SIZE="40">
def file_field(name = "", size = 20, maxlength = nil)
@@ -298,7 +298,7 @@
#
# +method+ should be either "get" or "post", and defaults to the latter.
# +action+ defaults to the current CGI script name. +enctype+
- # defaults to "application/x-www-form-urlencoded".
+ # defaults to "application/x-www-form-urlencoded".
#
# Alternatively, the attributes can be specified as a hash.
#
@@ -306,19 +306,19 @@
#
# form{ "string" }
# # <FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
- #
+ #
# form("get") { "string" }
# # <FORM METHOD="get" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
- #
+ #
# form("get", "url") { "string" }
# # <FORM METHOD="get" ACTION="url" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
- #
+ #
# form("METHOD" => "post", "ENCTYPE" => "enctype") { "string" }
# # <FORM METHOD="post" ENCTYPE="enctype">string</FORM>
def form(method = "post", action = script_name, enctype = "application/x-www-form-urlencoded")
attributes = if method.kind_of?(String)
{ "METHOD" => method, "ACTION" => action,
- "ENCTYPE" => enctype }
+ "ENCTYPE" => enctype }
else
unless method.has_key?("METHOD")
method["METHOD"] = "post"
@@ -350,10 +350,10 @@
#
# hidden("name")
# # <INPUT TYPE="hidden" NAME="name">
- #
+ #
# hidden("name", "value")
# # <INPUT TYPE="hidden" NAME="name" VALUE="value">
- #
+ #
# hidden("NAME" => "name", "VALUE" => "reset", "ID" => "foo")
# # <INPUT TYPE="hidden" NAME="name" VALUE="value" ID="foo">
def hidden(name = "", value = nil)
@@ -376,36 +376,36 @@
# should include the entire text of this tag, including angle brackets.
#
# The body of the html element is supplied as a block.
- #
+ #
# html{ "string" }
# # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>string</HTML>
- #
+ #
# html("LANG" => "ja") { "string" }
# # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML LANG="ja">string</HTML>
- #
+ #
# html("DOCTYPE" => false) { "string" }
# # <HTML>string</HTML>
- #
+ #
# html("DOCTYPE" => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">') { "string" }
# # <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML>string</HTML>
- #
+ #
# html("PRETTY" => " ") { "<BODY></BODY>" }
# # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
# # <HTML>
# # <BODY>
# # </BODY>
# # </HTML>
- #
+ #
# html("PRETTY" => "\t") { "<BODY></BODY>" }
# # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
# # <HTML>
# # <BODY>
# # </BODY>
# # </HTML>
- #
+ #
# html("PRETTY") { "<BODY></BODY>" }
# # = html("PRETTY" => " ") { "<BODY></BODY>" }
- #
+ #
# html(if $VERBOSE then "PRETTY" end) { "HTML string" }
#
def html(attributes = {}) # :yield:
@@ -444,18 +444,18 @@
# Generate an Image Button Input element as a string.
#
- # +src+ is the URL of the image to use for the button. +name+
+ # +src+ is the URL of the image to use for the button. +name+
# is the input name. +alt+ is the alternative text for the image.
#
# Alternatively, the attributes can be specified as a hash.
- #
+ #
# image_button("url")
# # <INPUT TYPE="image" SRC="url">
- #
+ #
# image_button("url", "name", "string")
# # <INPUT TYPE="image" SRC="url" NAME="name" ALT="string">
- #
- # image_button("SRC" => "url", "ATL" => "strng")
+ #
+ # image_button("SRC" => "url", "ALT" => "string")
# # <INPUT TYPE="image" SRC="url" ALT="string">
def image_button(src = "", name = nil, alt = nil)
attributes = if src.kind_of?(String)
@@ -480,7 +480,7 @@
#
# img("src", "alt", 100, 50)
# # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
- #
+ #
# img("SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50)
# # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
def img(src = "", alt = "", width = nil, height = nil)
@@ -506,15 +506,15 @@
#
# multipart_form{ "string" }
# # <FORM METHOD="post" ENCTYPE="multipart/form-data">string</FORM>
- #
+ #
# multipart_form("url") { "string" }
# # <FORM METHOD="post" ACTION="url" ENCTYPE="multipart/form-data">string</FORM>
def multipart_form(action = nil, enctype = "multipart/form-data")
attributes = if action == nil
- { "METHOD" => "post", "ENCTYPE" => enctype }
+ { "METHOD" => "post", "ENCTYPE" => enctype }
elsif action.kind_of?(String)
{ "METHOD" => "post", "ACTION" => action,
- "ENCTYPE" => enctype }
+ "ENCTYPE" => enctype }
else
unless action.has_key?("METHOD")
action["METHOD"] = "post"
@@ -542,13 +542,13 @@
#
# password_field("name")
# # <INPUT TYPE="password" NAME="name" SIZE="40">
- #
+ #
# password_field("name", "value")
# # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="40">
- #
+ #
# password_field("password", "value", 80, 200)
# # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
- #
+ #
# password_field("NAME" => "name", "VALUE" => "value")
# # <INPUT TYPE="password" NAME="name" VALUE="value">
def password_field(name = "", value = nil, size = 40, maxlength = nil)
@@ -584,21 +584,21 @@
# # <OPTION VALUE="bar">bar</OPTION>
# # <OPTION VALUE="baz">baz</OPTION>
# # </SELECT>
- #
+ #
# popup_menu("name", ["foo"], ["bar", true], "baz")
# # <SELECT NAME="name">
# # <OPTION VALUE="foo">foo</OPTION>
# # <OPTION VALUE="bar" SELECTED>bar</OPTION>
# # <OPTION VALUE="baz">baz</OPTION>
# # </SELECT>
- #
+ #
# popup_menu("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
# # <SELECT NAME="name">
# # <OPTION VALUE="1">Foo</OPTION>
# # <OPTION SELECTED VALUE="2">Bar</OPTION>
# # <OPTION VALUE="Baz">Baz</OPTION>
# # </SELECT>
- #
+ #
# popup_menu("NAME" => "name", "SIZE" => 2, "MULTIPLE" => true,
# "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
# # <SELECT NAME="name" MULTIPLE SIZE="2">
@@ -649,10 +649,10 @@
#
# radio_button("name", "value")
# # <INPUT TYPE="radio" NAME="name" VALUE="value">
- #
+ #
# radio_button("name", "value", true)
# # <INPUT TYPE="radio" NAME="name" VALUE="value" CHECKED>
- #
+ #
# radio_button("NAME" => "name", "VALUE" => "value", "ID" => "foo")
# # <INPUT TYPE="radio" NAME="name" VALUE="value" ID="foo">
def radio_button(name = "", value = nil, checked = nil)
@@ -670,28 +670,28 @@
#
# This works the same as #checkbox_group(). However, it is not valid
# to have more than one radiobutton in a group checked.
- #
+ #
# radio_group("name", "foo", "bar", "baz")
# # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
# # <INPUT TYPE="radio" NAME="name" VALUE="bar">bar
# # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
- #
+ #
# radio_group("name", ["foo"], ["bar", true], "baz")
# # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
# # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="bar">bar
# # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
- #
+ #
# radio_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
# # <INPUT TYPE="radio" NAME="name" VALUE="1">Foo
# # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="2">Bar
# # <INPUT TYPE="radio" NAME="name" VALUE="Baz">Baz
- #
+ #
# radio_group("NAME" => "name",
# "VALUES" => ["foo", "bar", "baz"])
- #
+ #
# radio_group("NAME" => "name",
# "VALUES" => [["foo"], ["bar", true], "baz"])
- #
+ #
# radio_group("NAME" => "name",
# "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
def radio_group(name = "", *values)
@@ -723,10 +723,10 @@
#
# reset
# # <INPUT TYPE="reset">
- #
+ #
# reset("reset")
# # <INPUT TYPE="reset" VALUE="reset">
- #
+ #
# reset("VALUE" => "reset", "ID" => "foo")
# # <INPUT TYPE="reset" VALUE="reset" ID="foo">
def reset(value = nil, name = nil)
@@ -750,13 +750,13 @@
#
# submit
# # <INPUT TYPE="submit">
- #
+ #
# submit("ok")
# # <INPUT TYPE="submit" VALUE="ok">
- #
+ #
# submit("ok", "button1")
# # <INPUT TYPE="submit" VALUE="ok" NAME="button1">
- #
+ #
# submit("VALUE" => "ok", "NAME" => "button1", "ID" => "foo")
# # <INPUT TYPE="submit" VALUE="ok" NAME="button1" ID="foo">
def submit(value = nil, name = nil)
@@ -779,16 +779,16 @@
#
# text_field("name")
# # <INPUT TYPE="text" NAME="name" SIZE="40">
- #
+ #
# text_field("name", "value")
# # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="40">
- #
+ #
# text_field("name", "value", 80)
# # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80">
- #
+ #
# text_field("name", "value", 80, 200)
# # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
- #
+ #
# text_field("NAME" => "name", "VALUE" => "value")
# # <INPUT TYPE="text" NAME="name" VALUE="value">
def text_field(name = "", value = nil, size = 40, maxlength = nil)
Modified: MacRuby/trunk/lib/cgi/session/pstore.rb
===================================================================
--- MacRuby/trunk/lib/cgi/session/pstore.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/cgi/session/pstore.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -2,7 +2,7 @@
# cgi/session/pstore.rb - persistent storage of marshalled session data
#
# Documentation: William Webber (william at williamwebber.com)
-#
+#
# == Overview
#
# This file provides the CGI::Session::PStore class, which builds
@@ -29,7 +29,7 @@
# created. The session id must only contain alphanumeric
# characters; automatically generated session ids observe
# this requirement.
- #
+ #
# +option+ is a hash of options for the initializer. The
# following options are recognised:
#
@@ -77,7 +77,7 @@
end
# Save session state to the session's PStore file.
- def update
+ def update
@p.transaction do
@p['hash'] = @hash
end
Modified: MacRuby/trunk/lib/cgi/session.rb
===================================================================
--- MacRuby/trunk/lib/cgi/session.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/cgi/session.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -13,7 +13,7 @@
#
# This file provides the +CGI::Session+ class, which provides session
# support for CGI scripts. A session is a sequence of HTTP requests
-# and responses linked together and associated with a single client.
+# and responses linked together and associated with a single client.
# Information associated with the session is stored
# on the server between requests. A session id is passed between client
# and server with every request and response, transparently
@@ -28,7 +28,7 @@
class CGI
- # Class representing an HTTP session. See documentation for the file
+ # Class representing an HTTP session. See documentation for the file
# cgi/session.rb for an introduction to HTTP sessions.
#
# == Lifecycle
@@ -47,7 +47,7 @@
# == Setting and retrieving session data.
#
# The Session class associates data with a session as key-value pairs.
- # This data can be set and retrieved by indexing the Session instance
+ # This data can be set and retrieved by indexing the Session instance
# using '[]', much the same as hashes (although other hash methods
# are not supported).
#
@@ -60,21 +60,21 @@
#
# == Storing session state
#
- # The caller can specify what form of storage to use for the session's
+ # The caller can specify what form of storage to use for the session's
# data with the +database_manager+ option to CGI::Session::new. The
# following storage classes are provided as part of the standard library:
#
- # CGI::Session::FileStore:: stores data as plain text in a flat file. Only
- # works with String data. This is the default
+ # CGI::Session::FileStore:: stores data as plain text in a flat file. Only
+ # works with String data. This is the default
# storage type.
- # CGI::Session::MemoryStore:: stores data in an in-memory hash. The data
- # only persists for as long as the current ruby
+ # CGI::Session::MemoryStore:: stores data in an in-memory hash. The data
+ # only persists for as long as the current ruby
# interpreter instance does.
# CGI::Session::PStore:: stores data in Marshalled format. Provided by
- # cgi/session/pstore.rb. Supports data of any type,
+ # cgi/session/pstore.rb. Supports data of any type,
# and provides file-locking and transaction support.
#
- # Custom storage types can also be created by defining a class with
+ # Custom storage types can also be created by defining a class with
# the following methods:
#
# new(session, options)
@@ -99,14 +99,14 @@
# The simplest way to do this is via cookies. The CGI::Session class
# provides transparent support for session id communication via cookies
# if the client has cookies enabled.
- #
+ #
# If the client has cookies disabled, the session id must be included
# as a parameter of all requests sent by the client to the server. The
# CGI::Session class in conjunction with the CGI class will transparently
# add the session id as a hidden input field to all forms generated
# using the CGI#form() HTML generation method. No built-in support is
# provided for other mechanisms, such as URL re-writing. The caller is
- # responsible for extracting the session id from the session_id
+ # responsible for extracting the session id from the session_id
# attribute and manually encoding it in URLs and adding it as a hidden
# input to HTML forms created by other mechanisms. Also, session expiry
# is not automatically handled.
@@ -124,10 +124,10 @@
# session = CGI::Session.new(cgi,
# 'database_manager' => CGI::Session::PStore, # use PStore
# 'session_key' => '_rb_sess_id', # custom session key
- # 'session_expires' => Time.now + 30 * 60, # 30 minute timeout
+ # 'session_expires' => Time.now + 30 * 60, # 30 minute timeout
# 'prefix' => 'pstore_sid_') # PStore option
# if cgi.has_key?('user_name') and cgi['user_name'] != ''
- # # coerce to String: cgi[] returns the
+ # # coerce to String: cgi[] returns the
# # string-like CGI::QueryExtension::Value
# session['user_name'] = cgi['user_name'].to_s
# elsif !session['user_name']
@@ -143,11 +143,11 @@
# cgi = CGI.new("html4")
#
# # We make sure to delete an old session if one exists,
- # # not just to free resources, but to prevent the session
+ # # not just to free resources, but to prevent the session
# # from being maliciously hijacked later on.
# begin
- # session = CGI::Session.new(cgi, 'new_session' => false)
- # session.delete
+ # session = CGI::Session.new(cgi, 'new_session' => false)
+ # session.delete
# rescue ArgumentError # if no old session
# end
# session = CGI::Session.new(cgi, 'new_session' => true)
@@ -172,7 +172,7 @@
# The session id is an MD5 hash based upon the time,
# a random number, and a constant string. This routine
# is used internally for automatically generated
- # session ids.
+ # session ids.
def create_new_id
require 'securerandom'
begin
@@ -205,7 +205,7 @@
# it is retrieved from the +session_key+ parameter
# of the request, or automatically generated for
# a new session.
- # new_session:: if true, force creation of a new session. If not set,
+ # new_session:: if true, force creation of a new session. If not set,
# a new session is only created if none currently
# exists. If false, a new session is never created,
# and if none currently exists and the +session_id+
@@ -220,7 +220,7 @@
# The following options are also recognised, but only apply if the
# session id is stored in a cookie.
#
- # session_expires:: the time the current session expires, as a
+ # session_expires:: the time the current session expires, as a
# +Time+ object. If not set, the session will terminate
# when the user's browser is closed.
# session_domain:: the hostname domain for which this session is valid.
@@ -232,10 +232,10 @@
# +option+ is also passed on to the session storage class initializer; see
# the documentation for each session storage class for the options
# they support.
- #
+ #
# The retrieved or created session is automatically added to +request+
# as a cookie, and also to its +output_hidden+ table, which is used
- # to add hidden input elements to forms.
+ # to add hidden input elements to forms.
#
# *WARNING* the +output_hidden+
# fields are surrounded by a <fieldset> tag in HTML 4 generation, which
@@ -294,7 +294,7 @@
"expires" => option['session_expires'],
"domain" => option['session_domain'],
"secure" => option['session_secure'],
- "path" =>
+ "path" =>
if option['session_path']
option['session_path']
elsif ENV["SCRIPT_NAME"]
@@ -323,11 +323,11 @@
# Store session data on the server. For some session storage types,
# this is a no-op.
- def update
+ def update
@dbman.update
end
- # Store session data on the server and close the session storage.
+ # Store session data on the server and close the session storage.
# For some session storage types, this is a no-op.
def close
@dbman.close
@@ -359,7 +359,7 @@
# created. The session id must only contain alphanumeric
# characters; automatically generated session ids observe
# this requirement.
- #
+ #
# +option+ is a hash of options for the initializer. The
# following options are recognised:
#
@@ -450,7 +450,7 @@
# In-memory session storage class.
#
# Implements session storage as a global in-memory hash. Session
- # data will only persist for as long as the ruby interpreter
+ # data will only persist for as long as the ruby interpreter
# instance does.
class MemoryStore
GLOBAL_HASH_TABLE = {} #:nodoc:
Modified: MacRuby/trunk/lib/cgi/util.rb
===================================================================
--- MacRuby/trunk/lib/cgi/util.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/cgi/util.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,4 +1,5 @@
class CGI
+ @@accept_charset="UTF-8" unless defined?(@@accept_charset)
# URL-encode a string.
# url_encoded_string = CGI::escape("'Stop!' said Fred")
# # => "%27Stop%21%27+said+Fred"
@@ -9,14 +10,14 @@
end
- # URL-decode a string.
+ # URL-decode a string with encoding(optional).
# string = CGI::unescape("%27Stop%21%27+said+Fred")
# # => "'Stop!' said Fred"
- def CGI::unescape(string)
- enc = string.encoding
- string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do
- [$1.delete('%')].pack('H*').force_encoding(enc)
- end
+ def CGI::unescape(string,encoding=@@accept_charset)
+ str=string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do
+ [$1.delete('%')].pack('H*')
+ end.force_encoding(encoding)
+ str.valid_encoding? ? str : str.force_encoding(string.encoding)
end
TABLE_FOR_ESCAPE_HTML__ = {
@@ -119,7 +120,7 @@
# print CGI::unescapeElement(
# CGI::escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
# # "<BR><A HREF="url"></A>"
- #
+ #
# print CGI::unescapeElement(
# CGI::escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
# # "<BR><A HREF="url"></A>"
@@ -140,6 +141,12 @@
unescapeElement(str)
end
+ # Abbreviated day-of-week names specified by RFC 822
+ RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
+
+ # Abbreviated month names specified by RFC 822
+ RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
+
# Format a +Time+ object as a String using the format specified by RFC 1123.
#
# CGI::rfc1123_date(Time.now)
@@ -161,7 +168,7 @@
# # <BODY>
# # </BODY>
# # </HTML>
- #
+ #
# print CGI::pretty("<HTML><BODY></BODY></HTML>", "\t")
# # <HTML>
# # <BODY>
@@ -169,7 +176,7 @@
# # </HTML>
#
def CGI::pretty(string, shift = " ")
- lines = string.gsub(/(?!\A)<(?:.|\n)*?>/, "\n\\0").gsub(/<(?:.|\n)*?>(?!\n)/, "\\0\n")
+ lines = string.gsub(/(?!\A)<.*?>/m, "\n\\0").gsub(/<.*?>(?!\n)/m, "\\0\n")
end_pos = 0
while end_pos = lines.index(/^<\/(\w+)/, end_pos)
element = $1.dup
Modified: MacRuby/trunk/lib/cgi.rb
===================================================================
--- MacRuby/trunk/lib/cgi.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/cgi.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,14 +1,14 @@
-#
+#
# cgi.rb - cgi support library
-#
+#
# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
-#
+#
# Copyright (C) 2000 Information-technology Promotion Agency, Japan
#
# Author: Wakou Aoyama <wakou at ruby-lang.org>
#
-# Documentation: Wakou Aoyama (RDoc'd and embellished by William Webber)
-#
+# Documentation: Wakou Aoyama (RDoc'd and embellished by William Webber)
+#
# == Overview
#
# The Common Gateway Interface (CGI) is a simple protocol
@@ -18,7 +18,7 @@
# parameters of the request passed in either in the
# environment (GET) or via $stdin (POST), and everything
# it prints to $stdout is returned to the client.
-#
+#
# This file holds the +CGI+ class. This class provides
# functionality for retrieving HTTP request parameters,
# managing cookies, and generating HTML output. See the
@@ -75,18 +75,18 @@
#
#
# For each of these variables, there is a corresponding attribute with the
-# same name, except all lower case and without a preceding HTTP_.
+# same name, except all lower case and without a preceding HTTP_.
# +content_length+ and +server_port+ are integers; the rest are strings.
#
# === Parameters
#
# The method #params() returns a hash of all parameters in the request as
# name/value-list pairs, where the value-list is an Array of one or more
-# values. The CGI object itself also behaves as a hash of parameter names
-# to values, but only returns a single value (as a String) for each
+# values. The CGI object itself also behaves as a hash of parameter names
+# to values, but only returns a single value (as a String) for each
# parameter name.
#
-# For instance, suppose the request contains the parameter
+# For instance, suppose the request contains the parameter
# "favourite_colours" with the multiple values "blue" and "green". The
# following behaviour would occur:
#
@@ -105,7 +105,7 @@
#
# === Multipart requests
#
-# If a request's method is POST and its content type is multipart/form-data,
+# If a request's method is POST and its content type is multipart/form-data,
# then it may contain uploaded files. These are stored by the QueryExtension
# module in the parameters of the request. The parameter name is the name
# attribute of the file input field, as usual. However, the value is not
@@ -136,7 +136,7 @@
#
# Each HTML element has a corresponding method for generating that
# element as a String. The name of this method is the same as that
-# of the element, all lowercase. The attributes of the element are
+# of the element, all lowercase. The attributes of the element are
# passed in as a hash, and the body as a no-argument block that evaluates
# to a String. The HTML generation module knows which elements are
# always empty, and silently drops any passed-in body. It also knows
@@ -150,57 +150,57 @@
# as arguments, rather than via a hash.
#
# == Examples of use
-#
+#
# === Get form values
-#
+#
# require "cgi"
# cgi = CGI.new
# value = cgi['field_name'] # <== value string for 'field_name'
# # if not 'field_name' included, then return "".
# fields = cgi.keys # <== array of field names
-#
+#
# # returns true if form has 'field_name'
# cgi.has_key?('field_name')
# cgi.has_key?('field_name')
# cgi.include?('field_name')
-#
-# CAUTION! cgi['field_name'] returned an Array with the old
+#
+# CAUTION! cgi['field_name'] returned an Array with the old
# cgi.rb(included in ruby 1.6)
-#
+#
# === Get form values as hash
-#
+#
# require "cgi"
# cgi = CGI.new
# params = cgi.params
-#
+#
# cgi.params is a hash.
-#
+#
# cgi.params['new_field_name'] = ["value"] # add new param
# cgi.params['field_name'] = ["new_value"] # change value
# cgi.params.delete('field_name') # delete param
# cgi.params.clear # delete all params
-#
-#
+#
+#
# === Save form values to file
-#
+#
# require "pstore"
# db = PStore.new("query.db")
# db.transaction do
# db["params"] = cgi.params
# end
-#
-#
+#
+#
# === Restore form values from file
-#
+#
# require "pstore"
# db = PStore.new("query.db")
# db.transaction do
# cgi.params = db["params"]
# end
-#
-#
+#
+#
# === Get multipart form values
-#
+#
# require "cgi"
# cgi = CGI.new
# value = cgi['field_name'] # <== value string for 'field_name'
@@ -208,37 +208,37 @@
# value.local_path # <== path to local file of value
# value.original_filename # <== original filename of value
# value.content_type # <== content_type of value
-#
+#
# and value has StringIO or Tempfile class methods.
-#
+#
# === Get cookie values
-#
+#
# require "cgi"
# cgi = CGI.new
# values = cgi.cookies['name'] # <== array of 'name'
# # if not 'name' included, then return [].
# names = cgi.cookies.keys # <== array of cookie names
-#
+#
# and cgi.cookies is a hash.
-#
+#
# === Get cookie objects
-#
+#
# require "cgi"
# cgi = CGI.new
# for name, cookie in cgi.cookies
# cookie.expires = Time.now + 30
# end
# cgi.out("cookie" => cgi.cookies) {"string"}
-#
+#
# cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... }
-#
+#
# require "cgi"
# cgi = CGI.new
# cgi.cookies['name'].expires = Time.now + 30
# cgi.out("cookie" => cgi.cookies['name']) {"string"}
-#
+#
# === Print http header and html string to $DEFAULT_OUTPUT ($>)
-#
+#
# require "cgi"
# cgi = CGI.new("html3") # add HTML generation methods
# cgi.out() do
@@ -262,7 +262,7 @@
# end
# end
# end
-#
+#
# # add HTML generation methods
# CGI.new("html3") # html3.2
# CGI.new("html4") # html4.01 (Strict)
@@ -272,3 +272,4 @@
require 'cgi/core'
require 'cgi/cookie'
require 'cgi/util'
+CGI.autoload(:HtmlExtension, 'cgi/html')
Modified: MacRuby/trunk/lib/cmath.rb
===================================================================
--- MacRuby/trunk/lib/cmath.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/cmath.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -4,8 +4,10 @@
alias exp! exp
alias log! log
+ alias log2! log2
alias log10! log10
alias sqrt! sqrt
+ alias cbrt! cbrt
alias sin! sin
alias cos! cos
@@ -28,8 +30,9 @@
if z.real?
exp!(z)
else
- Complex(exp!(z.real) * cos!(z.imag),
- exp!(z.real) * sin!(z.imag))
+ ere = exp!(z.real)
+ Complex(ere * cos!(z.imag),
+ ere * sin!(z.imag))
end
end
@@ -38,8 +41,7 @@
if z.real? and z >= 0 and (b.nil? or b >= 0)
log!(*args)
else
- r, theta = z.polar
- a = Complex(log!(r.abs), theta)
+ a = Complex(log!(z.abs), z.arg)
if b
a /= log(b)
end
@@ -47,8 +49,16 @@
end
end
+ def log2(z)
+ if z.real? and z >= 0
+ log2!(z)
+ else
+ log(z) / log!(2)
+ end
+ end
+
def log10(z)
- if z.real?
+ if z.real? and z >= 0
log10!(z)
else
log(z) / log!(10)
@@ -63,7 +73,8 @@
sqrt!(z)
end
else
- if z.imag < 0
+ if z.imag < 0 ||
+ (z.imag == 0 && z.imag.to_s[0] == '-')
sqrt(z.conjugate).conjugate
else
r = z.abs
@@ -73,6 +84,14 @@
end
end
+ def cbrt(z)
+ if z.real? and z >= 0
+ cbrt!(z)
+ else
+ Complex(z) ** (1.0/3)
+ end
+ end
+
def sin(z)
if z.real?
sin!(z)
@@ -95,7 +114,7 @@
if z.real?
tan!(z)
else
- sin(z)/cos(z)
+ sin(z) / cos(z)
end
end
@@ -129,7 +148,7 @@
if z.real? and z >= -1 and z <= 1
asin!(z)
else
- Complex(0, -1.0) * log(Complex(0, 1.0) * z + sqrt(1.0 - z * z))
+ (-1.0).i * log(1.0.i * z + sqrt(1.0 - z * z))
end
end
@@ -137,7 +156,7 @@
if z.real? and z >= -1 and z <= 1
acos!(z)
else
- Complex(0, -1.0) * log(z + Complex(0, 1.0) * sqrt(1.0 - z * z))
+ (-1.0).i * log(z + 1.0.i * sqrt(1.0 - z * z))
end
end
@@ -145,7 +164,7 @@
if z.real?
atan!(z)
else
- Complex(0, 1.0) * log((Complex(0, 1.0) + z) / (Complex(0, 1.0) - z)) / 2.0
+ 1.0.i * log((1.0.i + z) / (1.0.i - z)) / 2.0
end
end
@@ -153,10 +172,18 @@
if y.real? and x.real?
atan2!(y,x)
else
- Complex(0, -1.0) * log((x + Complex(0, 1.0) * y) / sqrt(x * x + y * y))
+ (-1.0).i * log((x + 1.0.i * y) / sqrt(x * x + y * y))
end
end
+ def asinh(z)
+ if z.real?
+ asinh!(z)
+ else
+ log(z + sqrt(1.0 + z * z))
+ end
+ end
+
def acosh(z)
if z.real? and z >= 1
acosh!(z)
@@ -165,14 +192,6 @@
end
end
- def asinh(z)
- if z.real?
- asinh!(z)
- else
- log(z + sqrt(1.0 + z * z))
- end
- end
-
def atanh(z)
if z.real? and z >= -1 and z <= 1
atanh!(z)
@@ -185,10 +204,14 @@
module_function :exp
module_function :log!
module_function :log
+ module_function :log2!
+ module_function :log2
module_function :log10!
module_function :log10
module_function :sqrt!
module_function :sqrt
+ module_function :cbrt!
+ module_function :cbrt
module_function :sin!
module_function :sin
@@ -220,8 +243,6 @@
module_function :atanh!
module_function :atanh
- module_function :log2
- module_function :cbrt
module_function :frexp
module_function :ldexp
module_function :hypot
Modified: MacRuby/trunk/lib/complex.rb
===================================================================
--- MacRuby/trunk/lib/complex.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/complex.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +1,7 @@
+# :enddoc:
+
+warn('lib/complex.rb is deprecated') if $VERBOSE
+
require 'cmath'
unless defined?(Math.exp!)
Modified: MacRuby/trunk/lib/csv.rb
===================================================================
--- MacRuby/trunk/lib/csv.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/csv.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,42 +1,41 @@
-#!/usr/bin/env ruby -w
-# encoding: UTF-8
+# encoding: US-ASCII
# = csv.rb -- CSV Reading and Writing
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
-#
+#
# See CSV for documentation.
-#
+#
# == Description
-#
+#
# Welcome to the new and improved CSV.
-#
+#
# This version of the CSV library began its life as FasterCSV. FasterCSV was
# intended as a replacement to Ruby's then standard CSV library. It was
# designed to address concerns users of that library had and it had three
# primary goals:
-#
+#
# 1. Be significantly faster than CSV while remaining a pure Ruby library.
# 2. Use a smaller and easier to maintain code base. (FasterCSV eventually
# grew larger, was also but considerably richer in features. The parsing
# core remains quite small.)
# 3. Improve on the CSV interface.
-#
+#
# Obviously, the last one is subjective. I did try to defer to the original
# interface whenever I didn't have a compelling reason to change it though, so
# hopefully this won't be too radically different.
-#
+#
# We must have met our goals because FasterCSV was renamed to CSV and replaced
# the original library.
-#
+#
# == What's Different From the Old CSV?
-#
+#
# I'm sure I'll miss something, but I'll try to mention most of the major
# differences I am aware of, to help others quickly get up to speed:
-#
+#
# === CSV Parsing
-#
+#
# * This parser is m17n aware. See CSV for full details.
# * This library has a stricter parser and will throw MalformedCSVErrors on
# problematic data.
@@ -46,9 +45,9 @@
# * The old library returned empty lines as <tt>[nil]</tt>. This library calls
# them <tt>[]</tt>.
# * This library has a much faster parser.
-#
+#
# === Interface
-#
+#
# * CSV now uses Hash-style parameters to set options.
# * CSV no longer has generate_row() or parse_row().
# * The old CSV's Reader and Writer classes have been dropped.
@@ -60,33 +59,33 @@
# * CSV no longer supports partial reads. It works line-by-line.
# * CSV no longer allows the instance methods to override the separators for
# performance reasons. They must be set in the constructor.
-#
+#
# If you use this library and find yourself missing any functionality I have
# trimmed, please {let me know}[mailto:james at grayproductions.net].
-#
+#
# == Documentation
-#
+#
# See CSV for documentation.
-#
+#
# == What is CSV, really?
-#
+#
# CSV maintains a pretty strict definition of CSV taken directly from
# {the RFC}[http://www.ietf.org/rfc/rfc4180.txt]. I relax the rules in only one
# place and that is to make using this library easier. CSV will parse all valid
# CSV.
-#
+#
# What you don't want to do is feed CSV invalid data. Because of the way the
# CSV format works, it's common for a parser to need to read until the end of
# the file to be sure a field is invalid. This eats a lot of time and memory.
-#
+#
# Luckily, when working with invalid CSV, Ruby's built-in methods will almost
# always be superior in every way. For example, parsing non-quoted fields is as
# easy as:
-#
+#
# data.split(",")
-#
+#
# == Questions and/or Comments
-#
+#
# Feel free to email {James Edward Gray II}[mailto:james at grayproductions.net]
# with any questions.
@@ -95,139 +94,139 @@
require "date"
require "stringio"
-#
+#
# This class provides a complete interface to CSV files and data. It offers
# tools to enable you to read and write to and from Strings or IO objects, as
# needed.
-#
+#
# == Reading
-#
+#
# === From a File
-#
+#
# ==== A Line at a Time
-#
+#
# CSV.foreach("path/to/file.csv") do |row|
# # use row here...
# end
-#
+#
# ==== All at Once
-#
+#
# arr_of_arrs = CSV.read("path/to/file.csv")
-#
+#
# === From a String
-#
+#
# ==== A Line at a Time
-#
+#
# CSV.parse("CSV,data,String") do |row|
# # use row here...
# end
-#
+#
# ==== All at Once
-#
+#
# arr_of_arrs = CSV.parse("CSV,data,String")
-#
+#
# == Writing
-#
+#
# === To a File
-#
+#
# CSV.open("path/to/file.csv", "wb") do |csv|
# csv << ["row", "of", "CSV", "data"]
# csv << ["another", "row"]
# # ...
# end
-#
+#
# === To a String
-#
+#
# csv_string = CSV.generate do |csv|
# csv << ["row", "of", "CSV", "data"]
# csv << ["another", "row"]
# # ...
# end
-#
+#
# == Convert a Single Line
-#
+#
# csv_string = ["CSV", "data"].to_csv # to CSV
# csv_array = "CSV,String".parse_csv # from CSV
-#
+#
# == Shortcut Interface
-#
+#
# CSV { |csv_out| csv_out << %w{my data here} } # to $stdout
# CSV(csv = "") { |csv_str| csv_str << %w{my data here} } # to a String
# CSV($stderr) { |csv_err| csv_err << %w{my data here} } # to $stderr
-#
+#
# == CSV and Character Encodings (M17n or Multilingualization)
-#
+#
# This new CSV parser is m17n savvy. The parser works in the Encoding of the IO
# or String object being read from or written to. Your data is never transcoded
# (unless you ask Ruby to transcode it for you) and will literally be parsed in
# the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the
# Encoding of your data. This is accomplished by transcoding the parser itself
# into your Encoding.
-#
+#
# Some transcoding must take place, of course, to accomplish this multiencoding
# support. For example, <tt>:col_sep</tt>, <tt>:row_sep</tt>, and
# <tt>:quote_char</tt> must be transcoded to match your data. Hopefully this
# makes the entire process feel transparent, since CSV's defaults should just
# magically work for you data. However, you can set these values manually in
# the target Encoding to avoid the translation.
-#
+#
# It's also important to note that while all of CSV's core parser is now
# Encoding agnostic, some features are not. For example, the built-in
# converters will try to transcode data to UTF-8 before making conversions.
# Again, you can provide custom converters that are aware of your Encodings to
# avoid this translation. It's just too hard for me to support native
# conversions in all of Ruby's Encodings.
-#
+#
# Anyway, the practical side of this is simple: make sure IO and String objects
# passed into CSV have the proper Encoding set and everything should just work.
# CSV methods that allow you to open IO objects (CSV::foreach(), CSV::open(),
# CSV::read(), and CSV::readlines()) do allow you to specify the Encoding.
-#
+#
# One minor exception comes when generating CSV into a String with an Encoding
# that is not ASCII compatible. There's no existing data for CSV to use to
# prepare itself and thus you will probably need to manually specify the desired
# Encoding for most of those cases. It will try to guess using the fields in a
# row of output though, when using CSV::generate_line() or Array#to_csv().
-#
+#
# I try to point out any other Encoding issues in the documentation of methods
# as they come up.
-#
+#
# This has been tested to the best of my ability with all non-"dummy" Encodings
# Ruby ships with. However, it is brave new code and may have some bugs.
# Please feel free to {report}[mailto:james at grayproductions.net] any issues you
# find with it.
-#
+#
class CSV
# The version of the installed library.
- VERSION = "2.4.5".freeze
-
- #
+ VERSION = "2.4.6".freeze
+
+ #
# A CSV::Row is part Array and part Hash. It retains an order for the fields
# and allows duplicates just as an Array would, but also allows you to access
# fields by name just as you could if they were in a Hash.
- #
+ #
# All rows returned by CSV will be constructed from this class, if header row
# processing is activated.
- #
+ #
class Row
- #
+ #
# Construct a new CSV::Row from +headers+ and +fields+, which are expected
# to be Arrays. If one Array is shorter than the other, it will be padded
# with +nil+ objects.
- #
+ #
# The optional +header_row+ parameter can be set to +true+ to indicate, via
# CSV::Row.header_row?() and CSV::Row.field_row?(), that this is a header
# row. Otherwise, the row is assumes to be a field row.
- #
+ #
# A CSV::Row object supports the following Array methods through delegation:
- #
+ #
# * empty?()
# * length()
# * size()
- #
+ #
def initialize(headers, fields, header_row = false)
@header_row = header_row
-
+
# handle extra headers or fields
@row = if headers.size > fields.size
headers.zip(fields)
@@ -235,7 +234,7 @@
fields.zip(headers).map { |pair| pair.reverse }
end
end
-
+
# Internal data format used to compare equality.
attr_reader :row
protected :row
@@ -244,35 +243,35 @@
extend Forwardable
def_delegators :@row, :empty?, :length, :size
-
+
# Returns +true+ if this is a header row.
def header_row?
@header_row
end
-
+
# Returns +true+ if this is a field row.
def field_row?
not header_row?
end
-
+
# Returns the headers of this row.
def headers
@row.map { |pair| pair.first }
end
-
- #
+
+ #
# :call-seq:
# field( header )
# field( header, offset )
# field( index )
- #
+ #
# This method will fetch the field value by +header+ or +index+. If a field
# is not found, +nil+ is returned.
- #
+ #
# When provided, +offset+ ensures that a header match occurrs on or later
- # than the +offset+ index. You can use this to find duplicate headers,
+ # than the +offset+ index. You can use this to find duplicate headers,
# without resorting to hard-coding exact indices.
- #
+ #
def field(header_or_index, minimum_index = 0)
# locate the pair
finder = header_or_index.is_a?(Integer) ? :[] : :assoc
@@ -282,23 +281,23 @@
pair.nil? ? nil : pair.last
end
alias_method :[], :field
-
- #
+
+ #
# :call-seq:
# []=( header, value )
# []=( header, offset, value )
# []=( index, value )
- #
+ #
# Looks up the field by the semantics described in CSV::Row.field() and
# assigns the +value+.
- #
+ #
# Assigning past the end of the row with an index will set all pairs between
# to <tt>[nil, nil]</tt>. Assigning to an unused header appends the new
# pair.
- #
+ #
def []=(*args)
value = args.pop
-
+
if args.first.is_a? Integer
if @row[args.first].nil? # extending past the end with index
@row[args.first] = [nil, value]
@@ -315,20 +314,20 @@
end
end
end
-
- #
+
+ #
# :call-seq:
# <<( field )
# <<( header_and_field_array )
# <<( header_and_field_hash )
- #
+ #
# If a two-element Array is provided, it is assumed to be a header and field
# and the pair is appended. A Hash works the same way with the key being
# the header and the value being the field. Anything else is assumed to be
# a lone field which is appended with a +nil+ header.
- #
+ #
# This method returns the row for chaining.
- #
+ #
def <<(arg)
if arg.is_a?(Array) and arg.size == 2 # appending a header and name
@row << arg
@@ -337,62 +336,64 @@
else # append field value
@row << [nil, arg]
end
-
+
self # for chaining
end
-
- #
+
+ #
# A shortcut for appending multiple fields. Equivalent to:
- #
+ #
# args.each { |arg| csv_row << arg }
- #
+ #
# This method returns the row for chaining.
- #
+ #
def push(*args)
args.each { |arg| self << arg }
-
+
self # for chaining
end
-
- #
+
+ #
# :call-seq:
# delete( header )
# delete( header, offset )
# delete( index )
- #
+ #
# Used to remove a pair from the row by +header+ or +index+. The pair is
# located as described in CSV::Row.field(). The deleted pair is returned,
# or +nil+ if a pair could not be found.
- #
+ #
def delete(header_or_index, minimum_index = 0)
- if header_or_index.is_a? Integer # by index
+ if header_or_index.is_a? Integer # by index
@row.delete_at(header_or_index)
- else # by header
- @row.delete_at(index(header_or_index, minimum_index))
+ elsif i = index(header_or_index, minimum_index) # by header
+ @row.delete_at(i)
+ else
+ [ ]
end
end
-
- #
+
+ #
# The provided +block+ is passed a header and field for each pair in the row
# and expected to return +true+ or +false+, depending on whether the pair
# should be deleted.
- #
+ #
# This method returns the row for chaining.
- #
+ #
def delete_if(&block)
@row.delete_if(&block)
-
+
self # for chaining
end
-
- #
+
+ #
# This method accepts any number of arguments which can be headers, indices,
- # Ranges of either, or two-element Arrays containing a header and offset.
+ # Ranges of either, or two-element Arrays containing a header and offset.
# Each argument will be replaced with a field lookup as described in
# CSV::Row.field().
- #
+ #
# If called with no arguments, all fields are returned.
- #
+ #
def fields(*headers_and_or_indices)
if headers_and_or_indices.empty? # return all fields--no arguments
@row.map { |pair| pair.last }
@@ -413,80 +414,80 @@
end
end
alias_method :values_at, :fields
-
- #
+
+ #
# :call-seq:
# index( header )
# index( header, offset )
- #
+ #
# This method will return the index of a field with the provided +header+.
# The +offset+ can be used to locate duplicate header names, as described in
# CSV::Row.field().
- #
+ #
def index(header, minimum_index = 0)
# find the pair
index = headers[minimum_index..-1].index(header)
# return the index at the right offset, if we found one
index.nil? ? nil : index + minimum_index
end
-
+
# Returns +true+ if +name+ is a header for this row, and +false+ otherwise.
def header?(name)
headers.include? name
end
alias_method :include?, :header?
-
- #
+
+ #
# Returns +true+ if +data+ matches a field in this row, and +false+
# otherwise.
- #
+ #
def field?(data)
fields.include? data
end
include Enumerable
-
- #
+
+ #
# Yields each pair of the row as header and field tuples (much like
# iterating over a Hash).
- #
+ #
# Support for Enumerable.
- #
+ #
# This method returns the row for chaining.
- #
+ #
def each(&block)
@row.each(&block)
-
+
self # for chaining
end
-
- #
- # Returns +true+ if this row contains the same headers and fields in the
+
+ #
+ # Returns +true+ if this row contains the same headers and fields in the
# same order as +other+.
- #
+ #
def ==(other)
@row == other.row
end
-
- #
+
+ #
# Collapses the row into a simple Hash. Be warning that this discards field
# order and clobbers duplicate fields.
- #
+ #
def to_hash
# flatten just one level of the internal Array
Hash[*@row.inject(Array.new) { |ary, pair| ary.push(*pair) }]
end
-
- #
+
+ #
# Returns the row as a CSV String. Headers are not used. Equivalent to:
- #
+ #
# csv_row.fields.to_csv( options )
- #
+ #
def to_csv(options = Hash.new)
fields.to_csv(options)
end
alias_method :to_s, :to_csv
-
+
# A summary of fields, by header, in an ASCII compatible String.
def inspect
str = ["#<", self.class.to_s]
@@ -505,35 +506,35 @@
end
end
end
-
- #
+
+ #
# A CSV::Table is a two-dimensional data structure for representing CSV
- # documents. Tables allow you to work with the data by row or column,
+ # documents. Tables allow you to work with the data by row or column,
# manipulate the data, and even convert the results back to CSV, if needed.
- #
+ #
# All tables returned by CSV will be constructed from this class, if header
# row processing is activated.
- #
+ #
class Table
- #
+ #
# Construct a new CSV::Table from +array_of_rows+, which are expected
# to be CSV::Row objects. All rows are assumed to have the same headers.
- #
+ #
# A CSV::Table object supports the following Array methods through
# delegation:
- #
+ #
# * empty?()
# * length()
# * size()
- #
+ #
def initialize(array_of_rows)
@table = array_of_rows
@mode = :col_or_row
end
-
+
# The current access mode for indexing and iteration.
attr_reader :mode
-
+
# Internal data format used to compare equality.
attr_reader :table
protected :table
@@ -542,88 +543,88 @@
extend Forwardable
def_delegators :@table, :empty?, :length, :size
-
- #
- # Returns a duplicate table object, in column mode. This is handy for
- # chaining in a single call without changing the table mode, but be aware
+
+ #
+ # Returns a duplicate table object, in column mode. This is handy for
+ # chaining in a single call without changing the table mode, but be aware
# that this method can consume a fair amount of memory for bigger data sets.
- #
+ #
# This method returns the duplicate table for chaining. Don't chain
# destructive methods (like []=()) this way though, since you are working
# with a duplicate.
- #
+ #
def by_col
self.class.new(@table.dup).by_col!
end
-
- #
+
+ #
# Switches the mode of this table to column mode. All calls to indexing and
# iteration methods will work with columns until the mode is changed again.
- #
+ #
# This method returns the table and is safe to chain.
- #
+ #
def by_col!
@mode = :col
-
+
self
end
-
- #
- # Returns a duplicate table object, in mixed mode. This is handy for
- # chaining in a single call without changing the table mode, but be aware
+
+ #
+ # Returns a duplicate table object, in mixed mode. This is handy for
+ # chaining in a single call without changing the table mode, but be aware
# that this method can consume a fair amount of memory for bigger data sets.
- #
+ #
# This method returns the duplicate table for chaining. Don't chain
# destructive methods (like []=()) this way though, since you are working
# with a duplicate.
- #
+ #
def by_col_or_row
self.class.new(@table.dup).by_col_or_row!
end
-
- #
+
+ #
# Switches the mode of this table to mixed mode. All calls to indexing and
# iteration methods will use the default intelligent indexing system until
# the mode is changed again. In mixed mode an index is assumed to be a row
# reference while anything else is assumed to be column access by headers.
- #
+ #
# This method returns the table and is safe to chain.
- #
+ #
def by_col_or_row!
@mode = :col_or_row
-
+
self
end
-
- #
+
+ #
# Returns a duplicate table object, in row mode. This is handy for chaining
# in a single call without changing the table mode, but be aware that this
# method can consume a fair amount of memory for bigger data sets.
- #
+ #
# This method returns the duplicate table for chaining. Don't chain
# destructive methods (like []=()) this way though, since you are working
# with a duplicate.
- #
+ #
def by_row
self.class.new(@table.dup).by_row!
end
-
- #
+
+ #
# Switches the mode of this table to row mode. All calls to indexing and
# iteration methods will work with rows until the mode is changed again.
- #
+ #
# This method returns the table and is safe to chain.
- #
+ #
def by_row!
@mode = :row
-
+
self
end
-
- #
+
+ #
# Returns the headers for the first row of this table (assumed to match all
# other rows). An empty Array is returned for empty tables.
- #
+ #
def headers
if @table.empty?
Array.new
@@ -631,15 +632,15 @@
@table.first.headers
end
end
-
- #
+
+ #
# In the default mixed mode, this method returns rows for index access and
# columns for header access. You can force the index association by first
# calling by_col!() or by_row!().
- #
+ #
# Columns are returned as an Array of values. Altering that Array has no
# effect on the table.
- #
+ #
def [](index_or_header)
if @mode == :row or # by index
(@mode == :col_or_row and index_or_header.is_a? Integer)
@@ -648,23 +649,23 @@
@table.map { |row| row[index_or_header] }
end
end
-
- #
+
+ #
# In the default mixed mode, this method assigns rows for index access and
# columns for header access. You can force the index association by first
# calling by_col!() or by_row!().
- #
+ #
# Rows may be set to an Array of values (which will inherit the table's
# headers()) or a CSV::Row.
- #
- # Columns may be set to a single value, which is copied to each row of the
+ #
+ # Columns may be set to a single value, which is copied to each row of the
# column, or an Array of values. Arrays of values are assigned to rows top
# to bottom in row major order. Excess values are ignored and if the Array
# does not have a value for each row the extra rows will receive a +nil+.
- #
+ #
# Assigning to an existing column or row clobbers the data. Assigning to
# new columns creates them at the right end of the table.
- #
+ #
def []=(index_or_header, value)
if @mode == :row or # by index
(@mode == :col_or_row and index_or_header.is_a? Integer)
@@ -693,16 +694,16 @@
end
end
end
-
- #
+
+ #
# The mixed mode default is to treat a list of indices as row access,
# returning the rows indicated. Anything else is considered columnar
# access. For columnar access, the return set has an Array for each row
# with the values indicated by the headers in each Array. You can force
# column or row mode using by_col!() or by_row!().
- #
+ #
# You cannot mix column and row access.
- #
+ #
def values_at(*indices_or_headers)
if @mode == :row or # by indices
( @mode == :col_or_row and indices_or_headers.all? do |index|
@@ -717,41 +718,41 @@
end
end
- #
+ #
# Adds a new row to the bottom end of this table. You can provide an Array,
# which will be converted to a CSV::Row (inheriting the table's headers()),
# or a CSV::Row.
- #
+ #
# This method returns the table for chaining.
- #
+ #
def <<(row_or_array)
if row_or_array.is_a? Array # append Array
@table << Row.new(headers, row_or_array)
else # append Row
@table << row_or_array
end
-
+
self # for chaining
end
-
- #
+
+ #
# A shortcut for appending multiple rows. Equivalent to:
- #
+ #
# rows.each { |row| self << row }
- #
+ #
# This method returns the table for chaining.
- #
+ #
def push(*rows)
rows.each { |row| self << row }
-
+
self # for chaining
end
- #
+ #
# Removes and returns the indicated column or row. In the default mixed
# mode indices refer to rows and everything else is assumed to be a column
# header. Use by_col!() or by_row!() to force the lookup.
- #
+ #
def delete(index_or_header)
if @mode == :row or # by index
(@mode == :col_or_row and index_or_header.is_a? Integer)
@@ -760,15 +761,15 @@
@table.map { |row| row.delete(index_or_header).last }
end
end
-
- #
+
+ #
# Removes any column or row for which the block returns +true+. In the
# default mixed mode or row mode, iteration is the standard row major
# walking of rows. In column mode, interation will +yield+ two element
# tuples containing the column name and an Array of values for that column.
- #
+ #
# This method returns the table for chaining.
- #
+ #
def delete_if(&block)
if @mode == :row or @mode == :col_or_row # by index
@table.delete_if(&block)
@@ -779,38 +780,38 @@
end
to_delete.map { |header| delete(header) }
end
-
+
self # for chaining
end
-
+
include Enumerable
-
- #
+
+ #
# In the default mixed mode or row mode, iteration is the standard row major
# walking of rows. In column mode, interation will +yield+ two element
# tuples containing the column name and an Array of values for that column.
- #
+ #
# This method returns the table for chaining.
- #
+ #
def each(&block)
if @mode == :col
headers.each { |header| block[[header, self[header]]] }
else
@table.each(&block)
end
-
+
self # for chaining
end
-
+
# Returns +true+ if all rows of this table ==() +other+'s rows.
def ==(other)
@table == other.table
end
-
- #
+
+ #
# Returns the table as an Array of Arrays. Headers will be the first row,
# then all of the field rows will follow.
- #
+ #
def to_a
@table.inject([headers]) do |array, row|
if row.header_row?
@@ -820,13 +821,17 @@
end
end
end
-
- #
+
+ #
# Returns the table as a complete CSV String. Headers will be listed first,
# then all of the field rows.
+ #
+ # This method assumes you want the Table.headers(), unless you explicitly
+ # pass <tt>:write_headers => false</tt>.
#
def to_csv(options = Hash.new)
- @table.inject([headers.to_csv(options)]) do |rows, row|
+ wh = options.fetch(:write_headers, true)
+ @table.inject(wh ? [headers.to_csv(options)] : [ ]) do |rows, row|
if row.header_row?
rows
else
@@ -835,7 +840,7 @@
end.join
end
alias_method :to_s, :to_csv
-
+
# Shows the mode and size of this table in a US-ASCII String.
def inspect
"#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>".encode("US-ASCII")
@@ -844,19 +849,19 @@
# The error thrown when the parser encounters illegal CSV formatting.
class MalformedCSVError < RuntimeError; end
-
- #
+
+ #
# A FieldInfo Struct contains details about a field's position in the data
# source it was read from. CSV will pass this Struct to some blocks that make
# decisions based on field structure. See CSV.convert_fields() for an
# example.
- #
+ #
# <b><tt>index</tt></b>:: The zero-based index of the field in its row.
# <b><tt>line</tt></b>:: The line of the data source this row is from.
# <b><tt>header</tt></b>:: The header for the column, when available.
- #
+ #
FieldInfo = Struct.new(:index, :line, :header)
-
+
# A Regexp used to find and convert some common Date formats.
DateMatcher = / \A(?: (\w+,?\s+)?\w+\s+\d{1,2},?\s+\d{2,4} |
\d{4}-\d{2}-\d{2} )\z /x
@@ -864,34 +869,34 @@
DateTimeMatcher =
/ \A(?: (\w+,?\s+)?\w+\s+\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},?\s+\d{2,4} |
\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2} )\z /x
-
+
# The encoding used by all converters.
ConverterEncoding = Encoding.find("UTF-8")
-
- #
+
+ #
# This Hash holds the built-in converters of CSV that can be accessed by name.
# You can select Converters with CSV.convert() or through the +options+ Hash
# passed to CSV::new().
- #
+ #
# <b><tt>:integer</tt></b>:: Converts any field Integer() accepts.
# <b><tt>:float</tt></b>:: Converts any field Float() accepts.
- # <b><tt>:numeric</tt></b>:: A combination of <tt>:integer</tt>
+ # <b><tt>:numeric</tt></b>:: A combination of <tt>:integer</tt>
# and <tt>:float</tt>.
# <b><tt>:date</tt></b>:: Converts any field Date::parse() accepts.
# <b><tt>:date_time</tt></b>:: Converts any field DateTime::parse() accepts.
- # <b><tt>:all</tt></b>:: All built-in converters. A combination of
+ # <b><tt>:all</tt></b>:: All built-in converters. A combination of
# <tt>:date_time</tt> and <tt>:numeric</tt>.
- #
+ #
# All built-in converters transcode field data to UTF-8 before attempting a
# conversion. If your data cannot be transcoded to UTF-8 the conversion will
# fail and the field will remain unchanged.
- #
+ #
# This Hash is intentionally left unfrozen and users should feel free to add
# values to it that can be accessed by all CSV objects.
- #
+ #
# To add a combo field, the value should be an Array of names. Combo fields
# can be nested with other combo fields.
- #
+ #
Converters = { integer: lambda { |f|
Integer(f.encode(ConverterEncoding)) rescue f
},
@@ -917,26 +922,26 @@
},
all: [:date_time, :numeric] }
- #
+ #
# This Hash holds the built-in header converters of CSV that can be accessed
# by name. You can select HeaderConverters with CSV.header_convert() or
# through the +options+ Hash passed to CSV::new().
- #
+ #
# <b><tt>:downcase</tt></b>:: Calls downcase() on the header String.
# <b><tt>:symbol</tt></b>:: The header String is downcased, spaces are
# replaced with underscores, non-word characters
# are dropped, and finally to_sym() is called.
- #
+ #
# All built-in header converters transcode header data to UTF-8 before
# attempting a conversion. If your data cannot be transcoded to UTF-8 the
# conversion will fail and the header will remain unchanged.
- #
+ #
# This Hash is intetionally left unfrozen and users should feel free to add
# values to it that can be accessed by all CSV objects.
- #
+ #
# To add a combo field, the value should be an Array of names. Combo fields
# can be nested with other combo fields.
- #
+ #
HeaderConverters = {
downcase: lambda { |h| h.encode(ConverterEncoding).downcase },
symbol: lambda { |h|
@@ -944,10 +949,10 @@
gsub(/\W+/, "").to_sym
}
}
-
- #
+
+ #
# The options used when no overrides are given by calling code. They are:
- #
+ #
# <b><tt>:col_sep</tt></b>:: <tt>","</tt>
# <b><tt>:row_sep</tt></b>:: <tt>:auto</tt>
# <b><tt>:quote_char</tt></b>:: <tt>'"'</tt>
@@ -959,10 +964,10 @@
# <b><tt>:header_converters</tt></b>:: +nil+
# <b><tt>:skip_blanks</tt></b>:: +false+
# <b><tt>:force_quotes</tt></b>:: +false+
- #
+ #
DEFAULT_OPTIONS = { col_sep: ",",
row_sep: :auto,
- quote_char: '"',
+ quote_char: '"',
field_size_limit: nil,
converters: nil,
unconverted_fields: nil,
@@ -971,21 +976,21 @@
header_converters: nil,
skip_blanks: false,
force_quotes: false }.freeze
-
- #
+
+ #
# This method will return a CSV instance, just like CSV::new(), but the
# instance will be cached and returned for all future calls to this method for
# the same +data+ object (tested by Object#object_id()) with the same
# +options+.
- #
+ #
# If a block is given, the instance is passed to the block and the return
# value becomes the return value of the block.
- #
+ #
def self.instance(data = $stdout, options = Hash.new)
# create a _signature_ for this method call, data object and options
sig = [data.object_id] +
options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s })
-
+
# fetch or create the instance for this signature
@@instances ||= Hash.new
instance = (@@instances[sig] ||= new(data, options))
@@ -997,25 +1002,25 @@
end
end
- #
+ #
# This method allows you to serialize an Array of Ruby objects to a String or
# File of CSV data. This is not as powerful as Marshal or YAML, but perhaps
# useful for spreadsheet and database interaction.
- #
+ #
# Out of the box, this method is intended to work with simple data objects or
# Structs. It will serialize a list of instance variables and/or
# Struct.members().
- #
+ #
# If you need need more complicated serialization, you can control the process
# by adding methods to the class to be serialized.
- #
+ #
# A class method csv_meta() is responsible for returning the first row of the
# document (as an Array). This row is considered to be a Hash of the form
# key_1,value_1,key_2,value_2,... CSV::load() expects to find a class key
# with a value of the stringified class name and CSV::dump() will create this,
# if you do not define this method. This method is only called on the first
# object of the Array.
- #
+ #
# The next method you can provide is an instance method called csv_headers().
# This method is expected to return the second line of the document (again as
# an Array), which is to be used to give each column a header. By default,
@@ -1023,20 +1028,20 @@
# @ character or call send() passing the header as the method name and
# the field value as an argument. This method is only called on the first
# object of the Array.
- #
+ #
# Finally, you can provide an instance method called csv_dump(), which will
# be passed the headers. This should return an Array of fields that can be
# serialized for this object. This method is called once for every object in
# the Array.
- #
+ #
# The +io+ parameter can be used to serialize to a File, and +options+ can be
# anything CSV::new() accepts.
- #
+ #
def self.dump(ary_of_objs, io = "", options = Hash.new)
obj_template = ary_of_objs.first
-
+
csv = new(io, options)
-
+
# write meta information
begin
csv << obj_template.class.csv_meta
@@ -1054,7 +1059,7 @@
end
end
csv << headers
-
+
# serialize each object
ary_of_objs.each do |obj|
begin
@@ -1069,39 +1074,39 @@
end
end
end
-
+
if io.is_a? String
csv.string
else
csv.close
end
end
-
- #
+
+ #
# This method is the reading counterpart to CSV::dump(). See that method for
# a detailed description of the process.
- #
- # You can customize loading by adding a class method called csv_load() which
+ #
+ # You can customize loading by adding a class method called csv_load() which
# will be passed a Hash of meta information, an Array of headers, and an Array
# of fields for the object the method is expected to return.
- #
+ #
# Remember that all fields will be Strings after this load. If you need
# something else, use +options+ to setup converters or provide a custom
# csv_load() implementation.
- #
+ #
def self.load(io_or_str, options = Hash.new)
csv = new(io_or_str, options)
-
+
# load meta information
meta = Hash[*csv.shift]
cls = meta["class".encode(csv.encoding)].split("::".encode(csv.encoding)).
inject(Object) do |c, const|
c.const_get(const)
end
-
+
# load headers
headers = csv.shift
-
+
# unserialize each object stored in the file
results = csv.inject(Array.new) do |all, row|
begin
@@ -1118,36 +1123,36 @@
end
all << obj
end
-
+
csv.close unless io_or_str.is_a? String
-
+
results
end
-
- #
+
+ #
# :call-seq:
# filter( options = Hash.new ) { |row| ... }
# filter( input, options = Hash.new ) { |row| ... }
# filter( input, output, options = Hash.new ) { |row| ... }
- #
+ #
# This method is a convenience for building Unix-like filters for CSV data.
- # Each row is yielded to the provided block which can alter it as needed.
+ # Each row is yielded to the provided block which can alter it as needed.
# After the block returns, the row is appended to +output+ altered or not.
- #
+ #
# The +input+ and +output+ arguments can be anything CSV::new() accepts
- # (generally String or IO objects). If not given, they default to
+ # (generally String or IO objects). If not given, they default to
# <tt>ARGF</tt> and <tt>$stdout</tt>.
- #
+ #
# The +options+ parameter is also filtered down to CSV::new() after some
- # clever key parsing. Any key beginning with <tt>:in_</tt> or
+ # clever key parsing. Any key beginning with <tt>:in_</tt> or
# <tt>:input_</tt> will have that leading identifier stripped and will only
# be used in the +options+ Hash for the +input+ object. Keys starting with
- # <tt>:out_</tt> or <tt>:output_</tt> affect only +output+. All other keys
+ # <tt>:out_</tt> or <tt>:output_</tt> affect only +output+. All other keys
# are assigned to both objects.
- #
+ #
# The <tt>:output_row_sep</tt> +option+ defaults to
# <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).
- #
+ #
def self.filter(*args)
# parse options for input, output, or both
in_options, out_options = Hash.new, {row_sep: $INPUT_RECORD_SEPARATOR}
@@ -1167,19 +1172,19 @@
# build input and output wrappers
input = new(args.shift || ARGF, in_options)
output = new(args.shift || $stdout, out_options)
-
+
# read, yield, write
input.each do |row|
yield row
output << row
end
end
-
- #
+
+ #
# This method is intended as the primary interface for reading CSV files. You
# pass a +path+ and any +options+ you wish to set for the read. Each row of
# file will be passed to the provided +block+ in turn.
- #
+ #
# The +options+ parameter can be anything CSV::new() understands. This method
# also understands an additional <tt>:encoding</tt> parameter that you can use
# to specify the Encoding of the data in the file to be read. You must provide
@@ -1188,7 +1193,7 @@
# have the data transcoded as it is read. For example,
# <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
# but transcode it to UTF-8 before CSV parses it.
- #
+ #
def self.foreach(path, options = Hash.new, &block)
encoding = options.delete(:encoding)
mode = "rb"
@@ -1198,24 +1203,24 @@
end
end
- #
+ #
# :call-seq:
# generate( str, options = Hash.new ) { |csv| ... }
# generate( options = Hash.new ) { |csv| ... }
- #
- # This method wraps a String you provide, or an empty default String, in a
+ #
+ # This method wraps a String you provide, or an empty default String, in a
# CSV object which is passed to the provided block. You can use the block to
# append CSV rows to the String and when the block exits, the final String
# will be returned.
- #
+ #
# Note that a passed String *is* modfied by this method. Call dup() before
# passing if you need a new String.
- #
- # The +options+ parameter can be anthing CSV::new() understands. This method
+ #
+ # The +options+ parameter can be anything CSV::new() understands. This method
# understands an additional <tt>:encoding</tt> parameter when not passed a
# String to set the base Encoding for the output. CSV needs this hint if you
# plan to output non-ASCII compatible data.
- #
+ #
def self.generate(*args)
# add a default empty String, if none was given
if args.first.is_a? String
@@ -1233,19 +1238,19 @@
csv.string # return final String
end
- #
- # This method is a shortcut for converting a single row (Array) into a CSV
+ #
+ # This method is a shortcut for converting a single row (Array) into a CSV
# String.
- #
- # The +options+ parameter can be anthing CSV::new() understands. This method
- # understands an additional <tt>:encoding</tt> parameter to set the base
+ #
+ # The +options+ parameter can be anything CSV::new() understands. This method
+ # understands an additional <tt>:encoding</tt> parameter to set the base
# Encoding for the output. This method will try to guess your Encoding from
# the first non-+nil+ field in +row+, if possible, but you may need to use
# this parameter as a backup plan.
- #
+ #
# The <tt>:row_sep</tt> +option+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>
# (<tt>$/</tt>) when calling this method.
- #
+ #
def self.generate_line(row, options = Hash.new)
options = {row_sep: $INPUT_RECORD_SEPARATOR}.merge(options)
encoding = options.delete(:encoding)
@@ -1257,27 +1262,27 @@
end
(new(str, options) << row).string
end
-
- #
+
+ #
# :call-seq:
# open( filename, mode = "rb", options = Hash.new ) { |faster_csv| ... }
# open( filename, options = Hash.new ) { |faster_csv| ... }
# open( filename, mode = "rb", options = Hash.new )
# open( filename, options = Hash.new )
- #
+ #
# This method opens an IO object, and wraps that with CSV. This is intended
# as the primary interface for writing a CSV file.
- #
+ #
# You must pass a +filename+ and may optionally add a +mode+ for Ruby's
# open(). You may also pass an optional Hash containing any +options+
# CSV::new() understands as the final argument.
- #
+ #
# This method works like Ruby's open() call, in that it will pass a CSV object
# to a provided block and close it when the block terminates, or it will
# return the CSV object when no block is provided. (*Note*: This is different
# from the Ruby 1.8 CSV library which passed rows to the block. Use
# CSV::foreach() for that behavior.)
- #
+ #
# You must provide a +mode+ with an embedded Encoding designator unless your
# data is in Encoding::default_external(). CSV will check the Encoding of the
# underlying IO object (set by the +mode+ you pass) to deterime how to parse
@@ -1285,10 +1290,10 @@
# it is read just as you can with a normal call to IO::open(). For example,
# <tt>"rb:UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file but
# transcode it to UTF-8 before CSV parses it.
- #
+ #
# An opened CSV object will delegate to many IO methods for convenience. You
# may call:
- #
+ #
# * binmode()
# * binmode?()
# * close()
@@ -1320,7 +1325,7 @@
# * to_io()
# * truncate()
# * tty?()
- #
+ #
def self.open(*args)
# find the +options+ Hash
options = if args.last.is_a? Hash then args.pop else Hash.new end
@@ -1328,7 +1333,7 @@
args << "rb" if args.size == 1
# wrap a File opened with the remaining +args+
csv = new(File.open(*args), options)
-
+
# handle blocks like Ruby's open(), not like the CSV library
if block_given?
begin
@@ -1340,19 +1345,19 @@
csv
end
end
-
- #
+
+ #
# :call-seq:
# parse( str, options = Hash.new ) { |row| ... }
# parse( str, options = Hash.new )
- #
+ #
# This method can be used to easily parse CSV out of a String. You may either
# provide a +block+ which will be called with each row of the String in turn,
# or just use the returned Array of Arrays (when no +block+ is given).
- #
+ #
# You pass your +str+ to read from, and an optional +options+ Hash containing
# anything CSV::new() understands.
- #
+ #
def self.parse(*args, &block)
csv = new(*args)
if block.nil? # slurp contents, if no block is given
@@ -1365,20 +1370,20 @@
csv.each(&block)
end
end
-
- #
- # This method is a shortcut for converting a single line of a CSV String into
- # a into an Array. Note that if +line+ contains multiple rows, anything
+
+ #
+ # This method is a shortcut for converting a single line of a CSV String into
+ # a into an Array. Note that if +line+ contains multiple rows, anything
# beyond the first row is ignored.
- #
- # The +options+ parameter can be anthing CSV::new() understands.
- #
+ #
+ # The +options+ parameter can be anything CSV::new() understands.
+ #
def self.parse_line(line, options = Hash.new)
new(line, options).shift
end
-
- #
- # Use to slurp a CSV file into an Array of Arrays. Pass the +path+ to the
+
+ #
+ # Use to slurp a CSV file into an Array of Arrays. Pass the +path+ to the
# file and any +options+ CSV::new() understands. This method also understands
# an additional <tt>:encoding</tt> parameter that you can use to specify the
# Encoding of the data in the file to be read. You must provide this unless
@@ -1387,46 +1392,46 @@
# transcoded as it is read. For example,
# <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
# but transcode it to UTF-8 before CSV parses it.
- #
+ #
def self.read(path, options = Hash.new)
encoding = options.delete(:encoding)
mode = "rb"
mode << ":#{encoding}" if encoding
open(path, mode, options) { |csv| csv.read }
end
-
+
# Alias for CSV::read().
def self.readlines(*args)
read(*args)
end
-
- #
+
+ #
# A shortcut for:
- #
+ #
# CSV.read( path, { headers: true,
# converters: :numeric,
# header_converters: :symbol }.merge(options) )
- #
+ #
def self.table(path, options = Hash.new)
read( path, { headers: true,
converters: :numeric,
header_converters: :symbol }.merge(options) )
end
-
- #
+
+ #
# This constructor will wrap either a String or IO object passed in +data+ for
# reading and/or writing. In addition to the CSV instance methods, several IO
# methods are delegated. (See CSV::open() for a complete list.) If you pass
# a String for +data+, you can later retrieve it (after writing to it, for
# example) with CSV.string().
- #
- # Note that a wrapped String will be positioned at at the beginning (for
+ #
+ # Note that a wrapped String will be positioned at at the beginning (for
# reading). If you want it at the end (for writing), use CSV::generate().
# If you want any other positioning, pass a preset StringIO object instead.
- #
- # You may set any reading and/or writing preferences in the +options+ Hash.
+ #
+ # You may set any reading and/or writing preferences in the +options+ Hash.
# Available options are:
- #
+ #
# <b><tt>:col_sep</tt></b>:: The String placed between each field.
# This String will be transcoded into
# the data's Encoding before parsing.
@@ -1501,7 +1506,7 @@
# Array or String were not fields of the
# document and thus will have an empty
# Array attached.
- # <b><tt>:headers</tt></b>:: If set to <tt>:first_row</tt> or
+ # <b><tt>:headers</tt></b>:: If set to <tt>:first_row</tt> or
# +true+, the initial row of the CSV
# file will be treated as a row of
# headers. If set to an Array, the
@@ -1538,129 +1543,124 @@
# skip over any rows with no content.
# <b><tt>:force_quotes</tt></b>:: When set to a +true+ value, CSV will
# quote all CSV fields it creates.
- #
+ #
# See CSV::DEFAULT_OPTIONS for the default settings.
- #
+ #
# Options cannot be overriden in the instance methods for performance reasons,
# so be sure to set what you want here.
- #
+ #
def initialize(data, options = Hash.new)
# build the options for this read/write
options = DEFAULT_OPTIONS.merge(options)
-
+
# create the IO object we will read from
@io = if data.is_a? String then StringIO.new(data) else data end
# honor the IO encoding if we can, otherwise default to ASCII-8BIT
- @encoding = if @io.respond_to? :internal_encoding
- @io.internal_encoding || @io.external_encoding
- elsif @io.is_a? StringIO
- @io.string.encoding
- end
- @encoding ||= Encoding.default_internal || Encoding.default_external
- #
+ @encoding = raw_encoding || Encoding.default_internal || Encoding.default_external
+ #
# prepare for building safe regular expressions in the target encoding,
# if we can transcode the needed characters
- #
+ #
@re_esc = "\\".encode(@encoding) rescue ""
@re_chars = %w[ \\ . [ ] - ^ $ ?
* + { } ( ) | #
\ \r \n \t \f \v ].
map { |s| s.encode(@encoding) rescue nil }.compact
-
+
init_separators(options)
init_parsers(options)
init_converters(options)
init_headers(options)
-
+
unless options.empty?
raise ArgumentError, "Unknown options: #{options.keys.join(', ')}."
end
-
+
# track our own lineno since IO gets confused about line-ends is CSV fields
@lineno = 0
end
-
- #
+
+ #
# The encoded <tt>:col_sep</tt> used in parsing and writing. See CSV::new
# for details.
- #
+ #
attr_reader :col_sep
- #
+ #
# The encoded <tt>:row_sep</tt> used in parsing and writing. See CSV::new
# for details.
- #
+ #
attr_reader :row_sep
- #
+ #
# The encoded <tt>:quote_char</tt> used in parsing and writing. See CSV::new
# for details.
- #
+ #
attr_reader :quote_char
# The limit for field size, if any. See CSV::new for details.
attr_reader :field_size_limit
- #
+ #
# Returns the current list of converters in effect. See CSV::new for details.
# Built-in converters will be returned by name, while others will be returned
# as is.
- #
+ #
def converters
@converters.map do |converter|
name = Converters.rassoc(converter)
name ? name.first : converter
end
end
- #
+ #
# Returns +true+ if unconverted_fields() to parsed results. See CSV::new
# for details.
- #
+ #
def unconverted_fields?() @unconverted_fields end
- #
+ #
# Returns +nil+ if headers will not be used, +true+ if they will but have not
# yet been read, or the actual headers after they have been read. See
# CSV::new for details.
- #
+ #
def headers
@headers || true if @use_headers
end
- #
+ #
# Returns +true+ if headers will be returned as a row of results.
# See CSV::new for details.
- #
+ #
def return_headers?() @return_headers end
# Returns +true+ if headers are written in output. See CSV::new for details.
def write_headers?() @write_headers end
- #
+ #
# Returns the current list of converters in effect for headers. See CSV::new
# for details. Built-in converters will be returned by name, while others
# will be returned as is.
- #
+ #
def header_converters
@header_converters.map do |converter|
name = HeaderConverters.rassoc(converter)
name ? name.first : converter
end
end
- #
+ #
# Returns +true+ blank lines are skipped by the parser. See CSV::new
# for details.
- #
+ #
def skip_blanks?() @skip_blanks end
# Returns +true+ if all output fields are quoted. See CSV::new for details.
def force_quotes?() @force_quotes end
-
- #
+
+ #
# The Encoding CSV is parsing or writing in. This will be the Encoding you
# receive parsed data in and/or the Encoding data will be written in.
- #
+ #
attr_reader :encoding
-
- #
- # The line number of the last row read from this file. Fields with nested
+
+ #
+ # The line number of the last row read from this file. Fields with nested
# line-end characters will not affect this count.
- #
+ #
attr_reader :lineno
-
+
### IO and StringIO Delegation ###
-
+
extend Forwardable
def_delegators :@io, :binmode, :binmode?, :close, :close_read, :close_write,
:closed?, :eof, :eof?, :external_encoding, :fcntl,
@@ -1668,31 +1668,31 @@
:ioctl, :isatty, :path, :pid, :pos, :pos=, :reopen,
:seek, :stat, :string, :sync, :sync=, :tell, :to_i,
:to_io, :truncate, :tty?
-
+
# Rewinds the underlying IO object and resets CSV's lineno() counter.
def rewind
@headers = nil
@lineno = 0
-
+
@io.rewind
end
### End Delegation ###
-
- #
+
+ #
# The primary write method for wrapped Strings and IOs, +row+ (an Array or
# CSV::Row) is converted to CSV and appended to the data source. When a
# CSV::Row is passed, only the row's fields() are appended to the output.
- #
+ #
# The data source must be open for writing.
- #
+ #
def <<(row)
# make sure headers have been assigned
if header_row? and [Array, String].include? @use_headers.class
parse_headers # won't read data for Array or String
self << @headers if @write_headers
end
-
+
# handle CSV::Row objects and Hashes
row = case row
when self.class::Row then row.fields
@@ -1704,69 +1704,69 @@
@lineno += 1
@io << row.map(&@quote).join(@col_sep) + @row_sep # quote and separate
-
+
self # for chaining
end
alias_method :add_row, :<<
alias_method :puts, :<<
-
- #
+
+ #
# :call-seq:
# convert( name )
# convert { |field| ... }
# convert { |field, field_info| ... }
- #
+ #
# You can use this method to install a CSV::Converters built-in, or provide a
# block that handles a custom conversion.
- #
+ #
# If you provide a block that takes one argument, it will be passed the field
# and is expected to return the converted value or the field itself. If your
- # block takes two arguments, it will also be passed a CSV::FieldInfo Struct,
- # containing details about the field. Again, the block should return a
+ # block takes two arguments, it will also be passed a CSV::FieldInfo Struct,
+ # containing details about the field. Again, the block should return a
# converted field or the field itself.
- #
+ #
def convert(name = nil, &converter)
add_converter(:converters, self.class::Converters, name, &converter)
end
- #
+ #
# :call-seq:
# header_convert( name )
# header_convert { |field| ... }
# header_convert { |field, field_info| ... }
- #
+ #
# Identical to CSV#convert(), but for header rows.
- #
+ #
# Note that this method must be called before header rows are read to have any
# effect.
- #
+ #
def header_convert(name = nil, &converter)
add_converter( :header_converters,
self.class::HeaderConverters,
name,
&converter )
end
-
+
include Enumerable
-
- #
+
+ #
# Yields each row of the data source in turn.
- #
+ #
# Support for Enumerable.
- #
+ #
# The data source must be open for reading.
- #
+ #
def each
while row = shift
yield row
end
end
-
- #
+
+ #
# Slurps the remaining rows and returns an Array of Arrays.
- #
+ #
# The data source must be open for reading.
- #
+ #
def read
rows = to_a
if @use_headers
@@ -1776,25 +1776,25 @@
end
end
alias_method :readlines, :read
-
+
# Returns +true+ if the next row read will be a header row.
def header_row?
@use_headers and @headers.nil?
end
-
- #
+
+ #
# The primary read method for wrapped Strings and IOs, a single row is pulled
# from the data source, parsed and returned as an Array of fields (if header
# rows are not used) or a CSV::Row (when header rows are used).
- #
+ #
# The data source must be open for reading.
- #
+ #
def shift
#########################################################################
### This method is purposefully kept a bit long as simple conditional ###
### checks are faster than numerous (expensive) method calls. ###
#########################################################################
-
+
# handle headers not based on document content
if header_row? and @return_headers and
[Array, String].include? @use_headers.class
@@ -1804,74 +1804,103 @@
return parse_headers
end
end
-
+
# begin with a blank line, so we can always add to it
line = ""
- #
+ #
# it can take multiple calls to <tt>@io.gets()</tt> to get a full line,
# because of \r and/or \n characters embedded in quoted fields
- #
+ #
+ in_extended_col = false
+ csv = Array.new
+
loop do
# add another read to the line
- (line += @io.gets(@row_sep)) rescue return nil
- # copy the line so we can chop it up in parsing
- parse = line.dup
+ unless parse = @io.gets(@row_sep)
+ return nil
+ end
+
parse.sub!(@parsers[:line_end], "")
-
- #
- # I believe a blank line should be an <tt>Array.new</tt>, not Ruby 1.8
- # CSV's <tt>[nil]</tt>
- #
- if parse.empty?
- @lineno += 1
- if @skip_blanks
- line = ""
- next
- elsif @unconverted_fields
- return add_unconverted_fields(Array.new, Array.new)
- elsif @use_headers
- return self.class::Row.new(Array.new, Array.new)
- else
- return Array.new
+
+ if csv.empty?
+ #
+ # I believe a blank line should be an <tt>Array.new</tt>, not Ruby 1.8
+ # CSV's <tt>[nil]</tt>
+ #
+ if parse.empty?
+ @lineno += 1
+ if @skip_blanks
+ next
+ elsif @unconverted_fields
+ return add_unconverted_fields(Array.new, Array.new)
+ elsif @use_headers
+ return self.class::Row.new(Array.new, Array.new)
+ else
+ return Array.new
+ end
end
end
- #
- # shave leading empty fields if needed, because the main parser chokes
- # on these
- #
- csv = if parse.sub!(@parsers[:leading_fields], "")
- [nil] * ($&.length / @col_sep.length)
- else
- Array.new
- end
- #
- # then parse the main fields with a hyper-tuned Regexp from
- # Mastering Regular Expressions, Second Edition
- #
- parse.gsub!(@parsers[:csv_row]) do
- csv << if $1.nil? # we found an unquoted field
- if $2.empty? # switch empty unquoted fields to +nil+...
- nil # for Ruby 1.8 CSV compatibility
+ parts = parse.split(@col_sep, -1)
+ csv << nil if parts.empty?
+
+ # This loop is the hot path of csv parsing. Some things may be non-dry
+ # for a reason. Make sure to benchmark when refactoring.
+ parts.each do |part|
+ if in_extended_col
+ # If we are continuing a previous column
+ if part[-1] == @quote_char && part.count(@quote_char) % 2 != 0
+ # extended column ends
+ csv.last << part[0..-2]
+ raise MalformedCSVError if csv.last =~ @parsers[:stray_quote]
+ csv.last.gsub!(@quote_char * 2, @quote_char)
+ in_extended_col = false
else
- # I decided to take a strict approach to CSV parsing...
- if $2.count(@parsers[:return_newline]).zero? # verify correctness
- $2
- else
- # or throw an Exception
- raise MalformedCSVError, "Unquoted fields do not allow " +
- "\\r or \\n (line #{lineno + 1})."
- end
+ csv.last << part
+ csv.last << @col_sep
end
- else # we found a quoted field...
- $1.gsub(@quote_char * 2, @quote_char) # unescape contents
+ elsif part[0] == @quote_char
+ # If we are staring a new quoted column
+ if part[-1] != @quote_char || part.count(@quote_char) % 2 != 0
+ # start an extended column
+ csv << part[1..-1]
+ csv.last << @col_sep
+ in_extended_col = true
+ else
+ # regular quoted column
+ csv << part[1..-2]
+ raise MalformedCSVError if csv.last =~ @parsers[:stray_quote]
+ csv.last.gsub!(@quote_char * 2, @quote_char)
+ end
+ elsif part =~ @parsers[:quote_or_nl]
+ # Unquoted field with bad characters.
+ if part =~ @parsers[:nl_or_lf]
+ raise MalformedCSVError, "Unquoted fields do not allow " +
+ "\\r or \\n (line #{lineno + 1})."
+ else
+ raise MalformedCSVError, "Illegal quoting on line #{lineno + 1}."
+ end
+ else
+ # Regular ole unquoted field.
+ csv << (part.empty? ? nil : part)
end
- "" # gsub!'s replacement, clear the field
end
- # if parse is empty?(), we found all the fields on the line...
- if parse.empty?
+ # Replace tacked on @col_sep with @row_sep if we are still in an extended
+ # column.
+ csv[-1][-1] = @row_sep if in_extended_col
+
+ if in_extended_col
+ # if we're at eof?(), a quoted field wasn't closed...
+ if @io.eof?
+ raise MalformedCSVError,
+ "Unclosed quoted field on line #{lineno + 1}."
+ elsif @field_size_limit and csv.last.size >= @field_size_limit
+ raise MalformedCSVError, "Field size exceeded on line #{lineno + 1}."
+ end
+ # otherwise, we need to loop and pull some more data to complete the row
+ else
@lineno += 1
# save fields unconverted fields, if needed...
@@ -1890,24 +1919,15 @@
# return the results
break csv
end
- # if we're not empty?() but at eof?(), a quoted field wasn't closed...
- if @io.eof?
- raise MalformedCSVError, "Unclosed quoted field on line #{lineno + 1}."
- elsif parse =~ @parsers[:bad_field]
- raise MalformedCSVError, "Illegal quoting on line #{lineno + 1}."
- elsif @field_size_limit and parse.length >= @field_size_limit
- raise MalformedCSVError, "Field size exceeded on line #{lineno + 1}."
- end
- # otherwise, we need to loop and pull some more data to complete the row
end
end
alias_method :gets, :shift
alias_method :readline, :shift
-
- #
+
+ #
# Returns a simplified description of the key FasterCSV attributes in an
# ASCII compatible String.
- #
+ #
def inspect
str = ["<#", self.class.to_s, " io_type:"]
# show type of wrapped IO
@@ -1942,19 +1962,19 @@
end.join
end
end
-
+
private
-
- #
+
+ #
# Stores the indicated separators for later use.
- #
+ #
# If auto-discovery was requested for <tt>@row_sep</tt>, this method will read
# ahead in the <tt>@io</tt> and try to find one. +ARGF+, +STDIN+, +STDOUT+,
# +STDERR+ and any stream open for output only with a default
# <tt>@row_sep</tt> of <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).
- #
+ #
# This method also establishes the quoting rules used for CSV output.
- #
+ #
def init_separators(options)
# store the selected separators
@col_sep = options.delete(:col_sep).to_s.encode(@encoding)
@@ -1964,11 +1984,11 @@
if @quote_char.length != 1
raise ArgumentError, ":quote_char has to be a single character String"
end
-
- #
+
+ #
# automatically discover row separator when requested
# (not fully encoding safe)
- #
+ #
if @row_sep == :auto
if [ARGF, STDIN, STDOUT, STDERR].include?(@io) or
(defined?(Zlib) and @io.class == Zlib::GzipWriter)
@@ -1977,20 +1997,19 @@
begin
saved_pos = @io.pos # remember where we were
while @row_sep == :auto
- #
- # if we run out of data, it's probably a single line
+ #
+ # if we run out of data, it's probably a single line
# (use a sensible default)
- #
+ #
if @io.eof?
@row_sep = $INPUT_RECORD_SEPARATOR
break
end
-
+
# read ahead a bit
sample = read_to_char(1024)
sample += read_to_char(1) if sample[-1..-1] == encode_str("\r") and
not @io.eof?
-
# try to find a standard separator
if sample =~ encode_re("\r\n?|\n")
@row_sep = $&
@@ -2011,7 +2030,7 @@
end
end
@row_sep = @row_sep.to_s.encode(@encoding)
-
+
# establish quoting rules
@force_quotes = options.delete(:force_quotes)
do_quote = lambda do |field|
@@ -2039,72 +2058,50 @@
end
end
end
-
+
# Pre-compiles parsers and stores them by name for access during reads.
def init_parsers(options)
# store the parser behaviors
@skip_blanks = options.delete(:skip_blanks)
@field_size_limit = options.delete(:field_size_limit)
-
+
# prebuild Regexps for faster parsing
esc_col_sep = escape_re(@col_sep)
esc_row_sep = escape_re(@row_sep)
esc_quote = escape_re(@quote_char)
@parsers = {
- # for empty leading fields
- leading_fields: encode_re("\\A(?:", esc_col_sep, ")+"),
- # The Primary Parser
- csv_row: encode_re(
- "\\G(?:\\A|", esc_col_sep, ")", # anchor the match
- "(?:", esc_quote, # find quoted fields
- "((?>[^", esc_quote, "]*)", # "unrolling the loop"
- "(?>", esc_quote * 2, # double for escaping
- "[^", esc_quote, "]*)*)",
- esc_quote,
- "|", # ... or ...
- "([^", esc_quote, esc_col_sep, "]*))", # unquoted fields
- "(?=", esc_col_sep, "|\\z)" # ensure field is ended
- ),
- # a test for unescaped quotes
- bad_field: encode_re(
- "\\A", esc_col_sep, "?", # an optional comma
- "(?:", esc_quote, # a quoted field
- "(?>[^", esc_quote, "]*)", # "unrolling the loop"
- "(?>", esc_quote * 2, # double for escaping
- "[^", esc_quote, "]*)*",
- esc_quote, # the closing quote
- "[^", esc_quote, "]", # an extra character
- "|", # ... or ...
- "[^", esc_quote, esc_col_sep, "]+", # an unquoted field
- esc_quote, ")" # an extra quote
- ),
+ # for detecting parse errors
+ quote_or_nl: encode_re("[", esc_quote, "\r\n]"),
+ nl_or_lf: encode_re("[\r\n]"),
+ stray_quote: encode_re( "[^", esc_quote, "]", esc_quote,
+ "[^", esc_quote, "]" ),
# safer than chomp!()
line_end: encode_re(esc_row_sep, "\\z"),
# illegal unquoted characters
return_newline: encode_str("\r\n")
}
end
-
- #
+
+ #
# Loads any converters requested during construction.
- #
+ #
# If +field_name+ is set <tt>:converters</tt> (the default) field converters
# are set. When +field_name+ is <tt>:header_converters</tt> header converters
# are added instead.
- #
- # The <tt>:unconverted_fields</tt> option is also actived for
+ #
+ # The <tt>:unconverted_fields</tt> option is also actived for
# <tt>:converters</tt> calls, if requested.
- #
+ #
def init_converters(options, field_name = :converters)
if field_name == :converters
@unconverted_fields = options.delete(:unconverted_fields)
end
instance_variable_set("@#{field_name}", Array.new)
-
+
# find the correct method to add the converters
convert = method(field_name.to_s.sub(/ers\Z/, ""))
-
+
# load converters
unless options[field_name].nil?
# allow a single converter not wrapped in an Array
@@ -2120,10 +2117,10 @@
end
end
end
-
+
options.delete(field_name)
end
-
+
# Stores header row settings and loads header converters, if needed.
def init_headers(options)
@use_headers = options.delete(:headers)
@@ -2132,18 +2129,18 @@
# headers must be delayed until shift(), in case they need a row of content
@headers = nil
-
+
init_converters(options, :header_converters)
end
-
- #
+
+ #
# The actual work method for adding converters, used by both CSV.convert() and
# CSV.header_convert().
- #
+ #
# This method requires the +var_name+ of the instance variable to place the
# converters in, the +const+ Hash to lookup named converters in, and the
# normal parameters of the CSV.convert() and CSV.header_convert() methods.
- #
+ #
def add_converter(var_name, const, name = nil, &converter)
if name.nil? # custom converter
instance_variable_get("@#{var_name}") << converter
@@ -2159,18 +2156,18 @@
end
end
end
-
- #
+
+ #
# Processes +fields+ with <tt>@converters</tt>, or <tt>@header_converters</tt>
# if +headers+ is passed as +true+, returning the converted field set. Any
# converter that changes the field into something other than a String halts
# the pipeline of conversion for that field. This is primarily an efficiency
# shortcut.
- #
+ #
def convert_fields(fields, headers = false)
# see if we are converting headers or fields
converters = headers ? @header_converters : @converters
-
+
fields.map.with_index do |field, index|
converters.each do |converter|
field = if converter.arity == 1 # straight field converter
@@ -2184,17 +2181,17 @@
field # final state of each field, converted or original
end
end
-
- #
+
+ #
# This methods is used to turn a finished +row+ into a CSV::Row. Header rows
# are also dealt with here, either by returning a CSV::Row with identical
# headers and fields (save that the fields do not go through the converters)
# or by reading past them to return a field row. Headers are also saved in
# <tt>@headers</tt> for use in future rows.
- #
+ #
# When +nil+, +row+ is assumed to be a header row not based on an actual row
# of the stream.
- #
+ #
def parse_headers(row = nil)
if @headers.nil? # header row
@headers = case @use_headers # save headers
@@ -2209,11 +2206,11 @@
# first row is headers
else row
end
-
+
# prepare converted and unconverted copies
row = @headers if row.nil?
@headers = convert_fields(@headers, true)
-
+
if @return_headers # return headers
return self.class::Row.new(@headers, row, true)
elsif not [Array, String].include? @use_headers.class # skip to field row
@@ -2223,12 +2220,12 @@
self.class::Row.new(@headers, convert_fields(row)) # field row
end
-
- #
+
+ #
# Thiw methods injects an instance variable <tt>unconverted_fields</tt> into
# +row+ and an accessor method for it called unconverted_fields(). The
# variable is set to the contents of +fields+.
- #
+ #
def add_unconverted_fields(row, fields)
class << row
attr_reader :unconverted_fields
@@ -2236,45 +2233,46 @@
row.instance_eval { @unconverted_fields = fields }
row
end
-
- #
- # This method is an encoding safe version of Regexp::escape(). I will escape
+
+ #
+ # This method is an encoding safe version of Regexp::escape(). It will escape
# any characters that would change the meaning of a regular expression in the
# encoding of +str+. Regular expression characters that cannot be transcoded
- # to the target encodign will be skipped and no escaping will be performed if
+ # to the target encoding will be skipped and no escaping will be performed if
# a backslash cannot be transcoded.
- #
+ #
def escape_re(str)
str.chars.map { |c| @re_chars.include?(c) ? @re_esc + c : c }.join
end
-
- #
+
+ #
# Builds a regular expression in <tt>@encoding</tt>. All +chunks+ will be
# transcoded to that encoding.
- #
+ #
def encode_re(*chunks)
Regexp.new(encode_str(*chunks))
end
-
- #
+
+ #
# Builds a String in <tt>@encoding</tt>. All +chunks+ will be transcoded to
# that encoding.
- #
+ #
def encode_str(*chunks)
chunks.map { |chunk| chunk.encode(@encoding.name) }.join
end
- #
+ #
# Reads at least +bytes+ from <tt>@io</tt>, but will read up 10 bytes ahead if
# needed to ensure the data read is valid in the ecoding of that data. This
# should ensure that it is safe to use regular expressions on the read data,
# unless it is actually a broken encoding. The read data will be returned in
# <tt>@encoding</tt>.
- #
+ #
def read_to_char(bytes)
return "" if @io.eof?
- data = @io.read(bytes)
+ data = read_io(bytes)
begin
+ raise unless data.valid_encoding?
encoded = encode_str(data)
raise unless encoded.valid_encoding?
return encoded
@@ -2282,13 +2280,28 @@
if @io.eof? or data.size >= bytes + 10
return data
else
- data += @io.read(1) until data.valid_encoding? or
- @io.eof? or
- data.size >= bytes + 10
+ data += read_io(1)
retry
end
end
end
+
+ private
+ def raw_encoding
+ if @io.respond_to? :internal_encoding
+ @io.internal_encoding || @io.external_encoding
+ elsif @io.is_a? StringIO
+ @io.string.encoding
+ elsif @io.respond_to? :encoding
+ @io.encoding
+ else
+ Encoding::ASCII_8BIT
+ end
+ end
+
+ def read_io(bytes)
+ @io.read(bytes).force_encoding(raw_encoding)
+ end
end
# Another name for CSV::instance().
Modified: MacRuby/trunk/lib/date/format.rb
===================================================================
--- MacRuby/trunk/lib/date/format.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/date/format.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,4 +1,4 @@
-# format.rb: Written by Tadayoshi Funaba 1999-2008
+# format.rb: Written by Tadayoshi Funaba 1999-2009
# $Id: format.rb,v 2.43 2008-01-17 20:16:31+09 tadf Exp $
class Date
@@ -563,8 +563,8 @@
end
else
case c
- when /\A[\s\v]/
- str.sub!(/\A[\s\v]+/, '')
+ when /\A\s/
+ str.sub!(/\A\s+/, '')
else
return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
end
Modified: MacRuby/trunk/lib/date.rb
===================================================================
--- MacRuby/trunk/lib/date.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/date.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,7 +1,7 @@
#
# date.rb - date and time library
#
-# Author: Tadayoshi Funaba 1998-2008
+# Author: Tadayoshi Funaba 1998-2010
#
# Documentation: William Webber <william at williamwebber.com>
#
@@ -927,7 +927,7 @@
elem[e] = d.__send__(e)
end
elem[:wnum1] ||= 0
- elem[:wday] ||= 0
+ elem[:wday] ||= 1
end
end
@@ -1371,6 +1371,12 @@
case other
when Numeric; return @ajd <=> other
when Date; return @ajd <=> other.ajd
+ else
+ begin
+ l, r = other.coerce(self)
+ return l <=> r
+ rescue NoMethodError
+ end
end
nil
end
@@ -1385,6 +1391,9 @@
case other
when Numeric; return jd == other
when Date; return jd == other.jd
+ else
+ l, r = other.coerce(self)
+ return l === r
end
false
end
@@ -1407,7 +1416,10 @@
y, m = (year * 12 + (mon - 1) + n).divmod(12)
m, = (m + 1) .divmod(1)
d = mday
- d -= 1 until jd2 = _valid_civil?(y, m, d, @sg)
+ until jd2 = _valid_civil?(y, m, d, @sg)
+ d -= 1
+ raise ArgumentError, 'invalid date' unless d > 0
+ end
self + (jd2 - jd)
end
@@ -1775,7 +1787,7 @@
def to_datetime
jd = DateTime.__send__(:civil_to_jd, year, mon, mday, DateTime::ITALY)
fr = DateTime.__send__(:time_to_day_fraction, hour, min, [sec, 59].min) +
- Rational(nsec, 86400_000_000_000)
+ Rational(subsec, 86400)
of = Rational(utc_offset, 86400)
DateTime.new!(DateTime.__send__(:jd_to_ajd, jd, fr, of),
of, DateTime::ITALY)
@@ -1805,7 +1817,7 @@
t = Time.now
jd = civil_to_jd(t.year, t.mon, t.mday, sg)
fr = time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) +
- Rational(t.nsec, 86400_000_000_000)
+ Rational(t.subsec, 86400)
of = Rational(t.utc_offset, 86400)
new!(jd_to_ajd(jd, fr, of), of, sg)
end
Modified: MacRuby/trunk/lib/drb/drb.rb
===================================================================
--- MacRuby/trunk/lib/drb/drb.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/drb/drb.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -18,7 +18,7 @@
#
# The Ruby standard library contains the core classes of the dRuby package.
# However, the full package also includes access control lists and the
-# Rinda tuple-space distributed task management system, as well as a
+# Rinda tuple-space distributed task management system, as well as a
# large number of samples. The full dRuby package can be downloaded from
# the dRuby home page (see *References*).
#
@@ -121,7 +121,7 @@
# are forwarded to the local object, as described in the discussion of
# DRbObjects. This has semantics similar to the normal Ruby
# pass-by-reference.
-#
+#
# The easiest way to signal that we want an otherwise marshallable
# object to be passed or returned as a DRbObject reference, rather
# than marshalled and sent as a copy, is to include the
@@ -135,7 +135,7 @@
# passed back to the remote execution context to be collected, before
# the collected values are finally returned to the local context as
# the return value of the method invocation.
-#
+#
# == Examples of usage
#
# For more dRuby samples, see the +samples+ directory in the full
@@ -148,33 +148,33 @@
# starting the server code first.
#
# ==== Server code
-#
+#
# require 'drb/drb'
-#
+#
# # The URI for the server to connect to
-# URI="druby://localhost:8787"
-#
+# URI="druby://localhost:8787"
+#
# class TimeServer
-#
+#
# def get_current_time
# return Time.now
# end
-#
+#
# end
-#
+#
# # The object that handles requests on the server
# FRONT_OBJECT=TimeServer.new
#
# $SAFE = 1 # disable eval() and friends
-#
+#
# DRb.start_service(URI, FRONT_OBJECT)
# # Wait for the drb server thread to finish before exiting.
# DRb.thread.join
#
# ==== Client code
-#
+#
# require 'drb/drb'
-#
+#
# # The URI to connect to
# SERVER_URI="druby://localhost:8787"
#
@@ -184,43 +184,43 @@
# # as soon as we pass a non-marshallable object as an argument
# # to a dRuby call.
# DRb.start_service
-#
+#
# timeserver = DRbObject.new_with_uri(SERVER_URI)
-# puts timeserver.get_current_time
+# puts timeserver.get_current_time
#
# === Remote objects under dRuby
#
# This example illustrates returning a reference to an object
# from a dRuby call. The Logger instances live in the server
# process. References to them are returned to the client process,
-# where methods can be invoked upon them. These methods are
+# where methods can be invoked upon them. These methods are
# executed in the server process.
#
# ==== Server code
-#
+#
# require 'drb/drb'
-#
+#
# URI="druby://localhost:8787"
-#
+#
# class Logger
#
# # Make dRuby send Logger instances as dRuby references,
# # not copies.
# include DRb::DRbUndumped
-#
+#
# def initialize(n, fname)
# @name = n
# @filename = fname
# end
-#
+#
# def log(message)
# File.open(@filename, "a") do |f|
# f.puts("#{Time.now}: #{@name}: #{message}")
# end
# end
-#
+#
# end
-#
+#
# # We have a central object for creating and retrieving loggers.
# # This retains a local reference to all loggers created. This
# # is so an existing logger can be looked up by name, but also
@@ -228,12 +228,12 @@
# # reference to an object is not sufficient to prevent it being
# # garbage collected!
# class LoggerFactory
-#
+#
# def initialize(bdir)
# @basedir = bdir
# @loggers = {}
# end
-#
+#
# def get_logger(name)
# if !@loggers.has_key? name
# # make the filename safe, then declare it to be so
@@ -242,34 +242,34 @@
# end
# return @loggers[name]
# end
-#
+#
# end
-#
+#
# FRONT_OBJECT=LoggerFactory.new("/tmp/dlog")
#
# $SAFE = 1 # disable eval() and friends
-#
+#
# DRb.start_service(URI, FRONT_OBJECT)
# DRb.thread.join
#
# ==== Client code
#
# require 'drb/drb'
-#
+#
# SERVER_URI="druby://localhost:8787"
#
# DRb.start_service
-#
+#
# log_service=DRbObject.new_with_uri(SERVER_URI)
-#
+#
# ["loga", "logb", "logc"].each do |logname|
-#
+#
# logger=log_service.get_logger(logname)
-#
+#
# logger.log("Hello, world!")
# logger.log("Goodbye, world!")
# logger.log("=== EOT ===")
-#
+#
# end
#
# == Security
@@ -288,9 +288,9 @@
# ro.instance_eval("`rm -rf *`")
#
# The dangers posed by instance_eval and friends are such that a
-# DRbServer should generally be run with $SAFE set to at least
-# level 1. This will disable eval() and related calls on strings
-# passed across the wire. The sample usage code given above follows
+# DRbServer should generally be run with $SAFE set to at least
+# level 1. This will disable eval() and related calls on strings
+# passed across the wire. The sample usage code given above follows
# this practice.
#
# A DRbServer can be configured with an access control list to
@@ -360,7 +360,7 @@
#
# This, the default implementation, uses an object's local ObjectSpace
# __id__ as its id. This means that an object's identification over
- # drb remains valid only while that object instance remains alive
+ # drb remains valid only while that object instance remains alive
# within the server runtime.
#
# For alternative mechanisms, see DRb::TimerIdConv in rdb/timeridconv.rb
@@ -374,7 +374,7 @@
def to_obj(ref)
ObjectSpace._id2ref(ref)
end
-
+
# Convert an object into a reference id.
#
# This implementation returns the object's __id__ in the local
@@ -390,7 +390,7 @@
# called over drb, then the object remains in the server space
# and a reference to the object is returned, rather than the
# object being marshalled and moved into the client space.
- module DRbUndumped
+ module DRbUndumped
def _dump(dummy) # :nodoc:
raise TypeError, 'can\'t dump'
end
@@ -424,7 +424,7 @@
def self._load(s) # :nodoc:
Marshal::load(s)
end
-
+
def _dump(lv) # :nodoc:
Marshal::dump(@unknown)
end
@@ -456,11 +456,11 @@
# +name+ attribute. The marshalled object is held in the +buf+
# attribute.
class DRbUnknown
-
+
# Create a new DRbUnknown object.
#
# +buf+ is a string containing a marshalled object that could not
- # be unmarshalled. +err+ is the error message that was raised
+ # be unmarshalled. +err+ is the error message that was raised
# when the unmarshalling failed. It is used to determine the
# name of the unmarshalled object.
def initialize(err, buf)
@@ -499,7 +499,7 @@
# Attempt to load the wrapped marshalled object again.
#
# If the class of the object is now known locally, the object
- # will be unmarshalled and returned. Otherwise, a new
+ # will be unmarshalled and returned. Otherwise, a new
# but identical DRbUnknown object will be returned.
def reload
self.class._load(@buf)
@@ -513,7 +513,7 @@
class DRbArray
def initialize(ary)
- @ary = ary.collect { |obj|
+ @ary = ary.collect { |obj|
if obj.kind_of? DRbUndumped
DRbObject.new(obj)
else
@@ -607,7 +607,7 @@
rescue
raise(DRbConnError, $!.message, $!.backtrace)
end
-
+
def recv_request(stream) # :nodoc:
ref = load(stream)
ro = DRb.to_obj(ref)
@@ -656,10 +656,10 @@
# using configuration +config+. Return a
# protocol instance for this listener.
# [uri_option(uri, config)] Take a URI, possibly containing an option
- # component (e.g. a trailing '?param=val'),
+ # component (e.g. a trailing '?param=val'),
# and return a [uri, option] tuple.
#
- # All of these methods should raise a DRbBadScheme error if the URI
+ # All of these methods should raise a DRbBadScheme error if the URI
# does not identify the protocol they support (e.g. "druby:" for
# the standard Ruby protocol). This is how the DRbProtocol module,
# given a URI, determines which protocol implementation serves that
@@ -675,14 +675,14 @@
#
# The protocol instance returned by #open must have the following methods:
#
- # [send_request (ref, msg_id, arg, b)]
+ # [send_request (ref, msg_id, arg, b)]
# Send a request to +ref+ with the given message id and arguments.
# This is most easily implemented by calling DRbMessage.send_request,
# providing a stream that sits on top of the current protocol.
# [recv_reply]
# Receive a reply from the server and return it as a [success-boolean,
# reply-value] pair. This is most easily implemented by calling
- # DRb.recv_reply, providing a stream that sits on top of the
+ # DRb.recv_reply, providing a stream that sits on top of the
# current protocol.
# [alive?]
# Is this connection still alive?
@@ -725,7 +725,7 @@
# URI by raising a DRbBadScheme error. If no protocol recognises the
# URI, then a DRbBadURI error is raised. If a protocol accepts the
# URI, but an error occurs in opening it, a DRbConnError is raised.
- def open(uri, config, first=true)
+ def open(uri, config, first=true)
@protocol.each do |prot|
begin
return prot.open(uri, config)
@@ -744,14 +744,14 @@
end
module_function :open
- # Open a server listening for connections at +uri+ with
+ # Open a server listening for connections at +uri+ with
# configuration +config+.
#
# The DRbProtocol module asks each registered protocol in turn to
- # try to open a server at the URI. Each protocol signals that it does
- # not handle that URI by raising a DRbBadScheme error. If no protocol
- # recognises the URI, then a DRbBadURI error is raised. If a protocol
- # accepts the URI, but an error occurs in opening it, the underlying
+ # try to open a server at the URI. Each protocol signals that it does
+ # not handle that URI by raising a DRbBadScheme error. If no protocol
+ # recognises the URI, then a DRbBadURI error is raised. If a protocol
+ # accepts the URI, but an error occurs in opening it, the underlying
# error is passed on to the caller.
def open_server(uri, config, first=true)
@protocol.each do |prot|
@@ -773,7 +773,7 @@
# The DRbProtocol module asks each registered protocol in turn to
# try to parse the URI. Each protocol signals that it does not handle that
# URI by raising a DRbBadScheme error. If no protocol recognises the
- # URI, then a DRbBadURI error is raised.
+ # URI, then a DRbBadURI error is raised.
def uri_option(uri, config, first=true)
@protocol.each do |prot|
begin
@@ -837,23 +837,18 @@
end
def self.open_server_inaddr_any(host, port)
- infos = Socket::getaddrinfo(host, nil,
+ infos = Socket::getaddrinfo(host, nil,
Socket::AF_UNSPEC,
- Socket::SOCK_STREAM,
+ Socket::SOCK_STREAM,
0,
Socket::AI_PASSIVE)
- family = infos.collect { |af, *_| af }.uniq
- case family
- when ['AF_INET']
- return TCPServer.open('0.0.0.0', port)
- when ['AF_INET6']
- return TCPServer.open('::', port)
- else
- return TCPServer.open(port)
- end
+ families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
+ return TCPServer.open('0.0.0.0', port) if families.has_key?('AF_INET')
+ return TCPServer.open('::', port) if families.has_key?('AF_INET6')
+ return TCPServer.open(port)
end
- # Open a server listening for connections at +uri+ using
+ # Open a server listening for connections at +uri+ using
# configuration +config+.
def self.open_server(uri, config)
uri = 'druby://:0' unless uri
@@ -899,7 +894,7 @@
def peeraddr
@socket.peeraddr
end
-
+
# Get the socket.
def stream; @socket; end
@@ -907,7 +902,7 @@
def send_request(ref, msg_id, arg, b)
@msg.send_request(stream, ref, msg_id, arg, b)
end
-
+
# On the server side, receive a request from the client.
def recv_request
@msg.recv_request(stream)
@@ -937,14 +932,14 @@
@socket = nil
end
end
-
- # On the server side, for an instance returned by #open_server,
+
+ # On the server side, for an instance returned by #open_server,
# accept a client connection and return a new instance to handle
# the server's side of this client-server session.
def accept
while true
s = @socket.accept
- break if (@acl ? @acl.allow_socket?(s) : true)
+ break if (@acl ? @acl.allow_socket?(s) : true)
s.close
end
if @config[:tcp_original_host].to_s.size == 0
@@ -981,16 +976,16 @@
end
attr :option
def to_s; @option; end
-
+
def ==(other)
return false unless DRbURIOption === other
@option == other.option
end
-
+
def hash
@option.hash
end
-
+
alias eql? ==
end
@@ -1007,7 +1002,7 @@
# created to act as a stub for the remote referenced object.
def self._load(s)
uri, ref = Marshal.load(s)
-
+
if DRb.here?(uri)
obj = DRb.to_obj(ref)
if ((! obj.tainted?) && Thread.current[:drb_untaint])
@@ -1057,7 +1052,7 @@
end
# Get the URI of the remote object.
- def __drburi
+ def __drburi
@uri
end
@@ -1085,7 +1080,7 @@
if DRb.here?(@uri)
obj = DRb.to_obj(@ref)
DRb.current_server.check_insecure_method(obj, msg_id)
- return obj.__send__(msg_id, *a, &b)
+ return obj.__send__(msg_id, *a, &b)
end
succ, result = self.class.with_friend(@uri) do
@@ -1108,7 +1103,7 @@
def self.with_friend(uri)
friend = DRb.fetch_server(uri)
return yield() unless friend
-
+
save = Thread.current['DRb']
Thread.current['DRb'] = { 'server' => friend }
return yield
@@ -1120,7 +1115,7 @@
prefix = "(#{uri}) "
bt = []
result.backtrace.each do |x|
- break if /`__send__'$/ =~ x
+ break if /`__send__'$/ =~ x
if /^\(druby:\/\// =~ x
bt.push(x)
else
@@ -1271,14 +1266,14 @@
def self.verbose=(on)
@@verbose = on
end
-
+
# Get the default value of the :verbose option.
def self.verbose
@@verbose
end
def self.make_config(hash={}) # :nodoc:
- default_config = {
+ default_config = {
:idconv => @@idconv,
:verbose => @@verbose,
:tcp_acl => @@acl,
@@ -1368,7 +1363,7 @@
attr_reader :thread
# The front object of the DRbServer.
- #
+ #
# This object receives remote method calls made on the server's
# URI alone, with an object id.
attr_reader :front
@@ -1399,7 +1394,7 @@
if Thread.current['DRb'] && Thread.current['DRb']['server'] == self
Thread.current['DRb']['stop_service'] = true
else
- @thread.kill
+ @thread.kill.join
end
end
@@ -1461,7 +1456,7 @@
def any_to_s(obj)
obj.to_s + ":#{obj.class}"
rescue
- sprintf("#<%s:0x%lx>", obj.class, obj.__id__)
+ sprintf("#<%s:0x%lx>", obj.class, obj.__id__)
end
# Check that a method is callable via dRuby.
@@ -1469,14 +1464,14 @@
# +obj+ is the object we want to invoke the method on. +msg_id+ is the
# method name, as a Symbol.
#
- # If the method is an insecure method (see #insecure_method?) a
+ # If the method is an insecure method (see #insecure_method?) a
# SecurityError is thrown. If the method is private or undefined,
# a NameError is thrown.
def check_insecure_method(obj, msg_id)
return true if Proc === obj && msg_id == :__drb_yield
raise(ArgumentError, "#{any_to_s(msg_id)} is not a symbol") unless Symbol == msg_id.class
raise(SecurityError, "insecure method `#{msg_id}'") if insecure_method?(msg_id)
-
+
if obj.private_methods.include?(msg_id)
desc = any_to_s(obj)
raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
@@ -1488,7 +1483,7 @@
end
end
public :check_insecure_method
-
+
class InvokeMethod # :nodoc:
def initialize(drb_server, client)
@drb_server = drb_server
@@ -1510,7 +1505,7 @@
perform_with_block
}.value
else
- @result = Thread.new {
+ @result = Thread.new {
Thread.current['DRb'] = info
$SAFE = @safe_level
perform_without_block
@@ -1525,7 +1520,7 @@
end
@succ = true
if @msg_id == :to_ary && @result.class == Array
- @result = DRbArray.new(@result)
+ @result = DRbArray.new(@result)
end
return @succ, @result
rescue StandardError, ScriptError, Interrupt
@@ -1541,7 +1536,7 @@
@argv = argv
@block = block
end
-
+
def check_insecure_method
@drb_server.check_insecure_method(@obj, @msg_id)
end
@@ -1550,7 +1545,7 @@
init_with_client
check_insecure_method
end
-
+
def perform_without_block
if Proc === @obj && @msg_id == :__drb_yield
if @argv.size == 1
@@ -1638,7 +1633,7 @@
# The primary local dRuby server.
#
- # This is the server created by the #start_service call.
+ # This is the server created by the #start_service call.
attr_accessor :primary_server
module_function :primary_server=, :primary_server
@@ -1653,8 +1648,8 @@
# If the above rule fails to find a server, a DRbServerNotFound
# error is raised.
def current_server
- drb = Thread.current['DRb']
- server = (drb && drb['server']) ? drb['server'] : @primary_server
+ drb = Thread.current['DRb']
+ server = (drb && drb['server']) ? drb['server'] : @primary_server
raise DRbServerNotFound unless server
return server
end
@@ -1700,7 +1695,7 @@
DRbServer.make_config
end
module_function :config
-
+
# Get the front object of the current server.
#
# This raises a DRbServerNotFound error if there is no current server.
@@ -1771,7 +1766,7 @@
@server.delete(server.uri)
end
module_function :remove_server
-
+
def fetch_server(uri)
@server[uri]
end
Modified: MacRuby/trunk/lib/drb/eq.rb
===================================================================
--- MacRuby/trunk/lib/drb/eq.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/drb/eq.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,3 @@
-require 'drb/drb'
-
module DRb
class DRbObject
def ==(other)
Modified: MacRuby/trunk/lib/drb/extserv.rb
===================================================================
--- MacRuby/trunk/lib/drb/extserv.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/drb/extserv.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,6 +1,6 @@
=begin
external service
- Copyright (c) 2000,2002 Masatoshi SEKI
+ Copyright (c) 2000,2002 Masatoshi SEKI
=end
require 'drb/drb'
Modified: MacRuby/trunk/lib/drb/extservm.rb
===================================================================
--- MacRuby/trunk/lib/drb/extservm.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/drb/extservm.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,6 +1,6 @@
=begin
external service manager
- Copyright (c) 2000 Masatoshi SEKI
+ Copyright (c) 2000 Masatoshi SEKI
=end
require 'drb/drb'
@@ -21,7 +21,7 @@
def self.command=(cmd)
@@command = cmd
end
-
+
def initialize
super()
@cond = new_cond
@@ -51,7 +51,7 @@
end
self
end
-
+
def unregist(name)
synchronize do
@servers.delete(name)
@@ -79,11 +79,7 @@
@servers[name] = false
end
uri = @uri || DRb.uri
- if RUBY_PLATFORM =~ /mswin32/ && /NT/ =~ ENV["OS"]
- system(%Q'cmd /c start "ruby" /b #{command} #{uri} #{name}')
- else
- system("#{command} #{uri} #{name} &")
- end
+ Process.detach spawn("#{command} #{uri} #{name}")
end
end
end
Modified: MacRuby/trunk/lib/drb/invokemethod.rb
===================================================================
--- MacRuby/trunk/lib/drb/invokemethod.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/drb/invokemethod.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -9,7 +9,7 @@
end
block_value = @block.call(*x)
end
-
+
def perform_with_block
@obj.__send__(@msg_id, *@argv) do |*x|
jump_error = nil
Modified: MacRuby/trunk/lib/drb/observer.rb
===================================================================
--- MacRuby/trunk/lib/drb/observer.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/drb/observer.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -6,16 +6,16 @@
def notify_observers(*arg)
if defined? @observer_state and @observer_state
- if defined? @observer_peers
- for i in @observer_peers.dup
- begin
- i.update(*arg)
- rescue
- delete_observer(i)
- end
- end
- end
- @observer_state = false
+ if defined? @observer_peers
+ @observer_peers.each do |observer, method|
+ begin
+ observer.send(method, *arg)
+ rescue
+ delete_observer(observer)
+ end
+ end
+ end
+ @observer_state = false
end
end
end
Modified: MacRuby/trunk/lib/drb/ssl.rb
===================================================================
--- MacRuby/trunk/lib/drb/ssl.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/drb/ssl.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -15,7 +15,7 @@
:SSLClientCA => nil,
:SSLCACertificatePath => nil,
:SSLCACertificateFile => nil,
- :SSLVerifyMode => ::OpenSSL::SSL::VERIFY_NONE,
+ :SSLVerifyMode => ::OpenSSL::SSL::VERIFY_NONE,
:SSLVerifyDepth => nil,
:SSLVerifyCallback => nil, # custom verification
:SSLCertificateStore => nil,
@@ -31,7 +31,7 @@
@ssl_ctx = nil
end
- def [](key);
+ def [](key);
@config[key] || DEFAULT[key]
end
@@ -41,14 +41,14 @@
ssl.connect
ssl
end
-
+
def accept(tcp)
ssl = OpenSSL::SSL::SSLSocket.new(tcp, @ssl_ctx)
ssl.sync = true
ssl.accept
ssl
end
-
+
def setup_certificate
if @cert && @pkey
return
@@ -77,7 +77,7 @@
cert.not_before = Time.now
cert.not_after = Time.now + (365*24*60*60)
cert.public_key = rsa.public_key
-
+
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
cert.extensions = [
ef.create_extension("basicConstraints","CA:FALSE"),
@@ -89,7 +89,7 @@
cert.add_extension(ef.create_extension("nsComment", comment))
end
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
-
+
@cert = cert
@pkey = rsa
end
@@ -143,7 +143,7 @@
end
port = soc.addr[1] if port == 0
@uri = "drbssl://#{host}:#{port}"
-
+
ssl_conf = SSLConfig.new(config)
ssl_conf.setup_certificate
ssl_conf.setup_ssl_context
@@ -159,7 +159,7 @@
@ssl = is_established ? soc : nil
super(uri, soc.to_io, config)
end
-
+
def stream; @ssl; end
def close
@@ -169,12 +169,12 @@
end
super
end
-
+
def accept
begin
while true
soc = @socket.accept
- break if (@acl ? @acl.allow_socket?(soc) : true)
+ break if (@acl ? @acl.allow_socket?(soc) : true)
soc.close
end
ssl = @config.accept(soc)
@@ -185,6 +185,6 @@
end
end
end
-
+
DRbProtocol.add_protocol(DRbSSLSocket)
end
Modified: MacRuby/trunk/lib/drb/timeridconv.rb
===================================================================
--- MacRuby/trunk/lib/drb/timeridconv.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/drb/timeridconv.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -19,7 +19,7 @@
end
def add(obj)
- synchronize do
+ synchronize do
key = obj.__id__
@curr[key] = obj
return key
@@ -27,7 +27,7 @@
end
def fetch(key, dv=@sentinel)
- synchronize do
+ synchronize do
obj = peek(key)
if obj == @sentinel
return dv unless dv == @sentinel
@@ -39,7 +39,7 @@
end
def include?(key)
- synchronize do
+ synchronize do
obj = peek(key)
return false if obj == @sentinel
true
@@ -47,7 +47,7 @@
end
def peek(key)
- synchronize do
+ synchronize do
return @curr.fetch(key, @renew.fetch(key, @gc.fetch(key, @sentinel)))
end
end
Modified: MacRuby/trunk/lib/drb/unix.rb
===================================================================
--- MacRuby/trunk/lib/drb/unix.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/drb/unix.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -8,7 +8,7 @@
class DRbUNIXSocket < DRbTCPSocket
def self.parse_uri(uri)
- if /^drbunix:(.*?)(\?(.*))?$/ =~ uri
+ if /^drbunix:(.*?)(\?(.*))?$/ =~ uri
filename = $1
option = $3
[filename, option]
@@ -59,7 +59,7 @@
@server_mode = server_mode
@acl = nil
end
-
+
# import from tempfile.rb
Max_try = 10
private
Modified: MacRuby/trunk/lib/e2mmap.rb
===================================================================
--- MacRuby/trunk/lib/e2mmap.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/e2mmap.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -56,7 +56,7 @@
super
cl.bind(self) unless cl < E2MM
end
-
+
def bind(cl)
self.module_eval %[
def Raise(err = nil, *rest)
@@ -88,7 +88,7 @@
def def_e2message(c, m)
E2MM.def_e2message(self, c, m)
end
-
+
# def_exception(n, m, s)
# n: exception_name
# m: message_form
@@ -115,7 +115,7 @@
E2MM.instance_eval{@MessageMap[[k, c]] = m}
c
end
-
+
# E2MM.def_exception(k, n, m, s)
# k: class to define exception under.
# n: exception_name
@@ -146,7 +146,7 @@
E2MM.Fail E2MM, ErrNotRegisteredException, err.inspect
end
end
- class <<E2MM
+ class << E2MM
alias Fail Raise
end
@@ -160,12 +160,12 @@
end
nil
end
- class <<self
+ class << self
alias message e2mm_message
end
- E2MM.def_exception(E2MM,
- :ErrNotRegisteredException,
+ E2MM.def_exception(E2MM,
+ :ErrNotRegisteredException,
"not registerd exception(%s)")
end
Modified: MacRuby/trunk/lib/erb.rb
===================================================================
--- MacRuby/trunk/lib/erb.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/erb.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -10,251 +10,251 @@
#
# You can redistribute it and/or modify it under the same terms as Ruby.
-=begin rdoc
-= ERB -- Ruby Templating
-
-== Introduction
-
-ERB provides an easy to use but powerful templating system for Ruby. Using
-ERB, actual Ruby code can be added to any plain text document for the
-purposes of generating document information details and/or flow control.
-
-A very simple example is this:
-
- require 'erb'
-
- x = 42
- template = ERB.new <<-EOF
- The value of x is: <%= x %>
- EOF
- puts template.result(binding)
-
-<em>Prints:</em> The value of x is: 42
-
-More complex examples are given below.
-
-
-== Recognized Tags
-
-ERB recognizes certain tags in the provided template and converts them based
-on the rules below:
-
- <% Ruby code -- inline with output %>
- <%= Ruby expression -- replace with result %>
- <%# comment -- ignored -- useful in testing %>
- % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
- %% replaced with % if first thing on a line and % processing is used
- <%% or %%> -- replace with <% or %> respectively
-
-All other text is passed through ERB filtering unchanged.
-
-
-== Options
-
-There are several settings you can change when you use ERB:
-* the nature of the tags that are recognized;
-* the value of <tt>$SAFE</tt> under which the template is run;
-* the binding used to resolve local variables in the template.
-
-See the ERB.new and ERB#result methods for more detail.
-
-== Character encodings
-
-ERB (or ruby code generated by ERB) returns a string in the same
-character encoding as the input string. When the input string has
-a magic comment, however, it returns a string in the encoding specified
-by the magic comment.
-
- # -*- coding: UTF-8 -*-
- require 'erb'
-
- template = ERB.new <<EOF
- <%#-*- coding: Big5 -*-%>
- \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
- EOF
- puts template.result
-
-<em>Prints:</em> \_\_ENCODING\_\_ is Big5.
-
-
-== Examples
-
-=== Plain Text
-
-ERB is useful for any generic templating situation. Note that in this example, we use the
-convenient "% at start of line" tag, and we quote the template literally with
-<tt>%q{...}</tt> to avoid trouble with the backslash.
-
- require "erb"
-
- # Create template.
- template = %q{
- From: James Edward Gray II <james at grayproductions.net>
- To: <%= to %>
- Subject: Addressing Needs
-
- <%= to[/\w+/] %>:
-
- Just wanted to send a quick note assuring that your needs are being
- addressed.
-
- I want you to know that my team will keep working on the issues,
- especially:
-
- <%# ignore numerous minor requests -- focus on priorities %>
- % priorities.each do |priority|
- * <%= priority %>
- % end
-
- Thanks for your patience.
-
- James Edward Gray II
- }.gsub(/^ /, '')
-
- message = ERB.new(template, 0, "%<>")
-
- # Set up template data.
- to = "Community Spokesman <spokesman at ruby_community.org>"
- priorities = [ "Run Ruby Quiz",
- "Document Modules",
- "Answer Questions on Ruby Talk" ]
-
- # Produce result.
- email = message.result
- puts email
-
-<i>Generates:</i>
-
- From: James Edward Gray II <james at grayproductions.net>
- To: Community Spokesman <spokesman at ruby_community.org>
- Subject: Addressing Needs
-
- Community:
-
- Just wanted to send a quick note assuring that your needs are being addressed.
-
- I want you to know that my team will keep working on the issues, especially:
-
- * Run Ruby Quiz
- * Document Modules
- * Answer Questions on Ruby Talk
-
- Thanks for your patience.
-
- James Edward Gray II
-
-=== Ruby in HTML
-
-ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby). Notice the need in
-this example to provide a special binding when the template is run, so that the instance
-variables in the Product object can be resolved.
-
- require "erb"
-
- # Build template data class.
- class Product
- def initialize( code, name, desc, cost )
- @code = code
- @name = name
- @desc = desc
- @cost = cost
-
- @features = [ ]
- end
-
- def add_feature( feature )
- @features << feature
- end
-
- # Support templating of member data.
- def get_binding
- binding
- end
-
- # ...
- end
-
- # Create template.
- template = %{
- <html>
- <head><title>Ruby Toys -- <%= @name %></title></head>
- <body>
-
- <h1><%= @name %> (<%= @code %>)</h1>
- <p><%= @desc %></p>
-
- <ul>
- <% @features.each do |f| %>
- <li><b><%= f %></b></li>
- <% end %>
- </ul>
-
- <p>
- <% if @cost < 10 %>
- <b>Only <%= @cost %>!!!</b>
- <% else %>
- Call for a price, today!
- <% end %>
- </p>
-
- </body>
- </html>
- }.gsub(/^ /, '')
-
- rhtml = ERB.new(template)
-
- # Set up template data.
- toy = Product.new( "TZ-1002",
- "Rubysapien",
- "Geek's Best Friend! Responds to Ruby commands...",
- 999.95 )
- toy.add_feature("Listens for verbal commands in the Ruby language!")
- toy.add_feature("Ignores Perl, Java, and all C variants.")
- toy.add_feature("Karate-Chop Action!!!")
- toy.add_feature("Matz signature on left leg.")
- toy.add_feature("Gem studded eyes... Rubies, of course!")
-
- # Produce result.
- rhtml.run(toy.get_binding)
-
-<i>Generates (some blank lines removed):</i>
-
- <html>
- <head><title>Ruby Toys -- Rubysapien</title></head>
- <body>
-
- <h1>Rubysapien (TZ-1002)</h1>
- <p>Geek's Best Friend! Responds to Ruby commands...</p>
-
- <ul>
- <li><b>Listens for verbal commands in the Ruby language!</b></li>
- <li><b>Ignores Perl, Java, and all C variants.</b></li>
- <li><b>Karate-Chop Action!!!</b></li>
- <li><b>Matz signature on left leg.</b></li>
- <li><b>Gem studded eyes... Rubies, of course!</b></li>
- </ul>
-
- <p>
- Call for a price, today!
- </p>
-
- </body>
- </html>
-
-
-== Notes
-
-There are a variety of templating solutions available in various Ruby projects:
-* ERB's big brother, eRuby, works the same but is written in C for speed;
-* Amrita (smart at producing HTML/XML);
-* cs/Template (written in C for speed);
-* RDoc, distributed with Ruby, uses its own template engine, which can be reused elsewhere;
-* and others; search the RAA.
-
-Rails, the web application framework, uses ERB to create views.
-=end
+#
+# = ERB -- Ruby Templating
+#
+# == Introduction
+#
+# ERB provides an easy to use but powerful templating system for Ruby. Using
+# ERB, actual Ruby code can be added to any plain text document for the
+# purposes of generating document information details and/or flow control.
+#
+# A very simple example is this:
+#
+# require 'erb'
+#
+# x = 42
+# template = ERB.new <<-EOF
+# The value of x is: <%= x %>
+# EOF
+# puts template.result(binding)
+#
+# <em>Prints:</em> The value of x is: 42
+#
+# More complex examples are given below.
+#
+#
+# == Recognized Tags
+#
+# ERB recognizes certain tags in the provided template and converts them based
+# on the rules below:
+#
+# <% Ruby code -- inline with output %>
+# <%= Ruby expression -- replace with result %>
+# <%# comment -- ignored -- useful in testing %>
+# % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
+# %% replaced with % if first thing on a line and % processing is used
+# <%% or %%> -- replace with <% or %> respectively
+#
+# All other text is passed through ERB filtering unchanged.
+#
+#
+# == Options
+#
+# There are several settings you can change when you use ERB:
+# * the nature of the tags that are recognized;
+# * the value of <tt>$SAFE</tt> under which the template is run;
+# * the binding used to resolve local variables in the template.
+#
+# See the ERB.new and ERB#result methods for more detail.
+#
+# == Character encodings
+#
+# ERB (or ruby code generated by ERB) returns a string in the same
+# character encoding as the input string. When the input string has
+# a magic comment, however, it returns a string in the encoding specified
+# by the magic comment.
+#
+# # -*- coding: UTF-8 -*-
+# require 'erb'
+#
+# template = ERB.new <<EOF
+# <%#-*- coding: Big5 -*-%>
+# \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
+# EOF
+# puts template.result
+#
+# <em>Prints:</em> \_\_ENCODING\_\_ is Big5.
+#
+#
+# == Examples
+#
+# === Plain Text
+#
+# ERB is useful for any generic templating situation. Note that in this example, we use the
+# convenient "% at start of line" tag, and we quote the template literally with
+# <tt>%q{...}</tt> to avoid trouble with the backslash.
+#
+# require "erb"
+#
+# # Create template.
+# template = %q{
+# From: James Edward Gray II <james at grayproductions.net>
+# To: <%= to %>
+# Subject: Addressing Needs
+#
+# <%= to[/\w+/] %>:
+#
+# Just wanted to send a quick note assuring that your needs are being
+# addressed.
+#
+# I want you to know that my team will keep working on the issues,
+# especially:
+#
+# <%# ignore numerous minor requests -- focus on priorities %>
+# % priorities.each do |priority|
+# * <%= priority %>
+# % end
+#
+# Thanks for your patience.
+#
+# James Edward Gray II
+# }.gsub(/^ /, '')
+#
+# message = ERB.new(template, 0, "%<>")
+#
+# # Set up template data.
+# to = "Community Spokesman <spokesman at ruby_community.org>"
+# priorities = [ "Run Ruby Quiz",
+# "Document Modules",
+# "Answer Questions on Ruby Talk" ]
+#
+# # Produce result.
+# email = message.result
+# puts email
+#
+# <i>Generates:</i>
+#
+# From: James Edward Gray II <james at grayproductions.net>
+# To: Community Spokesman <spokesman at ruby_community.org>
+# Subject: Addressing Needs
+#
+# Community:
+#
+# Just wanted to send a quick note assuring that your needs are being addressed.
+#
+# I want you to know that my team will keep working on the issues, especially:
+#
+# * Run Ruby Quiz
+# * Document Modules
+# * Answer Questions on Ruby Talk
+#
+# Thanks for your patience.
+#
+# James Edward Gray II
+#
+# === Ruby in HTML
+#
+# ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby). Notice the need in
+# this example to provide a special binding when the template is run, so that the instance
+# variables in the Product object can be resolved.
+#
+# require "erb"
+#
+# # Build template data class.
+# class Product
+# def initialize( code, name, desc, cost )
+# @code = code
+# @name = name
+# @desc = desc
+# @cost = cost
+#
+# @features = [ ]
+# end
+#
+# def add_feature( feature )
+# @features << feature
+# end
+#
+# # Support templating of member data.
+# def get_binding
+# binding
+# end
+#
+# # ...
+# end
+#
+# # Create template.
+# template = %{
+# <html>
+# <head><title>Ruby Toys -- <%= @name %></title></head>
+# <body>
+#
+# <h1><%= @name %> (<%= @code %>)</h1>
+# <p><%= @desc %></p>
+#
+# <ul>
+# <% @features.each do |f| %>
+# <li><b><%= f %></b></li>
+# <% end %>
+# </ul>
+#
+# <p>
+# <% if @cost < 10 %>
+# <b>Only <%= @cost %>!!!</b>
+# <% else %>
+# Call for a price, today!
+# <% end %>
+# </p>
+#
+# </body>
+# </html>
+# }.gsub(/^ /, '')
+#
+# rhtml = ERB.new(template)
+#
+# # Set up template data.
+# toy = Product.new( "TZ-1002",
+# "Rubysapien",
+# "Geek's Best Friend! Responds to Ruby commands...",
+# 999.95 )
+# toy.add_feature("Listens for verbal commands in the Ruby language!")
+# toy.add_feature("Ignores Perl, Java, and all C variants.")
+# toy.add_feature("Karate-Chop Action!!!")
+# toy.add_feature("Matz signature on left leg.")
+# toy.add_feature("Gem studded eyes... Rubies, of course!")
+#
+# # Produce result.
+# rhtml.run(toy.get_binding)
+#
+# <i>Generates (some blank lines removed):</i>
+#
+# <html>
+# <head><title>Ruby Toys -- Rubysapien</title></head>
+# <body>
+#
+# <h1>Rubysapien (TZ-1002)</h1>
+# <p>Geek's Best Friend! Responds to Ruby commands...</p>
+#
+# <ul>
+# <li><b>Listens for verbal commands in the Ruby language!</b></li>
+# <li><b>Ignores Perl, Java, and all C variants.</b></li>
+# <li><b>Karate-Chop Action!!!</b></li>
+# <li><b>Matz signature on left leg.</b></li>
+# <li><b>Gem studded eyes... Rubies, of course!</b></li>
+# </ul>
+#
+# <p>
+# Call for a price, today!
+# </p>
+#
+# </body>
+# </html>
+#
+#
+# == Notes
+#
+# There are a variety of templating solutions available in various Ruby projects:
+# * ERB's big brother, eRuby, works the same but is written in C for speed;
+# * Amrita (smart at producing HTML/XML);
+# * cs/Template (written in C for speed);
+# * RDoc, distributed with Ruby, uses its own template engine, which can be reused elsewhere;
+# * and others; search the RAA.
+#
+# Rails, the web application framework, uses ERB to create views.
+#
class ERB
- Revision = '$Date:: 2009-01-17 07:20:08 -0500#$' #'
+ Revision = '$Date:: 2009-10-02 05:04:37 -0700#$' #'
# Returns revision information for the erb.rb module.
def self.version
@@ -318,7 +318,7 @@
end
end
attr_accessor :stag
-
+
def scan(&block)
@stag = nil
if @percent
@@ -425,7 +425,7 @@
end
end
end
-
+
Scanner.regist_scanner(SimpleScanner, nil, false)
begin
@@ -484,13 +484,13 @@
def push(cmd)
@line << cmd
end
-
+
def cr
@script << (@line.join('; '))
@line = []
@script << "\n"
end
-
+
def close
return unless @line
@compiler.post_cmd.each do |x|
@@ -520,7 +520,7 @@
content = ''
scanner = make_scanner(s)
scanner.scan do |token|
- next if token.nil?
+ next if token.nil?
next if token == ''
if scanner.stag.nil?
case token
@@ -632,19 +632,19 @@
class ERB
#
# Constructs a new ERB object with the template specified in _str_.
- #
+ #
# An ERB object works by building a chunk of Ruby code that will output
# the completed template when run. If _safe_level_ is set to a non-nil value,
# ERB code will be run in a separate thread with <b>$SAFE</b> set to the
# provided level.
- #
+ #
# If _trim_mode_ is passed a String containing one or more of the following
# modifiers, ERB will adjust its code generation as listed:
- #
+ #
# % enables Ruby code processing for lines beginning with %
# <> omit newline for lines starting with <% and ending in %>
# > omit newline for lines ending in %>
- #
+ #
# _eoutvar_ can be used to set the name of the variable ERB will build up
# its output in. This is useful when you need to run multiple ERB
# templates through the same binding and/or when you want to control where
@@ -653,20 +653,20 @@
# === Example
#
# require "erb"
- #
+ #
# # build data class
# class Listings
# PRODUCT = { :name => "Chicken Fried Steak",
# :desc => "A well messages pattie, breaded and fried.",
# :cost => 9.95 }
- #
+ #
# attr_reader :product, :price
- #
+ #
# def initialize( product = "", price = "" )
# @product = product
# @price = price
# end
- #
+ #
# def build
# b = binding
# # create and run templates, filling member data variables
@@ -680,21 +680,21 @@
# END_PRICE
# end
# end
- #
+ #
# # setup template data
# listings = Listings.new
# listings.build
- #
+ #
# puts listings.product + "\n" + listings.price
#
# _Generates_
#
# Chicken Fried Steak
# A well messages pattie, breaded and fried.
- #
+ #
# Chicken Fried Steak -- 9.95
# A well messages pattie, breaded and fried.
- #
+ #
def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
@safe_level = safe_level
compiler = ERB::Compiler.new(trim_mode)
@@ -721,7 +721,7 @@
cmd = []
cmd.push "#{eoutvar} = ''"
-
+
compiler.pre_cmd = cmd
cmd = []
@@ -739,13 +739,13 @@
# Executes the generated ERB code to produce a completed template, returning
# the results of that code. (See ERB#new for details on how this process can
# be affected by _safe_level_.)
- #
+ #
# _b_ accepts a Binding or Proc object which is used to set the context of
# code evaluation.
#
def result(b=TOPLEVEL_BINDING)
if @safe_level
- proc {
+ proc {
$SAFE = @safe_level
eval(@src, b, (@filename || '(erb)'), 0)
}.call
@@ -813,14 +813,14 @@
public
#
# A utility method for escaping HTML tag characters in _s_.
- #
+ #
# require "erb"
# include ERB::Util
- #
+ #
# puts html_escape("is a > 0 & a < 10?")
- #
+ #
# _Generates_
- #
+ #
# is a > 0 & a < 10?
#
def html_escape(s)
@@ -829,17 +829,17 @@
alias h html_escape
module_function :h
module_function :html_escape
-
+
#
# A utility method for encoding the String _s_ as a URL.
- #
+ #
# require "erb"
# include ERB::Util
- #
+ #
# puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
- #
+ #
# _Generates_
- #
+ #
# Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
#
def url_encode(s)
Modified: MacRuby/trunk/lib/fileutils.rb
===================================================================
--- MacRuby/trunk/lib/fileutils.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/fileutils.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,17 +1,17 @@
-#
+#
# = fileutils.rb
-#
+#
# Copyright (c) 2000-2007 Minero Aoki
-#
+#
# This program is free software.
# You can distribute/modify this program under the same terms of ruby.
-#
+#
# == module FileUtils
-#
+#
# Namespace for several file utility methods for copying, moving, removing, etc.
-#
+#
# === Module Functions
-#
+#
# cd(dir, options)
# cd(dir, options) {|dir| .... }
# pwd()
@@ -64,23 +64,23 @@
# uptodate?(file, cmp_list)
#
# == module FileUtils::Verbose
-#
+#
# This module has all methods of FileUtils module, but it outputs messages
# before acting. This equates to passing the <tt>:verbose</tt> flag to methods
# in FileUtils.
-#
+#
# == module FileUtils::NoWrite
-#
+#
# This module has all methods of FileUtils module, but never changes
# files/directories. This equates to passing the <tt>:noop</tt> flag to methods
# in FileUtils.
-#
+#
# == module FileUtils::DryRun
-#
+#
# This module has all methods of FileUtils module, but never changes
# files/directories. This equates to passing the <tt>:noop</tt> and
# <tt>:verbose</tt> flags to methods in FileUtils.
-#
+#
module FileUtils
@@ -107,14 +107,14 @@
#
# Options: verbose
- #
+ #
# Changes the current directory to the directory +dir+.
- #
+ #
# If this method is called with block, resumes to the old
# working directory after the block execution finished.
- #
+ #
# FileUtils.cd('/', :verbose => true) # chdir and report it
- #
+ #
def cd(dir, options = {}, &block) # :yield: dir
fu_check_options options, OPT_TABLE['cd']
fu_output_message "cd #{dir}" if options[:verbose]
@@ -131,13 +131,13 @@
#
# Options: (none)
- #
+ #
# Returns true if +newer+ is newer than all +old_list+.
# Non-existent files are older than any file.
- #
+ #
# FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \
# system 'make hello.o'
- #
+ #
def uptodate?(new, old_list, options = nil)
raise ArgumentError, 'uptodate? does not accept any option' if options
@@ -154,14 +154,14 @@
#
# Options: mode noop verbose
- #
+ #
# Creates one or more directories.
- #
+ #
# FileUtils.mkdir 'test'
# FileUtils.mkdir %w( tmp data )
# FileUtils.mkdir 'notexist', :noop => true # Does not really create.
# FileUtils.mkdir 'tmp', :mode => 0700
- #
+ #
def mkdir(list, options = {})
fu_check_options options, OPT_TABLE['mkdir']
list = fu_list(list)
@@ -178,12 +178,12 @@
#
# Options: mode noop verbose
- #
+ #
# Creates a directory and all its parent directories.
# For example,
- #
+ #
# FileUtils.mkdir_p '/usr/local/lib/ruby'
- #
+ #
# causes to make following directories, if it does not exist.
# * /usr
# * /usr/local
@@ -191,7 +191,7 @@
# * /usr/local/lib/ruby
#
# You can pass several directories at a time in a list.
- #
+ #
def mkdir_p(list, options = {})
fu_check_options options, OPT_TABLE['mkdir_p']
list = fu_list(list)
@@ -247,14 +247,14 @@
#
# Options: noop, verbose
- #
+ #
# Removes one or more directories.
- #
+ #
# FileUtils.rmdir 'somedir'
# FileUtils.rmdir %w(somedir anydir otherdir)
# # Does not really remove directory; outputs message.
# FileUtils.rmdir 'somedir', :verbose => true, :noop => true
- #
+ #
def rmdir(list, options = {})
fu_check_options options, OPT_TABLE['rmdir']
list = fu_list(list)
@@ -286,19 +286,19 @@
# If +new+ already exists and it is a directory, creates a link +new/old+.
# If +new+ already exists and it is not a directory, raises Errno::EEXIST.
# But if :force option is set, overwrite +new+.
- #
+ #
# FileUtils.ln 'gcc', 'cc', :verbose => true
# FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs'
- #
+ #
# <b><tt>ln(list, destdir, options = {})</tt></b>
- #
+ #
# Creates several hard links in a directory, with each one pointing to the
# item in +list+. If +destdir+ is not a directory, raises Errno::ENOTDIR.
- #
+ #
# include FileUtils
# cd '/sbin'
# FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked.
- #
+ #
def ln(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln']
fu_output_message "ln#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
@@ -320,24 +320,24 @@
# Options: force noop verbose
#
# <b><tt>ln_s(old, new, options = {})</tt></b>
- #
+ #
# Creates a symbolic link +new+ which points to +old+. If +new+ already
# exists and it is a directory, creates a symbolic link +new/old+. If +new+
# already exists and it is not a directory, raises Errno::EEXIST. But if
# :force option is set, overwrite +new+.
- #
+ #
# FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby'
# FileUtils.ln_s 'verylongsourcefilename.c', 'c', :force => true
- #
+ #
# <b><tt>ln_s(list, destdir, options = {})</tt></b>
- #
+ #
# Creates several symbolic links in a directory, with each one pointing to the
# item in +list+. If +destdir+ is not a directory, raises Errno::ENOTDIR.
#
# If +destdir+ is not a directory, raises Errno::ENOTDIR.
- #
+ #
# FileUtils.ln_s Dir.glob('bin/*.rb'), '/home/aamine/bin'
- #
+ #
def ln_s(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln_s']
fu_output_message "ln -s#{options[:force] ? 'f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
@@ -357,10 +357,10 @@
#
# Options: noop verbose
- #
+ #
# Same as
# #ln_s(src, dest, :force)
- #
+ #
def ln_sf(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln_sf']
options = options.dup
@@ -383,7 +383,7 @@
# FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6'
# FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', :verbose => true
# FileUtils.cp 'symlink', 'dest' # copy content, "dest" is not a symlink
- #
+ #
def cp(src, dest, options = {})
fu_check_options options, OPT_TABLE['cp']
fu_output_message "cp#{options[:preserve] ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
@@ -394,6 +394,8 @@
end
module_function :cp
+ # XXX Will not work on MacRuby:
+ # raises "can't change visibility of non Ruby method `copy' (RuntimeError)"
#alias copy cp
#module_function :copy
@@ -402,17 +404,17 @@
#
# Options: preserve noop verbose dereference_root remove_destination
- #
+ #
# Copies +src+ to +dest+. If +src+ is a directory, this method copies
# all its contents recursively. If +dest+ is a directory, copies
# +src+ to +dest/src+.
#
# +src+ can be a list of files.
- #
+ #
# # Installing ruby library "mylib" under the site_ruby
# FileUtils.rm_r site_ruby + '/mylib', :force
# FileUtils.cp_r 'lib/', site_ruby + '/mylib'
- #
+ #
# # Examples of copying several files to target directory.
# FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
# FileUtils.cp_r Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true
@@ -422,11 +424,13 @@
# # use following code.
# FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes src/dest,
# # but this doesn't.
- #
+ #
def cp_r(src, dest, options = {})
fu_check_options options, OPT_TABLE['cp_r']
fu_output_message "cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
+ options = options.dup
+ options[:dereference_root] = true unless options.key?(:dereference_root)
fu_each_src_dest(src, dest) do |s, d|
copy_entry s, d, options[:preserve], options[:dereference_root], options[:remove_destination]
end
@@ -485,16 +489,16 @@
#
# Options: force noop verbose
- #
+ #
# Moves file(s) +src+ to +dest+. If +file+ and +dest+ exist on the different
- # disk partition, the file is copied instead.
- #
+ # disk partition, the file is copied then the original file is removed.
+ #
# FileUtils.mv 'badname.rb', 'goodname.rb'
# FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', :force => true # no error
- #
+ #
# FileUtils.mv %w(junk.txt dust.txt), '/home/aamine/.trash/'
# FileUtils.mv Dir.glob('test*.rb'), 'test', :noop => true, :verbose => true
- #
+ #
def mv(src, dest, options = {})
fu_check_options options, OPT_TABLE['mv']
fu_output_message "mv#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
@@ -539,14 +543,14 @@
#
# Options: force noop verbose
- #
+ #
# Remove file(s) specified in +list+. This method cannot remove directories.
# All StandardErrors are ignored when the :force option is set.
- #
+ #
# FileUtils.rm %w( junk.txt dust.txt )
# FileUtils.rm Dir.glob('*.so')
# FileUtils.rm 'NotExistFile', :force => true # never raises exception
- #
+ #
def rm(list, options = {})
fu_check_options options, OPT_TABLE['rm']
list = fu_list(list)
@@ -567,7 +571,7 @@
#
# Options: noop verbose
- #
+ #
# Equivalent to
#
# #rm(list, :force => true)
@@ -588,11 +592,11 @@
#
# Options: force noop verbose secure
- #
+ #
# remove files +list+[0] +list+[1]... If +list+[n] is a directory,
# removes its all contents recursively. This method ignores
# StandardError when :force option is set.
- #
+ #
# FileUtils.rm_r Dir.glob('/tmp/*')
# FileUtils.rm_r '/', :force => true # :-)
#
@@ -606,7 +610,7 @@
#
# NOTE: This method calls #remove_entry_secure if :secure option is set.
# See also #remove_entry_secure.
- #
+ #
def rm_r(list, options = {})
fu_check_options options, OPT_TABLE['rm_r']
# options[:secure] = true unless options.key?(:secure)
@@ -627,14 +631,14 @@
#
# Options: noop verbose secure
- #
+ #
# Equivalent to
#
# #rm_r(list, :force => true)
#
# WARNING: This method causes local vulnerability.
# Read the documentation of #rm_r first.
- #
+ #
def rm_rf(list, options = {})
fu_check_options options, OPT_TABLE['rm_rf']
options = options.dup
@@ -788,7 +792,7 @@
#
# Returns true if the contents of a file A and a file B are identical.
- #
+ #
# FileUtils.compare_file('somefile', 'somefile') #=> true
# FileUtils.compare_file('/bin/cp', '/bin/mv') #=> maybe false
#
@@ -828,22 +832,21 @@
#
# Options: mode preserve noop verbose
- #
+ #
# If +src+ is not same as +dest+, copies it and changes the permission
# mode to +mode+. If +dest+ is a directory, destination is +dest+/+src+.
# This method removes destination before copy.
- #
+ #
# FileUtils.install 'ruby', '/usr/local/bin/ruby', :mode => 0755, :verbose => true
# FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', :verbose => true
- #
+ #
def install(src, dest, options = {})
fu_check_options options, OPT_TABLE['install']
fu_output_message "install -c#{options[:preserve] && ' -p'}#{options[:mode] ? (' -m 0%o' % options[:mode]) : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
- fu_each_src_dest(src, dest) do |s, d|
+ fu_each_src_dest(src, dest) do |s, d, st|
unless File.exist?(d) and compare_file(s, d)
remove_file d, true
- st = File.stat(s) if options[:preserve]
copy_file s, d
File.utime st.atime, st.mtime, d if options[:preserve]
File.chmod options[:mode], d if options[:mode]
@@ -856,14 +859,14 @@
#
# Options: noop verbose
- #
+ #
# Changes permission bits on the named files (in +list+) to the bit pattern
# represented by +mode+.
- #
+ #
# FileUtils.chmod 0755, 'somecommand'
# FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb)
# FileUtils.chmod 0755, '/usr/bin/ruby', :verbose => true
- #
+ #
def chmod(mode, list, options = {})
fu_check_options options, OPT_TABLE['chmod']
list = fu_list(list)
@@ -879,12 +882,12 @@
#
# Options: noop verbose force
- #
+ #
# Changes permission bits on the named files (in +list+)
# to the bit pattern represented by +mode+.
- #
+ #
# FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
- #
+ #
def chmod_R(mode, list, options = {})
fu_check_options options, OPT_TABLE['chmod_R']
list = fu_list(list)
@@ -908,16 +911,16 @@
#
# Options: noop verbose
- #
+ #
# Changes owner and group on the named files (in +list+)
# to the user +user+ and the group +group+. +user+ and +group+
# may be an ID (Integer/String) or a name (String).
# If +user+ or +group+ is nil, this method does not change
# the attribute.
- #
+ #
# FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby'
# FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true
- #
+ #
def chown(user, group, list, options = {})
fu_check_options options, OPT_TABLE['chown']
list = fu_list(list)
@@ -937,16 +940,16 @@
#
# Options: noop verbose force
- #
+ #
# Changes owner and group on the named files (in +list+)
# to the user +user+ and the group +group+ recursively.
# +user+ and +group+ may be an ID (Integer/String) or
# a name (String). If +user+ or +group+ is nil, this
# method does not change the attribute.
- #
+ #
# FileUtils.chown_R 'www', 'www', '/var/www/htdocs'
# FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', :verbose => true
- #
+ #
def chown_R(user, group, list, options = {})
fu_check_options options, OPT_TABLE['chown_R']
list = fu_list(list)
@@ -977,19 +980,26 @@
def fu_get_uid(user) #:nodoc:
return nil unless user
- user = user.to_s
- if /\A\d+\z/ =~ user
- then user.to_i
- else Etc.getpwnam(user).uid
+ case user
+ when Integer
+ user
+ when /\A\d+\z/
+ user.to_i
+ else
+ Etc.getpwnam(user).uid
end
end
private_module_function :fu_get_uid
def fu_get_gid(group) #:nodoc:
return nil unless group
- if /\A\d+\z/ =~ group
- then group.to_i
- else Etc.getgrnam(group).gid
+ case group
+ when Integer
+ group
+ when /\A\d+\z/
+ group.to_i
+ else
+ Etc.getgrnam(group).gid
end
end
private_module_function :fu_get_gid
@@ -1010,13 +1020,13 @@
#
# Options: noop verbose
- #
+ #
# Updates modification time (mtime) and access time (atime) of file(s) in
# +list+. Files are created if they don't exist.
- #
+ #
# FileUtils.touch 'timestamp'
# FileUtils.touch Dir.glob('*.c'); system 'make'
- #
+ #
def touch(list, options = {})
fu_check_options options, OPT_TABLE['touch']
list = fu_list(list)
@@ -1168,7 +1178,9 @@
end
def entries
- Dir.entries(path())\
+ opts = {}
+ opts[:encoding] = "UTF-8" if /mswin|mignw/ =~ RUBY_PLATFORM
+ Dir.entries(path(), opts)\
.reject {|n| n == '.' or n == '..' }\
.map {|n| Entry_.new(prefix(), join(rel(), n.untaint)) }
end
@@ -1260,7 +1272,11 @@
end
def copy_file(dest)
- IO.copy_stream(path(), dest)
+ File.open(path()) do |s|
+ File.open(dest, 'wb') do |f|
+ IO.copy_stream(s, f)
+ end
+ end
end
def copy_metadata(path)
@@ -1390,7 +1406,7 @@
def fu_each_src_dest(src, dest) #:nodoc:
fu_each_src_dest0(src, dest) do |s, d|
raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s, d)
- yield s, d
+ yield s, d, File.stat(s)
end
end
private_module_function :fu_each_src_dest
@@ -1413,23 +1429,10 @@
private_module_function :fu_each_src_dest0
def fu_same?(a, b) #:nodoc:
- if fu_have_st_ino?
- st1 = File.stat(a)
- st2 = File.stat(b)
- st1.dev == st2.dev and st1.ino == st2.ino
- else
- File.expand_path(a) == File.expand_path(b)
- end
- rescue Errno::ENOENT
- return false
+ File.identical?(a, b)
end
private_module_function :fu_same?
- def fu_have_st_ino? #:nodoc:
- not fu_windows?
- end
- private_module_function :fu_have_st_ino?
-
def fu_check_options(options, optdecl) #:nodoc:
h = options.dup
optdecl.each do |opt|
@@ -1510,11 +1513,11 @@
METHODS = singleton_methods() - [:private_module_function,
:commands, :options, :have_option?, :options_of, :collect_method]
- #
+ #
# This module has all methods of FileUtils module, but it outputs messages
# before acting. This equates to passing the <tt>:verbose</tt> flag to
# methods in FileUtils.
- #
+ #
module Verbose
include FileUtils
@fileutils_output = $stderr
@@ -1535,11 +1538,11 @@
end
end
- #
+ #
# This module has all methods of FileUtils module, but never changes
# files/directories. This equates to passing the <tt>:noop</tt> flag
# to methods in FileUtils.
- #
+ #
module NoWrite
include FileUtils
@fileutils_output = $stderr
@@ -1560,12 +1563,12 @@
end
end
- #
+ #
# This module has all methods of FileUtils module, but never changes
# files/directories, with printing message before acting.
# This equates to passing the <tt>:noop</tt> and <tt>:verbose</tt> flag
# to methods in FileUtils.
- #
+ #
module DryRun
include FileUtils
@fileutils_output = $stderr
Modified: MacRuby/trunk/lib/find.rb
===================================================================
--- MacRuby/trunk/lib/find.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/find.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -39,28 +39,24 @@
while file = paths.shift
catch(:prune) do
yield file.dup.taint
- next unless File.exist? file
- begin
- if File.lstat(file).directory? then
- d = Dir.open(file)
- begin
- for f in d
- next if f == "." or f == ".."
- if File::ALT_SEPARATOR and file =~ /^(?:[\/\\]|[A-Za-z]:[\/\\]?)$/ then
- f = file + f
- elsif file == "/" then
- f = "/" + f
- else
- f = File.join(file, f)
- end
- paths.unshift f.untaint
- end
- ensure
- d.close
- end
- end
- rescue Errno::ENOENT, Errno::EACCES
- end
+ begin
+ s = File.lstat(file)
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
+ next
+ end
+ if s.directory? then
+ begin
+ fs = Dir.entries(file)
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
+ next
+ end
+ fs.sort!
+ fs.reverse_each {|f|
+ next if f == "." or f == ".."
+ f = File.join(file, f)
+ paths.unshift f.untaint
+ }
+ end
end
end
end
Modified: MacRuby/trunk/lib/forwardable.rb
===================================================================
--- MacRuby/trunk/lib/forwardable.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/forwardable.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,7 +1,7 @@
#
-# forwardable.rb -
+# forwardable.rb -
# $Release Version: 1.1$
-# $Revision: 16810 $
+# $Revision: 25189 $
# by Keiju ISHITSUKA(keiju at ishitsuka.com)
# original definition by delegator.rb
# Revised by Daniel J. Berger with suggestions from Florian Gross.
@@ -33,28 +33,28 @@
#
# class Queue
# extend Forwardable
-#
+#
# def initialize
# @q = [ ] # prepare delegate object
# end
-#
+#
# # setup preferred interface, enq() and deq()...
# def_delegator :@q, :push, :enq
# def_delegator :@q, :shift, :deq
-#
+#
# # support some general Array methods that fit Queues well
# def_delegators :@q, :clear, :first, :push, :shift, :size
# end
-#
+#
# q = Queue.new
# q.enq 1, 2, 3, 4, 5
# q.push 6
-#
+#
# q.shift # => 1
# while q.size > 0
# puts q.deq
# end
-#
+#
# q.enq "Ruby", "Perl", "Python"
# puts q.first
# q.clear
@@ -70,9 +70,30 @@
# Ruby
# nil
#
-# Forwardable can be used to setup delegation at the object level as well.
+# SingleForwardable can be used to setup delegation at the object level as well.
#
# printer = String.new
+# printer.extend SingleForwardable # prepare object for delegation
+# printer.def_delegator "STDOUT", "puts" # add delegation for STDOUT.puts()
+# printer.puts "Howdy!"
+#
+# Also, SingleForwardable can be use to Class or Module.
+#
+# module Facade
+# extend SingleForwardable
+# def_delegator :Implementation, :service
+#
+# class Implementation
+# def service...
+# end
+# end
+#
+# If you want to use both Forwardable and SingleForwardable, you can
+# use methods def_instance_delegator and def_single_delegator, etc.
+#
+# If the object isn't a Module and Class, You can too extend
+# Forwardable module.
+# printer = String.new
# printer.extend Forwardable # prepare object for delegation
# printer.def_delegator "STDOUT", "puts" # add delegation for STDOUT.puts()
# printer.puts "Howdy!"
@@ -111,8 +132,13 @@
# Also see the example at forwardable.rb.
module Forwardable
- FORWARDABLE_VERSION = "1.0.0"
-
+ FORWARDABLE_VERSION = "1.1.0"
+
+ @debug = nil
+ class<<self
+ attr_accessor :debug
+ end
+
# Takes a hash as its argument. The key is a symbol or an array of
# symbols. These symbols correspond to method names. The value is
# the accessor to which the methods will be delegated.
@@ -121,7 +147,7 @@
# delegate method => accessor
# delegate [method, method, ...] => accessor
#
- def delegate(hash)
+ def instance_delegate(hash)
hash.each{ |methods, accessor|
methods = methods.to_s unless methods.respond_to?(:each)
methods.each{ |method|
@@ -144,34 +170,101 @@
def def_instance_delegators(accessor, *methods)
methods.delete("__send__")
methods.delete("__id__")
- methods.each{ |method|
+ for method in methods
def_instance_delegator(accessor, method)
- }
+ end
end
- #
- # Defines a method _method_ which delegates to _obj_ (i.e. it calls
- # the method of the same name in _obj_). If _new_name_ is
- # provided, it is used as the name for the delegate method.
- #
def def_instance_delegator(accessor, method, ali = method)
- str = %Q{
+ line_no = __LINE__; str = %{
def #{ali}(*args, &block)
- #{accessor}.send(:#{method}, *args, &block)
+ begin
+ #{accessor}.__send__(:#{method}, *args, &block)
+ rescue Exception
+ $@.delete_if{|s| %r"#{Regexp.quote(__FILE__)}"o =~ s} unless Forwardable::debug
+ ::Kernel::raise
+ end
end
}
-
# If it's not a class or module, it's an instance
begin
- module_eval(str)
+ module_eval(str, __FILE__, line_no)
rescue
- instance_eval(str)
+ instance_eval(str, __FILE__, line_no)
end
+
end
+ alias delegate instance_delegate
alias def_delegators def_instance_delegators
alias def_delegator def_instance_delegator
end
-# compatibility
-SingleForwardable = Forwardable
+#
+# Usage of The SingleForwardable is like Fowadable module.
+#
+module SingleForwardable
+ # Takes a hash as its argument. The key is a symbol or an array of
+ # symbols. These symbols correspond to method names. The value is
+ # the accessor to which the methods will be delegated.
+ #
+ # :call-seq:
+ # delegate method => accessor
+ # delegate [method, method, ...] => accessor
+ #
+ def single_delegate(hash)
+ hash.each{ |methods, accessor|
+ methods = methods.to_s unless methods.respond_to?(:each)
+ methods.each{ |method|
+ def_single_delegator(accessor, method)
+ }
+ }
+ end
+
+ #
+ # Shortcut for defining multiple delegator methods, but with no
+ # provision for using a different name. The following two code
+ # samples have the same effect:
+ #
+ # def_delegators :@records, :size, :<<, :map
+ #
+ # def_delegator :@records, :size
+ # def_delegator :@records, :<<
+ # def_delegator :@records, :map
+ #
+ def def_single_delegators(accessor, *methods)
+ methods.delete("__send__")
+ methods.delete("__id__")
+ for method in methods
+ def_single_delegator(accessor, method)
+ end
+ end
+
+ #
+ # Defines a method _method_ which delegates to _obj_ (i.e. it calls
+ # the method of the same name in _obj_). If _new_name_ is
+ # provided, it is used as the name for the delegate method.
+ #
+ def def_single_delegator(accessor, method, ali = method)
+ line_no = __LINE__; str = %{
+ def #{ali}(*args, &block)
+ begin
+ #{accessor}.__send__(:#{method}, *args, &block)
+ rescue Exception
+ $@.delete_if{|s| %r"#{Regexp.quote(__FILE__)}"o =~ s} unless Forwardable::debug
+ ::Kernel::raise
+ end
+ end
+ }
+
+ instance_eval(str, __FILE__, __LINE__)
+ end
+
+ alias delegate single_delegate
+ alias def_delegators def_single_delegators
+ alias def_delegator def_single_delegator
+end
+
+
+
+
Modified: MacRuby/trunk/lib/getoptlong.rb
===================================================================
--- MacRuby/trunk/lib/getoptlong.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/getoptlong.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -12,10 +12,10 @@
# found at http://www.sra.co.jp/people/m-kasahr/ruby/getoptlong/
# The GetoptLong class allows you to parse command line options similarly to
-# the GNU getopt_long() C library call. Note, however, that GetoptLong is a
+# the GNU getopt_long() C library call. Note, however, that GetoptLong is a
# pure Ruby implementation.
#
-# GetoptLong allows for POSIX-style options like <tt>--file</tt> as well
+# GetoptLong allows for POSIX-style options like <tt>--file</tt> as well
# as single letter options like <tt>-f</tt>
#
# The empty option <tt>--</tt> (two minus symbols) is used to end option
@@ -25,14 +25,13 @@
# Here is a simple example of usage:
#
# require 'getoptlong'
-# require 'rdoc/usage'
-#
+#
# opts = GetoptLong.new(
# [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
# [ '--repeat', '-n', GetoptLong::REQUIRED_ARGUMENT ],
# [ '--name', GetoptLong::OPTIONAL_ARGUMENT ]
# )
-#
+#
# dir = nil
# name = nil
# repetitions = 1
@@ -41,16 +40,16 @@
# when '--help'
# puts <<-EOF
# hello [OPTION] ... DIR
-#
+#
# -h, --help:
# show help
-#
+#
# --repeat x, -n x:
# repeat x times
-#
+#
# --name [name]:
# greet user by name, if name not supplied default is John
-#
+#
# DIR: The directory in which to issue the greeting.
# EOF
# when '--repeat'
@@ -63,12 +62,12 @@
# end
# end
# end
-#
+#
# if ARGV.length != 1
# puts "Missing dir argument (try --help)"
# exit 0
# end
-#
+#
# dir = ARGV.shift
#
# Dir.chdir(dir)
@@ -114,7 +113,7 @@
# Set up option processing.
#
# The options to support are passed to new() as an array of arrays.
- # Each sub-array contains any number of String option names which carry
+ # Each sub-array contains any number of String option names which carry
# the same meaning, and one of the following flags:
#
# GetoptLong::NO_ARGUMENT :: Option does not take an argument.
@@ -194,23 +193,23 @@
# the processing of options as follows:
#
# <b>REQUIRE_ORDER</b> :
- #
+ #
# Options are required to occur before non-options.
#
# Processing of options ends as soon as a word is encountered that has not
# been preceded by an appropriate option flag.
#
# For example, if -a and -b are options which do not take arguments,
- # parsing command line arguments of '-a one -b two' would result in
- # 'one', '-b', 'two' being left in ARGV, and only ('-a', '') being
+ # parsing command line arguments of '-a one -b two' would result in
+ # 'one', '-b', 'two' being left in ARGV, and only ('-a', '') being
# processed as an option/arg pair.
#
# This is the default ordering, if the environment variable
# POSIXLY_CORRECT is set. (This is for compatibility with GNU getopt_long.)
#
# <b>PERMUTE</b> :
- #
- # Options can occur anywhere in the command line parsed. This is the
+ #
+ # Options can occur anywhere in the command line parsed. This is the
# default behavior.
#
# Every sequence of words which can be interpreted as an option (with or
@@ -227,7 +226,7 @@
#
# <b>RETURN_IN_ORDER</b> :
#
- # All words on the command line are processed as options. Words not
+ # All words on the command line are processed as options. Words not
# preceded by a short or long option flag are passed as arguments
# with an option of '' (empty string).
#
@@ -273,7 +272,7 @@
# The method is failed if option processing has already started.
#
if @status != STATUS_YET
- raise RuntimeError,
+ raise RuntimeError,
"invoke set_options, but option processing has already started"
end
@@ -283,8 +282,11 @@
@canonical_names.clear
@argument_flags.clear
- arguments.each do |*arg|
- arg = arg.first # TODO: YARV Hack
+ arguments.each do |arg|
+ if !arg.is_a?(Array)
+ raise ArgumentError, "the option list contains non-Array argument"
+ end
+
#
# Find an argument flag and it set to `argument_flag'.
#
@@ -320,7 +322,7 @@
end
#
- # Register the option (`i') to the `@canonical_names' and
+ # Register the option (`i') to the `@canonical_names' and
# `@canonical_names' Hashes.
#
if canonical_name == nil
@@ -452,7 +454,7 @@
return nil
end
argument = ARGV.shift
- elsif @ordering == REQUIRE_ORDER
+ elsif @ordering == REQUIRE_ORDER
if (ARGV[0] !~ /^-./)
terminate
return nil
@@ -589,7 +591,7 @@
#
# The block is called repeatedly with two arguments:
# The first is the option name.
- # The second is the argument which followed it (if any).
+ # The second is the argument which followed it (if any).
# Example: ('--opt', 'value')
#
# The option name is always converted to the first (preferred)
Modified: MacRuby/trunk/lib/gserver.rb
===================================================================
--- MacRuby/trunk/lib/gserver.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/gserver.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -13,7 +13,7 @@
#
# GServer implements a generic server, featuring thread pool management,
-# simple logging, and multi-server management. See HttpServer in
+# simple logging, and multi-server management. See HttpServer in
# <tt>xmlrpc/httpserver.rb</tt> in the Ruby standard library for an example of
# GServer in action.
#
@@ -34,7 +34,7 @@
#
# #
# # A server that returns the time in seconds since 1970.
-# #
+# #
# class TimeServer < GServer
# def initialize(port=10001, *args)
# super(port, *args)
@@ -47,17 +47,17 @@
# # Run the server with logging enabled (it's a separate thread).
# server = TimeServer.new
# server.audit = true # Turn logging on.
-# server.start
+# server.start
#
# # *** Now point your browser to http://localhost:10001 to see it working ***
#
-# # See if it's still running.
+# # See if it's still running.
# GServer.in_service?(10001) # -> true
# server.stopped? # -> false
#
# # Shut the server down gracefully.
# server.shutdown
-#
+#
# # Alternatively, stop it immediately.
# GServer.stop(10001)
# # or, of course, "server.stop".
Modified: MacRuby/trunk/lib/ipaddr.rb
===================================================================
--- MacRuby/trunk/lib/ipaddr.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/ipaddr.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -7,7 +7,7 @@
#
# You can redistribute and/or modify it under the same terms as Ruby.
#
-# $Id: ipaddr.rb 19504 2008-09-23 21:39:21Z ryan $
+# $Id: ipaddr.rb 27000 2010-03-21 12:10:53Z akr $
#
# Contact:
# - Akinori MUSHA <knu at iDaemons.org> (current maintainer)
@@ -18,7 +18,7 @@
require 'socket'
unless Socket.const_defined? "AF_INET6"
- class Socket
+ class Socket < BasicSocket
AF_INET6 = Object.new
end
@@ -66,19 +66,19 @@
# == Example
#
# require 'ipaddr'
-#
+#
# ipaddr1 = IPAddr.new "3ffe:505:2::1"
-#
+#
# p ipaddr1 #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
-#
+#
# p ipaddr1.to_s #=> "3ffe:505:2::1"
-#
+#
# ipaddr2 = ipaddr1.mask(48) #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>
-#
+#
# p ipaddr2.to_s #=> "3ffe:505:2::"
-#
+#
# ipaddr3 = IPAddr.new "192.168.2.0/24"
-#
+#
# p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
class IPAddr
@@ -331,6 +331,16 @@
end
include Comparable
+ # Checks equality used by Hash.
+ def eql?(other)
+ return self.class == other.class && self.hash == other.hash && self == other
+ end
+
+ # Returns a hash value used by Hash, Set, and Array classes
+ def hash
+ return ([@addr, @mask_addr].hash << 1) | (ipv4? ? 0 : 1)
+ end
+
# Creates a Range object for the network address.
def to_range
begin_addr = (@addr & @mask_addr)
@@ -425,7 +435,7 @@
# Creates a new ipaddr object either from a human readable IP
# address representation in string, or from a packed in_addr value
# followed by an address family.
- #
+ #
# In the former case, the following are the valid formats that will
# be recognized: "address", "address/prefixlen" and "address/mask",
# where IPv6 address may be enclosed in square brackets (`[' and
@@ -433,8 +443,8 @@
# IP address. Although the address family is determined
# automatically from a specified string, you can specify one
# explicitly by the optional second argument.
- #
- # Otherwise an IP addess is generated from a packed in_addr value
+ #
+ # Otherwise an IP address is generated from a packed in_addr value
# and an address family.
#
# The IPAddr class defines many methods and operators, and some of
@@ -462,7 +472,7 @@
#Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil,
# Socket::AI_NUMERICHOST)
begin
- IPSocket.getaddress(prefix) # test if address is vaild
+ IPSocket.getaddress(prefix) # test if address is valid
rescue
raise ArgumentError, "invalid address"
end
@@ -810,4 +820,31 @@
end
+ def test_hash
+ a1 = IPAddr.new('192.168.2.0')
+ a2 = IPAddr.new('192.168.2.0')
+ a3 = IPAddr.new('3ffe:505:2::1')
+ a4 = IPAddr.new('3ffe:505:2::1')
+ a5 = IPAddr.new('127.0.0.1')
+ a6 = IPAddr.new('::1')
+ a7 = IPAddr.new('192.168.2.0/25')
+ a8 = IPAddr.new('192.168.2.0/25')
+
+ h = { a1 => 'ipv4', a2 => 'ipv4', a3 => 'ipv6', a4 => 'ipv6', a5 => 'ipv4', a6 => 'ipv6', a7 => 'ipv4', a8 => 'ipv4'}
+ assert_equal(5, h.size)
+ assert_equal('ipv4', h[a1])
+ assert_equal('ipv4', h[a2])
+ assert_equal('ipv6', h[a3])
+ assert_equal('ipv6', h[a4])
+
+ require 'set'
+ s = Set[a1, a2, a3, a4, a5, a6, a7, a8]
+ assert_equal(5, s.size)
+ assert_equal(true, s.include?(a1))
+ assert_equal(true, s.include?(a2))
+ assert_equal(true, s.include?(a3))
+ assert_equal(true, s.include?(a4))
+ assert_equal(true, s.include?(a5))
+ assert_equal(true, s.include?(a6))
+ end
end
Modified: MacRuby/trunk/lib/logger.rb
===================================================================
--- MacRuby/trunk/lib/logger.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/logger.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,24 +1,19 @@
# logger.rb - simple logging utility
-# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi <nakahiro at sarion.co.jp>.
-
-require 'monitor'
-
-# = logger.rb
+# Copyright (C) 2000-2003, 2005, 2008 NAKAMURA, Hiroshi <nahi at ruby-lang.org>.
#
-# Simple logging utility.
-#
# Author:: NAKAMURA, Hiroshi <nakahiro at sarion.co.jp>
# Documentation:: NAKAMURA, Hiroshi and Gavin Sinclair
# License::
# You can redistribute it and/or modify it under the same terms of Ruby's
# license; either the dual license version in 2003, or any later version.
-# Revision:: $Id: logger.rb 20321 2008-11-22 14:52:06Z yugui $
+# Revision:: $Id: logger.rb 25413 2009-10-20 15:08:38Z nahi $
#
# See Logger for documentation.
-#
-#
+require 'monitor'
+
+
# == Description
#
# The Logger class provides a simple but sophisticated logging utility that
@@ -180,8 +175,8 @@
class Logger
- VERSION = "1.2.6"
- id, name, rev = %w$Id: logger.rb 20321 2008-11-22 14:52:06Z yugui $
+ VERSION = "1.2.7"
+ id, name, rev = %w$Id: logger.rb 25413 2009-10-20 15:08:38Z nahi $
if name
name = name.chomp(",v")
else
@@ -191,7 +186,7 @@
ProgName = "#{name}/#{rev}"
class Error < RuntimeError; end
- class ShiftingError < Error; end
+ class ShiftingError < Error; end # not used after 1.2.7. just for compat.
# Logging severity.
module Severity
@@ -334,10 +329,10 @@
progname ||= @progname
if message.nil?
if block_given?
- message = yield
+ message = yield
else
- message = progname
- progname = @progname
+ message = progname
+ progname = @progname
end
end
@logdev.write(
@@ -499,32 +494,44 @@
@dev = @filename = @shift_age = @shift_size = nil
@mutex = LogDeviceMutex.new
if log.respond_to?(:write) and log.respond_to?(:close)
- @dev = log
+ @dev = log
else
- @dev = open_logfile(log)
- @dev.sync = true
- @filename = log
- @shift_age = opt[:shift_age] || 7
- @shift_size = opt[:shift_size] || 1048576
+ @dev = open_logfile(log)
+ @dev.sync = true
+ @filename = log
+ @shift_age = opt[:shift_age] || 7
+ @shift_size = opt[:shift_size] || 1048576
end
end
def write(message)
- @mutex.synchronize do
- if @shift_age and @dev.respond_to?(:stat)
+ begin
+ @mutex.synchronize do
+ if @shift_age and @dev.respond_to?(:stat)
+ begin
+ check_shift_log
+ rescue
+ warn("log shifting failed. #{$!}")
+ end
+ end
begin
- check_shift_log
+ @dev.write(message)
rescue
- raise Logger::ShiftingError.new("Shifting failed. #{$!}")
+ warn("log writing failed. #{$!}")
end
end
- @dev.write(message)
+ rescue Exception => ignored
+ warn("log writing failed. #{ignored}")
end
end
def close
- @mutex.synchronize do
- @dev.close
+ begin
+ @mutex.synchronize do
+ @dev.close rescue nil
+ end
+ rescue Exception => ignored
+ @dev.close rescue nil
end
end
@@ -532,9 +539,9 @@
def open_logfile(filename)
if (FileTest.exist?(filename))
- open(filename, (File::WRONLY | File::APPEND))
+ open(filename, (File::WRONLY | File::APPEND))
else
- create_logfile(filename)
+ create_logfile(filename)
end
end
@@ -547,8 +554,8 @@
def add_log_header(file)
file.write(
- "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName]
- )
+ "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName]
+ )
end
SiD = 24 * 60 * 60
@@ -561,8 +568,9 @@
end
else
now = Time.now
- if @dev.stat.mtime <= previous_period_end(now)
- shift_log_period(now)
+ period_end = previous_period_end(now)
+ if @dev.stat.mtime <= period_end
+ shift_log_period(period_end)
end
end
end
@@ -573,19 +581,26 @@
File.rename("#{@filename}.#{i}", "#{@filename}.#{i+1}")
end
end
- @dev.close
+ @dev.close rescue nil
File.rename("#{@filename}", "#{@filename}.0")
@dev = create_logfile(@filename)
return true
end
- def shift_log_period(now)
- postfix = previous_period_end(now).strftime("%Y%m%d") # YYYYMMDD
+ def shift_log_period(period_end)
+ postfix = period_end.strftime("%Y%m%d") # YYYYMMDD
age_file = "#{@filename}.#{postfix}"
if FileTest.exist?(age_file)
- raise RuntimeError.new("'#{ age_file }' already exists.")
+ # try to avoid filename crash caused by Timestamp change.
+ idx = 0
+ # .99 can be overriden; avoid too much file search with 'loop do'
+ while idx < 100
+ idx += 1
+ age_file = "#{@filename}.#{postfix}.#{idx}"
+ break unless FileTest.exist?(age_file)
+ end
end
- @dev.close
+ @dev.close rescue nil
File.rename("#{@filename}", age_file)
@dev = create_logfile(@filename)
return true
@@ -672,12 +687,12 @@
def start
status = -1
begin
- log(INFO, "Start of #{ @appname }.")
- status = run
+ log(INFO, "Start of #{ @appname }.")
+ status = run
rescue
- log(FATAL, "Detected an exception. Stopping ... #{$!} (#{$!.class})\n" << $@.join("\n"))
+ log(FATAL, "Detected an exception. Stopping ... #{$!} (#{$!.class})\n" << $@.join("\n"))
ensure
- log(INFO, "End of #{ @appname }. (status: #{ status.to_s })")
+ log(INFO, "End of #{ @appname }. (status: #{ status.to_s })")
end
status
end
@@ -692,6 +707,8 @@
#
def logger=(logger)
@log = logger
+ @log.progname = @appname
+ @log.level = @level
end
#
@@ -726,6 +743,7 @@
private
def run
+ # TODO: should be an NotImplementedError
raise RuntimeError.new('Method run must be defined in the derived class.')
end
end
Modified: MacRuby/trunk/lib/mathn.rb
===================================================================
--- MacRuby/trunk/lib/mathn.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/mathn.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,20 +1,20 @@
#
-# mathn.rb -
+# mathn.rb -
# $Release Version: 0.5 $
# $Revision: 1.1.1.1.4.1 $
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
# --
#
-#
#
+#
require "cmath.rb"
require "matrix.rb"
require "prime.rb"
-#require "mathn/rational"
-#require "mathn/complex"
+# require "mathn/rational"
+# require "mathn/complex"
unless defined?(Math.exp!)
Object.instance_eval{remove_const :Math}
@@ -25,7 +25,7 @@
remove_method :/
alias / quo
- alias power! ** unless defined?(0.power!)
+ alias power! ** unless method_defined? :power!
def ** (other)
if self < 0 && other.round != other
@@ -41,7 +41,7 @@
remove_method :/
alias / quo
- alias power! ** unless defined?(0.power!)
+ alias power! ** unless method_defined? :power!
def ** (other)
if self < 0 && other.round != other
@@ -54,6 +54,7 @@
end
class Rational
+ remove_method :**
def ** (other)
if other.kind_of?(Rational)
other2 = other
@@ -66,14 +67,14 @@
elsif self == 1
return Rational(1,1)
end
-
+
npd = numerator.prime_division
dpd = denominator.prime_division
if other < 0
other = -other
npd, dpd = dpd, npd
end
-
+
for elm in npd
elm[1] = elm[1] * other
if !elm[1].kind_of?(Integer) and elm[1].denominator != 1
@@ -81,7 +82,7 @@
end
elm[1] = elm[1].to_i
end
-
+
for elm in dpd
elm[1] = elm[1] * other
if !elm[1].kind_of?(Integer) and elm[1].denominator != 1
@@ -89,12 +90,12 @@
end
elm[1] = elm[1].to_i
end
-
+
num = Integer.from_prime_division(npd)
den = Integer.from_prime_division(dpd)
-
+
Rational(num,den)
-
+
elsif other.kind_of?(Integer)
if other > 0
num = numerator ** other
@@ -129,7 +130,7 @@
# if !(x.kind_of?(Rational) and y.kind_of?(Rational))
# return a**Rational(1,2)
# end
- if a.imag >= 0
+ if a.imag >= 0
Complex(x, y)
else
Complex(x, -y)
@@ -142,7 +143,7 @@
Complex(0,rsqrt(-a))
end
end
-
+
def rsqrt(a)
if a.kind_of?(Float)
sqrt!(a)
@@ -156,7 +157,7 @@
while (src >= max) and (src >>= 32)
byte_a.unshift src & 0xffffffff
end
-
+
answer = 0
main = 0
side = 0
@@ -166,13 +167,13 @@
if answer != 0
if main * 4 < side * side
applo = main.div(side)
- else
+ else
applo = ((sqrt!(side * side + 4 * main) - side)/2.0).to_i + 1
end
else
applo = sqrt!(main).to_i + 1
end
-
+
while (x = (side + applo) * applo) > main
applo -= 1
end
@@ -188,6 +189,9 @@
end
end
+ class << self
+ remove_method(:sqrt)
+ end
module_function :sqrt
module_function :rsqrt
end
Modified: MacRuby/trunk/lib/matrix.rb
===================================================================
--- MacRuby/trunk/lib/matrix.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/matrix.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,22 +1,15 @@
-#!/usr/local/bin/ruby
-#--
-# matrix.rb -
-# $Release Version: 1.0$
-# $Revision: 1.13 $
-# Original Version from Smalltalk-80 version
-# on July 23, 1985 at 8:37:17 am
-# by Keiju ISHITSUKA
-#++
+# encoding: utf-8
#
# = matrix.rb
#
# An implementation of Matrix and Vector classes.
#
-# Author:: Keiju ISHITSUKA
-# Documentation:: Gavin Sinclair (sourced from <i>Ruby in a Nutshell</i> (Matsumoto, O'Reilly))
+# See classes Matrix and Vector for documentation.
#
-# See classes Matrix and Vector for documentation.
-#
+# Current Maintainer:: Marc-André Lafortune
+# Original Author:: Keiju ISHITSUKA
+# Original Documentation:: Gavin Sinclair (sourced from <i>Ruby in a Nutshell</i> (Matsumoto, O'Reilly))
+##
require "e2mmap.rb"
@@ -24,24 +17,18 @@
extend Exception2MessageMapper
def_e2message(TypeError, "wrong argument type %s (expected %s)")
def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)")
-
+
def_exception("ErrDimensionMismatch", "\#{self.name} dimension mismatch")
def_exception("ErrNotRegular", "Not Regular Matrix")
- def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined")
+ def_exception("ErrOperationNotDefined", "Operation(%s) can\\'t be defined: %s op %s")
+ def_exception("ErrOperationNotImplemented", "Sorry, Operation(%s) not implemented: %s op %s")
end
#
-# The +Matrix+ class represents a mathematical matrix, and provides methods for creating
-# special-case matrices (zero, identity, diagonal, singular, vector), operating on them
-# arithmetically and algebraically, and determining their mathematical properties (trace, rank,
-# inverse, determinant).
+# The +Matrix+ class represents a mathematical matrix. It provides methods for creating
+# matrices, operating on them arithmetically and algebraically,
+# and determining their mathematical properties (trace, rank, inverse, determinant).
#
-# Note that although matrices should theoretically be rectangular, this is not
-# enforced by the class.
-#
-# Also note that the determinant of integer matrices may be incorrectly calculated unless you
-# also <tt>require 'mathn'</tt>. This may be fixed in the future.
-#
# == Method Catalogue
#
# To create a matrix:
@@ -49,9 +36,9 @@
# * <tt> Matrix.[](*rows) </tt>
# * <tt> Matrix.rows(rows, copy = true) </tt>
# * <tt> Matrix.columns(columns) </tt>
+# * <tt> Matrix.build(row_size, column_size, &block) </tt>
# * <tt> Matrix.diagonal(*values) </tt>
# * <tt> Matrix.scalar(n, value) </tt>
-# * <tt> Matrix.scalar(n, value) </tt>
# * <tt> Matrix.identity(n) </tt>
# * <tt> Matrix.unit(n) </tt>
# * <tt> Matrix.I(n) </tt>
@@ -59,7 +46,7 @@
# * <tt> Matrix.row_vector(row) </tt>
# * <tt> Matrix.column_vector(column) </tt>
#
-# To access Matrix elements/columns/rows/submatrices/properties:
+# To access Matrix elements/columns/rows/submatrices/properties:
# * <tt> [](i, j) </tt>
# * <tt> #row_size </tt>
# * <tt> #column_size </tt>
@@ -67,9 +54,13 @@
# * <tt> #column(j) </tt>
# * <tt> #collect </tt>
# * <tt> #map </tt>
+# * <tt> #each </tt>
+# * <tt> #each_with_index </tt>
# * <tt> #minor(*param) </tt>
#
# Properties of a matrix:
+# * <tt> #empty? </tt>
+# * <tt> #real? </tt>
# * <tt> #regular? </tt>
# * <tt> #singular? </tt>
# * <tt> #square? </tt>
@@ -92,6 +83,15 @@
# * <tt> #transpose </tt>
# * <tt> #t </tt>
#
+# Complex arithmetic:
+# * <tt> conj </tt>
+# * <tt> conjugate </tt>
+# * <tt> imag </tt>
+# * <tt> imaginary </tt>
+# * <tt> real </tt>
+# * <tt> rect </tt>
+# * <tt> rectangular </tt>
+#
# Conversion to other data types:
# * <tt> #coerce(other) </tt>
# * <tt> #row_vectors </tt>
@@ -103,14 +103,14 @@
# * <tt> #inspect </tt>
#
class Matrix
- @RCS_ID='-$Id: matrix.rb,v 1.13 2001/12/09 14:22:23 keiju Exp keiju $-'
-
-# extend Exception2MessageMapper
+ include Enumerable
include ExceptionForMatrix
-
+
# instance creations
private_class_method :new
-
+ attr_reader :rows
+ protected :rows
+
#
# Creates a matrix where each argument is a row.
# Matrix[ [25, 93], [-1, 66] ]
@@ -118,37 +118,64 @@
# -1 66
#
def Matrix.[](*rows)
- new(:init_rows, rows, false)
+ Matrix.rows(rows, false)
end
-
+
#
# Creates a matrix where +rows+ is an array of arrays, each of which is a row
- # to the matrix. If the optional argument +copy+ is false, use the given
+ # of the matrix. If the optional argument +copy+ is false, use the given
# arrays as the internal structure of the matrix without copying.
# Matrix.rows([[25, 93], [-1, 66]])
# => 25 93
# -1 66
+ #
def Matrix.rows(rows, copy = true)
- new(:init_rows, rows, copy)
+ rows = convert_to_array(rows)
+ rows.map! do |row|
+ convert_to_array(row, copy)
+ end
+ size = (rows[0] || []).size
+ rows.each do |row|
+ Matrix.Raise ErrDimensionMismatch, "row size differs (#{row.size} should be #{size})" unless row.size == size
+ end
+ new rows, size
end
-
+
#
# Creates a matrix using +columns+ as an array of column vectors.
# Matrix.columns([[25, 93], [-1, 66]])
# => 25 -1
# 93 66
#
- #
def Matrix.columns(columns)
- rows = (0 .. columns[0].size - 1).collect {|i|
- (0 .. columns.size - 1).collect {|j|
- columns[j][i]
- }
- }
- Matrix.rows(rows, false)
+ Matrix.rows(columns, false).transpose
end
-
+
#
+ # Creates a matrix of size +row_size+ x +column_size+.
+ # It fills the values by calling the given block,
+ # passing the current row and column.
+ # Returns an enumerator if no block is given.
+ #
+ # m = Matrix.build(2, 4) {|row, col| col - row }
+ # => Matrix[[0, 1, 2, 3], [-1, 0, 1, 2]]
+ # m = Matrix.build(3) { rand }
+ # => a 3x3 matrix with random elements
+ #
+ def Matrix.build(row_size, column_size = row_size)
+ row_size = CoercionHelper.coerce_to_int(row_size)
+ column_size = CoercionHelper.coerce_to_int(column_size)
+ raise ArgumentError if row_size < 0 || column_size < 0
+ return to_enum :build, row_size, column_size unless block_given?
+ rows = row_size.times.map do |i|
+ column_size.times.map do |j|
+ yield i, j
+ end
+ end
+ new rows, column_size
+ end
+
+ #
# Creates a matrix where the diagonal elements are composed of +values+.
# Matrix.diagonal(9, 5, -3)
# => 9 0 0
@@ -157,14 +184,14 @@
#
def Matrix.diagonal(*values)
size = values.size
- rows = (0 .. size - 1).collect {|j|
- row = Array.new(size).fill(0, 0, size)
+ rows = (0 ... size).collect {|j|
+ row = Array.new(size, 0)
row[j] = values[j]
row
}
- rows(rows, false)
+ new rows
end
-
+
#
# Creates an +n+ by +n+ diagonal matrix where each diagonal element is
# +value+.
@@ -173,7 +200,7 @@
# 0 5
#
def Matrix.scalar(n, value)
- Matrix.diagonal(*Array.new(n).fill(value, 0, n))
+ Matrix.diagonal(*Array.new(n, value))
end
#
@@ -185,11 +212,11 @@
def Matrix.identity(n)
Matrix.scalar(n, 1)
end
- class << Matrix
+ class << Matrix
alias unit identity
alias I identity
end
-
+
#
# Creates an +n+ by +n+ zero matrix.
# Matrix.zero(2)
@@ -199,7 +226,7 @@
def Matrix.zero(n)
Matrix.scalar(n, 0)
end
-
+
#
# Creates a single-row matrix where the values of that row are as given in
# +row+.
@@ -207,16 +234,10 @@
# => 4 5 6
#
def Matrix.row_vector(row)
- case row
- when Vector
- Matrix.rows([row.to_a], false)
- when Array
- Matrix.rows([row.dup], false)
- else
- Matrix.rows([[row]], false)
- end
+ row = convert_to_array(row)
+ new [row]
end
-
+
#
# Creates a single-column matrix where the values of that column are as given
# in +column+.
@@ -226,39 +247,51 @@
# 6
#
def Matrix.column_vector(column)
- case column
- when Vector
- Matrix.columns([column.to_a])
- when Array
- Matrix.columns([column])
- else
- Matrix.columns([[column]])
- end
+ column = convert_to_array(column)
+ new [column].transpose, 1
end
#
- # This method is used by the other methods that create matrices, and is of no
- # use to general users.
+ # Creates a empty matrix of +row_size+ x +column_size+.
+ # At least one of +row_size+ or +column_size+ must be 0.
#
- def initialize(init_method, *argv)
- self.send(init_method, *argv)
+ # m = Matrix.empty(2, 0)
+ # m == Matrix[ [], [] ]
+ # => true
+ # n = Matrix.empty(0, 3)
+ # n == Matrix.columns([ [], [], [] ])
+ # => true
+ # m * n
+ # => Matrix[[0, 0, 0], [0, 0, 0]]
+ #
+ def Matrix.empty(row_size = 0, column_size = 0)
+ Matrix.Raise ArgumentError, "One size must be 0" if column_size != 0 && row_size != 0
+ Matrix.Raise ArgumentError, "Negative size" if column_size < 0 || row_size < 0
+
+ new([[]]*row_size, column_size)
end
-
- def init_rows(rows, copy)
- if copy
- @rows = rows.collect{|row| row.dup}
- else
- @rows = rows
- end
- self
+
+ #
+ # Matrix.new is private; use Matrix.rows, columns, [], etc... to create.
+ #
+ def initialize(rows, column_size = rows[0].size)
+ # No checking is done at this point. rows must be an Array of Arrays.
+ # column_size must be the size of the first row, if there is one,
+ # otherwise it *must* be specified and can be any integer >= 0
+ @rows = rows
+ @column_size = column_size
end
- private :init_rows
-
+
+ def new_matrix(rows, column_size = rows[0].size) # :nodoc:
+ Matrix.send(:new, rows, column_size) # bypass privacy of Matrix.new
+ end
+ private :new_matrix
+
#
# Returns element (+i+,+j+) of the matrix. That is: row +i+, column +j+.
#
def [](i, j)
- @rows[i][j]
+ @rows.fetch(i){return nil}[j]
end
alias element []
alias component []
@@ -276,28 +309,22 @@
def row_size
@rows.size
end
-
+
#
- # Returns the number of columns. Note that it is possible to construct a
- # matrix with uneven columns (e.g. Matrix[ [1,2,3], [4,5] ]), but this is
- # mathematically unsound. This method uses the first row to determine the
- # result.
+ # Returns the number of columns.
#
- def column_size
- @rows[0].size
- end
+ attr_reader :column_size
#
# Returns row vector number +i+ of the matrix as a Vector (starting at 0 like
# an array). When a block is given, the elements of that vector are iterated.
#
- def row(i) # :yield: e
+ def row(i, &block) # :yield: e
if block_given?
- for e in @rows[i]
- yield e
- end
+ @rows.fetch(i){return self}.each(&block)
+ self
else
- Vector.elements(@rows[i])
+ Vector.elements(@rows.fetch(i){return nil})
end
end
@@ -308,17 +335,20 @@
#
def column(j) # :yield: e
if block_given?
- 0.upto(row_size - 1) do |i|
+ return self if j >= column_size || j < -column_size
+ row_size.times do |i|
yield @rows[i][j]
end
+ self
else
- col = (0 .. row_size - 1).collect {|i|
+ return nil if j >= column_size || j < -column_size
+ col = (0 ... row_size).collect {|i|
@rows[i][j]
}
Vector.elements(col, false)
end
end
-
+
#
# Returns a matrix that is the result of iteration of the given block over all
# elements of the matrix.
@@ -326,71 +356,135 @@
# => 1 4
# 9 16
#
- def collect # :yield: e
- rows = @rows.collect{|row| row.collect{|e| yield e}}
- Matrix.rows(rows, false)
+ def collect(&block) # :yield: e
+ return to_enum(:collect) unless block_given?
+ rows = @rows.collect{|row| row.collect(&block)}
+ new_matrix rows, column_size
end
alias map collect
-
+
#
+ # Yields all elements of the matrix, starting with those of the first row,
+ # or returns an Enumerator is no block given
+ # Matrix[ [1,2], [3,4] ].each { |e| puts e }
+ # # => prints the numbers 1 to 4
+ #
+ def each(&block) # :yield: e
+ return to_enum(:each) unless block_given?
+ @rows.each do |row|
+ row.each(&block)
+ end
+ self
+ end
+
+ #
+ # Yields all elements of the matrix, starting with those of the first row,
+ # along with the row index and column index,
+ # or returns an Enumerator is no block given
+ # Matrix[ [1,2], [3,4] ].each_with_index do |e, row, col|
+ # puts "#{e} at #{row}, #{col}"
+ # end
+ # # => 1 at 0, 0
+ # # => 2 at 0, 1
+ # # => 3 at 1, 0
+ # # => 4 at 1, 1
+ #
+ def each_with_index(&block) # :yield: e, row, column
+ return to_enum(:each_with_index) unless block_given?
+ @rows.each_with_index do |row, row_index|
+ row.each_with_index do |e, col_index|
+ yield e, row_index, col_index
+ end
+ end
+ self
+ end
+
+ #
# Returns a section of the matrix. The parameters are either:
# * start_row, nrows, start_col, ncols; OR
- # * col_range, row_range
+ # * row_range, col_range
#
# Matrix.diagonal(9, 5, -3).minor(0..1, 0..2)
# => 9 0 0
# 0 5 0
#
+ # Like Array#[], negative indices count backward from the end of the
+ # row or column (-1 is the last element). Returns nil if the starting
+ # row or column is greater than row_size or column_size respectively.
+ #
def minor(*param)
case param.size
when 2
- from_row = param[0].first
- size_row = param[0].end - from_row
- size_row += 1 unless param[0].exclude_end?
- from_col = param[1].first
- size_col = param[1].end - from_col
- size_col += 1 unless param[1].exclude_end?
+ row_range, col_range = param
+ from_row = row_range.first
+ from_row += row_size if from_row < 0
+ to_row = row_range.end
+ to_row += row_size if to_row < 0
+ to_row += 1 unless row_range.exclude_end?
+ size_row = to_row - from_row
+
+ from_col = col_range.first
+ from_col += column_size if from_col < 0
+ to_col = col_range.end
+ to_col += column_size if to_col < 0
+ to_col += 1 unless col_range.exclude_end?
+ size_col = to_col - from_col
when 4
- from_row = param[0]
- size_row = param[1]
- from_col = param[2]
- size_col = param[3]
+ from_row, size_row, from_col, size_col = param
+ return nil if size_row < 0 || size_col < 0
+ from_row += row_size if from_row < 0
+ from_col += column_size if from_col < 0
else
Matrix.Raise ArgumentError, param.inspect
end
-
+
+ return nil if from_row > row_size || from_col > column_size || from_row < 0 || from_col < 0
rows = @rows[from_row, size_row].collect{|row|
row[from_col, size_col]
}
- Matrix.rows(rows, false)
+ new_matrix rows, column_size - from_col
end
-
+
#--
# TESTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
#
- # Returns +true+ if this is a regular matrix.
+ # Returns +true+ if this is an empty matrix, i.e. if the number of rows
+ # or the number of columns is 0.
#
+ def empty?
+ column_size == 0 || row_size == 0
+ end
+
+ #
+ # Returns +true+ if all entries of the matrix are real.
+ #
+ def real?
+ all?(&:real?)
+ end
+
+ #
+ # Returns +true+ if this is a regular (i.e. non-singular) matrix.
+ #
def regular?
- square? and rank == column_size
+ not singular?
end
-
+
#
- # Returns +true+ is this is a singular (i.e. non-regular) matrix.
+ # Returns +true+ is this is a singular matrix.
#
def singular?
- not regular?
+ determinant == 0
end
#
- # Returns +true+ is this is a square matrix. See note in column_size about this
- # being unreliable, though.
+ # Returns +true+ is this is a square matrix.
#
def square?
column_size == row_size
end
-
+
#--
# OBJECT METHODS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
@@ -400,52 +494,34 @@
#
def ==(other)
return false unless Matrix === other
-
- other.compare_by_row_vectors(@rows)
+ rows == other.rows
end
+
def eql?(other)
return false unless Matrix === other
-
- other.compare_by_row_vectors(@rows, :eql?)
+ rows.eql? other.rows
end
-
+
#
- # Not really intended for general consumption.
- #
- def compare_by_row_vectors(rows, comparison = :==)
- return false unless @rows.size == rows.size
-
- 0.upto(@rows.size - 1) do |i|
- return false unless @rows[i].send(comparison, rows[i])
- end
- true
- end
-
- #
# Returns a clone of the matrix, so that the contents of each do not reference
# identical objects.
+ # There should be no good reason to do this since Matrices are immutable.
#
def clone
- Matrix.rows(@rows)
+ new_matrix @rows.map(&:dup), column_size
end
-
+
#
# Returns a hash-code for the matrix.
#
def hash
- value = 0
- for row in @rows
- for e in row
- value ^= e.hash
- end
- end
- return value
+ @rows.hash
end
-
+
#--
# ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
-
+
#
# Matrix multiplication.
# Matrix[[2,4], [6,8]] * Matrix.identity(2)
@@ -460,30 +536,27 @@
e * m
}
}
- return Matrix.rows(rows, false)
+ return new_matrix rows, column_size
when Vector
m = Matrix.column_vector(m)
r = self * m
return r.column(0)
when Matrix
Matrix.Raise ErrDimensionMismatch if column_size != m.row_size
-
- rows = (0 .. row_size - 1).collect {|i|
- (0 .. m.column_size - 1).collect {|j|
- vij = 0
- 0.upto(column_size - 1) do |k|
- vij += self[i, k] * m[k, j]
+
+ rows = (0 ... row_size).collect {|i|
+ (0 ... m.column_size).collect {|j|
+ (0 ... column_size).inject(0) do |vij, k|
+ vij + self[i, k] * m[k, j]
end
- vij
}
}
- return Matrix.rows(rows, false)
+ return new_matrix rows, m.column_size
else
- x, y = m.coerce(self)
- return x * y
+ return apply_through_coercion(m, __method__)
end
end
-
+
#
# Matrix addition.
# Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]]
@@ -493,23 +566,22 @@
def +(m)
case m
when Numeric
- Matrix.Raise ErrOperationNotDefined, "+"
+ Matrix.Raise ErrOperationNotDefined, "+", self.class, m.class
when Vector
m = Matrix.column_vector(m)
when Matrix
else
- x, y = m.coerce(self)
- return x + y
+ return apply_through_coercion(m, __method__)
end
-
+
Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
-
- rows = (0 .. row_size - 1).collect {|i|
- (0 .. column_size - 1).collect {|j|
+
+ rows = (0 ... row_size).collect {|i|
+ (0 ... column_size).collect {|j|
self[i, j] + m[i, j]
}
}
- Matrix.rows(rows, false)
+ new_matrix rows, column_size
end
#
@@ -521,25 +593,24 @@
def -(m)
case m
when Numeric
- Matrix.Raise ErrOperationNotDefined, "-"
+ Matrix.Raise ErrOperationNotDefined, "-", self.class, m.class
when Vector
m = Matrix.column_vector(m)
when Matrix
else
- x, y = m.coerce(self)
- return x - y
+ return apply_through_coercion(m, __method__)
end
-
+
Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
-
- rows = (0 .. row_size - 1).collect {|i|
- (0 .. column_size - 1).collect {|j|
+
+ rows = (0 ... row_size).collect {|i|
+ (0 ... column_size).collect {|j|
self[i, j] - m[i, j]
}
}
- Matrix.rows(rows, false)
+ new_matrix rows, column_size
end
-
+
#
# Matrix division (multiplication by the inverse).
# Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]]
@@ -554,38 +625,34 @@
e / other
}
}
- return Matrix.rows(rows, false)
+ return new_matrix rows, column_size
when Matrix
return self * other.inverse
else
- x, y = other.coerce(self)
- rerurn x / y
+ return apply_through_coercion(other, __method__)
end
end
#
# Returns the inverse of the matrix.
- # Matrix[[1, 2], [2, 1]].inverse
+ # Matrix[[-1, -1], [0, -1]].inverse
# => -1 1
# 0 -1
#
def inverse
Matrix.Raise ErrDimensionMismatch unless square?
- Matrix.I(row_size).inverse_from(self)
+ Matrix.I(row_size).send(:inverse_from, self)
end
alias inv inverse
- #
- # Not for public consumption?
- #
- def inverse_from(src)
- size = row_size - 1
+ def inverse_from(src) # :nodoc:
+ last = row_size - 1
a = src.to_a
-
- for k in 0..size
+
+ 0.upto(last) do |k|
i = k
akk = a[k][k].abs
- ((k+1)..size).each do |j|
+ (k+1).upto(last) do |j|
v = a[j][k].abs
if v > akk
i = j
@@ -598,258 +665,206 @@
@rows[i], @rows[k] = @rows[k], @rows[i]
end
akk = a[k][k]
-
- for i in 0 .. size
- next if i == k
- q = a[i][k].quo(akk)
- a[i][k] = 0
-
- for j in (k + 1).. size
- a[i][j] -= a[k][j] * q
+
+ 0.upto(last) do |ii|
+ next if ii == k
+ q = a[ii][k].quo(akk)
+ a[ii][k] = 0
+
+ (k + 1).upto(last) do |j|
+ a[ii][j] -= a[k][j] * q
end
- for j in 0..size
- @rows[i][j] -= @rows[k][j] * q
+ 0.upto(last) do |j|
+ @rows[ii][j] -= @rows[k][j] * q
end
end
-
- for j in (k + 1).. size
+
+ (k+1).upto(last) do |j|
a[k][j] = a[k][j].quo(akk)
end
- for j in 0..size
+ 0.upto(last) do |j|
@rows[k][j] = @rows[k][j].quo(akk)
end
end
self
end
- #alias reciprocal inverse
-
+ private :inverse_from
+
#
- # Matrix exponentiation. Defined for integer powers only. Equivalent to
- # multiplying the matrix by itself N times.
+ # Matrix exponentiation. Currently implemented for integer powers only.
+ # Equivalent to multiplying the matrix by itself N times.
# Matrix[[7,6], [3,9]] ** 2
# => 67 96
# 48 99
#
def ** (other)
- if other.kind_of?(Integer)
+ case other
+ when Integer
x = self
if other <= 0
x = self.inverse
return Matrix.identity(self.column_size) if other == 0
other = -other
end
- z = x
- n = other - 1
- while n != 0
- while (div, mod = n.divmod(2)
- mod == 0)
- x = x * x
- n = div
- end
- z *= x
- n -= 1
+ z = nil
+ loop do
+ z = z ? z * x : x if other[0] == 1
+ return z if (other >>= 1).zero?
+ x *= x
end
- z
- elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational)
- Matrix.Raise ErrOperationNotDefined, "**"
+ when Float, Rational
+ Matrix.Raise ErrOperationNotImplemented, "**", self.class, other.class
else
- Matrix.Raise ErrOperationNotDefined, "**"
+ Matrix.Raise ErrOperationNotDefined, "**", self.class, other.class
end
end
-
+
#--
# MATRIX FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
-
+
#
- # Returns the determinant of the matrix. If the matrix is not square, the
- # result is 0. This method's algorism is Gaussian elimination method
- # and using Numeric#quo(). Beware that using Float values, with their
- # usual lack of precision, can affect the value returned by this method. Use
- # Rational values or Matrix#det_e instead if this is important to you.
+ # Returns the determinant of the matrix.
#
+ # Beware that using Float values can yield erroneous results
+ # because of their lack of precision.
+ # Consider using exact types like Rational or BigDecimal instead.
+ #
# Matrix[[7,6], [3,9]].determinant
- # => 63.0
+ # => 45
#
def determinant
- return 0 unless square?
-
- size = row_size - 1
- a = to_a
-
- det = 1
- k = 0
- loop do
- if (akk = a[k][k]) == 0
- i = k
- loop do
- return 0 if (ii += 1) > size
- break unless a[i][k] == 0
- end
- a[i], a[k] = a[k], a[i]
- akk = a[k][k]
- det *= -1
- end
-
- for i in k + 1 .. size
- q = a[i][k].quo(akk)
- (k + 1).upto(size) do |j|
- a[i][j] -= a[k][j] * q
- end
- end
- det *= akk
- break unless (k += 1) <= size
+ Matrix.Raise ErrDimensionMismatch unless square?
+ m = @rows
+ case row_size
+ # Up to 4x4, give result using Laplacian expansion by minors.
+ # This will typically be faster, as well as giving good results
+ # in case of Floats
+ when 0
+ +1
+ when 1
+ + m[0][0]
+ when 2
+ + m[0][0] * m[1][1] - m[0][1] * m[1][0]
+ when 3
+ m0 = m[0]; m1 = m[1]; m2 = m[2]
+ + m0[0] * m1[1] * m2[2] - m0[0] * m1[2] * m2[1] \
+ - m0[1] * m1[0] * m2[2] + m0[1] * m1[2] * m2[0] \
+ + m0[2] * m1[0] * m2[1] - m0[2] * m1[1] * m2[0]
+ when 4
+ m0 = m[0]; m1 = m[1]; m2 = m[2]; m3 = m[3]
+ + m0[0] * m1[1] * m2[2] * m3[3] - m0[0] * m1[1] * m2[3] * m3[2] \
+ - m0[0] * m1[2] * m2[1] * m3[3] + m0[0] * m1[2] * m2[3] * m3[1] \
+ + m0[0] * m1[3] * m2[1] * m3[2] - m0[0] * m1[3] * m2[2] * m3[1] \
+ - m0[1] * m1[0] * m2[2] * m3[3] + m0[1] * m1[0] * m2[3] * m3[2] \
+ + m0[1] * m1[2] * m2[0] * m3[3] - m0[1] * m1[2] * m2[3] * m3[0] \
+ - m0[1] * m1[3] * m2[0] * m3[2] + m0[1] * m1[3] * m2[2] * m3[0] \
+ + m0[2] * m1[0] * m2[1] * m3[3] - m0[2] * m1[0] * m2[3] * m3[1] \
+ - m0[2] * m1[1] * m2[0] * m3[3] + m0[2] * m1[1] * m2[3] * m3[0] \
+ + m0[2] * m1[3] * m2[0] * m3[1] - m0[2] * m1[3] * m2[1] * m3[0] \
+ - m0[3] * m1[0] * m2[1] * m3[2] + m0[3] * m1[0] * m2[2] * m3[1] \
+ + m0[3] * m1[1] * m2[0] * m3[2] - m0[3] * m1[1] * m2[2] * m3[0] \
+ - m0[3] * m1[2] * m2[0] * m3[1] + m0[3] * m1[2] * m2[1] * m3[0]
+ else
+ # For bigger matrices, use an efficient and general algorithm.
+ # Currently, we use the Gauss-Bareiss algorithm
+ determinant_bareiss
end
- det
end
- alias det determinant
+ alias_method :det, :determinant
#
- # Returns the determinant of the matrix. If the matrix is not square, the
- # result is 0. This method's algorism is Gaussian elimination method.
- # This method uses Euclidean algorism. If all elements are integer,
- # really exact value. But, if an element is a float, can't return
- # exact value.
+ # Private. Use Matrix#determinant
#
- # Matrix[[7,6], [3,9]].determinant
- # => 63
+ # Returns the determinant of the matrix, using
+ # Bareiss' multistep integer-preserving gaussian elimination.
+ # It has the same computational cost order O(n^3) as standard Gaussian elimination.
+ # Intermediate results are fraction free and of lower complexity.
+ # A matrix of Integers will have thus intermediate results that are also Integers,
+ # with smaller bignums (if any), while a matrix of Float will usually have
+ # intermediate results with better precision.
#
- def determinant_e
- return 0 unless square?
-
- size = row_size - 1
+ def determinant_bareiss
+ size = row_size
+ last = size - 1
a = to_a
-
- det = 1
- k = 0
- loop do
- if a[k][k].zero?
- i = k
- loop do
- return 0 if (i += 1) > size
- break unless a[i][k].zero?
- end
- a[i], a[k] = a[k], a[i]
- det *= -1
+ no_pivot = Proc.new{ return 0 }
+ sign = +1
+ pivot = 1
+ size.times do |k|
+ previous_pivot = pivot
+ if (pivot = a[k][k]) == 0
+ switch = (k+1 ... size).find(no_pivot) {|row|
+ a[row][k] != 0
+ }
+ a[switch], a[k] = a[k], a[switch]
+ pivot = a[k][k]
+ sign = -sign
end
-
- for i in (k + 1)..size
- q = a[i][k].quo(a[k][k])
- k.upto(size) do |j|
- a[i][j] -= a[k][j] * q
+ (k+1).upto(last) do |i|
+ ai = a[i]
+ (k+1).upto(last) do |j|
+ ai[j] = (pivot * ai[j] - ai[k] * a[k][j]) / previous_pivot
end
- unless a[i][k].zero?
- a[i], a[k] = a[k], a[i]
- det *= -1
- redo
- end
end
- det *= a[k][k]
- break unless (k += 1) <= size
end
- det
+ sign * pivot
end
+ private :determinant_bareiss
+
+ #
+ # deprecated; use Matrix#determinant
+ #
+ def determinant_e
+ warn "#{caller(1)[0]}: warning: Matrix#determinant_e is deprecated; use #determinant"
+ rank
+ end
alias det_e determinant_e
#
- # Returns the rank of the matrix. Beware that using Float values,
- # probably return faild value. Use Rational values or Matrix#rank_e
- # for getting exact result.
+ # Returns the rank of the matrix.
+ # Beware that using Float values can yield erroneous results
+ # because of their lack of precision.
+ # Consider using exact types like Rational or BigDecimal instead.
#
# Matrix[[7,6], [3,9]].rank
# => 2
#
def rank
- if column_size > row_size
- a = transpose.to_a
- a_column_size = row_size
- a_row_size = column_size
- else
- a = to_a
- a_column_size = column_size
- a_row_size = row_size
- end
+ # We currently use Bareiss' multistep integer-preserving gaussian elimination
+ # (see comments on determinant)
+ a = to_a
+ last_column = column_size - 1
+ last_row = row_size - 1
rank = 0
- k = 0
- loop do
- if (akk = a[k][k]) == 0
- i = k
- exists = true
- loop do
- if (i += 1) > a_column_size - 1
- exists = false
- break
- end
- break unless a[i][k] == 0
- end
- if exists
- a[i], a[k] = a[k], a[i]
- akk = a[k][k]
- else
- i = k
- exists = true
- loop do
- if (i += 1) > a_row_size - 1
- exists = false
- break
- end
- break unless a[k][i] == 0
- end
- if exists
- k.upto(a_column_size - 1) do |j|
- a[j][k], a[j][i] = a[j][i], a[j][k]
- end
- akk = a[k][k]
- else
- next
- end
- end
+ pivot_row = 0
+ previous_pivot = 1
+ 0.upto(last_column) do |k|
+ switch_row = (pivot_row .. last_row).find {|row|
+ a[row][k] != 0
+ }
+ if switch_row
+ a[switch_row], a[pivot_row] = a[pivot_row], a[switch_row] unless pivot_row == switch_row
+ pivot = a[pivot_row][k]
+ (pivot_row+1).upto(last_row) do |i|
+ ai = a[i]
+ (k+1).upto(last_column) do |j|
+ ai[j] = (pivot * ai[j] - ai[k] * a[pivot_row][j]) / previous_pivot
+ end
+ end
+ pivot_row += 1
+ previous_pivot = pivot
end
-
- for i in (k + 1)..(a_row_size - 1)
- q = a[i][k].quo(akk)
- for j in (k + 1)..(a_column_size - 1)
- a[i][j] -= a[k][j] * q
- end
- end
- rank += 1
- break unless (k += 1) <= a_column_size - 1
end
- return rank
+ pivot_row
end
#
- # Returns the rank of the matrix. This method uses Euclidean
- # algorism. If all elements are integer, really exact value. But, if
- # an element is a float, can't return exact value.
+ # deprecated; use Matrix#rank
#
- # Matrix[[7,6], [3,9]].rank
- # => 2
- #
def rank_e
- a = to_a
- a_column_size = column_size
- a_row_size = row_size
- pi = 0
- (0 ... a_column_size).each do |j|
- if i = (pi ... a_row_size).find{|i0| !a[i0][j].zero?}
- if i != pi
- a[pi], a[i] = a[i], a[pi]
- end
- (pi + 1 ... a_row_size).each do |k|
- q = a[k][j].quo(a[pi][j])
- (pi ... a_column_size).each do |j0|
- a[k][j0] -= q * a[pi][j0]
- end
- if k > pi && !a[k][j].zero?
- a[k], a[pi] = a[pi], a[k]
- redo
- end
- end
- pi += 1
- end
- end
- pi
+ warn "#{caller(1)[0]}: warning: Matrix#rank_e is deprecated; use #rank"
+ rank
end
@@ -859,14 +874,13 @@
# => 16
#
def trace
- tr = 0
- 0.upto(column_size - 1) do |i|
- tr += @rows[i][i]
+ Matrix.Raise ErrDimensionMismatch unless square?
+ (0...column_size).inject(0) do |tr, i|
+ tr + @rows[i][i]
end
- tr
end
alias tr trace
-
+
#
# Returns the transpose of the matrix.
# Matrix[[1,2], [3,4], [5,6]]
@@ -878,16 +892,77 @@
# 2 4 6
#
def transpose
- Matrix.columns(@rows)
+ return Matrix.empty(column_size, 0) if row_size.zero?
+ new_matrix @rows.transpose, row_size
end
alias t transpose
-
+
#--
+ # COMPLEX ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ #++
+
+ #
+ # Returns the conjugate of the matrix.
+ # Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
+ # => 1+2i i 0
+ # 1 2 3
+ # Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].conjugate
+ # => 1-2i -i 0
+ # 1 2 3
+ #
+ def conjugate
+ collect(&:conjugate)
+ end
+ alias conj conjugate
+
+ #
+ # Returns the imaginary part of the matrix.
+ # Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
+ # => 1+2i i 0
+ # 1 2 3
+ # Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].imaginary
+ # => 2i i 0
+ # 0 0 0
+ #
+ def imaginary
+ collect(&:imaginary)
+ end
+ alias imag imaginary
+
+ #
+ # Returns the real part of the matrix.
+ # Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
+ # => 1+2i i 0
+ # 1 2 3
+ # Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].real
+ # => 1 0 0
+ # 1 2 3
+ #
+ def real
+ collect(&:real)
+ end
+
+ #
+ # Returns an array containing matrices corresponding to the real and imaginary
+ # parts of the matrix
+ #
+ # m.rect == [m.real, m.imag] # ==> true for all matrices m
+ #
+ def rect
+ [real, imag]
+ end
+ alias rectangular rect
+
+ #--
# CONVERTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
-
+
#
- # FIXME: describe #coerce.
+ # The coerce method provides support for Ruby type coercion.
+ # This coercion mechanism is used by Ruby to handle mixed-type
+ # numeric operations: it is intended to find a compatible common
+ # type between the two operands of the operator.
+ # See also Numeric#coerce.
#
def coerce(other)
case other
@@ -902,99 +977,171 @@
# Returns an array of the row vectors of the matrix. See Vector.
#
def row_vectors
- rows = (0 .. row_size - 1).collect {|i|
+ (0 ... row_size).collect {|i|
row(i)
}
- rows
end
-
+
#
# Returns an array of the column vectors of the matrix. See Vector.
#
def column_vectors
- columns = (0 .. column_size - 1).collect {|i|
+ (0 ... column_size).collect {|i|
column(i)
}
- columns
end
-
+
#
# Returns an array of arrays that describe the rows of the matrix.
#
def to_a
- @rows.collect{|row| row.collect{|e| e}}
+ @rows.collect{|row| row.dup}
end
-
+
def elements_to_f
- collect{|e| e.to_f}
+ warn "#{caller(1)[0]}: warning: Matrix#elements_to_f is deprecated, use map(&:to_f)"
+ map(&:to_f)
end
-
+
def elements_to_i
- collect{|e| e.to_i}
+ warn "#{caller(1)[0]}: warning: Matrix#elements_to_i is deprecated, use map(&:to_i)"
+ map(&:to_i)
end
-
+
def elements_to_r
- collect{|e| e.to_r}
+ warn "#{caller(1)[0]}: warning: Matrix#elements_to_r is deprecated, use map(&:to_r)"
+ map(&:to_r)
end
-
+
#--
# PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
-
+
#
# Overrides Object#to_s
#
def to_s
- "Matrix[" + @rows.collect{|row|
- "[" + row.collect{|e| e.to_s}.join(", ") + "]"
- }.join(", ")+"]"
+ if empty?
+ "Matrix.empty(#{row_size}, #{column_size})"
+ else
+ "Matrix[" + @rows.collect{|row|
+ "[" + row.collect{|e| e.to_s}.join(", ") + "]"
+ }.join(", ")+"]"
+ end
end
-
+
#
# Overrides Object#inspect
#
def inspect
- "Matrix"+ at rows.inspect
+ if empty?
+ "Matrix.empty(#{row_size}, #{column_size})"
+ else
+ "Matrix#{@rows.inspect}"
+ end
end
-
+
+ # Private helper modules
+
+ module ConversionHelper # :nodoc:
+ #
+ # Converts the obj to an Array. If copy is set to true
+ # a copy of obj will be made if necessary.
+ #
+ def convert_to_array(obj, copy = false) # :nodoc:
+ case obj
+ when Array
+ copy ? obj.dup : obj
+ when Vector
+ obj.to_a
+ else
+ begin
+ converted = obj.to_ary
+ rescue Exception => e
+ raise TypeError, "can't convert #{obj.class} into an Array (#{e.message})"
+ end
+ raise TypeError, "#{obj.class}#to_ary should return an Array" unless converted.is_a? Array
+ converted
+ end
+ end
+ private :convert_to_array
+ end
+
+ extend ConversionHelper
+
+ module CoercionHelper # :nodoc:
+ #
+ # Applies the operator +oper+ with argument +obj+
+ # through coercion of +obj+
+ #
+ def apply_through_coercion(obj, oper)
+ coercion = obj.coerce(self)
+ raise TypeError unless coercion.is_a?(Array) && coercion.length == 2
+ coercion[0].public_send(oper, coercion[1])
+ rescue
+ raise TypeError, "#{obj.inspect} can't be coerced into #{self.class}"
+ end
+ private :apply_through_coercion
+
+ #
+ # Helper method to coerce a value into a specific class.
+ # Raises a TypeError if the coercion fails or the returned value
+ # is not of the right class.
+ # (from Rubinius)
+ #
+ def self.coerce_to(obj, cls, meth) # :nodoc:
+ return obj if obj.kind_of?(cls)
+
+ begin
+ ret = obj.__send__(meth)
+ rescue Exception => e
+ raise TypeError, "Coercion error: #{obj.inspect}.#{meth} => #{cls} failed:\n" \
+ "(#{e.message})"
+ end
+ raise TypeError, "Coercion error: obj.#{meth} did NOT return a #{cls} (was #{ret.class})" unless ret.kind_of? cls
+ ret
+ end
+
+ def self.coerce_to_int(obj)
+ coerce_to(obj, Integer, :to_int)
+ end
+ end
+
+ include CoercionHelper
+
# Private CLASS
-
+
class Scalar < Numeric # :nodoc:
include ExceptionForMatrix
-
+ include CoercionHelper
+
def initialize(value)
@value = value
end
-
+
# ARITHMETIC
def +(other)
case other
when Numeric
Scalar.new(@value + other)
when Vector, Matrix
- Scalar.Raise WrongArgType, other.class, "Numeric or Scalar"
- when Scalar
- Scalar.new(@value + other.value)
+ Scalar.Raise ErrOperationNotDefined, "+", @value.class, other.class
else
- x, y = other.coerce(self)
- x + y
+ apply_through_coercion(other, __method__)
end
end
-
+
def -(other)
case other
when Numeric
Scalar.new(@value - other)
when Vector, Matrix
- Scalar.Raise WrongArgType, other.class, "Numeric or Scalar"
- when Scalar
- Scalar.new(@value - other.value)
+ Scalar.Raise ErrOperationNotDefined, "-", @value.class, other.class
else
- x, y = other.coerce(self)
- x - y
+ apply_through_coercion(other, __method__)
end
end
-
+
def *(other)
case other
when Numeric
@@ -1002,39 +1149,38 @@
when Vector, Matrix
other.collect{|e| @value * e}
else
- x, y = other.coerce(self)
- x * y
+ apply_through_coercion(other, __method__)
end
end
-
+
def / (other)
case other
when Numeric
Scalar.new(@value / other)
when Vector
- Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
+ Scalar.Raise ErrOperationNotDefined, "/", @value.class, other.class
when Matrix
- self * other.inverse
+ self * other.inverse
else
- x, y = other.coerce(self)
- x.quo(y)
+ apply_through_coercion(other, __method__)
end
end
-
+
def ** (other)
case other
when Numeric
Scalar.new(@value ** other)
when Vector
- Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
+ Scalar.Raise ErrOperationNotDefined, "**", @value.class, other.class
when Matrix
- other.powered_by(self)
+ #other.powered_by(self)
+ Scalar.Raise ErrOperationNotImplemented, "**", @value.class, other.class
else
- x, y = other.coerce(self)
- x ** y
+ apply_through_coercion(other, __method__)
end
end
end
+
end
@@ -1079,47 +1225,41 @@
#
class Vector
include ExceptionForMatrix
-
+ include Enumerable
+ include Matrix::CoercionHelper
+ extend Matrix::ConversionHelper
#INSTANCE CREATION
-
+
private_class_method :new
+ attr_reader :elements
+ protected :elements
#
# Creates a Vector from a list of elements.
# Vector[7, 4, ...]
#
def Vector.[](*array)
- new(:init_elements, array, copy = false)
+ new convert_to_array(array, copy = false)
end
-
+
#
# Creates a vector from an Array. The optional second argument specifies
# whether the array itself or a copy is used internally.
#
def Vector.elements(array, copy = true)
- new(:init_elements, array, copy)
+ new convert_to_array(array, copy)
end
-
+
#
- # For internal use.
+ # Vector.new is private; use Vector[] or Vector.elements to create.
#
- def initialize(method, array, copy)
- self.send(method, array, copy)
+ def initialize(array)
+ # No checking is done at this point.
+ @elements = array
end
-
- #
- # For internal use.
- #
- def init_elements(array, copy)
- if copy
- @elements = array.dup
- else
- @elements = array
- end
- end
-
+
# ACCESSING
-
+
#
# Returns element number +i+ (starting at zero) of the vector.
#
@@ -1135,35 +1275,49 @@
alias set_element []=
alias set_component []=
private :[]=, :set_element, :set_component
-
+
#
# Returns the number of elements in the vector.
#
def size
@elements.size
end
-
+
#--
# ENUMERATIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
#
+ # Iterate over the elements of this vector
+ #
+ def each(&block)
+ return to_enum(:each) unless block_given?
+ @elements.each(&block)
+ self
+ end
+
+ #
# Iterate over the elements of this vector and +v+ in conjunction.
#
def each2(v) # :yield: e1, e2
+ raise TypeError, "Integer is not like Vector" if v.kind_of?(Integer)
Vector.Raise ErrDimensionMismatch if size != v.size
- 0.upto(size - 1) do |i|
+ return to_enum(:each2, v) unless block_given?
+ size.times do |i|
yield @elements[i], v[i]
end
+ self
end
-
+
#
# Collects (as in Enumerable#collect) over the elements of this vector and +v+
# in conjunction.
#
def collect2(v) # :yield: e1, e2
+ raise TypeError, "Integer is not like Vector" if v.kind_of?(Integer)
Vector.Raise ErrDimensionMismatch if size != v.size
- (0 .. size - 1).collect do |i|
+ return to_enum(:collect2, v) unless block_given?
+ size.times.collect do |i|
yield @elements[i], v[i]
end
end
@@ -1177,40 +1331,32 @@
#
def ==(other)
return false unless Vector === other
-
- other.compare_by(@elements)
+ @elements == other.elements
end
+
def eql?(other)
return false unless Vector === other
-
- other.compare_by(@elements, :eql?)
+ @elements.eql? other.elements
end
-
+
#
- # For internal use.
- #
- def compare_by(elements, comparison = :==)
- @elements.send(comparison, elements)
- end
-
- #
# Return a copy of the vector.
#
def clone
Vector.elements(@elements)
end
-
+
#
# Return a hash-code for the vector.
#
def hash
@elements.hash
end
-
+
#--
# ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
-
+
#
# Multiplies the vector by +x+, where +x+ is a number or another vector.
#
@@ -1221,9 +1367,10 @@
Vector.elements(els, false)
when Matrix
Matrix.column_vector(self) * x
+ when Vector
+ Vector.Raise ErrOperationNotDefined, "*", self.class, x.class
else
- s, x = x.coerce(self)
- s * x
+ apply_through_coercion(x, __method__)
end
end
@@ -1241,8 +1388,7 @@
when Matrix
Matrix.column_vector(self) + v
else
- s, x = v.coerce(self)
- s + x
+ apply_through_coercion(v, __method__)
end
end
@@ -1260,62 +1406,70 @@
when Matrix
Matrix.column_vector(self) - v
else
- s, x = v.coerce(self)
- s - x
+ apply_through_coercion(v, __method__)
end
end
-
+
+ #
+ # Vector division.
+ #
+ def /(x)
+ case x
+ when Numeric
+ els = @elements.collect{|e| e / x}
+ Vector.elements(els, false)
+ when Matrix, Vector
+ Vector.Raise ErrOperationNotDefined, "/", self.class, x.class
+ else
+ apply_through_coercion(x, __method__)
+ end
+ end
+
#--
# VECTOR FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
-
+
#
# Returns the inner product of this vector with the other.
# Vector[4,7].inner_product Vector[10,1] => 47
#
def inner_product(v)
Vector.Raise ErrDimensionMismatch if size != v.size
-
+
p = 0
each2(v) {|v1, v2|
p += v1 * v2
}
p
end
-
+
#
# Like Array#collect.
#
- def collect # :yield: e
- els = @elements.collect {|v|
- yield v
- }
+ def collect(&block) # :yield: e
+ return to_enum(:collect) unless block_given?
+ els = @elements.collect(&block)
Vector.elements(els, false)
end
alias map collect
-
+
#
# Like Vector#collect2, but returns a Vector instead of an Array.
#
- def map2(v) # :yield: e1, e2
- els = collect2(v) {|v1, v2|
- yield v1, v2
- }
+ def map2(v, &block) # :yield: e1, e2
+ return to_enum(:map2, v) unless block_given?
+ els = collect2(v, &block)
Vector.elements(els, false)
end
-
+
#
# Returns the modulus (Pythagorean distance) of the vector.
# Vector[5,8,2].r => 9.643650761
#
def r
- v = 0
- for e in @elements
- v += e*e
- end
- return Math.sqrt(v)
+ Math.sqrt(@elements.inject(0) {|v, e| v + e*e})
end
-
+
#--
# CONVERTING
#++
@@ -1326,28 +1480,35 @@
def covector
Matrix.row_vector(self)
end
-
+
#
# Returns the elements of the vector in an array.
#
def to_a
@elements.dup
end
-
+
def elements_to_f
- collect{|e| e.to_f}
+ warn "#{caller(1)[0]}: warning: Vector#elements_to_f is deprecated"
+ map(&:to_f)
end
-
+
def elements_to_i
- collect{|e| e.to_i}
+ warn "#{caller(1)[0]}: warning: Vector#elements_to_i is deprecated"
+ map(&:to_i)
end
-
+
def elements_to_r
- collect{|e| e.to_r}
+ warn "#{caller(1)[0]}: warning: Vector#elements_to_r is deprecated"
+ map(&:to_r)
end
-
+
#
- # FIXME: describe Vector#coerce.
+ # The coerce method provides support for Ruby type coercion.
+ # This coercion mechanism is used by Ruby to handle mixed-type
+ # numeric operations: it is intended to find a compatible common
+ # type between the two operands of the operator.
+ # See also Numeric#coerce.
#
def coerce(other)
case other
@@ -1357,18 +1518,18 @@
raise TypeError, "#{self.class} can't be coerced into #{other.class}"
end
end
-
+
#--
# PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
-
+
#
# Overrides Object#to_s
#
def to_s
"Vector[" + @elements.join(", ") + "]"
end
-
+
#
# Overrides Object#inspect
#
@@ -1376,7 +1537,3 @@
str = "Vector"+ at elements.inspect
end
end
-
-
-# Documentation comments:
-# - Matrix#coerce and Vector#coerce need to be documented
Modified: MacRuby/trunk/lib/minitest/autorun.rb
===================================================================
--- MacRuby/trunk/lib/minitest/autorun.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/minitest/autorun.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -5,5 +5,7 @@
############################################################
require 'minitest/unit'
+require 'minitest/spec'
+require 'minitest/mock'
MiniTest::Unit.autorun
Modified: MacRuby/trunk/lib/minitest/mock.rb
===================================================================
--- MacRuby/trunk/lib/minitest/mock.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/minitest/mock.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -16,6 +16,7 @@
def expect(name, retval, args=[])
n, r, a = name, retval, args # for the closure below
@expected_calls[name] = { :retval => retval, :args => args }
+ self.class.__send__ :remove_method, name if respond_to? name
self.class.__send__(:define_method, name) { |*x|
raise ArgumentError unless @expected_calls[n][:args].size == x.size
@actual_calls[n] << { :retval => r, :args => x }
Modified: MacRuby/trunk/lib/minitest/spec.rb
===================================================================
--- MacRuby/trunk/lib/minitest/spec.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/minitest/spec.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -9,7 +9,23 @@
require 'minitest/unit'
class Module
- def infect_with_assertions pos_prefix, neg_prefix, skip_re, map = {}
+ def infect_an_assertion meth, new_name, dont_flip = false
+ # warn "%-22p -> %p %p" % [meth, new_name, dont_flip]
+ self.class_eval <<-EOM
+ def #{new_name} *args, &block
+ return MiniTest::Spec.current.#{meth}(*args, &self) if
+ Proc === self
+ return MiniTest::Spec.current.#{meth}(args.first, self) if
+ args.size == 1 unless #{!!dont_flip}
+ return MiniTest::Spec.current.#{meth}(self, *args)
+ end
+ EOM
+ end
+
+ def infect_with_assertions(pos_prefix, neg_prefix,
+ skip_re,
+ dont_flip_re = /\c0/,
+ map = {})
MiniTest::Assertions.public_instance_methods(false).each do |meth|
meth = meth.to_s
@@ -25,14 +41,7 @@
regexp, replacement = map.find { |re, _| new_name =~ re }
new_name.sub! regexp, replacement if replacement
- # warn "%-22p -> %p %p" % [meth, new_name, regexp]
- self.class_eval <<-EOM
- def #{new_name} *args, &block
- return MiniTest::Spec.current.#{meth}(*args, &self) if Proc === self
- return MiniTest::Spec.current.#{meth}(args.first, self) if args.size == 1
- return MiniTest::Spec.current.#{meth}(self, *args)
- end
- EOM
+ infect_an_assertion meth, new_name, new_name =~ dont_flip_re
end
end
end
@@ -40,6 +49,7 @@
Object.infect_with_assertions(:must, :wont,
/^(must|wont)$|wont_(throw)|
must_(block|not?_|nothing|raise$)/x,
+ /(must|wont)_(include|respond_to)/,
/(must_throw)s/ => '\1',
/(?!not)_same/ => '_be_same_as',
/_in_/ => '_be_within_',
@@ -54,36 +64,229 @@
end
module Kernel
+ ##
+ # Describe a series of expectations for a given target +desc+.
+ #
+ # TODO: find good tutorial url.
+ #
+ # Defines a test class subclassing from either
+ # MiniTest::Unit::TestCase or from the surrounding describe's class.
+
def describe desc, &block
- cls = Class.new(MiniTest::Spec)
- Object.const_set desc.to_s.split(/\W+/).map { |s| s.capitalize }.join, cls
+ stack = MiniTest::Spec.describe_stack
+ name = desc.to_s.split(/\W+/).map { |s| s.capitalize }.join + "Spec"
+ prev = stack.last
+ name = "#{prev == MiniTest::Spec ? nil : prev}::#{name}"
+ cls = Object.class_eval "class #{name} < #{prev}; end; #{name}"
+ cls.nuke_test_methods!
+
+ stack.push cls
cls.class_eval(&block)
+ stack.pop
end
private :describe
end
+class Module
+ def classes type = Object # :nodoc:
+ constants.map { |n| const_get n }.find_all { |c|
+ c.class == Class and type > c
+ } - [self]
+ end
+end
+
class MiniTest::Spec < MiniTest::Unit::TestCase
- def self.current
+ @@describe_stack = [MiniTest::Spec]
+ def self.describe_stack # :nodoc:
+ @@describe_stack
+ end
+
+ def self.current # :nodoc:
@@current_spec
end
- def initialize name
+ def initialize name # :nodoc:
super
@@current_spec = self
end
- def self.before(type = :each, &block)
+ def self.nuke_test_methods! # :nodoc:
+ self.public_instance_methods.grep(/^test_/).each do |name|
+ self.send :undef_method, name
+ end
+ end
+
+ def self.define_inheritable_method name, &block # :nodoc:
+ super_method = self.superclass.instance_method name
+
+ define_method name do
+ super_method.bind(self).call if super_method # regular super() warns
+ instance_eval(&block)
+ end
+ end
+
+ ##
+ # Define a 'before' action. Inherits the way normal methods should.
+ #
+ # NOTE: +type+ is ignored and is only there to make porting easier.
+ #
+ # Equivalent to MiniTest::Unit::TestCase#setup.
+
+ def self.before type = :each, &block
raise "unsupported before type: #{type}" unless type == :each
- define_method :setup, &block
+ define_inheritable_method :setup, &block
end
- def self.after(type = :each, &block)
+ ##
+ # Define an 'after' action. Inherits the way normal methods should.
+ #
+ # NOTE: +type+ is ignored and is only there to make porting easier.
+ #
+ # Equivalent to MiniTest::Unit::TestCase#teardown.
+
+ def self.after type = :each, &block
raise "unsupported after type: #{type}" unless type == :each
- define_method :teardown, &block
+ define_inheritable_method :teardown, &block
end
+ ##
+ # Define an expectation with name +desc+. Name gets morphed to a
+ # proper test method name. For some freakish reason, people who
+ # write specs don't like class inheritence, so this goes way out of
+ # its way to make sure that expectations aren't inherited.
+ #
+ # Hint: If you _do_ want inheritence, use minitest/unit. You can mix
+ # and match between assertions and expectations as much as you want.
+
def self.it desc, &block
- define_method "test_#{desc.gsub(/\W+/, '_').downcase}", &block
+ block ||= proc { skip "(no tests defined)" }
+
+ @specs ||= 0
+ @specs += 1
+
+ name = "test_%04d_%s" % [ @specs, desc.gsub(/\W+/, '_').downcase ]
+
+ define_method name, &block
+
+ classes(MiniTest::Spec).each do |mod|
+ mod.send :undef_method, name if mod.respond_to? name
+ end
end
+
+ ##
+ # :method: must_be
+ # See MiniTest::Assertions#assert
+
+ ##
+ # :method: must_be_close_to
+ # See MiniTest::Assertions#assert_in_delta
+
+ ##
+ # :method: must_be_empty
+ # See MiniTest::Assertions#assert_empty
+
+ ##
+ # :method: must_be_instance_of
+ # See MiniTest::Assertions#assert_instance_of
+
+ ##
+ # :method: must_be_kind_of
+ # See MiniTest::Assertions#assert_kind_of
+
+ ##
+ # :method: must_be_nil
+ # See MiniTest::Assertions#assert_nil
+
+ ##
+ # :method: must_be_same_as
+ # See MiniTest::Assertions#assert_same
+
+ ##
+ # :method: must_be_within_delta
+ # See MiniTest::Assertions#assert_in_delta
+
+ ##
+ # :method: must_be_within_epsilon
+ # See MiniTest::Assertions#assert_in_epsilon
+
+ ##
+ # :method: must_equal
+ # See MiniTest::Assertions#assert_equal
+
+ ##
+ # :method: must_include
+ # See MiniTest::Assertions#assert_includes
+
+ ##
+ # :method: must_match
+ # See MiniTest::Assertions#assert_match
+
+ ##
+ # :method: must_raise
+ # See MiniTest::Assertions#assert_raises
+
+ ##
+ # :method: must_respond_to
+ # See MiniTest::Assertions#assert_respond_to
+
+ ##
+ # :method: must_send
+ # See MiniTest::Assertions#assert_send
+
+ ##
+ # :method: must_throw
+ # See MiniTest::Assertions#assert_throw
+
+ ##
+ # :method: wont_be
+ # See MiniTest::Assertions#refute
+
+ ##
+ # :method: wont_be_close_to
+ # See MiniTest::Assertions#refute_in_delta
+
+ ##
+ # :method: wont_be_empty
+ # See MiniTest::Assertions#refute_empty
+
+ ##
+ # :method: wont_be_instance_of
+ # See MiniTest::Assertions#refute_instance_of
+
+ ##
+ # :method: wont_be_kind_of
+ # See MiniTest::Assertions#refute_kind_of
+
+ ##
+ # :method: wont_be_nil
+ # See MiniTest::Assertions#refute_nil
+
+ ##
+ # :method: wont_be_same_as
+ # See MiniTest::Assertions#refute_same
+
+ ##
+ # :method: wont_be_within_delta
+ # See MiniTest::Assertions#refute_in_delta
+
+ ##
+ # :method: wont_be_within_epsilon
+ # See MiniTest::Assertions#refute_in_epsilon
+
+ ##
+ # :method: wont_equal
+ # See MiniTest::Assertions#refute_equal
+
+ ##
+ # :method: wont_include
+ # See MiniTest::Assertions#refute_includes
+
+ ##
+ # :method: wont_match
+ # See MiniTest::Assertions#refute_match
+
+ ##
+ # :method: wont_respond_to
+ # See MiniTest::Assertions#refute_respond_to
end
Modified: MacRuby/trunk/lib/minitest/unit.rb
===================================================================
--- MacRuby/trunk/lib/minitest/unit.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/minitest/unit.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -4,14 +4,21 @@
# File a patch instead and assign it to Ryan Davis
############################################################
+require 'optparse'
+
##
-#
-# Totally minimal drop-in replacement for test-unit
-#
-# TODO: refute -> debunk, prove/rebut, show/deny... lots of possibilities
+# Minimal (mostly drop-in) replacement for test-unit.
module MiniTest
+
+ ##
+ # Assertion base class
+
class Assertion < Exception; end
+
+ ##
+ # Assertion raised when skipping a test
+
class Skip < Assertion; end
file = if RUBY_VERSION =~ /^1\.9/ then # bt's expanded, but __FILE__ isn't :(
@@ -27,9 +34,9 @@
end
# './lib' in project dir, or '/usr/local/blahblah' if installed
- MINI_DIR = File.dirname(File.dirname(file))
+ MINI_DIR = File.dirname(File.dirname(file)) # :nodoc:
- def self.filter_backtrace bt
+ def self.filter_backtrace bt # :nodoc:
return ["No backtrace"] unless bt
new_bt = []
@@ -43,21 +50,33 @@
new_bt
end
+ ##
+ # MiniTest Assertions. All assertion methods accept a +msg+ which is
+ # printed if the assertion fails.
+
module Assertions
- def mu_pp(obj)
+
+ ##
+ # mu_pp gives a human-readable version of +obj+. By default #inspect is
+ # called. You can override this to use #pretty_print if you want.
+
+ def mu_pp obj
s = obj.inspect
s = s.force_encoding(Encoding.default_external) if defined? Encoding
s
end
- def _assertions= n
+ def _assertions= n # :nodoc:
@_assertions = n
end
- def _assertions
+ def _assertions # :nodoc:
@_assertions ||= 0
end
+ ##
+ # Fails unless +test+ is a true value.
+
def assert test, msg = nil
msg ||= "Failed assertion, no message given."
self._assertions += 1
@@ -68,105 +87,163 @@
true
end
+ ##
+ # Fails unless the block returns a true value.
+
def assert_block msg = nil
msg = message(msg) { "Expected block to return true value" }
assert yield, msg
end
+ ##
+ # Fails unless +obj+ is empty.
+
def assert_empty obj, msg = nil
msg = message(msg) { "Expected #{obj.inspect} to be empty" }
assert_respond_to obj, :empty?
assert obj.empty?, msg
end
+ ##
+ # Fails unless <tt>exp == act</tt>.
+ #
+ # For floats use assert_in_delta
+
def assert_equal exp, act, msg = nil
msg = message(msg) { "Expected #{mu_pp(exp)}, not #{mu_pp(act)}" }
assert(exp == act, msg)
end
+ ##
+ # For comparing Floats. Fails unless +exp+ and +act+ are within +delta+
+ # of each other.
+ #
+ # assert_in_delta Math::PI, (22.0 / 7.0), 0.01
+
def assert_in_delta exp, act, delta = 0.001, msg = nil
n = (exp - act).abs
msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to be < #{delta}" }
assert delta >= n, msg
end
+ ##
+ # For comparing Floats. Fails unless +exp+ and +act+ have a relative
+ # error less than +epsilon+.
+
def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
assert_in_delta a, b, [a, b].min * epsilon, msg
end
+ ##
+ # Fails unless +collection+ includes +obj+.
+
def assert_includes collection, obj, msg = nil
- msg = message(msg) { "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" }
+ msg = message(msg) {
+ "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}"
+ }
assert_respond_to collection, :include?
assert collection.include?(obj), msg
end
+ ##
+ # Fails unless +obj+ is an instace of +cls+.
+
def assert_instance_of cls, obj, msg = nil
- msg = message(msg) { "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}" }
- flip = (Module === obj) && ! (Module === cls) # HACK for specs
- obj, cls = cls, obj if flip
+ msg = message(msg) {
+ "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}"
+ }
+
assert obj.instance_of?(cls), msg
end
+ ##
+ # Fails unless +obj+ is a kind of +cls+.
+
def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
msg = message(msg) {
"Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
- flip = (Module === obj) && ! (Module === cls) # HACK for specs
- obj, cls = cls, obj if flip
+
assert obj.kind_of?(cls), msg
end
+ ##
+ # Fails unless +exp+ is <tt>=~</tt> +act+.
+
def assert_match exp, act, msg = nil
msg = message(msg) { "Expected #{mu_pp(exp)} to match #{mu_pp(act)}" }
assert_respond_to act, :"=~"
- exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
+ exp = /#{Regexp.escape exp}/ if String === exp && String === act
assert exp =~ act, msg
end
+ ##
+ # Fails unless +obj+ is nil
+
def assert_nil obj, msg = nil
msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
assert obj.nil?, msg
end
+ ##
+ # For testing equality operators and so-forth.
+ #
+ # assert_operator 5, :<=, 4
+
def assert_operator o1, op, o2, msg = nil
msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
assert o1.__send__(op, o2), msg
end
+ ##
+ # Fails unless the block raises one of +exp+
+
def assert_raises *exp
msg = String === exp.last ? exp.pop : nil
+ msg = msg.to_s + "\n" if msg
should_raise = false
begin
yield
should_raise = true
rescue Exception => e
+ details = "#{msg}#{mu_pp(exp)} exception expected, not"
assert(exp.any? { |ex|
ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class
- }, exception_details(e, "#{mu_pp(exp)} exception expected, not"))
+ }, exception_details(e, details))
return e
end
exp = exp.first if exp.size == 1
- flunk "#{mu_pp(exp)} expected but nothing was raised." if should_raise
+ flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised." if
+ should_raise
end
+ ##
+ # Fails unless +obj+ responds to +meth+.
+
def assert_respond_to obj, meth, msg = nil
msg = message(msg) {
"Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
}
- flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
- obj, meth = meth, obj if flip
assert obj.respond_to?(meth), msg
end
+ ##
+ # Fails unless +exp+ and +act+ are #equal?
+
def assert_same exp, act, msg = nil
msg = message(msg) {
data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
- "Expected %s (0x%x) to be the same as %s (0x%x)" % data
+ "Expected %s (oid=%d) to be the same as %s (oid=%d)" % data
}
assert exp.equal?(act), msg
end
+ ##
+ # +send_ary+ is a receiver, message and arguments.
+ #
+ # Fails unless the call returns a true value
+
def assert_send send_ary, m = nil
recv, msg, *args = send_ary
m = message(m) {
@@ -174,6 +251,9 @@
assert recv.__send__(msg, *args), m
end
+ ##
+ # Fails unless the block throws +sym+
+
def assert_throws sym, msg = nil
default = "Expected #{mu_pp(sym)} to have been thrown"
caught = true
@@ -191,6 +271,15 @@
assert caught, message(msg) { default }
end
+ ##
+ # Captures $stdout and $stderr into strings:
+ #
+ # out, err = capture_io do
+ # warn "You did a bad thing"
+ # end
+ #
+ # assert_match %r%bad%, err
+
def capture_io
require 'stringio'
@@ -206,15 +295,24 @@
$stderr = orig_stderr
end
+ ##
+ # Returns details for exception +e+
+
def exception_details e, msg
"#{msg}\nClass: <#{e.class}>\nMessage: <#{e.message.inspect}>\n---Backtrace---\n#{MiniTest::filter_backtrace(e.backtrace).join("\n")}\n---------------"
end
+ ##
+ # Fails with +msg+
+
def flunk msg = nil
msg ||= "Epic Fail!"
assert false, msg
end
+ ##
+ # Returns a proc that will output +msg+ along with the default message.
+
def message msg = nil, &default
proc {
if msg then
@@ -228,86 +326,147 @@
}
end
+ ##
# used for counting assertions
+
def pass msg = nil
assert true
end
+ ##
+ # Fails if +test+ is a true value
+
def refute test, msg = nil
msg ||= "Failed refutation, no message given"
not assert(! test, msg)
end
+ ##
+ # Fails if +obj+ is empty.
+
def refute_empty obj, msg = nil
msg = message(msg) { "Expected #{obj.inspect} to not be empty" }
assert_respond_to obj, :empty?
refute obj.empty?, msg
end
+ ##
+ # Fails if <tt>exp == act</tt>.
+ #
+ # For floats use refute_in_delta.
+
def refute_equal exp, act, msg = nil
- msg = message(msg) { "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}" }
+ msg = message(msg) {
+ "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}"
+ }
refute exp == act, msg
end
+ ##
+ # For comparing Floats. Fails if +exp+ is within +delta+ of +act+
+ #
+ # refute_in_delta Math::PI, (22.0 / 7.0)
+
def refute_in_delta exp, act, delta = 0.001, msg = nil
n = (exp - act).abs
- msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to not be < #{delta}" }
+ msg = message(msg) {
+ "Expected #{exp} - #{act} (#{n}) to not be < #{delta}"
+ }
refute delta > n, msg
end
+ ##
+ # For comparing Floats. Fails if +exp+ and +act+ have a relative error
+ # less than +epsilon+.
+
def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
refute_in_delta a, b, a * epsilon, msg
end
+ ##
+ # Fails if +collection+ includes +obj+
+
def refute_includes collection, obj, msg = nil
- msg = message(msg) { "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}" }
+ msg = message(msg) {
+ "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}"
+ }
assert_respond_to collection, :include?
refute collection.include?(obj), msg
end
+ ##
+ # Fails if +obj+ is an instance of +cls+
+
def refute_instance_of cls, obj, msg = nil
- msg = message(msg) { "Expected #{mu_pp(obj)} to not be an instance of #{cls}" }
- flip = (Module === obj) && ! (Module === cls) # HACK for specs
- obj, cls = cls, obj if flip
+ msg = message(msg) {
+ "Expected #{mu_pp(obj)} to not be an instance of #{cls}"
+ }
refute obj.instance_of?(cls), msg
end
+ ##
+ # Fails if +obj+ is a kind of +cls+
+
def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of
msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
- flip = (Module === obj) && ! (Module === cls) # HACK for specs
- obj, cls = cls, obj if flip
refute obj.kind_of?(cls), msg
end
+ ##
+ # Fails if +exp+ <tt>=~</tt> +act+
+
def refute_match exp, act, msg = nil
msg = message(msg) { "Expected #{mu_pp(exp)} to not match #{mu_pp(act)}" }
assert_respond_to act, :"=~"
- exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
+ exp = (/#{Regexp.escape exp}/) if String === exp and String === act
refute exp =~ act, msg
end
+ ##
+ # Fails if +obj+ is nil.
+
def refute_nil obj, msg = nil
msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
refute obj.nil?, msg
end
+ ##
+ # Fails if +o1+ is not +op+ +o2+ nil. eg:
+ #
+ # refute_operator 1, :>, 2 #=> pass
+ # refute_operator 1, :<, 2 #=> fail
+
def refute_operator o1, op, o2, msg = nil
- msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}" }
+ msg = message(msg) {
+ "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}"
+ }
refute o1.__send__(op, o2), msg
end
+ ##
+ # Fails if +obj+ responds to the message +meth+.
+
def refute_respond_to obj, meth, msg = nil
msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
- flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
- obj, meth = meth, obj if flip
+
refute obj.respond_to?(meth), msg
end
+ ##
+ # Fails if +exp+ is the same (by object identity) as +act+.
+
def refute_same exp, act, msg = nil
- msg = message(msg) { "Expected #{mu_pp(act)} to not be the same as #{mu_pp(exp)}" }
+ msg = message(msg) {
+ data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
+ "Expected %s (oid=%d) to not be the same as %s (oid=%d)" % data
+ }
refute exp.equal?(act), msg
end
+ ##
+ # Skips the current test. Gets listed at the end of the run but
+ # doesn't cause a failure exit code.
+
def skip msg = nil, bt = caller
msg ||= "Skipped, no message given"
raise MiniTest::Skip, msg, bt
@@ -315,14 +474,18 @@
end
class Unit
- VERSION = "1.3.1"
+ VERSION = "1.6.0" # :nodoc:
- attr_accessor :report, :failures, :errors, :skips
- attr_accessor :test_count, :assertion_count
+ attr_accessor :report, :failures, :errors, :skips # :nodoc:
+ attr_accessor :test_count, :assertion_count # :nodoc:
+ attr_accessor :start_time # :nodoc:
@@installed_at_exit ||= false
@@out = $stdout
+ ##
+ # Registers MiniTest::Unit to run tests at process exit
+
def self.autorun
at_exit {
next if $! # don't run if there was an exception
@@ -332,19 +495,27 @@
@@installed_at_exit = true
end
+ ##
+ # Sets MiniTest::Unit to write output to +stream+. $stdout is the default
+ # output
+
def self.output= stream
@@out = stream
end
- def location e
+ def location e # :nodoc:
last_before_assertion = ""
e.backtrace.reverse_each do |s|
- break if s =~ /in .(assert|refute|flunk|pass|fail|raise)/
+ break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
last_before_assertion = s
end
last_before_assertion.sub(/:in .*$/, '')
end
+ ##
+ # Writes status for failed test +meth+ in +klass+ which finished with
+ # exception +e+
+
def puke klass, meth, e
e = case e
when MiniTest::Skip then
@@ -362,26 +533,61 @@
e[0, 1]
end
- def initialize
+ def initialize # :nodoc:
@report = []
@errors = @failures = @skips = 0
@verbose = false
end
+ def process_args args = []
+ options = {}
+
+ OptionParser.new do |opts|
+ opts.banner = 'minitest options:'
+ opts.version = MiniTest::Unit::VERSION
+
+ opts.on '-h', '--help', 'Display this help.' do
+ puts opts
+ exit
+ end
+
+ opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m|
+ options[:seed] = m.to_i
+ end
+
+ opts.on '-v', '--verbose', "Verbose. Show progress processing files." do
+ options[:verbose] = true
+ end
+
+ opts.on '-n', '--name PATTERN', "Filter test names on pattern." do |a|
+ options[:filter] = a
+ end
+
+ opts.parse args
+ end
+
+ options
+ end
+
##
# Top level driver, controls all output and filtering.
def run args = []
- @verbose = args.delete('-v')
+ options = process_args args
- filter = if args.first =~ /^(-n|--name)$/ then
- args.shift
- arg = args.shift
- arg =~ /\/(.*)\// ? Regexp.new($1) : arg
- else
- /./ # anything - ^test_ already filtered by #tests
- end
+ @verbose = options[:verbose]
+ filter = options[:filter] || '/./'
+ filter = Regexp.new $1 if filter and filter =~ /\/(.*)\//
+
+ seed = options[:seed]
+ unless seed then
+ srand
+ seed = srand % 0xFFFF
+ end
+
+ srand seed
+
@@out.puts "Loaded suite #{$0.sub(/\.rb$/, '')}\nStarted"
start = Time.now
@@ -396,12 +602,32 @@
@@out.puts
- format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
- @@out.puts format % [test_count, assertion_count, failures, errors, skips]
+ status
+ @@out.puts
+
+ help = ["--seed", seed]
+ help.push "--verbose" if @verbose
+ help.push("--name", options[:filter].inspect) if options[:filter]
+
+ @@out.puts "Test run options: #{help.join(" ")}"
+
return failures + errors if @test_count > 0 # or return nil...
+ rescue Interrupt
+ abort 'Interrupted'
end
+ ##
+ # Writes status to +io+
+
+ def status io = @@out
+ format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
+ io.puts format % [test_count, assertion_count, failures, errors, skips]
+ end
+
+ ##
+ # Runs test suites matching +filter+
+
def run_test_suites filter = /./
@test_count, @assertion_count = 0, 0
old_sync, @@out.sync = @@out.sync, true if @@out.respond_to? :sync=
@@ -411,10 +637,10 @@
inst._assertions = 0
@@out.print "#{suite}##{test}: " if @verbose
- t = Time.now if @verbose
+ @start_time = Time.now
result = inst.run(self)
- @@out.print "%.2f s: " % (Time.now - t) if @verbose
+ @@out.print "%.2f s: " % (Time.now - @start_time) if @verbose
@@out.print result
@@out.puts if @verbose
@test_count += 1
@@ -425,73 +651,126 @@
[@test_count, @assertion_count]
end
+ ##
+ # Subclass TestCase to create your own tests. Typically you'll want a
+ # TestCase subclass per implementation class.
+
class TestCase
- attr_reader :name
+ attr_reader :__name__ # :nodoc:
+ PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException,
+ Interrupt, SystemExit] # :nodoc:
+
+ SUPPORTS_INFO_SIGNAL = Signal.list['INFO'] # :nodoc:
+
+ ##
+ # Runs the tests reporting the status to +runner+
+
def run runner
+ trap 'INFO' do
+ warn '%s#%s %.2fs' % [self.class, self.__name__,
+ (Time.now - runner.start_time)]
+ runner.status $stderr
+ end if SUPPORTS_INFO_SIGNAL
+
result = '.'
begin
@passed = nil
self.setup
- self.__send__ self.name
+ self.__send__ self.__name__
@passed = true
+ rescue *PASSTHROUGH_EXCEPTIONS
+ raise
rescue Exception => e
@passed = false
- result = runner.puke(self.class, self.name, e)
+ result = runner.puke(self.class, self.__name__, e)
ensure
begin
self.teardown
+ rescue *PASSTHROUGH_EXCEPTIONS
+ raise
rescue Exception => e
- result = runner.puke(self.class, self.name, e)
+ result = runner.puke(self.class, self.__name__, e)
end
+ trap 'INFO', 'DEFAULT' if SUPPORTS_INFO_SIGNAL
end
result
end
- def initialize name
- @name = name
+ def initialize name # :nodoc:
+ @__name__ = name
@passed = nil
end
- def self.reset
+ def self.reset # :nodoc:
@@test_suites = {}
end
reset
- def self.inherited klass
+ def self.inherited klass # :nodoc:
@@test_suites[klass] = true
end
+ ##
+ # Defines test order and is subclassable. Defaults to :random
+ # but can be overridden to return :alpha if your tests are order
+ # dependent (read: weak).
+
def self.test_order
:random
end
- def self.test_suites
+ def self.test_suites # :nodoc:
@@test_suites.keys.sort_by { |ts| ts.name }
end
- def self.test_methods
- methods = public_instance_methods(true).grep(/^test/).map { |m|
- m.to_s
- }.sort
+ def self.test_methods # :nodoc:
+ methods = public_instance_methods(true).grep(/^test/).map { |m| m.to_s }
- if self.test_order == :random then
+ case self.test_order
+ when :random then
max = methods.size
- methods = methods.sort_by { rand(max) }
+ methods.sort.sort_by { rand(max) }
+ when :alpha, :sorted then
+ methods.sort
+ else
+ raise "Unknown test_order: #{self.test_order.inspect}"
end
-
- methods
end
- def setup; end
- def teardown; end
+ ##
+ # Returns true if the test passed.
def passed?
@passed
end
+ ##
+ # Runs before every test. Use this to refactor test initialization.
+
+ def setup; end
+
+ ##
+ # Runs after every test. Use this to refactor test cleanup.
+
+ def teardown; end
+
include MiniTest::Assertions
end # class TestCase
- end # class Test
-end # module Mini
+ end # class Unit
+end # module MiniTest
+
+if $DEBUG then
+ module Test # :nodoc:
+ module Unit # :nodoc:
+ class TestCase # :nodoc:
+ def self.inherited x # :nodoc:
+ # this helps me ferret out porting issues
+ raise "Using minitest and test/unit in the same process: #{x}"
+ end
+ end
+ end
+ end
+end
+
Modified: MacRuby/trunk/lib/mkmf.rb
===================================================================
--- MacRuby/trunk/lib/mkmf.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/mkmf.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +1,4 @@
+# -*- indent-tabs-mode: t -*-
# module to create Makefile for extension modules
# invoke like: ruby -r mkmf extconf.rb
@@ -9,10 +10,10 @@
ORIG_LIBPATH = ENV['LIB']
CXX_EXT = %w[cc cxx cpp]
-if /mswin|bccwin|mingw|os2/ !~ CONFIG['build_os']
+if File::FNM_SYSCASE.zero?
CXX_EXT.concat(%w[C])
end
-SRC_EXT = %w[c m] << CXX_EXT
+SRC_EXT = %w[c m].concat(CXX_EXT)
$static = nil
$config_h = '$(arch_hdrdir)/ruby/config.h'
$default_static = $static
@@ -65,6 +66,7 @@
$beos = /beos/ =~ RUBY_PLATFORM
$haiku = /haiku/ =~ RUBY_PLATFORM
$solaris = /solaris/ =~ RUBY_PLATFORM
+$universal = /universal/ =~ RUBY_PLATFORM
$dest_prefix_pattern = (File::PATH_SEPARATOR == ';' ? /\A([[:alpha:]]:)?/ : /\A/)
# :stopdoc:
@@ -154,7 +156,9 @@
topdir = File.dirname(libdir = File.dirname(__FILE__))
extdir = File.expand_path("ext", topdir)
path = File.expand_path($0)
-$extmk = path[0, topdir.size+1] == topdir+"/" && %r"\A(ext|enc|tool)\z" =~ File.dirname(path[topdir.size+1..-1])
+$extmk = path[0, topdir.size+1] == topdir+"/"
+$extmk &&= %r"\A(?:ext|enc|tool|test(?:/.+))\z" =~ File.dirname(path[topdir.size+1..-1])
+$extmk &&= true
if not $extmk and File.exist?(($hdrdir = RbConfig::CONFIG["rubyhdrdir"]) + "/ruby/ruby.h")
$topdir = $hdrdir
$top_srcdir = $hdrdir
@@ -191,11 +195,13 @@
end
def rm_f(*files)
- FileUtils.rm_f(Dir[*files])
+ opt = (Hash === files.last ? [files.pop] : [])
+ FileUtils.rm_f(Dir[*files.flatten], *opt)
end
def rm_rf(*files)
- FileUtils.rm_rf(Dir[*files])
+ opt = (Hash === files.last ? [files.pop] : [])
+ FileUtils.rm_rf(Dir[*files.flatten], *opt)
end
# Returns time stamp of the +target+ file if it exists and is newer
@@ -264,7 +270,7 @@
@log = nil
end
end
-
+
def self::postpone
tmplog = "mkmftmp#{@postpone += 1}.log"
open do
@@ -272,9 +278,9 @@
@log, @logfile, @orgout, @orgerr = nil, tmplog, log, log
begin
log.print(open {yield})
+ ensure
@log.close
File::open(tmplog) {|t| FileUtils.copy_stream(t, log)}
- ensure
@log, @logfile, @orgout, @orgerr = log, *save
@postpone -= 1
rm_f tmplog
@@ -357,15 +363,17 @@
def try_do(src, command, &b)
unless have_devel?
raise <<MSG
-The compiler failed to generate an executable file.
+The complier failed to generate an executable file.
You have to install development tools first.
MSG
end
- src = create_tmpsrc(src, &b)
- xsystem(command)
-ensure
- log_src(src)
- rm_rf 'conftest.dSYM'
+ begin
+ src = create_tmpsrc(src, &b)
+ xsystem(command)
+ ensure
+ log_src(src)
+ rm_rf 'conftest.dSYM'
+ end
end
def link_command(ldflags, opt="", libpath=$DEFLIBPATH|$LIBPATH)
@@ -397,7 +405,7 @@
'arch_hdrdir' => "#$arch_hdrdir",
'top_srcdir' => $top_srcdir.quote)
RbConfig::expand("$(CPP) #$INCFLAGS #$CPPFLAGS #$CFLAGS #{opt} #{CONFTEST_C} #{outfile}",
- conf).gsub(/-arch\s+\w+/,'')
+ conf)
end
def libpathflag(libpath=$DEFLIBPATH|$LIBPATH)
@@ -412,7 +420,20 @@
end
def try_link0(src, opt="", &b)
- try_do(src, link_command("", opt), &b)
+ cmd = link_command("", opt)
+ if $universal
+ require 'tmpdir'
+ Dir.mktmpdir("mkmf_", oldtmpdir = ENV["TMPDIR"]) do |tmpdir|
+ begin
+ ENV["TMPDIR"] = tmpdir
+ try_do(src, cmd, &b)
+ ensure
+ ENV["TMPDIR"] = oldtmpdir
+ end
+ end
+ else
+ try_do(src, cmd, &b)
+ end
end
def try_link(src, opt="", &b)
@@ -433,10 +454,14 @@
rm_f "conftest*"
end
+class Object
+ alias_method :try_header, (config_string('try_header') || :try_cpp)
+end
+
def cpp_include(header)
if header
header = [header] unless header.kind_of? Array
- header.map {|h| "#include <#{h}>\n"}.join
+ header.map {|h| String === h ? "#include <#{h}>\n" : h}.join
else
""
end
@@ -599,7 +624,7 @@
def install_files(mfile, ifiles, map = nil, srcprefix = nil)
ifiles or return
ifiles.empty? and return
- srcprefix ||= '$(srcdir)'
+ srcprefix ||= "$(srcdir)/#{srcprefix}".chomp('/')
RbConfig::expand(srcdir = srcprefix.dup)
dirs = []
path = Hash.new {|h, i| h[i] = dirs.push([i])[-1]}
@@ -804,13 +829,10 @@
# For example, if have_header('foo.h') returned true, then the HAVE_FOO_H
# preprocessor macro would be passed to the compiler.
#
-def have_header(header, &b)
+def have_header(header, preheaders = nil, &b)
checking_for header do
- if try_cpp(cpp_include(header), &b)
- #FIXME: cannot use this in MacRuby yet
- #$defs.push(format("-DHAVE_%s", header.tr("a-z./\055", "A-Z___")))
- str = header.tr("a-z", "A-Z").tr("./\055", "_")
- $defs.push(format("-DHAVE_%s", str))
+ if try_header(cpp_include(preheaders)+cpp_include(header), &b)
+ $defs.push(format("-DHAVE_%s", header.tr_cpp))
true
else
false
@@ -828,13 +850,13 @@
message = checking_message(header, paths)
header = cpp_include(header)
checking_for message do
- if try_cpp(header)
+ if try_header(header)
true
else
found = false
paths.each do |dir|
opt = "-I#{dir}".quote
- if try_cpp(header, opt)
+ if try_header(header, opt)
$INCFLAGS << " " << opt
found = true
break
@@ -857,7 +879,7 @@
# HAVE_STRUCT_FOO_BAR preprocessor macro would be passed to the compiler.
#
# HAVE_ST_BAR is also defined for backward compatibility.
-#
+#
def have_struct_member(type, member, headers = nil, &b)
checking_for checking_message("#{type}.#{member}", headers) do
if try_compile(<<"SRC", &b)
@@ -965,6 +987,11 @@
end
end
+STRING_OR_FAILED_FORMAT = "%s"
+def STRING_OR_FAILED_FORMAT.%(x)
+ x ? super : "failed"
+end
+
# Returns the size of the given +type+. You may optionally specify additional
# +headers+ to search in for the +type+.
#
@@ -975,20 +1002,60 @@
# For example, if check_sizeof('mystruct') returned 12, then the
# SIZEOF_MYSTRUCT=12 preprocessor macro would be passed to the compiler.
#
-def check_sizeof(type, headers = nil, &b)
- expr = "sizeof(#{type})"
- fmt = "%d"
- def fmt.%(x)
- x ? super : "failed"
- end
+def check_sizeof(type, headers = nil, opts = "", &b)
+ typename, member = type.split('.', 2)
+ prelude = cpp_include(headers).split(/$/)
+ prelude << "typedef #{typename} rbcv_typedef_;\n"
+ prelude << "static rbcv_typedef_ *rbcv_ptr_;\n"
+ prelude = [prelude]
+ expr = "sizeof((*rbcv_ptr_)#{"." << member if member})"
+ fmt = STRING_OR_FAILED_FORMAT
checking_for checking_message("size of #{type}", headers), fmt do
- if size = try_constant(expr, headers, &b)
- $defs.push(format("-DSIZEOF_%s=%d", type.tr_cpp, size))
+ if UNIVERSAL_INTS.include?(type)
+ type
+ elsif size = UNIVERSAL_INTS.find {|t|
+ try_static_assert("#{expr} == sizeof(#{t})", prelude, opts, &b)
+ }
+ $defs.push(format("-DSIZEOF_%s=SIZEOF_%s", type.tr_cpp, size.tr_cpp))
size
+ elsif size = try_constant(expr, prelude, opts, &b)
+ $defs.push(format("-DSIZEOF_%s=%s", type.tr_cpp, size))
+ size
end
end
end
+# Returns the signedness of the given +type+. You may optionally
+# specify additional +headers+ to search in for the +type+.
+#
+# If the +type+ is found and is a numeric type, a macro is passed as a
+# preprocessor constant to the compiler using the +type+ name, in
+# uppercase, prepended with 'SIGNEDNESS_OF_', followed by the +type+
+# name, followed by '=X' where 'X' is positive integer if the +type+ is
+# unsigned, or negative integer if the +type+ is signed.
+#
+# For example, if size_t is defined as unsigned, then
+# check_signedness('size_t') would returned +1 and the
+# SIGNEDNESS_OF_SIZE_T=+1 preprocessor macro would be passed to the
+# compiler, and SIGNEDNESS_OF_INT=-1 if check_signedness('int') is
+# done.
+#
+def check_signedness(type, headers = nil)
+ signed = nil
+ checking_for("signedness of #{type}", STRING_OR_FAILED_FORMAT) do
+ if try_static_assert("(#{type})-1 < 0")
+ signed = -1
+ elsif try_static_assert("(#{type})-1 > 0")
+ signed = +1
+ else
+ next nil
+ end
+ $defs.push("-DSIGNEDNESS_OF_%s=%+d" % [type.tr_cpp, signed])
+ signed < 0 ? "signed" : "unsigned"
+ end
+ signed
+end
+
# :stopdoc:
# Used internally by the what_type? method to determine if +type+ is a scalar
@@ -1015,35 +1082,74 @@
SRC
end
+# Used internally by the what_type? method to check if _typeof_ GCC
+# extension is available.
+def have_typeof?
+ return $typeof if defined?($typeof)
+ $typeof = %w[__typeof__ typeof].find do |t|
+ try_compile(<<SRC)
+int rbcv_foo;
+#{t}(rbcv_foo) rbcv_bar;
+SRC
+ end
+end
+
def what_type?(type, member = nil, headers = nil, &b)
m = "#{type}"
- name = type
+ var = val = "*rbcv_var_"
+ func = "rbcv_func_(void)"
if member
m << "." << member
- name = "(((#{type} *)0)->#{member})"
+ else
+ type, member = type.split('.', 2)
end
- fmt = "seems %s"
+ if member
+ val = "(#{var}).#{member}"
+ end
+ prelude = [cpp_include(headers).split(/^/)]
+ prelude << ["typedef #{type} rbcv_typedef_;\n",
+ "extern rbcv_typedef_ *#{func};\n",
+ "static rbcv_typedef_ #{var};\n",
+ ]
+ type = "rbcv_typedef_"
+ fmt = member && !(typeof = have_typeof?) ? "seems %s" : "%s"
+ if typeof
+ var = "*rbcv_member_"
+ func = "rbcv_mem_func_(void)"
+ member = nil
+ type = "rbcv_mem_typedef_"
+ prelude[-1] << "typedef #{typeof}(#{val}) #{type};\n"
+ prelude[-1] << "extern #{type} *#{func};\n"
+ prelude[-1] << "static #{type} #{var};\n"
+ val = var
+ end
def fmt.%(x)
x ? super : "unknown"
end
checking_for checking_message(m, headers), fmt do
- if scalar_ptr_type?(type, member, headers, &b)
- if try_static_assert("sizeof(*#{name}) == 1", headers)
- "string"
+ if scalar_ptr_type?(type, member, prelude, &b)
+ if try_static_assert("sizeof(*#{var}) == 1", prelude)
+ return "string"
end
- elsif scalar_type?(type, member, headers, &b)
- if try_static_assert("sizeof(#{name}) > sizeof(long)", headers)
- "long long"
- elsif try_static_assert("sizeof(#{name}) > sizeof(int)", headers)
- "long"
- elsif try_static_assert("sizeof(#{name}) > sizeof(short)", headers)
- "int"
- elsif try_static_assert("sizeof(#{name}) > 1", headers)
- "short"
- else
- "char"
+ ptr = "*"
+ elsif scalar_type?(type, member, prelude, &b)
+ unless member and !typeof or try_static_assert("(#{type})-1 < 0", prelude)
+ unsigned = "unsigned"
end
+ ptr = ""
+ else
+ next
end
+ type = UNIVERSAL_INTS.find do |t|
+ pre = prelude
+ unless member
+ pre += [["static #{unsigned} #{t} #{ptr}#{var};\n",
+ "extern #{unsigned} #{t} #{ptr}*#{func};\n"]]
+ end
+ try_static_assert("sizeof(#{ptr}#{val}) == sizeof(#{unsigned} #{t})", pre)
+ end
+ type or next
+ [unsigned, type, ptr].join(" ").strip
end
end
@@ -1052,10 +1158,12 @@
# Internal use only.
#
def find_executable0(bin, path = nil)
- ext = config_string('EXEEXT')
+ exts = config_string('EXECUTABLE_EXTS') {|s| s.split} || config_string('EXEEXT') {|s| [s]}
if File.expand_path(bin) == bin
return bin if File.executable?(bin)
- ext and File.executable?(file = bin + ext) and return file
+ if exts
+ exts.each {|ext| File.executable?(file = bin + ext) and return file}
+ end
return nil
end
if path ||= ENV['PATH']
@@ -1066,7 +1174,9 @@
file = nil
path.each do |dir|
return file if File.executable?(file = File.join(dir, bin))
- return file if ext and File.executable?(file << ext)
+ if exts
+ exts.each {|ext| File.executable?(ext = file + ext) and return ext}
+ end
end
nil
end
@@ -1166,7 +1276,7 @@
# 'extconf.h'.
#
# For example:
-#
+#
# # extconf.rb
# require 'mkmf'
# have_func('realpath')
@@ -1188,22 +1298,20 @@
#
def create_header(header = "extconf.h")
message "creating %s\n", header
- #FIXME: cannot use this in MacRuby yet
- #sym = header.tr("a-z./\055", "A-Z___")
- sym = header.tr("a-z", "A-Z").tr("./\055", "_")
+ sym = header.tr_cpp
hdr = ["#ifndef #{sym}\n#define #{sym}\n"]
- for line in $defs
- case line
- when /^-D([^=]+)(?:=(.*))?/
- hdr << "#define #$1 #{$2 ? Shellwords.shellwords($2)[0] : 1}\n"
- when /^-U(.*)/
+ for line in $defs
+ case line
+ when /^-D([^=]+)(?:=(.*))?/
+ hdr << "#define #$1 #{$2 ? Shellwords.shellwords($2)[0].gsub(/(?=\t+)/, "\\\n") : 1}\n"
+ when /^-U(.*)/
hdr << "#undef #$1\n"
- end
- end
+ end
+ end
hdr << "#endif\n"
hdr = hdr.join
unless (IO.read(header) == hdr rescue false)
- open(header, "w") do |hfile|
+ open(header, "wb") do |hfile|
hfile.write(hdr)
end
end
@@ -1232,7 +1340,7 @@
ldir = with_config(target + "-lib", ldefault)
$arg_config.last[1] ||= "${#{target}-dir}/lib"
- idirs = idir ? Array === idir ? idir : idir.split(File::PATH_SEPARATOR) : []
+ idirs = idir ? Array === idir ? idir.dup : idir.split(File::PATH_SEPARATOR) : []
if defaults
idirs.concat(defaults.collect {|d| d + "/include"})
idir = ([idir] + idirs).compact.join(File::PATH_SEPARATOR)
@@ -1245,7 +1353,7 @@
end
end
- ldirs = ldir ? Array === ldir ? ldir : ldir.split(File::PATH_SEPARATOR) : []
+ ldirs = ldir ? Array === ldir ? ldir.dup : ldir.split(File::PATH_SEPARATOR) : []
if defaults
ldirs.concat(defaults.collect {|d| d + "/lib"})
ldir = ([ldir] + ldirs).compact.join(File::PATH_SEPARATOR)
@@ -1263,7 +1371,7 @@
if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig)
# iff package specific config command is given
get = proc {|opt| `#{pkgconfig} --#{opt}`.chomp}
- elsif ($PKGCONFIG ||=
+ elsif ($PKGCONFIG ||=
(pkgconfig = with_config("pkg-config", ("pkg-config" unless CROSS_COMPILING))) &&
find_executable0(pkgconfig) && pkgconfig) and
system("#{$PKGCONFIG} --exists #{pkg}")
@@ -1396,13 +1504,14 @@
CXXFLAGS = $(CFLAGS) #{CONFIG['CXXFLAGS']}
ldflags = #{$LDFLAGS}
dldflags = #{$DLDFLAGS}
-archflag = #{$ARCH_FLAG}
-DLDFLAGS = $(ldflags) $(dldflags) $(archflag)
+ARCH_FLAG = #{$ARCH_FLAG}
+DLDFLAGS = $(ldflags) $(dldflags)
LDSHARED = #{CONFIG['LDSHARED']}
LDSHAREDXX = #{config_string('LDSHAREDXX') || '$(LDSHARED)'}
AR = #{CONFIG['AR']}
EXEEXT = #{CONFIG['EXEEXT']}
+RUBY_BASE_NAME = #{CONFIG['RUBY_BASE_NAME']}
RUBY_INSTALL_NAME = #{CONFIG['RUBY_INSTALL_NAME']}
RUBY_SO_NAME = #{CONFIG['RUBY_SO_NAME']}
arch = #{CONFIG['arch']}
@@ -1442,6 +1551,8 @@
DISTCLEANFILES = #{$distcleanfiles.join(' ')}
all install static install-so install-rb: Makefile
+.PHONY: all install static install-so install-rb
+.PHONY: clean clean-so clean-rb
RULES
end
@@ -1526,7 +1637,7 @@
# Makefile.
#
# Setting the +target_prefix+ will, in turn, install the generated binary in
-# a directory under your Config::CONFIG['sitearchdir'] that mimics your local
+# a directory under your RbConfig::CONFIG['sitearchdir'] that mimics your local
# filesystem when you run 'make install'.
#
# For example, given the following file tree:
@@ -1573,26 +1684,27 @@
target_prefix = ""
end
- srcprefix ||= '$(srcdir)'
- RbConfig::expand(srcdir = srcprefix.dup)
+ srcprefix ||= "$(srcdir)/#{srcprefix}".chomp('/')
+ RbConfig.expand(srcdir = srcprefix.dup)
+ ext = ".#{$OBJEXT}"
if not $objs
- $objs = []
- srcs = Dir[File.join(srcdir, "*.{#{SRC_EXT.join(%q{,})}}")]
- for f in srcs
- obj = File.basename(f, ".*") << ".o"
- $objs.push(obj) unless $objs.index(obj)
+ srcs = $srcs || Dir[File.join(srcdir, "*.{#{SRC_EXT.join(%q{,})}}")]
+ objs = srcs.inject(Hash.new {[]}) {|h, f| h[File.basename(f, ".*") << ext] <<= f; h}
+ $objs = objs.keys
+ unless objs.delete_if {|b, f| f.size == 1}.empty?
+ dups = objs.sort.map {|b, f|
+ "#{b[/.*\./]}{#{f.collect {|n| n[/([^.]+)\z/]}.join(',')}}"
+ }
+ abort "source files duplication - #{dups.join(", ")}"
end
- elsif !(srcs = $srcs)
- srcs = $objs.collect {|o| o.sub(/\.o\z/, '.c')}
+ else
+ $objs.collect! {|o| File.basename(o, ".*") << ext} unless $OBJEXT == "o"
+ srcs = $srcs || $objs.collect {|o| o.chomp(ext) << ".c"}
end
$srcs = srcs
- for i in $objs
- i.sub!(/\.o\z/, ".#{$OBJEXT}")
- end
- $objs = $objs.join(" ")
- target = nil if $objs == ""
+ target = nil if $objs.empty?
if target and EXPORT_PREFIX
if File.exist?(File.join(srcdir, target + '.def'))
@@ -1604,7 +1716,7 @@
makedef = %{-e "puts 'EXPORTS', '#{EXPORT_PREFIX}Init_$(TARGET)'"}
end
if makedef
- $distcleanfiles << '$(DEFFILE)'
+ $cleanfiles << '$(DEFFILE)'
origdef = deffile
deffile = "$(TARGET)-$(arch).def"
end
@@ -1625,7 +1737,9 @@
dllib = target ? "$(TARGET).#{CONFIG['DLEXT']}" : ""
staticlib = target ? "$(TARGET).#$LIBEXT" : ""
mfile = open("Makefile", "wb")
- mfile.print(*configuration(srcprefix))
+ conf = configuration(srcprefix)
+ conf = yield(conf) if block_given?
+ mfile.puts(conf)
mfile.print "
libpath = #{($DEFLIBPATH|$LIBPATH).join(" ")}
LIBPATH = #{libpath}
@@ -1635,13 +1749,13 @@
DISTCLEANFILES = #{$distcleanfiles.join(' ')}
DISTCLEANDIRS = #{$distcleandirs.join(' ')}
-extout = #{$extout}
+extout = #{$extout && $extout.quote}
extout_prefix = #{$extout_prefix}
target_prefix = #{target_prefix}
LOCAL_LIBS = #{$LOCAL_LIBS}
LIBS = #{$LIBRUBYARG} #{$libs} #{$LIBS}
SRCS = #{srcs.collect(&File.method(:basename)).join(' ')}
-OBJS = #{$objs}
+OBJS = #{$objs.join(" ")}
TARGET = #{target}
DLLIB = #{dllib}
EXTSTATIC = #{$static || ""}
@@ -1654,10 +1768,12 @@
mfile.print "
TARGET_SO = #{($extout ? '$(RUBYARCHDIR)/' : '')}$(DLLIB)
CLEANLIBS = #{n}.#{CONFIG['DLEXT']} #{config_string('cleanlibs') {|t| t.gsub(/\$\*/) {n}}}
-CLEANOBJS = *.#{$OBJEXT} #{config_string('cleanobjs') {|t| t.gsub(/\$\*/, '$(TARGET)')}} *.bak
+CLEANOBJS = *.#{$OBJEXT} #{config_string('cleanobjs') {|t| t.gsub(/\$\*/, "$(TARGET)#{deffile ? '-$(arch)': ''}")} if target} *.bak
all: #{$extout ? "install" : target ? "$(DLLIB)" : "Makefile"}
static: $(STATIC_LIB)#{$extout ? " install-rb" : ""}
+.PHONY: all install static install-so install-rb
+.PHONY: clean clean-so clean-rb
"
mfile.print CLEANINGS
fsep = config_string('BUILD_FILE_SEPARATOR') {|s| s unless s == "/"}
@@ -1685,8 +1801,8 @@
mfile.print "\t at -$(RM) #{fseprepl[dest]}\n"
mfile.print "\t at -$(RMDIRS) #{fseprepl[dir]}\n"
else
- mfile.print "#{dest}: #{f}\n"
- mfile.print "\t$(INSTALL_PROG) #{fseprepl[f]} #{fseprepl[dir]}\n"
+ mfile.print "#{dest}: #{f}\n\t at -$(MAKEDIRS) $(@D#{sep})\n"
+ mfile.print "\t$(INSTALL_PROG) #{fseprepl[f]} $(@D#{sep})\n"
if defined?($installed_list)
mfile.print "\t at echo #{dir}/#{File.basename(f)}>>$(INSTALLED_LIST)\n"
end
@@ -1708,9 +1824,8 @@
for f in files
dest = "#{dir}/#{File.basename(f)}"
mfile.print("install-rb#{sfx}: #{dest}\n")
- mfile.print("#{dest}: #{f}\n")
- mfile.print("\t$(#{$extout ? 'COPY' : 'INSTALL_DATA'}) ")
- mfile.print("#{fseprepl[f]} $(@D#{sep})\n")
+ mfile.print("#{dest}: #{f}\n\t at -$(MAKEDIRS) $(@D#{sep})\n")
+ mfile.print("\t$(#{$extout ? 'COPY' : 'INSTALL_DATA'}) #{f} $(@D#{sep})\n")
if defined?($installed_list) and !$extout
mfile.print("\t at echo #{dest}>>$(INSTALLED_LIST)\n")
end
@@ -1722,10 +1837,9 @@
end
if $extout
dirs.uniq!
- dirs.reverse!
unless dirs.empty?
mfile.print("clean-rb#{sfx}::\n")
- for dir in dirs
+ for dir in dirs.sort_by {|d| -d.count('/')}
mfile.print("\t at -$(RMDIRS) #{fseprepl[dir]}\n")
end
end
@@ -1744,19 +1858,19 @@
return unless target
- mfile.puts SRC_EXT.collect {|ext| ".path.#{ext} = $(VPATH)"} if $nmake == ?b
+ mfile.puts SRC_EXT.collect {|e| ".path.#{e} = $(VPATH)"} if $nmake == ?b
mfile.print ".SUFFIXES: .#{SRC_EXT.join(' .')} .#{$OBJEXT}\n"
mfile.print "\n"
- CXX_EXT.each do |ext|
+ CXX_EXT.each do |e|
COMPILE_RULES.each do |rule|
- mfile.printf(rule, ext, $OBJEXT)
+ mfile.printf(rule, e, $OBJEXT)
mfile.printf("\n\t%s\n\n", COMPILE_CXX)
end
end
- %w[c].each do |ext|
+ %w[c].each do |e|
COMPILE_RULES.each do |rule|
- mfile.printf(rule, ext, $OBJEXT)
+ mfile.printf(rule, e, $OBJEXT)
mfile.printf("\n\t%s\n\n", COMPILE_C)
end
end
@@ -1825,7 +1939,7 @@
$LIBRUBYARG = ""
$LIBRUBYARG_STATIC = config['LIBRUBYARG_STATIC']
$LIBRUBYARG_SHARED = config['LIBRUBYARG_SHARED']
- $DEFLIBPATH = $extmk ? ["$(topdir)"] : CROSS_COMPILING ? [] : ["$(libdir)"]
+ $DEFLIBPATH = [$extmk ? "$(topdir)" : "$(libdir)"]
$DEFLIBPATH.unshift(".")
$LIBPATH = []
$INSTALLFILES = []
@@ -1936,8 +2050,10 @@
RPATHFLAG = config_string('RPATHFLAG') || ''
LIBARG = config_string('LIBARG') || '-l%s'
MAIN_DOES_NOTHING = config_string('MAIN_DOES_NOTHING') || 'int main() {return 0;}'
+UNIVERSAL_INTS = config_string('UNIVERSAL_INTS') {|s| Shellwords.shellwords(s)} ||
+ %w[int short long long\ long]
-sep = config_string('BUILD_FILE_SEPARATOR') {|s| ":/=#{s}" if sep != "/"} || ""
+sep = config_string('BUILD_FILE_SEPARATOR') {|s| ":/=#{s}" if s != "/"} || ""
CLEANINGS = "
clean-rb-default::
clean-rb::
Modified: MacRuby/trunk/lib/monitor.rb
===================================================================
--- MacRuby/trunk/lib/monitor.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/monitor.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -12,11 +12,11 @@
This is a simple example.
require 'monitor.rb'
-
+
buf = []
buf.extend(MonitorMixin)
empty_cond = buf.new_cond
-
+
# consumer
Thread.start do
loop do
@@ -26,7 +26,7 @@
end
end
end
-
+
# producer
while line = ARGF.gets
buf.synchronize do
@@ -49,11 +49,11 @@
# +include+. For example:
#
# require 'monitor'
-#
+#
# buf = []
# buf.extend(MonitorMixin)
# empty_cond = buf.new_cond
-#
+#
# # consumer
# Thread.start do
# loop do
@@ -63,7 +63,7 @@
# end
# end
# end
-#
+#
# # producer
# while line = ARGF.gets
# buf.synchronize do
@@ -71,7 +71,7 @@
# empty_cond.signal
# end
# end
-#
+#
# The consumer thread waits for the producer thread to push a line
# to buf while buf.empty?, and the producer thread (main thread)
# reads a line from ARGF and push it to buf, then call
@@ -86,47 +86,58 @@
#
class ConditionVariable
class Timeout < Exception; end
-
+
+ #
+ # Releases the lock held in the associated monitor and waits; reacquires the lock on wakeup.
+ #
+ # If +timeout+ is given, this method returns after +timeout+ seconds passed,
+ # even if no other thread doesn't signal.
+ #
def wait(timeout = nil)
- if timeout
- raise NotImplementedError, "timeout is not implemented yet"
- end
- @monitor.send(:mon_check_owner)
- count = @monitor.send(:mon_exit_for_cond)
+ @monitor.__send__(:mon_check_owner)
+ count = @monitor.__send__(:mon_exit_for_cond)
begin
- @cond.wait(@monitor.instance_variable_get("@mon_mutex"))
+ @cond.wait(@monitor.instance_variable_get("@mon_mutex"), timeout)
return true
ensure
- @monitor.send(:mon_enter_for_cond, count)
+ @monitor.__send__(:mon_enter_for_cond, count)
end
end
-
+
+ #
+ # Calls wait repeatedly while the given block yields a truthy value.
+ #
def wait_while
while yield
wait
end
end
-
+
+ #
+ # Calls wait repeatedly until the given block yields a truthy value.
+ #
def wait_until
until yield
wait
end
end
-
+
+ #
+ # Wakes up the first thread in line waiting for this lock.
+ #
def signal
- @monitor.send(:mon_check_owner)
+ @monitor.__send__(:mon_check_owner)
@cond.signal
end
-
+
+ #
+ # Wakes up all threads waiting for this lock.
+ #
def broadcast
- @monitor.send(:mon_check_owner)
+ @monitor.__send__(:mon_check_owner)
@cond.broadcast
end
-
- def count_waiters
- raise NotImplementedError
- end
-
+
private
def initialize(monitor)
@@ -134,12 +145,12 @@
@cond = ::ConditionVariable.new
end
end
-
+
def self.extend_object(obj)
super(obj)
- obj.send(:mon_initialize)
+ obj.__send__(:mon_initialize)
end
-
+
#
# Attempts to enter exclusive section. Returns +false+ if lock fails.
#
@@ -166,7 +177,7 @@
end
@mon_count += 1
end
-
+
#
# Leaves exclusive section.
#
@@ -193,9 +204,10 @@
end
end
alias synchronize mon_synchronize
-
+
#
- # FIXME: This isn't documented in Nutshell.
+ # Creates a new MonitorMixin::ConditionVariable associated with the
+ # receiver.
#
def new_cond
return ConditionVariable.new(self)
Modified: MacRuby/trunk/lib/mutex_m.rb
===================================================================
--- MacRuby/trunk/lib/mutex_m.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/mutex_m.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,5 @@
#
-# mutex_m.rb -
+# mutex_m.rb -
# $Release Version: 3.0$
# $Revision: 1.7 $
# Original from mutex.rb
@@ -34,13 +34,13 @@
alias try_lock mu_try_lock
alias synchronize mu_synchronize
}
- end
+ end
def Mutex_m.append_features(cl)
super
define_aliases(cl) unless cl.instance_of?(Module)
end
-
+
def Mutex_m.extend_object(obj)
super
obj.mu_extended
@@ -56,30 +56,30 @@
end
mu_initialize
end
-
- # locking
+
+ # locking
def mu_synchronize(&block)
@_mutex.synchronize(&block)
end
-
+
def mu_locked?
@_mutex.locked?
end
-
+
def mu_try_lock
@_mutex.try_lock
end
-
+
def mu_lock
@_mutex.lock
end
-
+
def mu_unlock
@_mutex.unlock
end
-
+
private
-
+
def mu_initialize
@_mutex = Mutex.new
end
Modified: MacRuby/trunk/lib/net/ftp.rb
===================================================================
--- MacRuby/trunk/lib/net/ftp.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/net/ftp.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,11 +1,11 @@
-#
+#
# = net/ftp.rb - FTP Client Library
-#
+#
# Written by Shugo Maeda <shugo at ruby-lang.org>.
#
# Documentation by Gavin Sinclair, sourced from "Programming Ruby" (Hunt/Thomas)
# and "Ruby In a Nutshell" (Matsumoto), used with permission.
-#
+#
# This library is distributed under the terms of the Ruby license.
# You can freely distribute/modify this library.
#
@@ -22,9 +22,10 @@
# :stopdoc:
class FTPError < StandardError; end
class FTPReplyError < FTPError; end
- class FTPTempError < FTPError; end
- class FTPPermError < FTPError; end
+ class FTPTempError < FTPError; end
+ class FTPPermError < FTPError; end
class FTPProtoError < FTPError; end
+ class FTPConnectionError < FTPError; end
# :startdoc:
#
@@ -34,11 +35,11 @@
# advantage of Ruby's style and strengths.
#
# == Example
- #
+ #
# require 'net/ftp'
#
# === Example 1
- #
+ #
# ftp = Net::FTP.new('ftp.netlab.co.jp')
# ftp.login
# files = ftp.chdir('pub/lang/ruby/contrib')
@@ -71,13 +72,13 @@
#
class FTP
include MonitorMixin
-
+
# :stopdoc:
FTP_PORT = 21
CRLF = "\r\n"
DEFAULT_BLOCKSIZE = 4096
# :startdoc:
-
+
# When +true+, transfers are performed in binary mode. Default: +true+.
attr_reader :binary
@@ -101,7 +102,7 @@
# The server's last response.
attr_reader :last_response
-
+
#
# A synonym for <tt>FTP.new</tt>, but with a mandatory host parameter.
#
@@ -120,7 +121,7 @@
new(host, user, passwd, acct)
end
end
-
+
#
# Creates and returns a new +FTP+ object. If a +host+ is given, a connection
# is made. Additionally, if the +user+ is given, the given user name,
@@ -128,10 +129,12 @@
#
def initialize(host = nil, user = nil, passwd = nil, acct = nil)
super()
- @binary = false
+ @binary = true
@passive = false
@debug_mode = false
@resume = false
+ @sock = NullSocket.new
+ @logged_in = false
if host
connect(host)
if user
@@ -143,10 +146,19 @@
def binary=(newmode)
if newmode != @binary
@binary = newmode
- @binary ? voidcmd("TYPE I") : voidcmd("TYPE A")
+ send_type_command if @logged_in
end
end
+ def send_type_command
+ if @binary
+ voidcmd("TYPE I")
+ else
+ voidcmd("TYPE A")
+ end
+ end
+ private :send_type_command
+
def with_binary(newmode)
oldmode = binary
self.binary = newmode
@@ -178,7 +190,7 @@
end
end
private :open_socket
-
+
#
# Establishes an FTP connection to host, optionally overriding the default
# port. If the environment variable +SOCKS_SERVER+ is set, sets up the
@@ -215,7 +227,7 @@
end
end
private :sanitize
-
+
def putline(line)
if @debug_mode
print "put: ", sanitize(line), "\n"
@@ -224,7 +236,7 @@
@sock.write(line)
end
private :putline
-
+
def getline
line = @sock.readline # if get EOF, raise EOFError
line.sub!(/(\r\n|\n|\r)\z/n, "")
@@ -234,7 +246,7 @@
return line
end
private :getline
-
+
def getmultiline
line = getline
buff = line
@@ -248,7 +260,7 @@
return buff << "\n"
end
private :getmultiline
-
+
def getresp
@last_response = getmultiline
@last_response_code = @last_response[0, 3]
@@ -264,7 +276,7 @@
end
end
private :getresp
-
+
def voidresp
resp = getresp
if resp[0] != ?2
@@ -272,7 +284,7 @@
end
end
private :voidresp
-
+
#
# Sends a command and returns the response.
#
@@ -282,7 +294,7 @@
return getresp
end
end
-
+
#
# Sends a command and expect a response beginning with '2'.
#
@@ -292,7 +304,7 @@
voidresp
end
end
-
+
def sendport(host, port)
af = (@sock.peeraddr)[0]
if af == "AF_INET"
@@ -305,7 +317,7 @@
voidcmd(cmd)
end
private :sendport
-
+
def makeport
sock = TCPServer.open(@sock.addr[3], 0)
port = sock.addr[1]
@@ -314,7 +326,7 @@
return sock
end
private :makeport
-
+
def makepasv
if @sock.peeraddr[0] == "AF_INET"
host, port = parse227(sendcmd("PASV"))
@@ -325,13 +337,13 @@
return host, port
end
private :makepasv
-
+
def transfercmd(cmd, rest_offset = nil)
if @passive
host, port = makepasv
conn = open_socket(host, port)
if @resume and rest_offset
- resp = sendcmd("REST " + rest_offset.to_s)
+ resp = sendcmd("REST " + rest_offset.to_s)
if resp[0] != ?3
raise FTPReplyError, resp
end
@@ -345,7 +357,7 @@
else
sock = makeport
if @resume and rest_offset
- resp = sendcmd("REST " + rest_offset.to_s)
+ resp = sendcmd("REST " + rest_offset.to_s)
if resp[0] != ?3
raise FTPReplyError, resp
end
@@ -362,23 +374,7 @@
return conn
end
private :transfercmd
-
- def getaddress
- thishost = Socket.gethostname
- if not thishost.index(".")
- thishost = Socket.gethostbyname(thishost)[0]
- end
- if ENV.has_key?("LOGNAME")
- realuser = ENV["LOGNAME"]
- elsif ENV.has_key?("USER")
- realuser = ENV["USER"]
- else
- realuser = "anonymous"
- end
- return realuser + "@" + thishost
- end
- private :getaddress
-
+
#
# Logs in to the remote host. The session must have been previously
# connected. If +user+ is the string "anonymous" and the +password+ is
@@ -389,9 +385,9 @@
#
def login(user = "anonymous", passwd = nil, acct = nil)
if user == "anonymous" and passwd == nil
- passwd = getaddress
+ passwd = "anonymous@"
end
-
+
resp = ""
synchronize do
resp = sendcmd('USER ' + user)
@@ -408,9 +404,10 @@
raise FTPReplyError, resp
end
@welcome = resp
- self.binary = true
+ send_type_command
+ @logged_in = true
end
-
+
#
# Puts the connection into binary (image) mode, issues the given command,
# and fetches the data returned, passing it to the associated block in
@@ -431,7 +428,7 @@
end
end
end
-
+
#
# Puts the connection into ASCII (text) mode, issues the given command, and
# passes the resulting data, one line at a time, to the associated block. If
@@ -445,19 +442,14 @@
loop do
line = conn.gets
break if line == nil
- if line[-2, 2] == CRLF
- line = line[0 .. -3]
- elsif line[-1] == ?\n
- line = line[0 .. -2]
- end
- yield(line)
+ yield(line.sub(/\r?\n\z/, ""), !line.match(/\n\z/).nil?)
end
conn.close
voidresp
end
end
end
-
+
#
# Puts the connection into binary (image) mode, issues the given server-side
# command (such as "STOR myfile"), and sends the contents of the file named
@@ -470,7 +462,7 @@
end
synchronize do
with_binary(true) do
- conn = transfercmd(cmd, rest_offset)
+ conn = transfercmd(cmd)
loop do
buf = file.read(blocksize)
break if buf == nil
@@ -489,7 +481,7 @@
getresp
raise
end
-
+
#
# Puts the connection into ASCII (text) mode, issues the given server-side
# command (such as "STOR myfile"), and sends the contents of the file
@@ -544,7 +536,7 @@
end
begin
f.binmode if localfile
- retrbinary("RETR " + remotefile, blocksize, rest_offset) do |data|
+ retrbinary("RETR " + remotefile.to_s, blocksize, rest_offset) do |data|
f.write(data) if localfile
yield(data) if block_given?
result.concat(data) if result
@@ -554,7 +546,7 @@
f.close if localfile
end
end
-
+
#
# Retrieves +remotefile+ in ASCII (text) mode, storing the result in
# +localfile+.
@@ -570,10 +562,11 @@
result = ""
end
begin
- retrlines("RETR " + remotefile) do |line|
- f.puts(line) if localfile
- yield(line) if block_given?
- result.concat(line + "\n") if result
+ retrlines("RETR " + remotefile) do |line, newline|
+ l = newline ? line + "\n" : line
+ f.print(l) if localfile
+ yield(line, newline) if block_given?
+ result.concat(l) if result
end
return result
ensure
@@ -593,7 +586,7 @@
gettextfile(remotefile, localfile, &block)
end
end
-
+
#
# Transfers +localfile+ to the server in binary mode, storing the result in
# +remotefile+. If a block is supplied, calls it, passing in the transmitted
@@ -613,12 +606,16 @@
f = open(localfile)
begin
f.binmode
- storbinary("STOR " + remotefile, f, blocksize, rest_offset, &block)
+ if rest_offset
+ storbinary("APPE " + remotefile, f, blocksize, rest_offset, &block)
+ else
+ storbinary("STOR " + remotefile, f, blocksize, rest_offset, &block)
+ end
ensure
f.close
end
end
-
+
#
# Transfers +localfile+ to the server in ASCII (text) mode, storing the result
# in +remotefile+. If callback or an associated block is supplied, calls it,
@@ -653,7 +650,7 @@
cmd = "ACCT " + account
voidcmd(cmd)
end
-
+
#
# Returns an array of filenames in the remote directory.
#
@@ -668,7 +665,7 @@
end
return files
end
-
+
#
# Returns an array of file information in the directory (the output is like
# `ls -l`). If a block is given, it iterates through the listing.
@@ -676,7 +673,7 @@
def list(*args, &block) # :yield: line
cmd = "LIST"
args.each do |arg|
- cmd = cmd + " " + arg
+ cmd = cmd + " " + arg.to_s
end
if block
retrlines(cmd, &block)
@@ -690,7 +687,7 @@
end
alias ls list
alias dir list
-
+
#
# Renames a file on the server.
#
@@ -701,7 +698,7 @@
end
voidcmd("RNTO " + toname)
end
-
+
#
# Deletes a file on the server.
#
@@ -715,7 +712,7 @@
raise FTPReplyError, resp
end
end
-
+
#
# Changes the (remote) directory.
#
@@ -733,22 +730,22 @@
cmd = "CWD " + dirname
voidcmd(cmd)
end
-
+
#
# Returns the size of the given (remote) filename.
#
def size(filename)
with_binary(true) do
resp = sendcmd("SIZE " + filename)
- if resp[0, 3] != "213"
+ if resp[0, 3] != "213"
raise FTPReplyError, resp
end
return resp[3..-1].strip.to_i
end
end
-
+
MDTM_REGEXP = /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/ # :nodoc:
-
+
#
# Returns the last modification time of the (remote) file. If +local+ is
# +true+, it is returned as a local time, otherwise it's a UTC time.
@@ -758,7 +755,7 @@
ary = str.scan(MDTM_REGEXP)[0].collect {|i| i.to_i}
return local ? Time.local(*ary) : Time.gm(*ary)
end
-
+
#
# Creates a remote directory.
#
@@ -766,14 +763,14 @@
resp = sendcmd("MKD " + dirname)
return parse257(resp)
end
-
+
#
# Removes a remote directory.
#
def rmdir(dirname)
voidcmd("RMD " + dirname)
end
-
+
#
# Returns the current remote directory.
#
@@ -782,7 +779,7 @@
return parse257(resp)
end
alias getdir pwd
-
+
#
# Returns system information.
#
@@ -793,7 +790,7 @@
end
return resp[4 .. -1]
end
-
+
#
# Aborts the previous command (ABOR command).
#
@@ -807,7 +804,7 @@
end
return resp
end
-
+
#
# Returns the status (STAT command).
#
@@ -817,7 +814,7 @@
@sock.send(line, Socket::MSG_OOB)
return getresp
end
-
+
#
# Issues the MDTM command. TODO: more info.
#
@@ -827,7 +824,7 @@
return resp[3 .. -1].strip
end
end
-
+
#
# Issues the HELP command.
#
@@ -838,7 +835,7 @@
end
sendcmd(cmd)
end
-
+
#
# Exits the FTP session.
#
@@ -860,7 +857,7 @@
cmd = "SITE " + arg
voidcmd(cmd)
end
-
+
#
# Closes the connection. Further operations are impossible until you open
# a new connection with #connect.
@@ -868,14 +865,14 @@
def close
@sock.close if @sock and not @sock.closed?
end
-
+
#
# Returns +true+ iff the connection is closed.
#
def closed?
@sock == nil or @sock.closed?
end
-
+
def parse227(resp)
if resp[0, 3] != "227"
raise FTPReplyError, resp
@@ -894,7 +891,7 @@
return host, port
end
private :parse227
-
+
def parse228(resp)
if resp[0, 3] != "228"
raise FTPReplyError, resp
@@ -922,11 +919,11 @@
end
host = v6[0, 8].join(":")
port = (numbers[19].to_i << 8) + numbers[20].to_i
- end
+ end
return host, port
end
private :parse228
-
+
def parse229(resp)
if resp[0, 3] != "229"
raise FTPReplyError, resp
@@ -945,7 +942,7 @@
return host, port
end
private :parse229
-
+
def parse257(resp)
if resp[0, 3] != "257"
raise FTPReplyError, resp
@@ -970,8 +967,15 @@
return dirname
end
private :parse257
+
+ # :stopdoc:
+ class NullSocket
+ def method_missing(mid, *args)
+ raise FTPConnectionError, "not connected"
+ end
+ end
+ # :startdoc:
end
-
end
Modified: MacRuby/trunk/lib/net/http.rb
===================================================================
--- MacRuby/trunk/lib/net/http.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/net/http.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -22,7 +22,7 @@
# http://www.ruby-lang.org/ja/man/html/net_http.html
#
#--
-# $Id$
+# $Id: http.rb 27605 2010-05-03 23:42:26Z mame $
#++
require 'net/protocol'
@@ -285,7 +285,7 @@
class HTTP < Protocol
# :stopdoc:
- Revision = %q$Revision$.split[1]
+ Revision = %q$Revision: 27605 $.split[1]
HTTPVersion = '1.1'
@newimpl = true
begin
Modified: MacRuby/trunk/lib/net/https.rb
===================================================================
--- MacRuby/trunk/lib/net/https.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/net/https.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,6 +1,6 @@
=begin
-= $RCSfile$ -- SSL/TLS enhancement for Net::HTTP.
+= net/https -- SSL/TLS enhancement for Net::HTTP.
== Info
'OpenSSL for Ruby 2' project
@@ -11,16 +11,6 @@
This program is licenced under the same licence as Ruby.
(See the file 'LICENCE'.)
-== Requirements
- This program requires Net 1.2.0 or higher version.
- You can get it from RAA or Ruby's CVS repository.
-
-== Version
- $Id: https.rb 18512 2008-08-12 05:20:09Z aamine $
-
- 2001-11-06: Contiributed to Ruby/OpenSSL project.
- 2004-03-06: Some code is merged in to net/http.
-
== Example
Here is a simple HTTP client:
@@ -73,7 +63,7 @@
: ca_file, ca_file=((|path|))
Sets path of a CA certification file in PEM format.
- The file can contrain several CA certificats.
+ The file can contrain several CA certificates.
: ca_path, ca_path=((|path|))
Sets path of a CA certification directory containing certifications
@@ -81,7 +71,7 @@
: verify_mode, verify_mode=((|mode|))
Sets the flags for server the certification verification at
- begining of SSL/TLS session.
+ beginning of SSL/TLS session.
OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable.
: verify_callback, verify_callback=((|proc|))
@@ -100,37 +90,3 @@
require 'net/http'
require 'openssl'
-
-module Net
- class HTTP
- remove_method :use_ssl?
- def use_ssl?
- @use_ssl
- end
-
- # Turn on/off SSL.
- # This flag must be set before starting session.
- # If you change use_ssl value after session started,
- # a Net::HTTP object raises IOError.
- def use_ssl=(flag)
- flag = (flag ? true : false)
- if started? and @use_ssl != flag
- raise IOError, "use_ssl value changed, but session already started"
- end
- @use_ssl = flag
- end
-
- SSL_ATTRIBUTES = %w(
- ssl_version key cert ca_file ca_path cert_store ciphers
- verify_mode verify_callback verify_depth ssl_timeout
- )
- attr_accessor(*SSL_ATTRIBUTES)
-
- def peer_cert
- if not use_ssl? or not @socket
- return nil
- end
- @socket.io.peer_cert
- end
- end
-end
Modified: MacRuby/trunk/lib/net/imap.rb
===================================================================
--- MacRuby/trunk/lib/net/imap.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/net/imap.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -9,7 +9,7 @@
# Documentation: Shugo Maeda, with RDoc conversion and overview by William
# Webber.
#
-# See Net::IMAP for documentation.
+# See Net::IMAP for documentation.
#
@@ -18,7 +18,7 @@
require "digest/md5"
require "strscan"
begin
- require "openssl/ssl"
+ require "openssl"
rescue LoadError
end
@@ -45,12 +45,12 @@
# read-only access) #examine(). Once the client has successfully
# selected a mailbox, they enter _selected_ state, and that
# mailbox becomes the _current_ mailbox, on which mail-item
- # related commands implicitly operate.
+ # related commands implicitly operate.
#
# Messages have two sorts of identifiers: message sequence
- # numbers, and UIDs.
+ # numbers, and UIDs.
#
- # Message sequence numbers number messages within a mail box
+ # Message sequence numbers number messages within a mail box
# from 1 up to the number of items in the mail box. If new
# message arrives during a session, it receives a sequence
# number equal to the new size of the mail box. If messages
@@ -58,7 +58,7 @@
# sequence numbers "shuffled down" to fill the gaps.
#
# UIDs, on the other hand, are permanently guaranteed not to
- # identify another message within the same mailbox, even if
+ # identify another message within the same mailbox, even if
# the existing message is deleted. UIDs are required to
# be assigned in ascending (but not necessarily sequential)
# order within a mailbox; this means that if a non-IMAP client
@@ -91,11 +91,11 @@
# imap.store(message_id, "+FLAGS", [:Deleted])
# end
# imap.expunge
- #
+ #
# == Thread Safety
#
# Net::IMAP supports concurrent threads. For example,
- #
+ #
# imap = Net::IMAP.new("imap.foo.net", "imap2")
# imap.authenticate("cram-md5", "bar", "password")
# imap.select("inbox")
@@ -103,7 +103,7 @@
# search_result = imap.search(["BODY", "hello"])
# fetch_result = fetch_thread.value
# imap.disconnect
- #
+ #
# This script invokes the FETCH command and the SEARCH command concurrently.
#
# == Errors
@@ -113,9 +113,9 @@
#
# NO:: the attempted command could not be successfully completed. For
# instance, the username/password used for logging in are incorrect;
- # the selected mailbox does not exists; etc.
+ # the selected mailbox does not exists; etc.
#
- # BAD:: the request from the client does not follow the server's
+ # BAD:: the request from the client does not follow the server's
# understanding of the IMAP protocol. This includes attempting
# commands from the wrong client state; for instance, attempting
# to perform a SEARCH command without having SELECTed a current
@@ -147,8 +147,8 @@
#
# Finally, a Net::IMAP::DataFormatError is thrown if low-level data
# is found to be in an incorrect format (for instance, when converting
- # between UTF-8 and UTF-16), and Net::IMAP::ResponseParseError is
- # thrown if a server response is non-parseable.
+ # between UTF-8 and UTF-16), and Net::IMAP::ResponseParseError is
+ # thrown if a server response is non-parseable.
#
#
# == References
@@ -270,15 +270,25 @@
return @@debug = val
end
+ # Returns the max number of flags interned to symbols.
+ def self.max_flag_count
+ return @@max_flag_count
+ end
+
+ # Sets the max number of flags interned to symbols.
+ def self.max_flag_count=(count)
+ @@max_flag_count = count
+ end
+
# Adds an authenticator for Net::IMAP#authenticate. +auth_type+
# is the type of authentication this authenticator supports
# (for instance, "LOGIN"). The +authenticator+ is an object
# which defines a process() method to handle authentication with
- # the server. See Net::IMAP::LoginAuthenticator,
+ # the server. See Net::IMAP::LoginAuthenticator,
# Net::IMAP::CramMD5Authenticator, and Net::IMAP::DigestMD5Authenticator
# for examples.
- #
#
+ #
# If +auth_type+ refers to an existing authenticator, it will be
# replaced by the new one.
def self.add_authenticator(auth_type, authenticator)
@@ -297,9 +307,12 @@
end
rescue Errno::ENOTCONN
# ignore `Errno::ENOTCONN: Socket is not connected' on some platforms.
+ rescue Exception => e
+ @receiver_thread.raise(e)
end
@receiver_thread.join
@sock.close
+ raise e if e
end
# Returns true if disconnected from the server.
@@ -314,7 +327,7 @@
#
# Note that the Net::IMAP class does not modify its
# behaviour according to the capabilities of the server;
- # it is up to the user of the class to ensure that
+ # it is up to the user of the class to ensure that
# a certain capability is supported by a server before
# using it.
def capability
@@ -355,7 +368,7 @@
# the authentication mechanism to be used. Currently Net::IMAP
# supports authentication mechanisms:
#
- # LOGIN:: login using cleartext user and password.
+ # LOGIN:: login using cleartext user and password.
# CRAM-MD5:: login with cleartext user and encrypted password
# (see [RFC-2195] for a full description). This
# mechanism requires that the server have the user's
@@ -403,7 +416,7 @@
end
# Sends a SELECT command to select a +mailbox+ so that messages
- # in the +mailbox+ can be accessed.
+ # in the +mailbox+ can be accessed.
#
# After you have selected a mailbox, you may retrieve the
# number of items in that mailbox from @responses["EXISTS"][-1],
@@ -454,7 +467,7 @@
# Sends a RENAME command to change the name of the +mailbox+ to
# +newname+.
#
- # A Net::IMAP::NoResponseError is raised if a mailbox with the
+ # A Net::IMAP::NoResponseError is raised if a mailbox with the
# name +mailbox+ cannot be renamed to +newname+ for whatever
# reason; for instance, because +mailbox+ does not exist, or
# because there is already a mailbox with the name +newname+.
@@ -501,8 +514,8 @@
# imap.create("foo/bar")
# imap.create("foo/baz")
# p imap.list("", "foo/%")
- # #=> [#<Net::IMAP::MailboxList attr=[:Noselect], delim="/", name="foo/">, \\
- # #<Net::IMAP::MailboxList attr=[:Noinferiors, :Marked], delim="/", name="foo/bar">, \\
+ # #=> [#<Net::IMAP::MailboxList attr=[:Noselect], delim="/", name="foo/">, \\
+ # #<Net::IMAP::MailboxList attr=[:Noinferiors, :Marked], delim="/", name="foo/bar">, \\
# #<Net::IMAP::MailboxList attr=[:Noinferiors], delim="/", name="foo/baz">]
def list(refname, mailbox)
synchronize do
@@ -555,7 +568,7 @@
# then that user will be stripped of any rights to that mailbox.
# The IMAP ACL commands are described in [RFC-2086].
def setacl(mailbox, user, rights)
- if rights.nil?
+ if rights.nil?
send_command("SETACL", mailbox, user, "")
else
send_command("SETACL", mailbox, user, rights)
@@ -574,7 +587,7 @@
# Sends a LSUB command, and returns a subset of names from the set
# of names that the user has declared as being "active" or
- # "subscribed". +refname+ and +mailbox+ are interpreted as
+ # "subscribed". +refname+ and +mailbox+ are interpreted as
# for #list().
# The return value is an array of +Net::IMAP::MailboxList+.
def lsub(refname, mailbox)
@@ -597,7 +610,7 @@
# p imap.status("inbox", ["MESSAGES", "RECENT"])
# #=> {"RECENT"=>0, "MESSAGES"=>44}
#
- # A Net::IMAP::NoResponseError is raised if status values
+ # A Net::IMAP::NoResponseError is raised if status values
# for +mailbox+ cannot be returned, for instance because it
# does not exist.
def status(mailbox, attr)
@@ -608,9 +621,9 @@
end
# Sends a APPEND command to append the +message+ to the end of
- # the +mailbox+. The optional +flags+ argument is an array of
+ # the +mailbox+. The optional +flags+ argument is an array of
# flags to initially passing to the new message. The optional
- # +date_time+ argument specifies the creation time to assign to the
+ # +date_time+ argument specifies the creation time to assign to the
# new message; it defaults to the current time.
# For example:
#
@@ -618,7 +631,7 @@
# Subject: hello
# From: shugo at ruby-lang.org
# To: shugo at ruby-lang.org
- #
+ #
# hello world
# EOF
#
@@ -637,7 +650,7 @@
# Sends a CHECK command to request a checkpoint of the currently
# selected mailbox. This performs implementation-specific
- # housekeeping, for instance, reconciling the mailbox's
+ # housekeeping, for instance, reconciling the mailbox's
# in-memory and on-disk state.
def check
send_command("CHECK")
@@ -661,8 +674,8 @@
# Sends a SEARCH command to search the mailbox for messages that
# match the given searching criteria, and returns message sequence
- # numbers. +keys+ can either be a string holding the entire
- # search string, or a single-dimension array of search keywords and
+ # numbers. +keys+ can either be a string holding the entire
+ # search string, or a single-dimension array of search keywords and
# arguments. The following are some common search criteria;
# see [IMAP] section 6.4.4 for a full list.
#
@@ -686,7 +699,7 @@
#
# OR <search-key> <search-key>:: "or" two search keys together.
#
- # ON <date>:: messages with an internal date exactly equal to <date>,
+ # ON <date>:: messages with an internal date exactly equal to <date>,
# which has a format similar to 8-Aug-2002.
#
# SINCE <date>:: messages with an internal date on or after <date>.
@@ -694,7 +707,7 @@
# SUBJECT <string>:: messages with <string> in their subject.
#
# TO <string>:: messages with <string> in their TO field.
- #
+ #
# For example:
#
# p imap.search(["SUBJECT", "hello", "NOT", "NEW"])
@@ -717,8 +730,8 @@
# The return value is an array of Net::IMAP::FetchData. For example:
#
# p imap.fetch(6..8, "UID")
- # #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
- # #<Net::IMAP::FetchData seqno=7, attr={"UID"=>99}>, \\
+ # #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
+ # #<Net::IMAP::FetchData seqno=7, attr={"UID"=>99}>, \\
# #<Net::IMAP::FetchData seqno=8, attr={"UID"=>100}>]
# p imap.fetch(6, "BODY[HEADER.FIELDS (SUBJECT)]")
# #=> [#<Net::IMAP::FetchData seqno=6, attr={"BODY[HEADER.FIELDS (SUBJECT)]"=>"Subject: test\r\n\r\n"}>]
@@ -741,9 +754,9 @@
end
# Sends a STORE command to alter data associated with messages
- # in the mailbox, in particular their flags. The +set+ parameter
- # is a number or an array of numbers or a Range object. Each number
- # is a message sequence number. +attr+ is the name of a data item
+ # in the mailbox, in particular their flags. The +set+ parameter
+ # is a number or an array of numbers or a Range object. Each number
+ # is a message sequence number. +attr+ is the name of a data item
# to store: 'FLAGS' means to replace the message's flag list
# with the provided one; '+FLAGS' means to add the provided flags;
# and '-FLAGS' means to remove them. +flags+ is a list of flags.
@@ -751,8 +764,8 @@
# The return value is an array of Net::IMAP::FetchData. For example:
#
# p imap.store(6..8, "+FLAGS", [:Deleted])
- # #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
- # #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
+ # #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
+ # #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
# #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
def store(set, attr, flags)
return store_internal("STORE", set, attr, flags)
@@ -794,9 +807,9 @@
return sort_internal("UID SORT", sort_keys, search_keys, charset)
end
- # Adds a response handler. For example, to detect when
+ # Adds a response handler. For example, to detect when
# the server sends us a new EXISTS response (which normally
- # indicates new messages being added to the mail box),
+ # indicates new messages being added to the mail box),
# you could add the following handler after selecting the
# mailbox.
#
@@ -832,12 +845,50 @@
return thread_internal("THREAD", algorithm, search_keys, charset)
end
- # As for #thread(), but returns unique identifiers instead of
+ # As for #thread(), but returns unique identifiers instead of
# message sequence numbers.
def uid_thread(algorithm, search_keys, charset)
return thread_internal("UID THREAD", algorithm, search_keys, charset)
end
+ # Sends an IDLE command that waits for notifications of new or expunged
+ # messages. Yields responses from the server during the IDLE.
+ #
+ # Use #idle_done() to leave IDLE.
+ def idle(&response_handler)
+ raise LocalJumpError, "no block given" unless response_handler
+
+ response = nil
+
+ synchronize do
+ tag = Thread.current[:net_imap_tag] = generate_tag
+ put_string("#{tag} IDLE#{CRLF}")
+
+ begin
+ add_response_handler(response_handler)
+ @idle_done_cond = new_cond
+ @idle_done_cond.wait
+ @idle_done_cond = nil
+ ensure
+ remove_response_handler(response_handler)
+ put_string("DONE#{CRLF}")
+ response = get_tagged_response(tag, "IDLE")
+ end
+ end
+
+ return response
+ end
+
+ # Leaves IDLE.
+ def idle_done
+ synchronize do
+ if @idle_done_cond.nil?
+ raise Net::IMAP::Error, "not during IDLE"
+ end
+ @idle_done_cond.signal
+ end
+ end
+
# Decode a string from modified UTF-7 format to UTF-8.
#
# UTF-7 is a 7-bit encoding of Unicode [UTF7]. IMAP uses a
@@ -863,7 +914,7 @@
# Encode a string from UTF-8 format to modified UTF-7.
def self.encode_utf7(s)
- return s.gsub(/(&)|([^\x20-\x25\x27-\x7e]+)/u) {
+ return s.gsub(/(&)|([^\x20-\x7e]+)/u) {
if $1
"&-"
else
@@ -873,6 +924,16 @@
}.force_encoding("ASCII-8BIT")
end
+ # Formats +time+ as an IMAP-style date.
+ def self.format_date(time)
+ return time.strftime('%d-%b-%Y')
+ end
+
+ # Formats +time+ as an IMAP-style date-time.
+ def self.format_datetime(time)
+ return time.strftime('%d-%b-%Y %H:%M %z')
+ end
+
private
CRLF = "\r\n" # :nodoc:
@@ -881,6 +942,7 @@
@@debug = false
@@authenticators = {}
+ @@max_flag_count = 10000
# call-seq:
# Net::IMAP.new(host, options = {})
@@ -897,7 +959,7 @@
# to use SSL (now TLS) to connect to the server. For this to work
# OpenSSL [OSSL] and the Ruby OpenSSL [RSSL] extensions need to
# be installed.
- # if options[:ssl] is a hash, it's passed to
+ # if options[:ssl] is a hash, it's passed to
# OpenSSL::SSL::SSLContext#set_params as parameters.
#
# The most common errors are:
@@ -908,7 +970,7 @@
# being dropped by an intervening firewall).
# Errno::ENETUNREACH:: there is no route to that network.
# SocketError:: hostname not known or other socket error.
- # Net::IMAP::ByeResponseError:: we connected to the host, but they
+ # Net::IMAP::ByeResponseError:: we connected to the host, but they
# immediately said goodbye to us.
def initialize(host, port_or_options = {},
usessl = false, certs = nil, verify = true)
@@ -940,6 +1002,7 @@
@response_handlers = []
@tagged_response_arrival = new_cond
@continuation_request_arrival = new_cond
+ @idle_done_cond = nil
@logout_command_tag = nil
@debug_output_bol = true
@exception = nil
@@ -947,17 +1010,21 @@
@greeting = get_response
if @greeting.name == "BYE"
@sock.close
- raise ByeResponseError, @greeting.raw_data
+ raise ByeResponseError, @greeting
end
@client_thread = Thread.current
@receiver_thread = Thread.start {
- receive_responses
+ begin
+ receive_responses
+ rescue Exception
+ end
}
end
def receive_responses
- while true
+ connection_closed = false
+ until connection_closed
synchronize do
@exception = nil
end
@@ -993,8 +1060,8 @@
end
if resp.name == "BYE" && @logout_command_tag.nil?
@sock.close
- @exception = ByeResponseError.new(resp.raw_data)
- break
+ @exception = ByeResponseError.new(resp)
+ connection_closed = true
end
when ContinuationRequest
@continuation_request_arrival.signal
@@ -1025,9 +1092,9 @@
resp = @tagged_responses.delete(tag)
case resp.name
when /\A(?:NO)\z/ni
- raise NoResponseError, resp.data.text
+ raise NoResponseError, resp
when /\A(?:BAD)\z/ni
- raise BadResponseError, resp.data.text
+ raise BadResponseError, resp
else
return resp
end
@@ -1062,6 +1129,9 @@
def send_command(cmd, *args, &block)
synchronize do
+ args.each do |i|
+ validate_data(i)
+ end
tag = generate_tag
put_string(tag + " " + cmd)
args.each do |i|
@@ -1089,7 +1159,7 @@
@tagno += 1
return format("%s%04d", @tag_prefix, @tagno)
end
-
+
def put_string(str)
@sock.print(str)
if @@debug
@@ -1105,6 +1175,25 @@
end
end
+ def validate_data(data)
+ case data
+ when nil
+ when String
+ when Integer
+ if data < 0 || data >= 4294967296
+ raise DataFormatError, num.to_s
+ end
+ when Array
+ data.each do |i|
+ validate_data(i)
+ end
+ when Time
+ when Symbol
+ else
+ data.validate
+ end
+ end
+
def send_data(data)
case data
when nil
@@ -1138,7 +1227,7 @@
put_string(str)
end
end
-
+
def send_quoted_string(str)
put_string('"' + str.gsub(/["\\]/n, "\\\\\\&") + '"')
end
@@ -1151,9 +1240,6 @@
end
def send_number_data(num)
- if num < 0 || num >= 4294967296
- raise DataFormatError, num.to_s
- end
put_string(num.to_s)
end
@@ -1202,9 +1288,15 @@
end
def fetch_internal(cmd, set, attr)
- if attr.instance_of?(String)
+ case attr
+ when String then
attr = RawData.new(attr)
+ when Array then
+ attr = attr.map { |arg|
+ arg.is_a?(String) ? RawData.new(arg) : arg
+ }
end
+
synchronize do
@responses.delete("FETCH")
send_command(cmd, MessageSet.new(set), attr)
@@ -1294,7 +1386,7 @@
context = SSLContext.new
context.set_params(params)
if defined?(VerifyCallbackProc)
- context.verify_callback = VerifyCallbackProc
+ context.verify_callback = VerifyCallbackProc
end
@sock = SSLSocket.new(@sock, context)
@sock.sync_close = true
@@ -1309,6 +1401,9 @@
imap.send(:put_string, @data)
end
+ def validate
+ end
+
private
def initialize(data)
@@ -1321,6 +1416,9 @@
imap.send(:put_string, @data)
end
+ def validate
+ end
+
private
def initialize(data)
@@ -1333,6 +1431,9 @@
imap.send(:send_quoted_string, @data)
end
+ def validate
+ end
+
private
def initialize(data)
@@ -1345,6 +1446,9 @@
imap.send(:send_literal, @data)
end
+ def validate
+ end
+
private
def initialize(data)
@@ -1357,6 +1461,10 @@
imap.send(:put_string, format_internal(@data))
end
+ def validate
+ validate_internal(@data)
+ end
+
private
def initialize(data)
@@ -1368,7 +1476,6 @@
when "*"
return data
when Integer
- ensure_nz_number(data)
if data == -1
return "*"
else
@@ -1382,6 +1489,23 @@
when ThreadMember
return data.seqno.to_s +
":" + data.children.collect {|i| format_internal(i).join(",")}
+ end
+ end
+
+ def validate_internal(data)
+ case data
+ when "*"
+ when Integer
+ ensure_nz_number(data)
+ when Range
+ when Array
+ data.each do |i|
+ validate_internal(i)
+ end
+ when ThreadMember
+ data.children.each do |i|
+ validate_internal(i)
+ end
else
raise DataFormatError, data.inspect
end
@@ -1397,109 +1521,109 @@
end
# Net::IMAP::ContinuationRequest represents command continuation requests.
- #
+ #
# The command continuation request response is indicated by a "+" token
# instead of a tag. This form of response indicates that the server is
# ready to accept the continuation of a command from the client. The
# remainder of this response is a line of text.
- #
+ #
# continue_req ::= "+" SPACE (resp_text / base64)
- #
+ #
# ==== Fields:
- #
+ #
# data:: Returns the data (Net::IMAP::ResponseText).
- #
+ #
# raw_data:: Returns the raw data string.
ContinuationRequest = Struct.new(:data, :raw_data)
# Net::IMAP::UntaggedResponse represents untagged responses.
- #
+ #
# Data transmitted by the server to the client and status responses
# that do not indicate command completion are prefixed with the token
# "*", and are called untagged responses.
- #
+ #
# response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
# mailbox_data / message_data / capability_data)
- #
+ #
# ==== Fields:
- #
+ #
# name:: Returns the name such as "FLAGS", "LIST", "FETCH"....
- #
+ #
# data:: Returns the data such as an array of flag symbols,
# a ((<Net::IMAP::MailboxList>)) object....
- #
+ #
# raw_data:: Returns the raw data string.
UntaggedResponse = Struct.new(:name, :data, :raw_data)
-
+
# Net::IMAP::TaggedResponse represents tagged responses.
- #
+ #
# The server completion result response indicates the success or
# failure of the operation. It is tagged with the same tag as the
# client command which began the operation.
- #
+ #
# response_tagged ::= tag SPACE resp_cond_state CRLF
- #
+ #
# tag ::= 1*<any ATOM_CHAR except "+">
- #
+ #
# resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
- #
+ #
# ==== Fields:
- #
+ #
# tag:: Returns the tag.
- #
+ #
# name:: Returns the name. the name is one of "OK", "NO", "BAD".
- #
+ #
# data:: Returns the data. See ((<Net::IMAP::ResponseText>)).
- #
+ #
# raw_data:: Returns the raw data string.
#
TaggedResponse = Struct.new(:tag, :name, :data, :raw_data)
-
+
# Net::IMAP::ResponseText represents texts of responses.
# The text may be prefixed by the response code.
- #
+ #
# resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
# ;; text SHOULD NOT begin with "[" or "="
- #
+ #
# ==== Fields:
- #
+ #
# code:: Returns the response code. See ((<Net::IMAP::ResponseCode>)).
- #
+ #
# text:: Returns the text.
- #
+ #
ResponseText = Struct.new(:code, :text)
- #
+ #
# Net::IMAP::ResponseCode represents response codes.
- #
+ #
# resp_text_code ::= "ALERT" / "PARSE" /
# "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
# "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
# "UIDVALIDITY" SPACE nz_number /
# "UNSEEN" SPACE nz_number /
# atom [SPACE 1*<any TEXT_CHAR except "]">]
- #
+ #
# ==== Fields:
- #
+ #
# name:: Returns the name such as "ALERT", "PERMANENTFLAGS", "UIDVALIDITY"....
- #
+ #
# data:: Returns the data if it exists.
#
ResponseCode = Struct.new(:name, :data)
# Net::IMAP::MailboxList represents contents of the LIST response.
- #
+ #
# mailbox_list ::= "(" #("\Marked" / "\Noinferiors" /
# "\Noselect" / "\Unmarked" / flag_extension) ")"
# SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox
- #
+ #
# ==== Fields:
- #
+ #
# attr:: Returns the name attributes. Each name attribute is a symbol
# capitalized by String#capitalize, such as :Noselect (not :NoSelect).
- #
+ #
# delim:: Returns the hierarchy delimiter
- #
+ #
# name:: Returns the mailbox name.
#
MailboxList = Struct.new(:attr, :delim, :name)
@@ -1508,78 +1632,78 @@
# This object can also be a response to GETQUOTAROOT. In the syntax
# specification below, the delimiter used with the "#" construct is a
# single space (SPACE).
- #
+ #
# quota_list ::= "(" #quota_resource ")"
- #
+ #
# quota_resource ::= atom SPACE number SPACE number
- #
+ #
# quota_response ::= "QUOTA" SPACE astring SPACE quota_list
- #
+ #
# ==== Fields:
- #
+ #
# mailbox:: The mailbox with the associated quota.
- #
+ #
# usage:: Current storage usage of mailbox.
- #
+ #
# quota:: Quota limit imposed on mailbox.
#
MailboxQuota = Struct.new(:mailbox, :usage, :quota)
# Net::IMAP::MailboxQuotaRoot represents part of the GETQUOTAROOT
# response. (GETQUOTAROOT can also return Net::IMAP::MailboxQuota.)
- #
+ #
# quotaroot_response ::= "QUOTAROOT" SPACE astring *(SPACE astring)
- #
+ #
# ==== Fields:
- #
+ #
# mailbox:: The mailbox with the associated quota.
- #
+ #
# quotaroots:: Zero or more quotaroots that effect the quota on the
# specified mailbox.
#
MailboxQuotaRoot = Struct.new(:mailbox, :quotaroots)
# Net::IMAP::MailboxACLItem represents response from GETACL.
- #
+ #
# acl_data ::= "ACL" SPACE mailbox *(SPACE identifier SPACE rights)
- #
+ #
# identifier ::= astring
- #
+ #
# rights ::= astring
- #
+ #
# ==== Fields:
- #
+ #
# user:: Login name that has certain rights to the mailbox
# that was specified with the getacl command.
- #
+ #
# rights:: The access rights the indicated user has to the
# mailbox.
#
MailboxACLItem = Struct.new(:user, :rights)
# Net::IMAP::StatusData represents contents of the STATUS response.
- #
+ #
# ==== Fields:
- #
+ #
# mailbox:: Returns the mailbox name.
- #
+ #
# attr:: Returns a hash. Each key is one of "MESSAGES", "RECENT", "UIDNEXT",
# "UIDVALIDITY", "UNSEEN". Each value is a number.
- #
+ #
StatusData = Struct.new(:mailbox, :attr)
# Net::IMAP::FetchData represents contents of the FETCH response.
- #
+ #
# ==== Fields:
- #
+ #
# seqno:: Returns the message sequence number.
# (Note: not the unique identifier, even for the UID command response.)
- #
+ #
# attr:: Returns a hash. Each key is a data item name, and each value is
# its value.
- #
+ #
# The current data items are:
- #
+ #
# [BODY]
# A form of BODYSTRUCTURE without extension data.
# [BODY[<section>]<<origin_octet>>]
@@ -1606,67 +1730,67 @@
# Equivalent to BODY[TEXT].
# [UID]
# A number expressing the unique identifier of the message.
- #
+ #
FetchData = Struct.new(:seqno, :attr)
# Net::IMAP::Envelope represents envelope structures of messages.
- #
+ #
# ==== Fields:
- #
+ #
# date:: Returns a string that represents the date.
- #
+ #
# subject:: Returns a string that represents the subject.
- #
+ #
# from:: Returns an array of Net::IMAP::Address that represents the from.
- #
+ #
# sender:: Returns an array of Net::IMAP::Address that represents the sender.
- #
+ #
# reply_to:: Returns an array of Net::IMAP::Address that represents the reply-to.
- #
+ #
# to:: Returns an array of Net::IMAP::Address that represents the to.
- #
+ #
# cc:: Returns an array of Net::IMAP::Address that represents the cc.
- #
+ #
# bcc:: Returns an array of Net::IMAP::Address that represents the bcc.
- #
+ #
# in_reply_to:: Returns a string that represents the in-reply-to.
- #
+ #
# message_id:: Returns a string that represents the message-id.
- #
+ #
Envelope = Struct.new(:date, :subject, :from, :sender, :reply_to,
:to, :cc, :bcc, :in_reply_to, :message_id)
- #
+ #
# Net::IMAP::Address represents electronic mail addresses.
- #
+ #
# ==== Fields:
- #
+ #
# name:: Returns the phrase from [RFC-822] mailbox.
- #
+ #
# route:: Returns the route from [RFC-822] route-addr.
- #
+ #
# mailbox:: nil indicates end of [RFC-822] group.
# If non-nil and host is nil, returns [RFC-822] group name.
# Otherwise, returns [RFC-822] local-part
- #
+ #
# host:: nil indicates [RFC-822] group syntax.
# Otherwise, returns [RFC-822] domain name.
#
Address = Struct.new(:name, :route, :mailbox, :host)
- #
+ #
# Net::IMAP::ContentDisposition represents Content-Disposition fields.
- #
+ #
# ==== Fields:
- #
+ #
# dsp_type:: Returns the disposition type.
- #
+ #
# param:: Returns a hash that represents parameters of the Content-Disposition
# field.
- #
+ #
ContentDisposition = Struct.new(:dsp_type, :param)
- # Net::IMAP::ThreadMember represents a thread-node returned
+ # Net::IMAP::ThreadMember represents a thread-node returned
# by Net::IMAP#thread
#
# ==== Fields:
@@ -1679,37 +1803,37 @@
ThreadMember = Struct.new(:seqno, :children)
# Net::IMAP::BodyTypeBasic represents basic body structures of messages.
- #
+ #
# ==== Fields:
- #
+ #
# media_type:: Returns the content media type name as defined in [MIME-IMB].
- #
+ #
# subtype:: Returns the content subtype name as defined in [MIME-IMB].
- #
+ #
# param:: Returns a hash that represents parameters as defined in [MIME-IMB].
- #
+ #
# content_id:: Returns a string giving the content id as defined in [MIME-IMB].
- #
+ #
# description:: Returns a string giving the content description as defined in
# [MIME-IMB].
- #
+ #
# encoding:: Returns a string giving the content transfer encoding as defined in
# [MIME-IMB].
- #
+ #
# size:: Returns a number giving the size of the body in octets.
- #
+ #
# md5:: Returns a string giving the body MD5 value as defined in [MD5].
- #
+ #
# disposition:: Returns a Net::IMAP::ContentDisposition object giving
# the content disposition.
- #
+ #
# language:: Returns a string or an array of strings giving the body
# language value as defined in [LANGUAGE-TAGS].
- #
+ #
# extension:: Returns extension data.
- #
+ #
# multipart?:: Returns false.
- #
+ #
class BodyTypeBasic < Struct.new(:media_type, :subtype,
:param, :content_id,
:description, :encoding, :size,
@@ -1720,7 +1844,7 @@
end
# Obsolete: use +subtype+ instead. Calling this will
- # generate a warning message to +stderr+, then return
+ # generate a warning message to +stderr+, then return
# the value of +subtype+.
def media_subtype
$stderr.printf("warning: media_subtype is obsolete.\n")
@@ -1730,13 +1854,13 @@
end
# Net::IMAP::BodyTypeText represents TEXT body structures of messages.
- #
+ #
# ==== Fields:
- #
+ #
# lines:: Returns the size of the body in text lines.
- #
+ #
# And Net::IMAP::BodyTypeText has all fields of Net::IMAP::BodyTypeBasic.
- #
+ #
class BodyTypeText < Struct.new(:media_type, :subtype,
:param, :content_id,
:description, :encoding, :size,
@@ -1748,7 +1872,7 @@
end
# Obsolete: use +subtype+ instead. Calling this will
- # generate a warning message to +stderr+, then return
+ # generate a warning message to +stderr+, then return
# the value of +subtype+.
def media_subtype
$stderr.printf("warning: media_subtype is obsolete.\n")
@@ -1758,13 +1882,13 @@
end
# Net::IMAP::BodyTypeMessage represents MESSAGE/RFC822 body structures of messages.
- #
+ #
# ==== Fields:
- #
+ #
# envelope:: Returns a Net::IMAP::Envelope giving the envelope structure.
- #
+ #
# body:: Returns an object giving the body structure.
- #
+ #
# And Net::IMAP::BodyTypeMessage has all methods of Net::IMAP::BodyTypeText.
#
class BodyTypeMessage < Struct.new(:media_type, :subtype,
@@ -1778,7 +1902,7 @@
end
# Obsolete: use +subtype+ instead. Calling this will
- # generate a warning message to +stderr+, then return
+ # generate a warning message to +stderr+, then return
# the value of +subtype+.
def media_subtype
$stderr.printf("warning: media_subtype is obsolete.\n")
@@ -1787,29 +1911,29 @@
end
end
- # Net::IMAP::BodyTypeMultipart represents multipart body structures
+ # Net::IMAP::BodyTypeMultipart represents multipart body structures
# of messages.
- #
+ #
# ==== Fields:
- #
+ #
# media_type:: Returns the content media type name as defined in [MIME-IMB].
- #
+ #
# subtype:: Returns the content subtype name as defined in [MIME-IMB].
- #
+ #
# parts:: Returns multiple parts.
- #
+ #
# param:: Returns a hash that represents parameters as defined in [MIME-IMB].
- #
+ #
# disposition:: Returns a Net::IMAP::ContentDisposition object giving
# the content disposition.
- #
+ #
# language:: Returns a string or an array of strings giving the body
# language value as defined in [LANGUAGE-TAGS].
- #
+ #
# extension:: Returns extension data.
- #
+ #
# multipart?:: Returns true.
- #
+ #
class BodyTypeMultipart < Struct.new(:media_type, :subtype,
:parts,
:param, :disposition, :language,
@@ -1819,7 +1943,7 @@
end
# Obsolete: use +subtype+ instead. Calling this will
- # generate a warning message to +stderr+, then return
+ # generate a warning message to +stderr+, then return
# the value of +subtype+.
def media_subtype
$stderr.printf("warning: media_subtype is obsolete.\n")
@@ -1829,6 +1953,14 @@
end
class ResponseParser # :nodoc:
+ def initialize
+ @str = nil
+ @pos = nil
+ @lex_state = nil
+ @token = nil
+ @flag_symbols = {}
+ end
+
def parse(str)
@str = str
@pos = 0
@@ -2620,35 +2752,35 @@
def thread_branch(token)
rootmember = nil
lastmember = nil
-
+
while true
shift_token # ignore first T_LPAR
token = lookahead
-
+
case token.symbol
when T_NUMBER
# new member
newmember = ThreadMember.new(number, [])
if rootmember.nil?
rootmember = newmember
- else
+ else
lastmember.children << newmember
- end
+ end
lastmember = newmember
- when T_SPACE
- # do nothing
+ when T_SPACE
+ # do nothing
when T_LPAR
if rootmember.nil?
# dummy member
lastmember = rootmember = ThreadMember.new(nil, [])
- end
-
+ end
+
lastmember.children << thread_branch(token)
when T_RPAR
- break
- end
+ break
+ end
end
-
+
return rootmember
end
@@ -2725,11 +2857,16 @@
match(T_SPACE)
result = ResponseCode.new(name, number)
else
- match(T_SPACE)
- @lex_state = EXPR_CTEXT
- token = match(T_TEXT)
- @lex_state = EXPR_BEG
- result = ResponseCode.new(name, token.value)
+ token = lookahead
+ if token.symbol == T_SPACE
+ shift_token
+ @lex_state = EXPR_CTEXT
+ token = match(T_TEXT)
+ @lex_state = EXPR_BEG
+ result = ResponseCode.new(name, token.value)
+ else
+ result = ResponseCode.new(name, nil)
+ end
end
match(T_RBRA)
@lex_state = EXPR_RTEXT
@@ -2834,7 +2971,16 @@
if @str.index(/\(([^)]*)\)/ni, @pos)
@pos = $~.end(0)
return $1.scan(FLAG_REGEXP).collect { |flag, atom|
- atom || flag.capitalize.intern
+ if atom
+ atom
+ else
+ symbol = flag.capitalize.untaint.intern
+ @flag_symbols[symbol] = true
+ if @flag_symbols.length > IMAP.max_flag_count
+ raise FlagCountError, "number of flag symbols exceeded"
+ end
+ symbol
+ end
}
else
parse_error("invalid flag list")
@@ -3125,7 +3271,7 @@
@user = user
@password = password
end
- end
+ end
add_authenticator "PLAIN", PlainAuthenticator
# Authenticator for the "CRAM-MD5" authentication type. See
@@ -3151,8 +3297,8 @@
k_ipad = key + "\0" * (64 - key.length)
k_opad = key + "\0" * (64 - key.length)
for i in 0..63
- k_ipad[i] ^= 0x36
- k_opad[i] ^= 0x5c
+ k_ipad[i] = (k_ipad[i].ord ^ 0x36).chr
+ k_opad[i] = (k_opad[i].ord ^ 0x5c).chr
end
digest = Digest::MD5.digest(k_ipad + text)
@@ -3277,6 +3423,16 @@
# Superclass of all errors used to encapsulate "fail" responses
# from the server.
class ResponseError < Error
+
+ # The response that caused this error
+ attr_accessor :response
+
+ def initialize(response)
+ @response = response
+
+ super @response.data.text
+ end
+
end
# Error raised upon a "NO" response from the server, indicating
@@ -3290,11 +3446,15 @@
class BadResponseError < ResponseError
end
- # Error raised upon a "BYE" response from the server, indicating
+ # Error raised upon a "BYE" response from the server, indicating
# that the client is not being allowed to login, or has been timed
# out due to inactivity.
class ByeResponseError < ResponseError
end
+
+ # Error raised when too many flags are interned to symbols.
+ class FlagCountError < Error
+ end
end
end
@@ -3375,7 +3535,7 @@
usage
exit(1)
end
-
+
imap = Net::IMAP.new($host, :port => $port, :ssl => $ssl)
begin
password = get_password
Modified: MacRuby/trunk/lib/net/pop.rb
===================================================================
--- MacRuby/trunk/lib/net/pop.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/net/pop.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -3,20 +3,20 @@
# Copyright (c) 1999-2007 Yukihiro Matsumoto.
#
# Copyright (c) 1999-2007 Minero Aoki.
-#
+#
# Written & maintained by Minero Aoki <aamine at loveruby.net>.
#
# Documented by William Webber and Minero Aoki.
-#
+#
# This program is free software. You can re-distribute and/or
# modify this program under the same terms as Ruby itself,
# Ruby Distribute License.
-#
+#
# NOTE: You can find Japanese version of this document at:
# http://www.ruby-lang.org/ja/man/html/net_pop.html
-#
-# $Id: pop.rb 19776 2008-10-14 02:22:46Z kazu $
-#
+#
+# $Id: pop.rb 25189 2009-10-02 12:04:37Z akr $
+#
# See Net::POP3 for documentation.
#
@@ -25,7 +25,7 @@
require 'timeout'
begin
- require "openssl/ssl"
+ require "openssl"
rescue LoadError
end
@@ -45,25 +45,25 @@
# = Net::POP3
#
# == What is This Library?
- #
- # This library provides functionality for retrieving
+ #
+ # This library provides functionality for retrieving
# email via POP3, the Post Office Protocol version 3. For details
# of POP3, see [RFC1939] (http://www.ietf.org/rfc/rfc1939.txt).
- #
+ #
# == Examples
- #
- # === Retrieving Messages
- #
- # This example retrieves messages from the server and deletes them
+ #
+ # === Retrieving Messages
+ #
+ # This example retrieves messages from the server and deletes them
# on the server.
#
# Messages are written to files named 'inbox/1', 'inbox/2', ....
# Replace 'pop.example.com' with your POP3 server address, and
# 'YourAccount' and 'YourPassword' with the appropriate account
# details.
- #
+ #
# require 'net/pop'
- #
+ #
# pop = Net::POP3.new('pop.example.com')
# pop.start('YourAccount', 'YourPassword') # (1)
# if pop.mails.empty?
@@ -80,19 +80,19 @@
# puts "#{pop.mails.size} mails popped."
# end
# pop.finish # (3)
- #
+ #
# 1. Call Net::POP3#start and start POP session.
# 2. Access messages by using POP3#each_mail and/or POP3#mails.
# 3. Close POP session by calling POP3#finish or use the block form of #start.
- #
+ #
# === Shortened Code
- #
+ #
# The example above is very verbose. You can shorten the code by using
# some utility methods. First, the block form of Net::POP3.start can
# be used instead of POP3.new, POP3#start and POP3#finish.
- #
+ #
# require 'net/pop'
- #
+ #
# Net::POP3.start('pop.example.com', 110,
# 'YourAccount', 'YourPassword') do |pop|
# if pop.mails.empty?
@@ -109,11 +109,11 @@
# puts "#{pop.mails.size} mails popped."
# end
# end
- #
+ #
# POP3#delete_all is an alternative for #each_mail and #delete.
- #
+ #
# require 'net/pop'
- #
+ #
# Net::POP3.start('pop.example.com', 110,
# 'YourAccount', 'YourPassword') do |pop|
# if pop.mails.empty?
@@ -128,11 +128,11 @@
# end
# end
# end
- #
+ #
# And here is an even shorter example.
- #
+ #
# require 'net/pop'
- #
+ #
# i = 0
# Net::POP3.delete_all('pop.example.com', 110,
# 'YourAccount', 'YourPassword') do |m|
@@ -141,14 +141,14 @@
# end
# i += 1
# end
- #
+ #
# === Memory Space Issues
- #
+ #
# All the examples above get each message as one big string.
# This example avoids this.
- #
+ #
# require 'net/pop'
- #
+ #
# i = 1
# Net::POP3.delete_all('pop.example.com', 110,
# 'YourAccount', 'YourPassword') do |m|
@@ -159,44 +159,44 @@
# i += 1
# end
# end
- #
+ #
# === Using APOP
- #
+ #
# The net/pop library supports APOP authentication.
# To use APOP, use the Net::APOP class instead of the Net::POP3 class.
# You can use the utility method, Net::POP3.APOP(). For example:
- #
+ #
# require 'net/pop'
- #
+ #
# # Use APOP authentication if $isapop == true
# pop = Net::POP3.APOP($is_apop).new('apop.example.com', 110)
# pop.start(YourAccount', 'YourPassword') do |pop|
# # Rest of the code is the same.
# end
- #
+ #
# === Fetch Only Selected Mail Using 'UIDL' POP Command
- #
+ #
# If your POP server provides UIDL functionality,
# you can grab only selected mails from the POP server.
# e.g.
- #
+ #
# def need_pop?( id )
# # determine if we need pop this mail...
# end
- #
+ #
# Net::POP3.start('pop.example.com', 110,
# 'Your account', 'Your password') do |pop|
# pop.mails.select { |m| need_pop?(m.unique_id) }.each do |m|
# do_something(m.pop)
# end
# end
- #
+ #
# The POPMail#unique_id() method returns the unique-id of the message as a
# String. Normally the unique-id is a hash of the message.
- #
+ #
class POP3 < Protocol
- Revision = %q$Revision: 19776 $.split[1]
+ Revision = %q$Revision: 25189 $.split[1]
#
# Class Parameters
@@ -210,7 +210,7 @@
def POP3.default_pop3_port
110
end
-
+
# The default port for POP3S connections, port 995
def POP3.default_pop3s_port
995
@@ -375,7 +375,7 @@
# Session management
#
- # Creates a new POP3 object and open the connection. Equivalent to
+ # Creates a new POP3 object and open the connection. Equivalent to
#
# Net::POP3.new(address, port, isapop).start(account, password)
#
@@ -396,7 +396,7 @@
isapop = false, &block) # :yield: pop
new(address, port, isapop).start(account, password, &block)
end
-
+
# Creates a new POP3 object.
#
# +address+ is the hostname or ip address of your POP3 server.
@@ -412,7 +412,7 @@
@ssl_params = POP3.ssl_params
@port = port
@apop = isapop
-
+
@command = nil
@socket = nil
@started = false
@@ -434,7 +434,7 @@
def use_ssl?
return !@ssl_params.nil?
end
-
+
# call-seq:
# Net::POP#enable_ssl(params = {})
#
@@ -451,7 +451,7 @@
@port = port || @port
end
end
-
+
def disable_ssl
@ssl_params = nil
end
@@ -635,7 +635,7 @@
# Yields each message to the passed-in block in turn.
# Equivalent to:
- #
+ #
# pop3.mails.each do |popmail|
# ....
# end
@@ -742,7 +742,7 @@
#
# This method fetches the message. If called with a block, the
# message is yielded to the block one chunk at a time. If called
- # without a block, the message is returned as a String. The optional
+ # without a block, the message is returned as a String. The optional
# +dest+ argument will be prepended to the returned String; this
# argument is essentially obsolete.
#
@@ -753,7 +753,7 @@
# n = 1
# pop.mails.each do |popmail|
# File.open("inbox/#{n}", 'w') do |f|
- # f.write popmail.pop
+ # f.write popmail.pop
# end
# popmail.delete
# n += 1
@@ -792,7 +792,7 @@
alias all pop #:nodoc: obsolete
alias mail pop #:nodoc: obsolete
- # Fetches the message header and +lines+ lines of body.
+ # Fetches the message header and +lines+ lines of body.
#
# The optional +dest+ argument is obsolete.
#
@@ -804,7 +804,7 @@
dest
end
- # Fetches the message header.
+ # Fetches the message header.
#
# The optional +dest+ argument is obsolete.
#
@@ -933,7 +933,7 @@
@socket.each_message_chunk(&block)
}
end
-
+
def dele(num)
check_response(critical { get_response('DELE %d', num) })
end
Modified: MacRuby/trunk/lib/net/protocol.rb
===================================================================
--- MacRuby/trunk/lib/net/protocol.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/net/protocol.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -11,7 +11,7 @@
# modify this program under the same terms as Ruby itself,
# Ruby Distribute License or GNU General Public License.
#
-# $Id: protocol.rb 12091 2007-03-19 02:27:08Z aamine $
+# $Id: protocol.rb 25189 2009-10-02 12:04:37Z akr $
#++
#
# WARNING: This file is going to remove.
@@ -121,7 +121,7 @@
return rbuf_consume(@rbuf.size)
end
end
-
+
def readline
readuntil("\n").chop
end
@@ -131,9 +131,23 @@
BUFSIZE = 1024 * 16
def rbuf_fill
- timeout(@read_timeout) {
- @rbuf << @io.sysread(BUFSIZE)
- }
+ begin
+ @rbuf << @io.read_nonblock(BUFSIZE)
+ rescue IO::WaitReadable
+ if IO.select([@io], nil, nil, @read_timeout)
+ retry
+ else
+ raise Timeout::Error
+ end
+ rescue IO::WaitWritable
+ # OpenSSL::Buffering#read_nonblock may fail with IO::WaitWritable.
+ # http://www.openssl.org/support/faq.html#PROG10
+ if IO.select(nil, [@io], nil, @read_timeout)
+ retry
+ else
+ raise Timeout::Error
+ end
+ end
end
def rbuf_consume(len)
@@ -222,7 +236,7 @@
LOG_on()
LOG "read message (#{read_bytes} bytes)"
end
-
+
# *library private* (cannot handle 'break')
def each_list_item
while (str = readuntil("\r\n")) != ".\r\n"
Modified: MacRuby/trunk/lib/net/smtp.rb
===================================================================
--- MacRuby/trunk/lib/net/smtp.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/net/smtp.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,23 +1,23 @@
# = net/smtp.rb
-#
+#
# Copyright (c) 1999-2007 Yukihiro Matsumoto.
#
# Copyright (c) 1999-2007 Minero Aoki.
-#
+#
# Written & maintained by Minero Aoki <aamine at loveruby.net>.
#
# Documented by William Webber and Minero Aoki.
-#
+#
# This program is free software. You can re-distribute and/or
# modify this program under the same terms as Ruby itself.
-#
+#
# NOTE: You can find Japanese version of this document at:
# http://www.ruby-lang.org/ja/man/html/net_smtp.html
-#
-# $Id: smtp.rb 18351 2008-08-04 05:46:53Z shyouhei $
#
-# See Net::SMTP for documentation.
-#
+# $Id: smtp.rb 27512 2010-04-27 09:00:52Z nobu $
+#
+# See Net::SMTP for documentation.
+#
require 'net/protocol'
require 'digest/md5'
@@ -69,110 +69,110 @@
# = Net::SMTP
#
# == What is This Library?
- #
+ #
# This library provides functionality to send internet
# mail via SMTP, the Simple Mail Transfer Protocol. For details of
# SMTP itself, see [RFC2821] (http://www.ietf.org/rfc/rfc2821.txt).
- #
+ #
# == What is This Library NOT?
- #
+ #
# This library does NOT provide functions to compose internet mails.
# You must create them by yourself. If you want better mail support,
# try RubyMail or TMail. You can get both libraries from RAA.
# (http://www.ruby-lang.org/en/raa.html)
- #
+ #
# FYI: the official documentation on internet mail is: [RFC2822] (http://www.ietf.org/rfc/rfc2822.txt).
- #
+ #
# == Examples
- #
+ #
# === Sending Messages
- #
+ #
# You must open a connection to an SMTP server before sending messages.
- # The first argument is the address of your SMTP server, and the second
- # argument is the port number. Using SMTP.start with a block is the simplest
- # way to do this. This way, the SMTP connection is closed automatically
+ # The first argument is the address of your SMTP server, and the second
+ # argument is the port number. Using SMTP.start with a block is the simplest
+ # way to do this. This way, the SMTP connection is closed automatically
# after the block is executed.
- #
+ #
# require 'net/smtp'
# Net::SMTP.start('your.smtp.server', 25) do |smtp|
# # Use the SMTP object smtp only in this block.
# end
- #
+ #
# Replace 'your.smtp.server' with your SMTP server. Normally
# your system manager or internet provider supplies a server
# for you.
- #
+ #
# Then you can send messages.
- #
+ #
# msgstr = <<END_OF_MESSAGE
# From: Your Name <your at mail.address>
# To: Destination Address <someone at example.com>
# Subject: test message
# Date: Sat, 23 Jun 2001 16:26:43 +0900
# Message-Id: <unique.message.id.string at example.com>
- #
+ #
# This is a test message.
# END_OF_MESSAGE
- #
+ #
# require 'net/smtp'
# Net::SMTP.start('your.smtp.server', 25) do |smtp|
# smtp.send_message msgstr,
# 'your at mail.address',
- # 'his_addess at example.com'
+ # 'his_address at example.com'
# end
- #
+ #
# === Closing the Session
- #
- # You MUST close the SMTP session after sending messages, by calling
+ #
+ # You MUST close the SMTP session after sending messages, by calling
# the #finish method:
- #
+ #
# # using SMTP#finish
# smtp = Net::SMTP.start('your.smtp.server', 25)
# smtp.send_message msgstr, 'from at address', 'to at address'
# smtp.finish
- #
+ #
# You can also use the block form of SMTP.start/SMTP#start. This closes
# the SMTP session automatically:
- #
+ #
# # using block form of SMTP.start
# Net::SMTP.start('your.smtp.server', 25) do |smtp|
# smtp.send_message msgstr, 'from at address', 'to at address'
# end
- #
+ #
# I strongly recommend this scheme. This form is simpler and more robust.
- #
+ #
# === HELO domain
- #
+ #
# In almost all situations, you must provide a third argument
# to SMTP.start/SMTP#start. This is the domain name which you are on
# (the host to send mail from). It is called the "HELO domain".
# The SMTP server will judge whether it should send or reject
# the SMTP session by inspecting the HELO domain.
- #
+ #
# Net::SMTP.start('your.smtp.server', 25,
# 'mail.from.domain') { |smtp| ... }
- #
+ #
# === SMTP Authentication
- #
+ #
# The Net::SMTP class supports three authentication schemes;
# PLAIN, LOGIN and CRAM MD5. (SMTP Authentication: [RFC2554])
- # To use SMTP authentication, pass extra arguments to
+ # To use SMTP authentication, pass extra arguments to
# SMTP.start/SMTP#start.
- #
+ #
# # PLAIN
# Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
# 'Your Account', 'Your Password', :plain)
# # LOGIN
# Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
# 'Your Account', 'Your Password', :login)
- #
+ #
# # CRAM MD5
# Net::SMTP.start('your.smtp.server', 25, 'mail.from.domain',
# 'Your Account', 'Your Password', :cram_md5)
#
class SMTP
- Revision = %q$Revision: 18351 $.split[1]
+ Revision = %q$Revision: 27512 $.split[1]
# The default SMTP port number, 25.
def SMTP.default_port
@@ -196,7 +196,7 @@
def SMTP.default_ssl_context
OpenSSL::SSL::SSLContext.new
end
-
+
#
# Creates a new Net::SMTP object.
#
@@ -223,7 +223,7 @@
@starttls = false
@ssl_context = nil
end
-
+
# Provide human-readable stringification of class state.
def inspect
"#<#{self.class} #{@address}:#{@port} started=#{@started}>"
@@ -235,7 +235,7 @@
end
#
- # Set whether to use ESMTP or not. This should be done before
+ # Set whether to use ESMTP or not. This should be done before
# calling #start. Note that if #start is called in ESMTP mode,
# and the connection fails due to a ProtocolError, the SMTP
# object will automatically switch to plain SMTP mode and
@@ -310,7 +310,7 @@
end
alias enable_ssl enable_tls
-
+
# Disables SMTP/TLS for this object. Must be called before the
# connection is established to have any effect.
def disable_tls
@@ -336,7 +336,7 @@
def starttls_auto?
@starttls == :auto
end
-
+
# Enables SMTP/TLS (STARTTLS) for this object.
# +context+ is a OpenSSL::SSL::SSLContext object.
def enable_starttls(context = SMTP.default_ssl_context)
@@ -413,7 +413,7 @@
# Creates a new Net::SMTP object and connects to the server.
#
# This method is equivalent to:
- #
+ #
# Net::SMTP.new(address, port).start(helo_domain, account, password, authtype)
#
# === Example
@@ -437,7 +437,7 @@
# +port+ is the port to connect to; it defaults to port 25.
#
# +helo+ is the _HELO_ _domain_ provided by the client to the
- # server (see overview comments); it defaults to 'localhost'.
+ # server (see overview comments); it defaults to 'localhost'.
#
# The remaining arguments are used for SMTP authentication, if required
# or desired. +user+ is the account name; +secret+ is your password
@@ -476,33 +476,33 @@
# +helo+ is the _HELO_ _domain_ that you'll dispatch mails from; see
# the discussion in the overview notes.
#
- # If both of +user+ and +secret+ are given, SMTP authentication
- # will be attempted using the AUTH command. +authtype+ specifies
+ # If both of +user+ and +secret+ are given, SMTP authentication
+ # will be attempted using the AUTH command. +authtype+ specifies
# the type of authentication to attempt; it must be one of
# :login, :plain, and :cram_md5. See the notes on SMTP Authentication
- # in the overview.
+ # in the overview.
#
# === Block Usage
#
# When this methods is called with a block, the newly-started SMTP
# object is yielded to the block, and automatically closed after
- # the block call finishes. Otherwise, it is the caller's
+ # the block call finishes. Otherwise, it is the caller's
# responsibility to close the session when finished.
#
# === Example
#
# This is very similar to the class method SMTP.start.
#
- # require 'net/smtp'
+ # require 'net/smtp'
# smtp = Net::SMTP.new('smtp.mail.server', 25)
# smtp.start(helo_domain, account, password, authtype) do |smtp|
# smtp.send_message msgstr, 'from at example.com', ['dest at example.com']
- # end
+ # end
#
# The primary use of this method (as opposed to SMTP.start)
# is probably to set debugging (#set_debug_output) or ESMTP
# (#esmtp=), which must be done before the session is
- # started.
+ # started.
#
# === Errors
#
@@ -548,7 +548,7 @@
check_auth_method(authtype || DEFAULT_AUTH_TYPE)
check_auth_args user, secret
end
- s = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
+ s = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
logging "Connection opened: #{@address}:#{@port}"
@socket = new_internet_message_io(tls? ? tlsconnect(s) : s)
check_response critical { recv_response() }
@@ -621,7 +621,7 @@
#
# Sends +msgstr+ as a message. Single CR ("\r") and LF ("\n") found
# in the +msgstr+, are converted into the CR LF pair. You cannot send a
- # binary message with this method. +msgstr+ should include both
+ # binary message with this method. +msgstr+ should include both
# the message headers and body.
#
# +from_addr+ is a String representing the source mail address.
@@ -651,8 +651,7 @@
def send_message(msgstr, from_addr, *to_addrs)
raise IOError, 'closed session' unless @socket
mailfrom from_addr
- rcptto_list to_addrs
- data msgstr
+ rcptto_list(to_addrs) {data msgstr}
end
alias send_mail send_message
@@ -705,8 +704,7 @@
def open_message_stream(from_addr, *to_addrs, &block) # :yield: stream
raise IOError, 'closed session' unless @socket
mailfrom from_addr
- rcptto_list to_addrs
- data(&block)
+ rcptto_list(to_addrs) {data(&block)}
end
alias ready open_message_stream # obsolete
@@ -769,7 +767,7 @@
"auth_#{type.to_s.downcase}".intern
end
- def check_auth_args(user, secret)
+ def check_auth_args(user, secret, authtype = DEFAULT_AUTH_TYPE)
unless user
raise ArgumentError, 'SMTP-AUTH requested but missing user name'
end
@@ -830,9 +828,23 @@
def rcptto_list(to_addrs)
raise ArgumentError, 'mail destination not given' if to_addrs.empty?
+ ok_users = []
+ unknown_users = []
to_addrs.flatten.each do |addr|
- rcptto addr
+ begin
+ rcptto addr
+ rescue SMTPAuthenticationError
+ unknown_users << addr.dump
+ else
+ ok_users << addr
+ end
end
+ raise ArgumentError, 'mail destination not given' if ok_users.empty?
+ ret = yield
+ unless unknown_users.empty?
+ raise SMTPAuthenticationError, "failed to deliver for #{unknown_users.join(', ')}"
+ end
+ ret
end
def rcptto(to_addr)
@@ -852,7 +864,7 @@
# From: john at example.com
# To: betty at example.com
# Subject: I found a bug
- #
+ #
# Check vm.c:58879.
# EndMessage
#
Modified: MacRuby/trunk/lib/net/telnet.rb
===================================================================
--- MacRuby/trunk/lib/net/telnet.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/net/telnet.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,7 +1,7 @@
# = net/telnet.rb - Simple Telnet Client Library
-#
+#
# Author:: Wakou Aoyama <wakou at ruby-lang.org>
-# Documentation:: William Webber and Wakou Aoyama
+# Documentation:: William Webber and Wakou Aoyama
#
# This file holds the class Net::Telnet, which provides client-side
# telnet functionality.
@@ -10,10 +10,9 @@
#
require "socket"
-require "delegate"
require "timeout"
require "English"
-
+
module Net
#
@@ -50,11 +49,11 @@
# have to handle authentication yourself.
#
# For some protocols, it will be possible to specify the +Prompt+
- # option once when you create the Telnet object and use #cmd() calls;
+ # option once when you create the Telnet object and use #cmd() calls;
# for others, you will have to specify the response sequence to
# look for as the Match option to every #cmd() call, or call
- # #puts() and #waitfor() directly; for yet others, you will have
- # to use #sysread() instead of #waitfor() and parse server
+ # #puts() and #waitfor() directly; for yet others, you will have
+ # to use #sysread() instead of #waitfor() and parse server
# responses yourself.
#
# It is worth noting that when you create a new Net::Telnet object,
@@ -63,21 +62,21 @@
# to already open sockets, or to any read-write IO object. This
# can be useful, for instance, for setting up a test fixture for
# unit testing.
- #
+ #
# == Examples
- #
+ #
# === Log in and send a command, echoing all output to stdout
- #
+ #
# localhost = Net::Telnet::new("Host" => "localhost",
# "Timeout" => 10,
# "Prompt" => /[$%#>] \z/n)
# localhost.login("username", "password") { |c| print c }
# localhost.cmd("command") { |c| print c }
# localhost.close
- #
- #
+ #
+ #
# === Check a POP server to see if you have mail
- #
+ #
# pop = Net::Telnet::new("Host" => "your_destination_host_here",
# "Port" => 110,
# "Telnetmode" => false,
@@ -93,78 +92,78 @@
# of relevant RFCs, see
# http://www.omnifarious.org/~hopper/technical/telnet-rfc.html
#
- class Telnet < SimpleDelegator
+ class Telnet
# :stopdoc:
IAC = 255.chr # "\377" # "\xff" # interpret as command
- DONT = 254.chr # "\376" # "\xfe" # you are not to use option
- DO = 253.chr # "\375" # "\xfd" # please, you use option
- WONT = 252.chr # "\374" # "\xfc" # I won't use option
- WILL = 251.chr # "\373" # "\xfb" # I will use option
- SB = 250.chr # "\372" # "\xfa" # interpret as subnegotiation
- GA = 249.chr # "\371" # "\xf9" # you may reverse the line
- EL = 248.chr # "\370" # "\xf8" # erase the current line
- EC = 247.chr # "\367" # "\xf7" # erase the current character
- AYT = 246.chr # "\366" # "\xf6" # are you there
- AO = 245.chr # "\365" # "\xf5" # abort output--but let prog finish
- IP = 244.chr # "\364" # "\xf4" # interrupt process--permanently
- BREAK = 243.chr # "\363" # "\xf3" # break
- DM = 242.chr # "\362" # "\xf2" # data mark--for connect. cleaning
- NOP = 241.chr # "\361" # "\xf1" # nop
- SE = 240.chr # "\360" # "\xf0" # end sub negotiation
- EOR = 239.chr # "\357" # "\xef" # end of record (transparent mode)
- ABORT = 238.chr # "\356" # "\xee" # Abort process
- SUSP = 237.chr # "\355" # "\xed" # Suspend process
- EOF = 236.chr # "\354" # "\xec" # End of file
- SYNCH = 242.chr # "\362" # "\xf2" # for telfunc calls
+ DONT = 254.chr # "\376" # "\xfe" # you are not to use option
+ DO = 253.chr # "\375" # "\xfd" # please, you use option
+ WONT = 252.chr # "\374" # "\xfc" # I won't use option
+ WILL = 251.chr # "\373" # "\xfb" # I will use option
+ SB = 250.chr # "\372" # "\xfa" # interpret as subnegotiation
+ GA = 249.chr # "\371" # "\xf9" # you may reverse the line
+ EL = 248.chr # "\370" # "\xf8" # erase the current line
+ EC = 247.chr # "\367" # "\xf7" # erase the current character
+ AYT = 246.chr # "\366" # "\xf6" # are you there
+ AO = 245.chr # "\365" # "\xf5" # abort output--but let prog finish
+ IP = 244.chr # "\364" # "\xf4" # interrupt process--permanently
+ BREAK = 243.chr # "\363" # "\xf3" # break
+ DM = 242.chr # "\362" # "\xf2" # data mark--for connect. cleaning
+ NOP = 241.chr # "\361" # "\xf1" # nop
+ SE = 240.chr # "\360" # "\xf0" # end sub negotiation
+ EOR = 239.chr # "\357" # "\xef" # end of record (transparent mode)
+ ABORT = 238.chr # "\356" # "\xee" # Abort process
+ SUSP = 237.chr # "\355" # "\xed" # Suspend process
+ EOF = 236.chr # "\354" # "\xec" # End of file
+ SYNCH = 242.chr # "\362" # "\xf2" # for telfunc calls
- OPT_BINARY = 0.chr # "\000" # "\x00" # Binary Transmission
- OPT_ECHO = 1.chr # "\001" # "\x01" # Echo
- OPT_RCP = 2.chr # "\002" # "\x02" # Reconnection
- OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead
- OPT_NAMS = 4.chr # "\004" # "\x04" # Approx Message Size Negotiation
- OPT_STATUS = 5.chr # "\005" # "\x05" # Status
- OPT_TM = 6.chr # "\006" # "\x06" # Timing Mark
- OPT_RCTE = 7.chr # "\a" # "\x07" # Remote Controlled Trans and Echo
- OPT_NAOL = 8.chr # "\010" # "\x08" # Output Line Width
- OPT_NAOP = 9.chr # "\t" # "\x09" # Output Page Size
- OPT_NAOCRD = 10.chr # "\n" # "\x0a" # Output Carriage-Return Disposition
- OPT_NAOHTS = 11.chr # "\v" # "\x0b" # Output Horizontal Tab Stops
- OPT_NAOHTD = 12.chr # "\f" # "\x0c" # Output Horizontal Tab Disposition
- OPT_NAOFFD = 13.chr # "\r" # "\x0d" # Output Formfeed Disposition
- OPT_NAOVTS = 14.chr # "\016" # "\x0e" # Output Vertical Tabstops
- OPT_NAOVTD = 15.chr # "\017" # "\x0f" # Output Vertical Tab Disposition
- OPT_NAOLFD = 16.chr # "\020" # "\x10" # Output Linefeed Disposition
- OPT_XASCII = 17.chr # "\021" # "\x11" # Extended ASCII
- OPT_LOGOUT = 18.chr # "\022" # "\x12" # Logout
- OPT_BM = 19.chr # "\023" # "\x13" # Byte Macro
- OPT_DET = 20.chr # "\024" # "\x14" # Data Entry Terminal
- OPT_SUPDUP = 21.chr # "\025" # "\x15" # SUPDUP
- OPT_SUPDUPOUTPUT = 22.chr # "\026" # "\x16" # SUPDUP Output
- OPT_SNDLOC = 23.chr # "\027" # "\x17" # Send Location
- OPT_TTYPE = 24.chr # "\030" # "\x18" # Terminal Type
- OPT_EOR = 25.chr # "\031" # "\x19" # End of Record
- OPT_TUID = 26.chr # "\032" # "\x1a" # TACACS User Identification
- OPT_OUTMRK = 27.chr # "\e" # "\x1b" # Output Marking
- OPT_TTYLOC = 28.chr # "\034" # "\x1c" # Terminal Location Number
- OPT_3270REGIME = 29.chr # "\035" # "\x1d" # Telnet 3270 Regime
- OPT_X3PAD = 30.chr # "\036" # "\x1e" # X.3 PAD
- OPT_NAWS = 31.chr # "\037" # "\x1f" # Negotiate About Window Size
- OPT_TSPEED = 32.chr # " " # "\x20" # Terminal Speed
- OPT_LFLOW = 33.chr # "!" # "\x21" # Remote Flow Control
- OPT_LINEMODE = 34.chr # "\"" # "\x22" # Linemode
- OPT_XDISPLOC = 35.chr # "#" # "\x23" # X Display Location
- OPT_OLD_ENVIRON = 36.chr # "$" # "\x24" # Environment Option
- OPT_AUTHENTICATION = 37.chr # "%" # "\x25" # Authentication Option
- OPT_ENCRYPT = 38.chr # "&" # "\x26" # Encryption Option
- OPT_NEW_ENVIRON = 39.chr # "'" # "\x27" # New Environment Option
- OPT_EXOPL = 255.chr # "\377" # "\xff" # Extended-Options-List
+ OPT_BINARY = 0.chr # "\000" # "\x00" # Binary Transmission
+ OPT_ECHO = 1.chr # "\001" # "\x01" # Echo
+ OPT_RCP = 2.chr # "\002" # "\x02" # Reconnection
+ OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead
+ OPT_NAMS = 4.chr # "\004" # "\x04" # Approx Message Size Negotiation
+ OPT_STATUS = 5.chr # "\005" # "\x05" # Status
+ OPT_TM = 6.chr # "\006" # "\x06" # Timing Mark
+ OPT_RCTE = 7.chr # "\a" # "\x07" # Remote Controlled Trans and Echo
+ OPT_NAOL = 8.chr # "\010" # "\x08" # Output Line Width
+ OPT_NAOP = 9.chr # "\t" # "\x09" # Output Page Size
+ OPT_NAOCRD = 10.chr # "\n" # "\x0a" # Output Carriage-Return Disposition
+ OPT_NAOHTS = 11.chr # "\v" # "\x0b" # Output Horizontal Tab Stops
+ OPT_NAOHTD = 12.chr # "\f" # "\x0c" # Output Horizontal Tab Disposition
+ OPT_NAOFFD = 13.chr # "\r" # "\x0d" # Output Formfeed Disposition
+ OPT_NAOVTS = 14.chr # "\016" # "\x0e" # Output Vertical Tabstops
+ OPT_NAOVTD = 15.chr # "\017" # "\x0f" # Output Vertical Tab Disposition
+ OPT_NAOLFD = 16.chr # "\020" # "\x10" # Output Linefeed Disposition
+ OPT_XASCII = 17.chr # "\021" # "\x11" # Extended ASCII
+ OPT_LOGOUT = 18.chr # "\022" # "\x12" # Logout
+ OPT_BM = 19.chr # "\023" # "\x13" # Byte Macro
+ OPT_DET = 20.chr # "\024" # "\x14" # Data Entry Terminal
+ OPT_SUPDUP = 21.chr # "\025" # "\x15" # SUPDUP
+ OPT_SUPDUPOUTPUT = 22.chr # "\026" # "\x16" # SUPDUP Output
+ OPT_SNDLOC = 23.chr # "\027" # "\x17" # Send Location
+ OPT_TTYPE = 24.chr # "\030" # "\x18" # Terminal Type
+ OPT_EOR = 25.chr # "\031" # "\x19" # End of Record
+ OPT_TUID = 26.chr # "\032" # "\x1a" # TACACS User Identification
+ OPT_OUTMRK = 27.chr # "\e" # "\x1b" # Output Marking
+ OPT_TTYLOC = 28.chr # "\034" # "\x1c" # Terminal Location Number
+ OPT_3270REGIME = 29.chr # "\035" # "\x1d" # Telnet 3270 Regime
+ OPT_X3PAD = 30.chr # "\036" # "\x1e" # X.3 PAD
+ OPT_NAWS = 31.chr # "\037" # "\x1f" # Negotiate About Window Size
+ OPT_TSPEED = 32.chr # " " # "\x20" # Terminal Speed
+ OPT_LFLOW = 33.chr # "!" # "\x21" # Remote Flow Control
+ OPT_LINEMODE = 34.chr # "\"" # "\x22" # Linemode
+ OPT_XDISPLOC = 35.chr # "#" # "\x23" # X Display Location
+ OPT_OLD_ENVIRON = 36.chr # "$" # "\x24" # Environment Option
+ OPT_AUTHENTICATION = 37.chr # "%" # "\x25" # Authentication Option
+ OPT_ENCRYPT = 38.chr # "&" # "\x26" # Encryption Option
+ OPT_NEW_ENVIRON = 39.chr # "'" # "\x27" # New Environment Option
+ OPT_EXOPL = 255.chr # "\377" # "\xff" # Extended-Options-List
- NULL = "\000"
- CR = "\015"
- LF = "\012"
- EOL = CR + LF
- REVISION = '$Id: telnet.rb 17387 2008-06-17 14:04:48Z jeg2 $'
+ NULL = "\000"
+ CR = "\015"
+ LF = "\012"
+ EOL = CR + LF
+ REVISION = '$Id: telnet.rb 25733 2009-11-12 14:03:03Z xibbar $'
# :startdoc:
#
@@ -174,13 +173,13 @@
# provided: see below). If a block is provided, it is yielded
# status messages on the attempt to connect to the server, of
# the form:
- #
+ #
# Trying localhost...
# Connected to localhost.
#
# +options+ is a hash of options. The following example lists
# all options and their default values.
- #
+ #
# host = Net::Telnet::new(
# "Host" => "localhost", # default: "localhost"
# "Port" => 23, # default: 23
@@ -198,16 +197,16 @@
#
# The options have the following meanings:
#
- # Host:: the hostname or IP address of the host to connect to, as a String.
+ # Host:: the hostname or IP address of the host to connect to, as a String.
# Defaults to "localhost".
#
# Port:: the port to connect to. Defaults to 23.
#
- # Binmode:: if false (the default), newline substitution is performed.
+ # Binmode:: if false (the default), newline substitution is performed.
# Outgoing LF is
# converted to CRLF, and incoming CRLF is converted to LF. If
# true, this substitution is not performed. This value can
- # also be set with the #binmode() method. The
+ # also be set with the #binmode() method. The
# outgoing conversion only applies to the #puts() and #print()
# methods, not the #write() method. The precise nature of
# the newline conversion is also affected by the telnet options
@@ -217,13 +216,13 @@
# and all received traffic to. In the case of a proper
# Telnet session, this will include the client input as
# echoed by the host; otherwise, it only includes server
- # responses. Output is appended verbatim to this file.
+ # responses. Output is appended verbatim to this file.
# By default, no output log is kept.
#
# Dump_log:: as for Output_log, except that output is written in hexdump
# format (16 bytes per line as hex pairs, followed by their
# printable equivalent), with connection status messages
- # preceded by '#', sent traffic preceded by '>', and
+ # preceded by '#', sent traffic preceded by '>', and
# received traffic preceded by '<'. By default, not dump log
# is kept.
#
@@ -233,7 +232,7 @@
# ready to receive a new command. By default, this regular
# expression is /[$%#>] \z/n.
#
- # Telnetmode:: a boolean value, true by default. In telnet mode,
+ # Telnetmode:: a boolean value, true by default. In telnet mode,
# traffic received from the host is parsed for special
# command sequences, and these sequences are escaped
# in outgoing traffic sent using #puts() or #print()
@@ -255,11 +254,11 @@
# minutes), but other attempts to read data from the host
# will hand indefinitely if no data is forthcoming.
#
- # Waittime:: the amount of time to wait after seeing what looks like a
+ # Waittime:: the amount of time to wait after seeing what looks like a
# prompt (that is, received data that matches the Prompt
# option regular expression) to see if more data arrives.
# If more data does arrive in this time, Net::Telnet assumes
- # that what it saw was not really a prompt. This is to try to
+ # that what it saw was not really a prompt. This is to try to
# avoid false matches, but it can also lead to missing real
# prompts (if, for instance, a background process writes to
# the terminal soon after the prompt is displayed). By
@@ -267,12 +266,12 @@
#
# Proxy:: a proxy object to used instead of opening a direct connection
# to the host. Must be either another Net::Telnet object or
- # an IO object. If it is another Net::Telnet object, this
+ # an IO object. If it is another Net::Telnet object, this
# instance will use that one's socket for communication. If an
# IO object, it is used directly for communication. Any other
# kind of object will cause an error to be raised.
#
- def initialize(options) # :yield: mesg
+ def initialize(options) # :yield: mesg
@options = options
@options["Host"] = "localhost" unless @options.has_key?("Host")
@options["Port"] = 23 unless @options.has_key?("Port")
@@ -280,7 +279,7 @@
@options["Timeout"] = 10 unless @options.has_key?("Timeout")
@options["Waittime"] = 0 unless @options.has_key?("Waittime")
unless @options.has_key?("Binmode")
- @options["Binmode"] = false
+ @options["Binmode"] = false
else
unless (true == @options["Binmode"] or false == @options["Binmode"])
raise ArgumentError, "Binmode option must be true or false"
@@ -288,7 +287,7 @@
end
unless @options.has_key?("Telnetmode")
- @options["Telnetmode"] = true
+ @options["Telnetmode"] = true
else
unless (true == @options["Telnetmode"] or false == @options["Telnetmode"])
raise ArgumentError, "Telnetmode option must be true or false"
@@ -369,13 +368,12 @@
@dumplog.log_dump('#', message) if @options.has_key?("Dump_log")
end
- super(@sock)
end # initialize
# The socket the Telnet object is using. Note that this object becomes
# a delegate of the Telnet object, so normally you invoke its methods
# directly on the Telnet object.
- attr :sock
+ attr :sock
# Set telnet command interpretation on (+mode+ == true) or off
# (+mode+ == false), or return the current value (+mode+ not
@@ -409,7 +407,7 @@
def binmode(mode = nil)
case mode
when nil
- @options["Binmode"]
+ @options["Binmode"]
when true, false
@options["Binmode"] = mode
else
@@ -429,7 +427,7 @@
# Preprocess received data from the host.
#
# Performs newline conversion and detects telnet command sequences.
- # Called automatically by #waitfor(). You should only use this
+ # Called automatically by #waitfor(). You should only use this
# method yourself if you have read input directly using sysread()
# or similar, and even then only if in telnet mode.
def preprocess(string)
@@ -495,9 +493,9 @@
# Read data from the host until a certain sequence is matched.
#
# If a block is given, the received data will be yielded as it
- # is read in (not necessarily all in one go), or nil if EOF
+ # is read in (not necessarily all in one go), or nil if EOF
# occurs before any data is received. Whether a block is given
- # or not, all data read will be returned in a single string, or again
+ # or not, all data read will be returned in a single string, or again
# nil if EOF occurs before any data is received. Note that
# received data includes the matched sequence we were looking for.
#
@@ -511,7 +509,7 @@
# into a regular expression. Used only if Match and
# Prompt are not specified.
# Timeout:: the number of seconds to wait for data from the host
- # before raising a TimeoutError. If set to false,
+ # before raising a TimeoutError. If set to false,
# no timeout will occur. If not specified, the
# Timeout option value specified when this instance
# was created will be used, or, failing that, the
@@ -528,7 +526,7 @@
# EOFError will be raised. Otherwise, defaults to the old
# behaviour that the function will return whatever data
# has been received already, or nil if nothing was received.
- #
+ #
def waitfor(options) # :yield: recvdata
time_out = @options["Timeout"]
waittime = @options["Waittime"]
@@ -623,7 +621,7 @@
# Sends a string to the host.
#
# This does _not_ automatically append a newline to the string. Embedded
- # newlines may be converted and telnet command sequences escaped
+ # newlines may be converted and telnet command sequences escaped
# depending upon the values of telnetmode, binmode, and telnet options
# set by the host.
def print(string)
@@ -658,7 +656,7 @@
# data until is sees the prompt or other matched sequence.
#
# If a block is given, the received data will be yielded to it as
- # it is read in. Whether a block is given or not, the received data
+ # it is read in. Whether a block is given or not, the received data
# will be return as a string. Note that the received data includes
# the prompt and in most cases the host's echo of our command.
#
@@ -682,20 +680,22 @@
def cmd(options) # :yield: recvdata
match = @options["Prompt"]
time_out = @options["Timeout"]
+ fail_eof = @options["FailEOF"]
if options.kind_of?(Hash)
string = options["String"]
match = options["Match"] if options.has_key?("Match")
time_out = options["Timeout"] if options.has_key?("Timeout")
+ fail_eof = options["FailEOF"] if options.has_key?("FailEOF")
else
string = options
end
self.puts(string)
if block_given?
- waitfor({"Prompt" => match, "Timeout" => time_out}){|c| yield c }
+ waitfor({"Prompt" => match, "Timeout" => time_out, "FailEOF" => fail_eof}){|c| yield c }
else
- waitfor({"Prompt" => match, "Timeout" => time_out})
+ waitfor({"Prompt" => match, "Timeout" => time_out, "FailEOF" => fail_eof})
end
end
@@ -703,7 +703,7 @@
#
# The username and password can either be provided as two string
# arguments in that order, or as a hash with keys "Name" and
- # "Password".
+ # "Password".
#
# This method looks for the strings "login" and "Password" from the
# host to determine when to send the username and password. If the
Modified: MacRuby/trunk/lib/observer.rb
===================================================================
--- MacRuby/trunk/lib/observer.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/observer.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -7,7 +7,7 @@
#
# The Observer pattern, also known as Publish/Subscribe, provides a simple
# mechanism for one object to inform a set of interested third-party objects
-# when its state changes.
+# when its state changes.
#
# == Mechanism
#
@@ -39,14 +39,14 @@
# contracts are correct, nothing else can warn you.
#
# require "observer"
-#
+#
# class Ticker ### Periodically fetch a stock price.
# include Observable
-#
+#
# def initialize(symbol)
# @symbol = symbol
# end
-#
+#
# def run
# lastPrice = nil
# loop do
@@ -67,14 +67,14 @@
# 60 + rand(80)
# end
# end
-#
+#
# class Warner ### An abstract observer of Ticker objects.
# def initialize(ticker, limit)
# @limit = limit
# ticker.add_observer(self)
# end
# end
-#
+#
# class WarnLow < Warner
# def update(time, price) # callback for observer
# if price < @limit
@@ -82,7 +82,7 @@
# end
# end
# end
-#
+#
# class WarnHigh < Warner
# def update(time, price) # callback for observer
# if price > @limit
Modified: MacRuby/trunk/lib/open-uri.rb
===================================================================
--- MacRuby/trunk/lib/open-uri.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/open-uri.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -465,7 +465,9 @@
subtype = $2.downcase
parameters = []
$3.scan(/;#{RE_LWS}?(#{RE_TOKEN})#{RE_LWS}?=#{RE_LWS}?(?:(#{RE_TOKEN})|(#{RE_QUOTED_STRING}))/no) {|att, val, qval|
- val = qval.gsub(/[\r\n\t !#-\[\]-~\x80-\xff]+|(\\[\x00-\x7f])/n) { $1 ? $1[1,1] : $& } if qval
+ if qval
+ val = qval[1...-1].gsub(/[\r\n\t !#-\[\]-~\x80-\xff]+|(\\[\x00-\x7f])/n) { $1 ? $1[1,1] : $& }
+ end
parameters << [att.downcase, val]
}
["#{type}/#{subtype}", *parameters]
@@ -603,7 +605,7 @@
#
# If :progress_proc option is specified, the proc is called with one
# argument each time when `open' gets content fragment from network.
- # The argument `size' `size' is a accumulated transfered size in bytes.
+ # The argument `size' `size' is a accumulated transferred size in bytes.
#
# If two or more transfer is done by HTTP redirection, the procedure
# is called only one for a last transfer.
@@ -778,8 +780,9 @@
end
require 'net/ftp'
- directories = self.path.split(%r{/}, -1)
- directories.shift if directories[0] == '' # strip a field before leading slash
+ path = self.path
+ path = path.sub(%r{\A/}, '%2F') # re-encode the beginning slash because uri library decodes it.
+ directories = path.split(%r{/}, -1)
directories.each {|d|
d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") }
}
@@ -800,7 +803,8 @@
end
# The access sequence is defined by RFC 1738
- ftp = Net::FTP.open(self.host)
+ ftp = Net::FTP.new
+ ftp.connect(self.host, self.port)
ftp.passive = true if !options[:ftp_active_mode]
# todo: extract user/passwd from .netrc.
user = 'anonymous'
Modified: MacRuby/trunk/lib/open3.rb
===================================================================
--- MacRuby/trunk/lib/open3.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/open3.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -11,77 +11,708 @@
#
# Open3 grants you access to stdin, stdout, stderr and a thread to wait the
# child process when running another program.
+# You can specify various attributes, redirections, current directory, etc., of
+# the program as Process.spawn.
#
-# Example:
+# - Open3.popen3 : pipes for stdin, stdout, stderr
+# - Open3.popen2 : pipes for stdin, stdout
+# - Open3.popen2e : pipes for stdin, merged stdout and stderr
+# - Open3.capture3 : give a string for stdin. get strings for stdout, stderr
+# - Open3.capture2 : give a string for stdin. get a string for stdout
+# - Open3.capture2e : give a string for stdin. get a string for merged stdout and stderr
+# - Open3.pipeline_rw : pipes for first stdin and last stdout of a pipeline
+# - Open3.pipeline_r : pipe for last stdout of a pipeline
+# - Open3.pipeline_w : pipe for first stdin of a pipeline
+# - Open3.pipeline_start : a pipeline
+# - Open3.pipeline : run a pipline and wait
#
-# require "open3"
-# include Open3
-#
-# stdin, stdout, stderr, wait_thr = popen3('nroff -man')
-#
-# Open3.popen3 can also take a block which will receive stdin, stdout,
-# stderr and wait_thr as parameters.
-# This ensures stdin, stdout and stderr are closed and
-# the process is terminated once the block exits.
-#
-# Example:
-#
-# require "open3"
-#
-# Open3.popen3('nroff -man') { |stdin, stdout, stderr, wait_thr| ... }
-#
module Open3
- #
+
# Open stdin, stdout, and stderr streams and start external executable.
# In addition, a thread for waiting the started process is noticed.
- # The thread has a thread variable :pid which is the pid of the started
- # process.
+ # The thread has a pid method and thread variable :pid which is the pid of
+ # the started process.
#
+ # Block form:
+ #
+ # Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
+ # pid = wait_thr.pid # pid of the started process.
+ # ...
+ # exit_status = wait_thr.value # Process::Status object returned.
+ # }
+ #
# Non-block form:
- #
- # stdin, stdout, stderr, wait_thr = Open3.popen3(cmd)
+ #
+ # stdin, stdout, stderr, wait_thr = Open3.popen3([env,] cmd... [, opts])
# pid = wait_thr[:pid] # pid of the started process.
# ...
- # stdin.close # stdin, stdout and stderr should be closed in this form.
+ # stdin.close # stdin, stdout and stderr should be closed explicitly in this form.
# stdout.close
# stderr.close
# exit_status = wait_thr.value # Process::Status object returned.
#
- # Block form:
+ # The parameters +cmd...+ is passed to Process.spawn.
+ # So a commandline string and list of argument strings can be accepted as follows.
#
- # Open3.popen3(cmd) { |stdin, stdout, stderr, wait_thr| ... }
+ # Open3.popen3("echo a") {|i, o, e, t| ... }
+ # Open3.popen3("echo", "a") {|i, o, e, t| ... }
+ # Open3.popen3(["echo", "argv0"], "a") {|i, o, e, t| ... }
#
- # The parameter +cmd+ is passed directly to Kernel#spawn.
+ # If the last parameter, opts, is a Hash, it is recognized as an option for Process.spawn.
#
+ # Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
+ # p o.read.chomp #=> "/"
+ # }
+ #
# wait_thr.value waits the termination of the process.
# The block form also waits the process when it returns.
#
# Closing stdin, stdout and stderr does not wait the process.
#
- def popen3(*cmd)
- pw = IO::pipe # pipe[0] for read, pipe[1] for write
- pr = IO::pipe
- pe = IO::pipe
+ def popen3(*cmd, &block)
+ if Hash === cmd.last
+ opts = cmd.pop.dup
+ else
+ opts = {}
+ end
- pid = spawn(*cmd, STDIN=>pw[0], STDOUT=>pr[1], STDERR=>pe[1])
+ in_r, in_w = IO.pipe
+ opts[:in] = in_r
+ in_w.sync = true
+
+ out_r, out_w = IO.pipe
+ opts[:out] = out_w
+
+ err_r, err_w = IO.pipe
+ opts[:err] = err_w
+
+ popen_run(cmd, opts, [in_r, out_w, err_w], [in_w, out_r, err_r], &block)
+ end
+ module_function :popen3
+
+ # Open3.popen2 is similer to Open3.popen3 except it doesn't make a pipe for
+ # the standard error stream.
+ #
+ # Block form:
+ #
+ # Open3.popen2([env,] cmd... [, opts]) {|stdin, stdout, wait_thr|
+ # pid = wait_thr.pid # pid of the started process.
+ # ...
+ # exit_status = wait_thr.value # Process::Status object returned.
+ # }
+ #
+ # Non-block form:
+ #
+ # stdin, stdout, wait_thr = Open3.popen2([env,] cmd... [, opts])
+ # ...
+ # stdin.close # stdin and stdout should be closed explicitly in this form.
+ # stdout.close
+ #
+ # See Process.spawn for the optional hash arguments _env_ and _opts_.
+ #
+ # Example:
+ #
+ # Open3.popen2("wc -c") {|i,o,t|
+ # i.print "answer to life the universe and everything"
+ # i.close
+ # p o.gets #=> "42\n"
+ # }
+ #
+ # Open3.popen2("bc -q") {|i,o,t|
+ # i.puts "obase=13"
+ # i.puts "6 * 9"
+ # p o.gets #=> "42\n"
+ # }
+ #
+ # Open3.popen2("dc") {|i,o,t|
+ # i.print "42P"
+ # i.close
+ # p o.read #=> "*"
+ # }
+ #
+ def popen2(*cmd, &block)
+ if Hash === cmd.last
+ opts = cmd.pop.dup
+ else
+ opts = {}
+ end
+
+ in_r, in_w = IO.pipe
+ opts[:in] = in_r
+ in_w.sync = true
+
+ out_r, out_w = IO.pipe
+ opts[:out] = out_w
+
+ popen_run(cmd, opts, [in_r, out_w], [in_w, out_r], &block)
+ end
+ module_function :popen2
+
+ # Open3.popen2e is similer to Open3.popen3 except it merges
+ # the standard output stream and the standard error stream.
+ #
+ # Block form:
+ #
+ # Open3.popen2e([env,] cmd... [, opts]) {|stdin, stdout_and_stderr, wait_thr|
+ # pid = wait_thr.pid # pid of the started process.
+ # ...
+ # exit_status = wait_thr.value # Process::Status object returned.
+ # }
+ #
+ # Non-block form:
+ #
+ # stdin, stdout_and_stderr, wait_thr = Open3.popen2e([env,] cmd... [, opts])
+ # ...
+ # stdin.close # stdin and stdout_and_stderr should be closed explicitly in this form.
+ # stdout_and_stderr.close
+ #
+ # See Process.spawn for the optional hash arguments _env_ and _opts_.
+ #
+ # Example:
+ # # check gcc warnings
+ # source = "foo.c"
+ # Open3.popen2e("gcc", "-Wall", source) {|i,oe,t|
+ # oe.each {|line|
+ # if /warning/ =~ line
+ # ...
+ # end
+ # }
+ # }
+ #
+ def popen2e(*cmd, &block)
+ if Hash === cmd.last
+ opts = cmd.pop.dup
+ else
+ opts = {}
+ end
+
+ in_r, in_w = IO.pipe
+ opts[:in] = in_r
+ in_w.sync = true
+
+ out_r, out_w = IO.pipe
+ opts[[:out, :err]] = out_w
+
+ popen_run(cmd, opts, [in_r, out_w], [in_w, out_r], &block)
+ end
+ module_function :popen2e
+
+ def popen_run(cmd, opts, child_io, parent_io) # :nodoc:
+ pid = spawn(*cmd, opts)
wait_thr = Process.detach(pid)
- pw[0].close
- pr[1].close
- pe[1].close
- pi = [pw[1], pr[0], pe[0], wait_thr]
- pw[1].sync = true
+ child_io.each {|io| io.close }
+ result = [*parent_io, wait_thr]
if defined? yield
begin
- return yield(*pi)
+ return yield(*result)
ensure
- [pw[1], pr[0], pe[0]].each{|p| p.close unless p.closed?}
+ parent_io.each{|io| io.close unless io.closed?}
wait_thr.join
end
end
- pi
+ result
end
- module_function :popen3
+ module_function :popen_run
+ class << self
+ private :popen_run
+ end
+
+ # Open3.capture3 captures the standard output and the standard error of a command.
+ #
+ # stdout_str, stderr_str, status = Open3.capture3([env,] cmd... [, opts])
+ #
+ # The arguments env, cmd and opts are passed to Open3.popen3 except
+ # opts[:stdin_data] and opts[:stdin_data]. See Process.spawn.
+ #
+ # If opts[:stdin_data] is specified, it is sent to the command's standard input.
+ #
+ # If opts[:binmode] is true, internal pipes are set to binary mode.
+ #
+ # Example:
+ #
+ # # dot is a command of graphviz.
+ # graph = <<'End'
+ # digraph g {
+ # a -> b
+ # }
+ # End
+ # layouted_graph, dot_log = Open3.capture3("dot -v", :stdin_data=>graph)
+ #
+ # o, e, s = Open3.capture3("echo a; sort >&2", :stdin_data=>"foo\nbar\nbaz\n")
+ # p o #=> "a\n"
+ # p e #=> "bar\nbaz\nfoo\n"
+ # p s #=> #<Process::Status: pid 32682 exit 0>
+ #
+ # # generate a thumnail image using the convert command of ImageMagick.
+ # # However, if the image stored really in a file,
+ # # system("convert", "-thumbnail", "80", "png:#{filename}", "png:-") is better
+ # # because memory consumption.
+ # # But if the image is stored in a DB or generated by gnuplot Open3.capture2 example,
+ # # Open3.capture3 is considerable.
+ # #
+ # image = File.read("/usr/share/openclipart/png/animals/mammals/sheep-md-v0.1.png", :binmode=>true)
+ # thumnail, err, s = Open3.capture3("convert -thumbnail 80 png:- png:-", :stdin_data=>image, :binmode=>true)
+ # if s.success?
+ # STDOUT.binmode; print thumnail
+ # end
+ #
+ def capture3(*cmd, &block)
+ if Hash === cmd.last
+ opts = cmd.pop.dup
+ else
+ opts = {}
+ end
+
+ stdin_data = opts.delete(:stdin_data) || ''
+ binmode = opts.delete(:binmode)
+
+ popen3(*cmd, opts) {|i, o, e, t|
+ if binmode
+ i.binmode
+ o.binmode
+ e.binmode
+ end
+ out_reader = Thread.new { o.read }
+ err_reader = Thread.new { e.read }
+ i.write stdin_data
+ i.close
+ [out_reader.value, err_reader.value, t.value]
+ }
+ end
+ module_function :capture3
+
+ # Open3.capture2 captures the standard output of a command.
+ #
+ # stdout_str, status = Open3.capture2([env,] cmd... [, opts])
+ #
+ # The arguments env, cmd and opts are passed to Open3.popen3 except
+ # opts[:stdin_data] and opts[:stdin_data]. See Process.spawn.
+ #
+ # If opts[:stdin_data] is specified, it is sent to the command's standard input.
+ #
+ # If opts[:binmode] is true, internal pipes are set to binary mode.
+ #
+ # Example:
+ #
+ # # factor is a command for integer factorization.
+ # o, s = Open3.capture2("factor", :stdin_data=>"42")
+ # p o #=> "42: 2 3 7\n"
+ #
+ # # generate x**2 graph in png using gnuplot.
+ # gnuplot_commands = <<"End"
+ # set terminal png
+ # plot x**2, "-" with lines
+ # 1 14
+ # 2 1
+ # 3 8
+ # 4 5
+ # e
+ # End
+ # image, s = Open3.capture2("gnuplot", :stdin_data=>gnuplot_commands, :binmode=>true)
+ #
+ def capture2(*cmd, &block)
+ if Hash === cmd.last
+ opts = cmd.pop.dup
+ else
+ opts = {}
+ end
+
+ stdin_data = opts.delete(:stdin_data) || ''
+ binmode = opts.delete(:binmode)
+
+ popen2(*cmd, opts) {|i, o, t|
+ if binmode
+ i.binmode
+ o.binmode
+ end
+ out_reader = Thread.new { o.read }
+ i.write stdin_data
+ i.close
+ [out_reader.value, t.value]
+ }
+ end
+ module_function :capture2
+
+ # Open3.capture2e captures the standard output and the standard error of a command.
+ #
+ # stdout_and_stderr_str, status = Open3.capture2e([env,] cmd... [, opts])
+ #
+ # The arguments env, cmd and opts are passed to Open3.popen3 except
+ # opts[:stdin_data] and opts[:stdin_data]. See Process.spawn.
+ #
+ # If opts[:stdin_data] is specified, it is sent to the command's standard input.
+ #
+ # If opts[:binmode] is true, internal pipes are set to binary mode.
+ #
+ # Example:
+ #
+ # # capture make log
+ # make_log, s = Open3.capture2e("make")
+ #
+ def capture2e(*cmd, &block)
+ if Hash === cmd.last
+ opts = cmd.pop.dup
+ else
+ opts = {}
+ end
+
+ stdin_data = opts.delete(:stdin_data) || ''
+ binmode = opts.delete(:binmode)
+
+ popen2e(*cmd, opts) {|i, oe, t|
+ if binmode
+ i.binmode
+ oe.binmode
+ end
+ outerr_reader = Thread.new { oe.read }
+ i.write stdin_data
+ i.close
+ [outerr_reader.value, t.value]
+ }
+ end
+ module_function :capture2e
+
+ # Open3.pipeline_rw starts a list of commands as a pipeline with pipes
+ # which connects stdin of the first command and stdout of the last command.
+ #
+ # Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) {|first_stdin, last_stdout, wait_threads|
+ # ...
+ # }
+ #
+ # first_stdin, last_stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts])
+ # ...
+ # first_stdin.close
+ # last_stdout.close
+ #
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
+ #
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
+ #
+ # Note that env and opts are optional, as Process.spawn.
+ #
+ # The option to pass Process.spawn is constructed by merging
+ # +opts+, the last hash element of the array and
+ # specification for the pipe between each commands.
+ #
+ # Example:
+ #
+ # Open3.pipeline_rw("tr -dc A-Za-z", "wc -c") {|i,o,ts|
+ # i.puts "All persons more than a mile high to leave the court."
+ # i.close
+ # p o.gets #=> "42\n"
+ # }
+ #
+ # Open3.pipeline_rw("sort", "cat -n") {|stdin, stdout, wait_thrs|
+ # stdin.puts "foo"
+ # stdin.puts "bar"
+ # stdin.puts "baz"
+ # stdin.close # send EOF to sort.
+ # p stdout.read #=> " 1\tbar\n 2\tbaz\n 3\tfoo\n"
+ # }
+ def pipeline_rw(*cmds, &block)
+ if Hash === cmds.last
+ opts = cmds.pop.dup
+ else
+ opts = {}
+ end
+
+ in_r, in_w = IO.pipe
+ opts[:in] = in_r
+ in_w.sync = true
+
+ out_r, out_w = IO.pipe
+ opts[:out] = out_w
+
+ pipeline_run(cmds, opts, [in_r, out_w], [in_w, out_r], &block)
+ end
+ module_function :pipeline_rw
+
+ # Open3.pipeline_r starts a list of commands as a pipeline with a pipe
+ # which connects stdout of the last command.
+ #
+ # Open3.pipeline_r(cmd1, cmd2, ... [, opts]) {|last_stdout, wait_threads|
+ # ...
+ # }
+ #
+ # last_stdout, wait_threads = Open3.pipeline_r(cmd1, cmd2, ... [, opts])
+ # ...
+ # last_stdout.close
+ #
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
+ #
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
+ #
+ # Note that env and opts are optional, as Process.spawn.
+ #
+ # Example:
+ #
+ # Open3.pipeline_r("zcat /var/log/apache2/access.log.*.gz",
+ # [{"LANG"=>"C"}, "grep", "GET /favicon.ico"],
+ # "logresolve") {|o, ts|
+ # o.each_line {|line|
+ # ...
+ # }
+ # }
+ #
+ # Open3.pipeline_r("yes", "head -10") {|o, ts|
+ # p o.read #=> "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"
+ # p ts[0].value #=> #<Process::Status: pid 24910 SIGPIPE (signal 13)>
+ # p ts[1].value #=> #<Process::Status: pid 24913 exit 0>
+ # }
+ #
+ def pipeline_r(*cmds, &block)
+ if Hash === cmds.last
+ opts = cmds.pop.dup
+ else
+ opts = {}
+ end
+
+ out_r, out_w = IO.pipe
+ opts[:out] = out_w
+
+ pipeline_run(cmds, opts, [out_w], [out_r], &block)
+ end
+ module_function :pipeline_r
+
+ # Open3.pipeline_w starts a list of commands as a pipeline with a pipe
+ # which connects stdin of the first command.
+ #
+ # Open3.pipeline_w(cmd1, cmd2, ... [, opts]) {|first_stdin, wait_threads|
+ # ...
+ # }
+ #
+ # first_stdin, wait_threads = Open3.pipeline_w(cmd1, cmd2, ... [, opts])
+ # ...
+ # first_stdin.close
+ #
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
+ #
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
+ #
+ # Note that env and opts are optional, as Process.spawn.
+ #
+ # Example:
+ #
+ # Open3.pipeline_w("bzip2 -c", :out=>"/tmp/hello.bz2") {|i, ts|
+ # i.puts "hello"
+ # }
+ #
+ def pipeline_w(*cmds, &block)
+ if Hash === cmds.last
+ opts = cmds.pop.dup
+ else
+ opts = {}
+ end
+
+ in_r, in_w = IO.pipe
+ opts[:in] = in_r
+ in_w.sync = true
+
+ pipeline_run(cmds, opts, [in_r], [in_w], &block)
+ end
+ module_function :pipeline_w
+
+ # Open3.pipeline_start starts a list of commands as a pipeline.
+ # No pipe made for stdin of the first command and
+ # stdout of the last command.
+ #
+ # Open3.pipeline_start(cmd1, cmd2, ... [, opts]) {|wait_threads|
+ # ...
+ # }
+ #
+ # wait_threads = Open3.pipeline_start(cmd1, cmd2, ... [, opts])
+ # ...
+ #
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
+ #
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
+ #
+ # Note that env and opts are optional, as Process.spawn.
+ #
+ # Example:
+ #
+ # # run xeyes in 10 seconds.
+ # Open3.pipeline_start("xeyes") {|ts|
+ # sleep 10
+ # t = ts[0]
+ # Process.kill("TERM", t.pid)
+ # p t.value #=> #<Process::Status: pid 911 SIGTERM (signal 15)>
+ # }
+ #
+ # # convert pdf to ps and send it to a printer.
+ # # collect error message of pdftops and lpr.
+ # pdf_file = "paper.pdf"
+ # printer = "printer-name"
+ # err_r, err_w = IO.pipe
+ # Open3.pipeline_start(["pdftops", pdf_file, "-"],
+ # ["lpr", "-P#{printer}"],
+ # :err=>err_w) {|ts|
+ # err_w.close
+ # p err_r.read # error messages of pdftops and lpr.
+ # }
+ #
+ def pipeline_start(*cmds, &block)
+ if Hash === cmds.last
+ opts = cmds.pop.dup
+ else
+ opts = {}
+ end
+
+ if block
+ pipeline_run(cmds, opts, [], [], &block)
+ else
+ ts, = pipeline_run(cmds, opts, [], [])
+ ts
+ end
+ end
+ module_function :pipeline_start
+
+ # Open3.pipeline starts a list of commands as a pipeline.
+ # It waits the finish of the commands.
+ # No pipe made for stdin of the first command and
+ # stdout of the last command.
+ #
+ # status_list = Open3.pipeline(cmd1, cmd2, ... [, opts])
+ #
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
+ #
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
+ #
+ # Note that env and opts are optional, as Process.spawn.
+ #
+ # Example:
+ #
+ # fname = "/usr/share/man/man1/ruby.1.gz"
+ # p Open3.pipeline(["zcat", fname], "nroff -man", "less")
+ # #=> [#<Process::Status: pid 11817 exit 0>,
+ # # #<Process::Status: pid 11820 exit 0>,
+ # # #<Process::Status: pid 11828 exit 0>]
+ #
+ # fname = "/usr/share/man/man1/ls.1.gz"
+ # Open3.pipeline(["zcat", fname], "nroff -man", "colcrt")
+ #
+ # # convert PDF to PS and send to a printer by lpr
+ # pdf_file = "paper.pdf"
+ # printer = "printer-name"
+ # Open3.pipeline(["pdftops", pdf_file, "-"],
+ # ["lpr", "-P#{printer}"])
+ #
+ # # count lines
+ # Open3.pipeline("sort", "uniq -c", :in=>"names.txt", :out=>"count")
+ #
+ # # cyclic pipeline
+ # r,w = IO.pipe
+ # w.print "ibase=14\n10\n"
+ # Open3.pipeline("bc", "tee /dev/tty", :in=>r, :out=>w)
+ # #=> 14
+ # # 18
+ # # 22
+ # # 30
+ # # 42
+ # # 58
+ # # 78
+ # # 106
+ # # 202
+ #
+ def pipeline(*cmds)
+ if Hash === cmds.last
+ opts = cmds.pop.dup
+ else
+ opts = {}
+ end
+
+ pipeline_run(cmds, opts, [], []) {|ts|
+ ts.map {|t| t.value }
+ }
+ end
+ module_function :pipeline
+
+ def pipeline_run(cmds, pipeline_opts, child_io, parent_io, &block) # :nodoc:
+ if cmds.empty?
+ raise ArgumentError, "no commands"
+ end
+
+ opts_base = pipeline_opts.dup
+ opts_base.delete :in
+ opts_base.delete :out
+
+ wait_thrs = []
+ r = nil
+ cmds.each_with_index {|cmd, i|
+ cmd_opts = opts_base.dup
+ if String === cmd
+ cmd = [cmd]
+ else
+ cmd_opts.update cmd.pop if Hash === cmd.last
+ end
+ if i == 0
+ if !cmd_opts.include?(:in)
+ if pipeline_opts.include?(:in)
+ cmd_opts[:in] = pipeline_opts[:in]
+ end
+ end
+ else
+ cmd_opts[:in] = r
+ end
+ if i != cmds.length - 1
+ r2, w2 = IO.pipe
+ cmd_opts[:out] = w2
+ else
+ if !cmd_opts.include?(:out)
+ if pipeline_opts.include?(:out)
+ cmd_opts[:out] = pipeline_opts[:out]
+ end
+ end
+ end
+ pid = spawn(*cmd, cmd_opts)
+ wait_thrs << Process.detach(pid)
+ r.close if r
+ w2.close if w2
+ r = r2
+ }
+ result = parent_io + [wait_thrs]
+ child_io.each {|io| io.close }
+ if defined? yield
+ begin
+ return yield(*result)
+ ensure
+ parent_io.each{|io| io.close unless io.closed?}
+ wait_thrs.each {|t| t.join }
+ end
+ end
+ result
+ end
+ module_function :pipeline_run
+ class << self
+ private :pipeline_run
+ end
+
end
if $0 == __FILE__
Modified: MacRuby/trunk/lib/optparse.rb
===================================================================
--- MacRuby/trunk/lib/optparse.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/optparse.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,15 +1,15 @@
#
# optparse.rb - command-line option analysis with the OptionParser class.
-#
+#
# Author:: Nobu Nakada
# Documentation:: Nobu Nakada and Gavin Sinclair.
#
-# See OptionParser for documentation.
+# See OptionParser for documentation.
#
-# == Developer Documentation (not for RDoc output)
-#
+# == Developer Documentation (not for RDoc output)
+#
# === Class tree
#
# - OptionParser:: front end
@@ -51,7 +51,7 @@
# solution.
#
# === Features
-#
+#
# 1. The argument specification and the code to handle it are written in the
# same place.
# 2. It can output an option summary; you don't need to maintain this string
@@ -88,12 +88,12 @@
# require 'optparse/time'
# require 'ostruct'
# require 'pp'
-#
+#
# class OptparseExample
-#
+#
# CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
# CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
-#
+#
# #
# # Return a structure describing the options.
# #
@@ -106,19 +106,19 @@
# options.encoding = "utf8"
# options.transfer_type = :auto
# options.verbose = false
-#
+#
# opts = OptionParser.new do |opts|
# opts.banner = "Usage: example.rb [options]"
-#
+#
# opts.separator ""
# opts.separator "Specific options:"
-#
+#
# # Mandatory argument.
# opts.on("-r", "--require LIBRARY",
# "Require the LIBRARY before executing your script") do |lib|
# options.library << lib
# end
-#
+#
# # Optional argument; multi-line description.
# opts.on("-i", "--inplace [EXTENSION]",
# "Edit ARGV files in place",
@@ -127,28 +127,28 @@
# options.extension = ext || ''
# options.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
# end
-#
+#
# # Cast 'delay' argument to a Float.
# opts.on("--delay N", Float, "Delay N seconds before executing") do |n|
# options.delay = n
# end
-#
+#
# # Cast 'time' argument to a Time object.
# opts.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
# options.time = time
# end
-#
+#
# # Cast to octal integer.
# opts.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger,
# "Specify record separator (default \\0)") do |rs|
# options.record_separator = rs
# end
-#
+#
# # List of arguments.
# opts.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
# options.list = list
# end
-#
+#
# # Keyword completion. We are specifying a specific set of arguments (CODES
# # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
# # the shortest unambiguous text.
@@ -157,41 +157,41 @@
# " (#{code_list})") do |encoding|
# options.encoding = encoding
# end
-#
+#
# # Optional argument with keyword completion.
# opts.on("--type [TYPE]", [:text, :binary, :auto],
# "Select transfer type (text, binary, auto)") do |t|
# options.transfer_type = t
# end
-#
+#
# # Boolean switch.
# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
# options.verbose = v
# end
-#
+#
# opts.separator ""
# opts.separator "Common options:"
-#
+#
# # No argument, shows at tail. This will print an options summary.
# # Try it and see!
# opts.on_tail("-h", "--help", "Show this message") do
# puts opts
# exit
# end
-#
+#
# # Another typical switch to print the version.
# opts.on_tail("--version", "Show version") do
# puts OptionParser::Version.join('.')
# exit
# end
# end
-#
+#
# opts.parse!(args)
# options
# end # parse()
-#
+#
# end # class OptparseExample
-#
+#
# options = OptparseExample.parse(ARGV)
# pp options
#
@@ -203,7 +203,7 @@
#
class OptionParser
# :stopdoc:
- RCSID = %w$Id: optparse.rb 21070 2008-12-26 11:16:16Z yugui $[1..-1].each {|s| s.freeze}.freeze
+ RCSID = %w$Id: optparse.rb 27089 2010-03-29 09:10:12Z nobu $[1..-1].each {|s| s.freeze}.freeze
Version = (RCSID[1].split('.').collect {|s| s.to_i}.extend(Comparable).freeze if RCSID[1])
LastModified = (Time.gm(*RCSID[2, 2].join('-').scan(/\d+/).collect {|s| s.to_i}) if RCSID[2])
Release = RCSID[2]
@@ -276,7 +276,7 @@
# Individual switch class. Not important to the user.
#
# Defined within Switch are several Switch-derived classes: NoArgument,
- # RequiredArgument, etc.
+ # RequiredArgument, etc.
#
class Switch
attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
@@ -384,10 +384,16 @@
left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << s
end
- left[0] << arg if arg
+ if arg
+ left[0] << (left[1] ? arg.sub(/\A(\[?)=/, '\1') + ',' : arg)
+ end
mlen = left.collect {|ss| ss.length}.max.to_i
while mlen > width and l = left.shift
mlen = left.collect {|ss| ss.length}.max.to_i if l.length == mlen
+ if l.length < width and (r = right[0]) and !r.empty?
+ l = l.to_s.ljust(width) + ' ' + r
+ right.shift
+ end
yield(indent + l)
end
@@ -505,13 +511,13 @@
class List
# Map from acceptable argument types to pattern and converter pairs.
attr_reader :atype
-
+
# Map from short style option switches to actual switch objects.
attr_reader :short
-
+
# Map from long style option switches to actual switch objects.
attr_reader :long
-
+
# List of all switches and summary string.
attr_reader :list
@@ -528,7 +534,7 @@
#
# See OptionParser.accept.
#
- def accept(t, pat = /.*/nm, &block)
+ def accept(t, pat = /.*/m, &block)
if pat
pat.respond_to?(:match) or
raise TypeError, "has no `match'", ParseError.filter_backtrace(caller(2))
@@ -568,7 +574,7 @@
#
# Inserts +switch+ at the head of the list, and associates short, long
# and negated long options. Arguments are:
- #
+ #
# +switch+:: OptionParser::Switch instance to be inserted.
# +short_opts+:: List of short style options.
# +long_opts+:: List of long style options.
@@ -584,7 +590,7 @@
#
# Appends +switch+ at the tail of the list, and associates short, long
# and negated long options. Arguments are:
- #
+ #
# +switch+:: OptionParser::Switch instance to be inserted.
# +short_opts+:: List of short style options.
# +long_opts+:: List of long style options.
@@ -750,7 +756,7 @@
# Initializes a new instance and evaluates the optional block in context
# of the instance. Arguments +args+ are passed to #new, see there for
# description of parameters.
- #
+ #
# This method is *deprecated*, its behavior corresponds to the older #new
# method.
#
@@ -1043,7 +1049,7 @@
# There is also a special form which matches character range (not full
# set of regular expression):
# "-[a-z]MANDATORY"
- # "-[a-z][OPTIONAL]"
+ # "-[a-z][OPTIONAL]"
# "-[a-z]"
#
# [Argument style and description:]
@@ -1055,7 +1061,7 @@
# [Description:]
# Description string for the option.
# "Run verbosely"
- #
+ #
# [Handler:]
# Handler for the parsed argument value. Either give a block or pass a
# Proc or Method as an argument.
@@ -1259,7 +1265,7 @@
while arg = argv.shift
case arg
# long option
- when /\A--([^=]*)(?:=(.*))?/nm
+ when /\A--([^=]*)(?:=(.*))?/m
opt, rest = $1, $2
begin
sw, = complete(:long, opt, true)
@@ -1275,7 +1281,7 @@
end
# short option
- when /\A-(.)((=).*|.+)?/nm
+ when /\A-(.)((=).*|.+)?/m
opt, has_arg, eq, val, rest = $1, $3, $3, $2, $2
begin
sw, = search(:short, opt)
@@ -1298,7 +1304,7 @@
begin
opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
- argv.unshift(opt) if opt and (opt = opt.sub(/\A-*/, '-')) != '-'
+ argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
val = cb.call(val) if cb
setter.call(sw.switch_name, val) if setter
rescue ParseError
@@ -1502,7 +1508,7 @@
#
# Any non-empty string, and no conversion.
#
- accept(String, /.+/nm) {|s,*|s}
+ accept(String, /.+/m) {|s,*|s}
#
# Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal
@@ -1525,9 +1531,16 @@
#
# Generic numeric format, converts to Integer for integer format, Float
- # for float format.
+ # for float format, and Rational for rational format.
#
- accept(Numeric, %r"\A[-+]?(?:#{octal}|#{float})"io) {|s,| eval(s) if s}
+ real = "[-+]?(?:#{octal}|#{float})"
+ accept(Numeric, /\A(#{real})(?:\/(#{real}))?/io) {|s, d, n|
+ if n
+ Rational(d, n)
+ elsif s
+ eval(s)
+ end
+ }
#
# Decimal integer format, to be converted to Integer.
@@ -1557,7 +1570,7 @@
yesno = CompletingHash.new
%w[- no false].each {|el| yesno[el] = false}
%w[+ yes true].each {|el| yesno[el] = true}
- yesno['nil'] = false # shoud be nil?
+ yesno['nil'] = false # should be nil?
accept(TrueClass, yesno) {|arg, val| val == nil or val}
#
# Similar to TrueClass, but defaults to false.
Modified: MacRuby/trunk/lib/pathname.rb
===================================================================
--- MacRuby/trunk/lib/pathname.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/pathname.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -36,27 +36,27 @@
# === Example 1: Using Pathname
#
# require 'pathname'
-# p = Pathname.new("/usr/bin/ruby")
-# size = p.size # 27662
-# isdir = p.directory? # false
-# dir = p.dirname # Pathname:/usr/bin
-# base = p.basename # Pathname:ruby
-# dir, base = p.split # [Pathname:/usr/bin, Pathname:ruby]
-# data = p.read
-# p.open { |f| _ }
-# p.each_line { |line| _ }
+# pn = Pathname.new("/usr/bin/ruby")
+# size = pn.size # 27662
+# isdir = pn.directory? # false
+# dir = pn.dirname # Pathname:/usr/bin
+# base = pn.basename # Pathname:ruby
+# dir, base = pn.split # [Pathname:/usr/bin, Pathname:ruby]
+# data = pn.read
+# pn.open { |f| _ }
+# pn.each_line { |line| _ }
#
# === Example 2: Using standard Ruby
#
-# p = "/usr/bin/ruby"
-# size = File.size(p) # 27662
-# isdir = File.directory?(p) # false
-# dir = File.dirname(p) # "/usr/bin"
-# base = File.basename(p) # "ruby"
-# dir, base = File.split(p) # ["/usr/bin", "ruby"]
-# data = File.read(p)
-# File.open(p) { |f| _ }
-# File.foreach(p) { |line| _ }
+# pn = "/usr/bin/ruby"
+# size = File.size(pn) # 27662
+# isdir = File.directory?(pn) # false
+# dir = File.dirname(pn) # "/usr/bin"
+# base = File.basename(pn) # "ruby"
+# dir, base = File.split(pn) # ["/usr/bin", "ruby"]
+# data = File.read(pn)
+# File.open(pn) { |f| _ }
+# File.foreach(pn) { |line| _ }
#
# === Example 3: Special features
#
@@ -76,9 +76,9 @@
#
# === Core methods
#
-# These methods are effectively manipulating a String, because that's all a path
-# is. Except for #mountpoint?, #children, and #realpath, they don't access the
-# filesystem.
+# These methods are effectively manipulating a String, because that's
+# all a path is. Except for #mountpoint?, #children, #each_child,
+# #realdirpath and #realpath, they don't access the filesystem.
#
# - +
# - #join
@@ -90,7 +90,9 @@
# - #each_filename
# - #cleanpath
# - #realpath
+# - #realdirpath
# - #children
+# - #each_child
# - #mountpoint?
#
# === File status predicate methods
@@ -165,6 +167,7 @@
# These methods are a facade for IO:
# - #each_line(*args, &block)
# - #read(*args)
+# - #binread(*args)
# - #readlines(*args)
# - #sysopen(*args)
#
@@ -194,6 +197,13 @@
# to_path is implemented so Pathname objects are usable with File.open, etc.
TO_PATH = :to_path
end
+
+ SAME_PATHS = if File::FNM_SYSCASE.nonzero?
+ proc {|a, b| a.casecmp(b).zero?}
+ else
+ proc {|a, b| a == b}
+ end
+
# :startdoc:
#
@@ -204,9 +214,7 @@
path = path.__send__(TO_PATH) if path.respond_to? TO_PATH
@path = path.dup
- # XXX work around a multibyte oniguruma problem in MacRuby
- #if /\0/ =~ @path
- if @path.include?("\0")
+ if /\0/ =~ @path
raise ArgumentError, "pathname contains \\0: #{@path.inspect}"
end
@@ -253,7 +261,21 @@
# Return a pathname which is substituted by String#sub.
def sub(pattern, *rest, &block)
- self.class.new(@path.sub(pattern, *rest, &block))
+ if block
+ path = @path.sub(pattern, *rest) {|*args|
+ begin
+ old = Thread.current[:pathname_sub_matchdata]
+ Thread.current[:pathname_sub_matchdata] = $~
+ eval("$~ = Thread.current[:pathname_sub_matchdata]", block.binding)
+ ensure
+ Thread.current[:pathname_sub_matchdata] = old
+ end
+ yield(*args)
+ }
+ else
+ path = @path.sub(pattern, *rest)
+ end
+ self.class.new(path)
end
if File::ALT_SEPARATOR
@@ -276,7 +298,7 @@
# chop_basename(path) -> [pre-basename, basename] or nil
def chop_basename(path)
base = File.basename(path)
- if /\A#{SEPARATOR_PAT}?\z/ =~ base
+ if /\A#{SEPARATOR_PAT}?\z/o =~ base
return nil
else
return path[0, path.rindex(base)], base
@@ -298,7 +320,7 @@
def prepend_prefix(prefix, relpath)
if relpath.empty?
File.dirname(prefix)
- elsif /#{SEPARATOR_PAT}/ =~ prefix
+ elsif /#{SEPARATOR_PAT}/o =~ prefix
prefix = File.dirname(prefix)
prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a'
prefix + relpath
@@ -413,58 +435,25 @@
end
private :cleanpath_conservative
- def realpath_rec(prefix, unresolved, h)
- resolved = []
- until unresolved.empty?
- n = unresolved.shift
- if n == '.'
- next
- elsif n == '..'
- resolved.pop
- else
- path = prepend_prefix(prefix, File.join(*(resolved + [n])))
- if h.include? path
- if h[path] == :resolving
- raise Errno::ELOOP.new(path)
- else
- prefix, *resolved = h[path]
- end
- else
- s = File.lstat(path)
- if s.symlink?
- h[path] = :resolving
- link_prefix, link_names = split_names(File.readlink(path))
- if link_prefix == ''
- prefix, *resolved = h[path] = realpath_rec(prefix, resolved + link_names, h)
- else
- prefix, *resolved = h[path] = realpath_rec(link_prefix, link_names, h)
- end
- else
- resolved << n
- h[path] = [prefix, *resolved]
- end
- end
- end
- end
- return prefix, *resolved
+ #
+ # Returns the real (absolute) pathname of +self+ in the actual
+ # filesystem not containing symlinks or useless dots.
+ #
+ # All components of the pathname must exist when this method is
+ # called.
+ #
+ def realpath(basedir=nil)
+ self.class.new(File.realpath(@path, basedir))
end
- private :realpath_rec
#
- # Returns a real (absolute) pathname of +self+ in the actual filesystem.
+ # Returns the real (absolute) pathname of +self+ in the actual filesystem.
# The real pathname doesn't contain symlinks or useless dots.
#
- # No arguments should be given; the old behaviour is *obsoleted*.
+ # The last component of the real pathname can be nonexistent.
#
- def realpath
- path = @path
- prefix, names = split_names(path)
- if prefix == ''
- prefix, names2 = split_names(Dir.pwd)
- names = names2 + names
- end
- prefix, *names = realpath_rec(prefix, names, {})
- self.class.new(prepend_prefix(prefix, File.join(*names)))
+ def realdirpath(basedir=nil)
+ self.class.new(File.realdirpath(@path, basedir))
end
# #parent returns the parent directory.
@@ -666,12 +655,12 @@
# filename only.
#
# For example:
- # p = Pathname("/usr/lib/ruby/1.8")
- # p.children
+ # pn = Pathname("/usr/lib/ruby/1.8")
+ # pn.children
# # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
# Pathname:/usr/lib/ruby/1.8/Env.rb,
# Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
- # p.children(false)
+ # pn.children(false)
# # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]
#
# Note that the result never contain the entries <tt>.</tt> and <tt>..</tt> in
@@ -693,7 +682,37 @@
result
end
+ # Iterates over the children of the directory
+ # (files and subdirectories, not recursive).
+ # It yields Pathname object for each child.
+ # By default, the yielded pathnames will have enough information to access the files.
+ # If you set +with_directory+ to +false+, then the returned pathnames will contain the filename only.
#
+ # Pathname("/usr/local").each_child {|f| p f }
+ # #=> #<Pathname:/usr/local/share>
+ # # #<Pathname:/usr/local/bin>
+ # # #<Pathname:/usr/local/games>
+ # # #<Pathname:/usr/local/lib>
+ # # #<Pathname:/usr/local/include>
+ # # #<Pathname:/usr/local/sbin>
+ # # #<Pathname:/usr/local/src>
+ # # #<Pathname:/usr/local/man>
+ #
+ # Pathname("/usr/local").each_child(false) {|f| p f }
+ # #=> #<Pathname:share>
+ # # #<Pathname:bin>
+ # # #<Pathname:games>
+ # # #<Pathname:lib>
+ # # #<Pathname:include>
+ # # #<Pathname:sbin>
+ # # #<Pathname:src>
+ # # #<Pathname:man>
+ #
+ def each_child(with_directory=true, &b)
+ children(with_directory).each(&b)
+ end
+
+ #
# #relative_path_from returns a relative path from the argument to the
# receiver. If +self+ is absolute, the argument must be absolute too. If
# +self+ is relative, the argument must be relative too.
@@ -719,12 +738,12 @@
base_prefix, basename = r
base_names.unshift basename if basename != '.'
end
- if dest_prefix != base_prefix
+ unless SAME_PATHS[dest_prefix, base_prefix]
raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
end
while !dest_names.empty? &&
!base_names.empty? &&
- dest_names.first == base_names.first
+ SAME_PATHS[dest_names.first, base_names.first]
dest_names.shift
base_names.shift
end
@@ -752,16 +771,14 @@
IO.foreach(@path, *args, &block)
end
- # Pathname#foreachline is *obsoleted* at 1.8.1. Use #each_line.
- def foreachline(*args, &block)
- warn "Pathname#foreachline is obsoleted. Use Pathname#each_line."
- each_line(*args, &block)
- end
-
- # See <tt>IO.read</tt>. Returns all the bytes from the file, or the first +N+
+ # See <tt>IO.read</tt>. Returns all data from the file, or the first +N+ bytes
# if specified.
def read(*args) IO.read(@path, *args) end
+ # See <tt>IO.binread</tt>. Returns all the bytes from the file, or the first +N+
+ # if specified.
+ def binread(*args) IO.binread(@path, *args) end
+
# See <tt>IO.readlines</tt>. Returns all the lines from the file.
def readlines(*args) IO.readlines(@path, *args) end
@@ -848,20 +865,6 @@
# See <tt>File.split</tt>. Returns the #dirname and the #basename in an
# Array.
def split() File.split(@path).map {|f| self.class.new(f) } end
-
- # Pathname#link is confusing and *obsoleted* because the receiver/argument
- # order is inverted to corresponding system call.
- def link(old)
- warn 'Pathname#link is obsoleted. Use Pathname#make_link.'
- File.link(old, @path)
- end
-
- # Pathname#symlink is confusing and *obsoleted* because the receiver/argument
- # order is inverted to corresponding system call.
- def symlink(old)
- warn 'Pathname#symlink is obsoleted. Use Pathname#make_symlink.'
- File.symlink(old, @path)
- end
end
@@ -943,7 +946,7 @@
class Pathname # * Dir *
# See <tt>Dir.glob</tt>. Returns or yields Pathname objects.
- def Pathname.glob(*args) # :yield: p
+ def Pathname.glob(*args) # :yield: pathname
if block_given?
Dir.glob(*args) {|f| yield self.new(f) }
else
@@ -955,18 +958,6 @@
def Pathname.getwd() self.new(Dir.getwd) end
class << self; alias pwd getwd end
- # Pathname#chdir is *obsoleted* at 1.8.1.
- def chdir(&block)
- warn "Pathname#chdir is obsoleted. Use Dir.chdir."
- Dir.chdir(@path, &block)
- end
-
- # Pathname#chroot is *obsoleted* at 1.8.1.
- def chroot
- warn "Pathname#chroot is obsoleted. Use Dir.chroot."
- Dir.chroot(@path)
- end
-
# Return the entries (files and subdirectories) in the directory, each as a
# Pathname object.
def entries() Dir.entries(@path).map {|f| self.class.new(f) } end
@@ -975,16 +966,10 @@
# yields a Pathname object for each entry.
#
# This method has existed since 1.8.1.
- def each_entry(&block) # :yield: p
+ def each_entry(&block) # :yield: pathname
Dir.foreach(@path) {|f| yield self.class.new(f) }
end
- # Pathname#dir_foreach is *obsoleted* at 1.8.1.
- def dir_foreach(*args, &block)
- warn "Pathname#dir_foreach is obsoleted. Use Pathname#each_entry."
- each_entry(*args, &block)
- end
-
# See <tt>Dir.mkdir</tt>. Create the referenced directory.
def mkdir(*args) Dir.mkdir(@path, *args) end
@@ -1009,7 +994,7 @@
# If +self+ is <tt>.</tt>, yielded pathnames begin with a filename in the
# current directory, not <tt>./</tt>.
#
- def find(&block) # :yield: p
+ def find(&block) # :yield: pathname
require 'find'
if @path == '.'
Find.find(@path) {|f| yield self.class.new(f.sub(%r{\A\./}, '')) }
@@ -1051,18 +1036,6 @@
end
end
alias delete unlink
-
- # This method is *obsoleted* at 1.8.1. Use #each_line or #each_entry.
- def foreach(*args, &block)
- warn "Pathname#foreach is obsoleted. Use each_line or each_entry."
- if FileTest.directory? @path
- # For polymorphism between Dir.foreach and IO.foreach,
- # Pathname#foreach doesn't yield Pathname object.
- Dir.foreach(@path, *args, &block)
- else
- IO.foreach(@path, *args, &block)
- end
- end
end
class Pathname
Modified: MacRuby/trunk/lib/pp.rb
===================================================================
--- MacRuby/trunk/lib/pp.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/pp.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -54,12 +54,12 @@
private
# prints arguments in pretty form.
#
- # pp returns nil.
+ # pp returns argument(s).
def pp(*objs) # :doc:
objs.each {|obj|
PP.pp(obj)
}
- nil
+ objs.size <= 1 ? objs.first : objs
end
module_function :pp
end
@@ -107,17 +107,17 @@
module PPMethods
def guard_inspect_key
if Thread.current[:__recursive_key__] == nil
- Thread.current[:__recursive_key__] = {}
+ Thread.current[:__recursive_key__] = {}.untrust
end
if Thread.current[:__recursive_key__][:inspect] == nil
- Thread.current[:__recursive_key__][:inspect] = {}
+ Thread.current[:__recursive_key__][:inspect] = {}.untrust
end
save = Thread.current[:__recursive_key__][:inspect]
begin
- Thread.current[:__recursive_key__][:inspect] = {}
+ Thread.current[:__recursive_key__][:inspect] = {}.untrust
yield
ensure
Thread.current[:__recursive_key__][:inspect] = save
@@ -164,13 +164,7 @@
group(1, '#<' + obj.class.name, '>', &block)
end
- if 0x100000000.class == Bignum
- # 32bit
- PointerMask = 0xffffffff
- else
- # 64bit
- PointerMask = 0xffffffffffffffff
- end
+ PointerMask = (1 << ([""].pack("p").size * 8)) - 1
case Object.new.inspect
when /\A\#<Object:0x([0-9a-f]+)>\z/
@@ -270,7 +264,7 @@
module ObjectMixin
# 1. specific pretty_print
# 2. specific inspect
- # 3. specific to_s if instance variable is empty
+ # 3. specific to_s
# 4. generic pretty_print
# A default pretty printing method for general objects.
@@ -283,10 +277,23 @@
# This module provides predefined #pretty_print methods for some of
# the most commonly used built-in classes for convenience.
def pretty_print(q)
- if /\(Kernel\)#/ !~ Object.instance_method(:method).bind(self).call(:inspect).inspect
+ method_method = Object.instance_method(:method).bind(self)
+ begin
+ inspect_method = method_method.call(:inspect)
+ rescue NameError
+ end
+ begin
+ to_s_method = method_method.call(:to_s)
+ rescue NameError
+ end
+ if inspect_method && /\(Kernel\)#/ !~ inspect_method.inspect
q.text self.inspect
- elsif /\(Kernel\)#/ !~ Object.instance_method(:method).bind(self).call(:to_s).inspect && instance_variables.empty?
+ elsif !inspect_method && self.respond_to?(:inspect)
+ q.text self.inspect
+ elsif to_s_method && /\(Kernel\)#/ !~ to_s_method.inspect
q.text self.to_s
+ elsif !to_s_method && self.respond_to?(:to_s)
+ q.text self.to_s
else
q.pp_object(self)
end
@@ -361,7 +368,7 @@
class Struct
def pretty_print(q)
- q.group(1, '#<struct ' + PP.mcall(self, Kernel, :class).name, '>') {
+ q.group(1, sprintf("#<struct %s", PP.mcall(self, Kernel, :class).name), '>') {
q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member|
q.breakable
q.text member.to_s
@@ -515,186 +522,3 @@
end
}
}
-
-# :enddoc:
-if __FILE__ == $0
- require 'test/unit'
-
- class PPTest < Test::Unit::TestCase
- def test_list0123_12
- assert_equal("[0, 1, 2, 3]\n", PP.pp([0,1,2,3], '', 12))
- end
-
- def test_list0123_11
- assert_equal("[0,\n 1,\n 2,\n 3]\n", PP.pp([0,1,2,3], '', 11))
- end
-
- OverriddenStruct = Struct.new("OverriddenStruct", :members, :class)
- def test_struct_override_members # [ruby-core:7865]
- a = OverriddenStruct.new(1,2)
- assert_equal("#<struct Struct::OverriddenStruct members=1, class=2>\n", PP.pp(a, ''))
- end
-
- def test_redefined_method
- o = ""
- def o.method
- end
- assert_equal(%(""\n), PP.pp(o, ""))
- end
- end
-
- class HasInspect
- def initialize(a)
- @a = a
- end
-
- def inspect
- return "<inspect:#{@a.inspect}>"
- end
- end
-
- class HasPrettyPrint
- def initialize(a)
- @a = a
- end
-
- def pretty_print(q)
- q.text "<pretty_print:"
- q.pp @a
- q.text ">"
- end
- end
-
- class HasBoth
- def initialize(a)
- @a = a
- end
-
- def inspect
- return "<inspect:#{@a.inspect}>"
- end
-
- def pretty_print(q)
- q.text "<pretty_print:"
- q.pp @a
- q.text ">"
- end
- end
-
- class PrettyPrintInspect < HasPrettyPrint
- alias inspect pretty_print_inspect
- end
-
- class PrettyPrintInspectWithoutPrettyPrint
- alias inspect pretty_print_inspect
- end
-
- class PPInspectTest < Test::Unit::TestCase
- def test_hasinspect
- a = HasInspect.new(1)
- assert_equal("<inspect:1>\n", PP.pp(a, ''))
- end
-
- def test_hasprettyprint
- a = HasPrettyPrint.new(1)
- assert_equal("<pretty_print:1>\n", PP.pp(a, ''))
- end
-
- def test_hasboth
- a = HasBoth.new(1)
- assert_equal("<pretty_print:1>\n", PP.pp(a, ''))
- end
-
- def test_pretty_print_inspect
- a = PrettyPrintInspect.new(1)
- assert_equal("<pretty_print:1>", a.inspect)
- a = PrettyPrintInspectWithoutPrettyPrint.new
- assert_raise(RuntimeError) { a.inspect }
- end
-
- def test_proc
- a = proc {1}
- assert_equal("#{a.inspect}\n", PP.pp(a, ''))
- end
-
- def test_to_s_with_iv
- a = Object.new
- def a.to_s() "aaa" end
- a.instance_eval { @a = nil }
- result = PP.pp(a, '')
- assert_equal("#{a.inspect}\n", result)
- assert_match(/\A#<Object.*>\n\z/m, result)
- a = 1.0
- a.instance_eval { @a = nil }
- result = PP.pp(a, '')
- assert_equal("#{a.inspect}\n", result)
- end
-
- def test_to_s_without_iv
- a = Object.new
- def a.to_s() "aaa" end
- result = PP.pp(a, '')
- assert_equal("#{a.inspect}\n", result)
- assert_equal("aaa\n", result)
- end
- end
-
- class PPCycleTest < Test::Unit::TestCase
- def test_array
- a = []
- a << a
- assert_equal("[[...]]\n", PP.pp(a, ''))
- assert_equal("#{a.inspect}\n", PP.pp(a, ''))
- end
-
- def test_hash
- a = {}
- a[0] = a
- assert_equal("{0=>{...}}\n", PP.pp(a, ''))
- assert_equal("#{a.inspect}\n", PP.pp(a, ''))
- end
-
- S = Struct.new("S", :a, :b)
- def test_struct
- a = S.new(1,2)
- a.b = a
- assert_equal("#<struct Struct::S a=1, b=#<struct Struct::S:...>>\n", PP.pp(a, ''))
- assert_equal("#{a.inspect}\n", PP.pp(a, ''))
- end
-
- def test_object
- a = Object.new
- a.instance_eval {@a = a}
- assert_equal(a.inspect + "\n", PP.pp(a, ''))
- end
-
- def test_anonymous
- a = Class.new.new
- assert_equal(a.inspect + "\n", PP.pp(a, ''))
- end
-
- def test_withinspect
- a = []
- a << HasInspect.new(a)
- assert_equal("[<inspect:[...]>]\n", PP.pp(a, ''))
- assert_equal("#{a.inspect}\n", PP.pp(a, ''))
- end
-
- def test_share_nil
- begin
- PP.sharing_detection = true
- a = [nil, nil]
- assert_equal("[nil, nil]\n", PP.pp(a, ''))
- ensure
- PP.sharing_detection = false
- end
- end
- end
-
- class PPSingleLineTest < Test::Unit::TestCase
- def test_hash
- assert_equal("{1=>1}", PP.singleline_pp({ 1 => 1}, '')) # [ruby-core:02699]
- assert_equal("[1#{', 1'*99}]", PP.singleline_pp([1]*100, ''))
- end
- end
-end
Modified: MacRuby/trunk/lib/prettyprint.rb
===================================================================
--- MacRuby/trunk/lib/prettyprint.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/prettyprint.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,3 @@
-# $Id$
-
# This class implements a pretty printing algorithm. It finds line breaks and
# nice indentations for grouped structure.
#
@@ -377,520 +375,3 @@
end
end
end
-
-if __FILE__ == $0
- require 'test/unit'
-
- class WadlerExample < Test::Unit::TestCase # :nodoc:
- def setup
- @tree = Tree.new("aaaa", Tree.new("bbbbb", Tree.new("ccc"),
- Tree.new("dd")),
- Tree.new("eee"),
- Tree.new("ffff", Tree.new("gg"),
- Tree.new("hhh"),
- Tree.new("ii")))
- end
-
- def hello(width)
- PrettyPrint.format('', width) {|hello|
- hello.group {
- hello.group {
- hello.group {
- hello.group {
- hello.text 'hello'
- hello.breakable; hello.text 'a'
- }
- hello.breakable; hello.text 'b'
- }
- hello.breakable; hello.text 'c'
- }
- hello.breakable; hello.text 'd'
- }
- }
- end
-
- def test_hello_00_06
- expected = <<'End'.chomp
-hello
-a
-b
-c
-d
-End
- assert_equal(expected, hello(0))
- assert_equal(expected, hello(6))
- end
-
- def test_hello_07_08
- expected = <<'End'.chomp
-hello a
-b
-c
-d
-End
- assert_equal(expected, hello(7))
- assert_equal(expected, hello(8))
- end
-
- def test_hello_09_10
- expected = <<'End'.chomp
-hello a b
-c
-d
-End
- out = hello(9); assert_equal(expected, out)
- out = hello(10); assert_equal(expected, out)
- end
-
- def test_hello_11_12
- expected = <<'End'.chomp
-hello a b c
-d
-End
- assert_equal(expected, hello(11))
- assert_equal(expected, hello(12))
- end
-
- def test_hello_13
- expected = <<'End'.chomp
-hello a b c d
-End
- assert_equal(expected, hello(13))
- end
-
- def tree(width)
- PrettyPrint.format('', width) {|q| @tree.show(q)}
- end
-
- def test_tree_00_19
- expected = <<'End'.chomp
-aaaa[bbbbb[ccc,
- dd],
- eee,
- ffff[gg,
- hhh,
- ii]]
-End
- assert_equal(expected, tree(0))
- assert_equal(expected, tree(19))
- end
-
- def test_tree_20_22
- expected = <<'End'.chomp
-aaaa[bbbbb[ccc, dd],
- eee,
- ffff[gg,
- hhh,
- ii]]
-End
- assert_equal(expected, tree(20))
- assert_equal(expected, tree(22))
- end
-
- def test_tree_23_43
- expected = <<'End'.chomp
-aaaa[bbbbb[ccc, dd],
- eee,
- ffff[gg, hhh, ii]]
-End
- assert_equal(expected, tree(23))
- assert_equal(expected, tree(43))
- end
-
- def test_tree_44
- assert_equal(<<'End'.chomp, tree(44))
-aaaa[bbbbb[ccc, dd], eee, ffff[gg, hhh, ii]]
-End
- end
-
- def tree_alt(width)
- PrettyPrint.format('', width) {|q| @tree.altshow(q)}
- end
-
- def test_tree_alt_00_18
- expected = <<'End'.chomp
-aaaa[
- bbbbb[
- ccc,
- dd
- ],
- eee,
- ffff[
- gg,
- hhh,
- ii
- ]
-]
-End
- assert_equal(expected, tree_alt(0))
- assert_equal(expected, tree_alt(18))
- end
-
- def test_tree_alt_19_20
- expected = <<'End'.chomp
-aaaa[
- bbbbb[ ccc, dd ],
- eee,
- ffff[
- gg,
- hhh,
- ii
- ]
-]
-End
- assert_equal(expected, tree_alt(19))
- assert_equal(expected, tree_alt(20))
- end
-
- def test_tree_alt_20_49
- expected = <<'End'.chomp
-aaaa[
- bbbbb[ ccc, dd ],
- eee,
- ffff[ gg, hhh, ii ]
-]
-End
- assert_equal(expected, tree_alt(21))
- assert_equal(expected, tree_alt(49))
- end
-
- def test_tree_alt_50
- expected = <<'End'.chomp
-aaaa[ bbbbb[ ccc, dd ], eee, ffff[ gg, hhh, ii ] ]
-End
- assert_equal(expected, tree_alt(50))
- end
-
- class Tree # :nodoc:
- def initialize(string, *children)
- @string = string
- @children = children
- end
-
- def show(q)
- q.group {
- q.text @string
- q.nest(@string.length) {
- unless @children.empty?
- q.text '['
- q.nest(1) {
- first = true
- @children.each {|t|
- if first
- first = false
- else
- q.text ','
- q.breakable
- end
- t.show(q)
- }
- }
- q.text ']'
- end
- }
- }
- end
-
- def altshow(q)
- q.group {
- q.text @string
- unless @children.empty?
- q.text '['
- q.nest(2) {
- q.breakable
- first = true
- @children.each {|t|
- if first
- first = false
- else
- q.text ','
- q.breakable
- end
- t.altshow(q)
- }
- }
- q.breakable
- q.text ']'
- end
- }
- end
-
- end
- end
-
- class StrictPrettyExample < Test::Unit::TestCase # :nodoc:
- def prog(width)
- PrettyPrint.format('', width) {|q|
- q.group {
- q.group {q.nest(2) {
- q.text "if"; q.breakable;
- q.group {
- q.nest(2) {
- q.group {q.text "a"; q.breakable; q.text "=="}
- q.breakable; q.text "b"}}}}
- q.breakable
- q.group {q.nest(2) {
- q.text "then"; q.breakable;
- q.group {
- q.nest(2) {
- q.group {q.text "a"; q.breakable; q.text "<<"}
- q.breakable; q.text "2"}}}}
- q.breakable
- q.group {q.nest(2) {
- q.text "else"; q.breakable;
- q.group {
- q.nest(2) {
- q.group {q.text "a"; q.breakable; q.text "+"}
- q.breakable; q.text "b"}}}}}
- }
- end
-
- def test_00_04
- expected = <<'End'.chomp
-if
- a
- ==
- b
-then
- a
- <<
- 2
-else
- a
- +
- b
-End
- assert_equal(expected, prog(0))
- assert_equal(expected, prog(4))
- end
-
- def test_05
- expected = <<'End'.chomp
-if
- a
- ==
- b
-then
- a
- <<
- 2
-else
- a +
- b
-End
- assert_equal(expected, prog(5))
- end
-
- def test_06
- expected = <<'End'.chomp
-if
- a ==
- b
-then
- a <<
- 2
-else
- a +
- b
-End
- assert_equal(expected, prog(6))
- end
-
- def test_07
- expected = <<'End'.chomp
-if
- a ==
- b
-then
- a <<
- 2
-else
- a + b
-End
- assert_equal(expected, prog(7))
- end
-
- def test_08
- expected = <<'End'.chomp
-if
- a == b
-then
- a << 2
-else
- a + b
-End
- assert_equal(expected, prog(8))
- end
-
- def test_09
- expected = <<'End'.chomp
-if a == b
-then
- a << 2
-else
- a + b
-End
- assert_equal(expected, prog(9))
- end
-
- def test_10
- expected = <<'End'.chomp
-if a == b
-then
- a << 2
-else a + b
-End
- assert_equal(expected, prog(10))
- end
-
- def test_11_31
- expected = <<'End'.chomp
-if a == b
-then a << 2
-else a + b
-End
- assert_equal(expected, prog(11))
- assert_equal(expected, prog(15))
- assert_equal(expected, prog(31))
- end
-
- def test_32
- expected = <<'End'.chomp
-if a == b then a << 2 else a + b
-End
- assert_equal(expected, prog(32))
- end
-
- end
-
- class TailGroup < Test::Unit::TestCase # :nodoc:
- def test_1
- out = PrettyPrint.format('', 10) {|q|
- q.group {
- q.group {
- q.text "abc"
- q.breakable
- q.text "def"
- }
- q.group {
- q.text "ghi"
- q.breakable
- q.text "jkl"
- }
- }
- }
- assert_equal("abc defghi\njkl", out)
- end
- end
-
- class NonString < Test::Unit::TestCase # :nodoc:
- def format(width)
- PrettyPrint.format([], width, 'newline', lambda {|n| "#{n} spaces"}) {|q|
- q.text(3, 3)
- q.breakable(1, 1)
- q.text(3, 3)
- }
- end
-
- def test_6
- assert_equal([3, "newline", "0 spaces", 3], format(6))
- end
-
- def test_7
- assert_equal([3, 1, 3], format(7))
- end
-
- end
-
- class Fill < Test::Unit::TestCase # :nodoc:
- def format(width)
- PrettyPrint.format('', width) {|q|
- q.group {
- q.text 'abc'
- q.fill_breakable
- q.text 'def'
- q.fill_breakable
- q.text 'ghi'
- q.fill_breakable
- q.text 'jkl'
- q.fill_breakable
- q.text 'mno'
- q.fill_breakable
- q.text 'pqr'
- q.fill_breakable
- q.text 'stu'
- }
- }
- end
-
- def test_00_06
- expected = <<'End'.chomp
-abc
-def
-ghi
-jkl
-mno
-pqr
-stu
-End
- assert_equal(expected, format(0))
- assert_equal(expected, format(6))
- end
-
- def test_07_10
- expected = <<'End'.chomp
-abc def
-ghi jkl
-mno pqr
-stu
-End
- assert_equal(expected, format(7))
- assert_equal(expected, format(10))
- end
-
- def test_11_14
- expected = <<'End'.chomp
-abc def ghi
-jkl mno pqr
-stu
-End
- assert_equal(expected, format(11))
- assert_equal(expected, format(14))
- end
-
- def test_15_18
- expected = <<'End'.chomp
-abc def ghi jkl
-mno pqr stu
-End
- assert_equal(expected, format(15))
- assert_equal(expected, format(18))
- end
-
- def test_19_22
- expected = <<'End'.chomp
-abc def ghi jkl mno
-pqr stu
-End
- assert_equal(expected, format(19))
- assert_equal(expected, format(22))
- end
-
- def test_23_26
- expected = <<'End'.chomp
-abc def ghi jkl mno pqr
-stu
-End
- assert_equal(expected, format(23))
- assert_equal(expected, format(26))
- end
-
- def test_27
- expected = <<'End'.chomp
-abc def ghi jkl mno pqr stu
-End
- assert_equal(expected, format(27))
- end
-
- end
-end
Modified: MacRuby/trunk/lib/pstore.rb
===================================================================
--- MacRuby/trunk/lib/pstore.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/pstore.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -15,49 +15,49 @@
#
# PStore implements a file based persistence mechanism based on a Hash. User
# code can store hierarchies of Ruby objects (values) into the data store file
-# by name (keys). An object hierarchy may be just a single object. User code
+# by name (keys). An object hierarchy may be just a single object. User code
# may later read values back from the data store or even update data, as needed.
-#
+#
# The transactional behavior ensures that any changes succeed or fail together.
# This can be used to ensure that the data store is not left in a transitory
# state, where some values were updated but others were not.
-#
-# Behind the scenes, Ruby objects are stored to the data store file with
-# Marshal. That carries the usual limitations. Proc objects cannot be
+#
+# Behind the scenes, Ruby objects are stored to the data store file with
+# Marshal. That carries the usual limitations. Proc objects cannot be
# marshalled, for example.
#
# == Usage example:
-#
+#
# require "pstore"
-#
+#
# # a mock wiki object...
# class WikiPage
# def initialize( page_name, author, contents )
# @page_name = page_name
# @revisions = Array.new
-#
+#
# add_revision(author, contents)
# end
-#
+#
# attr_reader :page_name
-#
+#
# def add_revision( author, contents )
# @revisions << { :created => Time.now,
# :author => author,
# :contents => contents }
# end
-#
+#
# def wiki_page_references
# [@page_name] + @revisions.last[:contents].scan(/\b(?:[A-Z]+[a-z]+){2,}/)
# end
-#
+#
# # ...
# end
-#
+#
# # create a new page...
# home_page = WikiPage.new( "HomePage", "James Edward Gray II",
# "A page about the JoysOfDocumentation..." )
-#
+#
# # then we want to update page data and the index together, or not at all...
# wiki = PStore.new("wiki_pages.pstore")
# wiki.transaction do # begin transaction; do all of this or none of it
@@ -68,9 +68,9 @@
# # update wiki index...
# wiki[:wiki_index].push(*home_page.wiki_page_references)
# end # commit changes to wiki data store file
-#
+#
# ### Some time later... ###
-#
+#
# # read wiki data...
# wiki.transaction(true) do # begin read-only transaction, no changes allowed
# wiki.roots.each do |data_root_name|
@@ -102,7 +102,7 @@
# The error type thrown by all PStore methods.
class Error < StandardError
end
-
+
# Whether PStore should do its best to prevent file corruptions, even when under
# unlikely-to-occur error conditions such as out-of-space conditions and other
# unusual OS filesystem errors. Setting this flag comes at the price in the form
@@ -112,13 +112,13 @@
# all POSIX platforms: Linux, MacOS X, FreeBSD, etc). The default value is false.
attr_accessor :ultra_safe
- #
- # To construct a PStore object, pass in the _file_ path where you would like
+ #
+ # To construct a PStore object, pass in the _file_ path where you would like
# the data to be stored.
#
# PStore objects are always reentrant. But if _thread_safe_ is set to true,
# then it will become thread-safe at the cost of a minor performance hit.
- #
+ #
def initialize(file, thread_safe = false)
dir = File::dirname(file)
unless File::directory? dir
@@ -131,6 +131,7 @@
@filename = file
@abort = false
@ultra_safe = false
+ @thread_safe = thread_safe
if @thread_safe
@lock = Mutex.new
else
@@ -142,10 +143,10 @@
def in_transaction
raise PStore::Error, "not in transaction" unless @transaction
end
- #
+ #
# Raises PStore::Error if the calling code is not in a PStore#transaction or
# if the code is in a read-only PStore#transaction.
- #
+ #
def in_transaction_wr()
in_transaction()
raise PStore::Error, "in read-only transaction" if @rdonly
@@ -153,9 +154,9 @@
private :in_transaction, :in_transaction_wr
#
- # Retrieves a value from the PStore file data, by _name_. The hierarchy of
+ # Retrieves a value from the PStore file data, by _name_. The hierarchy of
# Ruby objects stored under that root _name_ will be returned.
- #
+ #
# *WARNING*: This method is only valid in a PStore#transaction. It will
# raise PStore::Error if called at any other time.
#
@@ -164,12 +165,12 @@
@table[name]
end
#
- # This method is just like PStore#[], save that you may also provide a
- # _default_ value for the object. In the event the specified _name_ is not
- # found in the data store, your _default_ will be returned instead. If you do
- # not specify a default, PStore::Error will be raised if the object is not
+ # This method is just like PStore#[], save that you may also provide a
+ # _default_ value for the object. In the event the specified _name_ is not
+ # found in the data store, your _default_ will be returned instead. If you do
+ # not specify a default, PStore::Error will be raised if the object is not
# found.
- #
+ #
# *WARNING*: This method is only valid in a PStore#transaction. It will
# raise PStore::Error if called at any other time.
#
@@ -188,11 +189,11 @@
# Stores an individual Ruby object or a hierarchy of Ruby objects in the data
# store file under the root _name_. Assigning to a _name_ already in the data
# store clobbers the old data.
- #
+ #
# == Example:
- #
+ #
# require "pstore"
- #
+ #
# store = PStore.new("data_file.pstore")
# store.transaction do # begin transaction
# # load some data into the store...
@@ -200,7 +201,7 @@
# store[:obj_heirarchy] = { "Kev Jackson" => ["rational.rb", "pstore.rb"],
# "James Gray" => ["erb.rb", "pstore.rb"] }
# end # commit changes to data store file
- #
+ #
# *WARNING*: This method is only valid in a PStore#transaction and it cannot
# be read-only. It will raise PStore::Error if called at any other time.
#
@@ -210,7 +211,7 @@
end
#
# Removes an object hierarchy from the data store, by _name_.
- #
+ #
# *WARNING*: This method is only valid in a PStore#transaction and it cannot
# be read-only. It will raise PStore::Error if called at any other time.
#
@@ -221,7 +222,7 @@
#
# Returns the names of all object hierarchies currently in the store.
- #
+ #
# *WARNING*: This method is only valid in a PStore#transaction. It will
# raise PStore::Error if called at any other time.
#
@@ -231,7 +232,7 @@
end
#
# Returns true if the supplied _name_ is currently in the data store.
- #
+ #
# *WARNING*: This method is only valid in a PStore#transaction. It will
# raise PStore::Error if called at any other time.
#
@@ -247,22 +248,22 @@
#
# Ends the current PStore#transaction, committing any changes to the data
# store immediately.
- #
+ #
# == Example:
- #
+ #
# require "pstore"
- #
+ #
# store = PStore.new("data_file.pstore")
# store.transaction do # begin transaction
# # load some data into the store...
# store[:one] = 1
# store[:two] = 2
- #
+ #
# store.commit # end transaction here, committing changes
- #
+ #
# store[:three] = 3 # this change is never reached
# end
- #
+ #
# *WARNING*: This method is only valid in a PStore#transaction. It will
# raise PStore::Error if called at any other time.
#
@@ -274,21 +275,21 @@
#
# Ends the current PStore#transaction, discarding any changes to the data
# store.
- #
+ #
# == Example:
- #
+ #
# require "pstore"
- #
+ #
# store = PStore.new("data_file.pstore")
# store.transaction do # begin transaction
# store[:one] = 1 # this change is not applied, see below...
# store[:two] = 2 # this change is not applied, see below...
- #
+ #
# store.abort # end transaction here, discard all changes
- #
+ #
# store[:three] = 3 # this change is never reached
# end
- #
+ #
# *WARNING*: This method is only valid in a PStore#transaction. It will
# raise PStore::Error if called at any other time.
#
@@ -300,19 +301,19 @@
#
# Opens a new transaction for the data store. Code executed inside a block
- # passed to this method may read and write data to and from the data store
+ # passed to this method may read and write data to and from the data store
# file.
- #
+ #
# At the end of the block, changes are committed to the data store
- # automatically. You may exit the transaction early with a call to either
+ # automatically. You may exit the transaction early with a call to either
# PStore#commit or PStore#abort. See those methods for details about how
- # changes are handled. Raising an uncaught Exception in the block is
+ # changes are handled. Raising an uncaught Exception in the block is
# equivalent to calling PStore#abort.
- #
+ #
# If _read_only_ is set to +true+, you will only be allowed to read from the
# data store during the transaction and any attempts to change the data will
# raise a PStore::Error.
- #
+ #
# Note that PStore does not support nested transactions.
#
def transaction(read_only = false, &block) # :yields: pstore
@@ -326,11 +327,11 @@
if file
begin
@table, checksum, original_data_size = load_data(file, read_only)
-
+
catch(:pstore_abort_transaction) do
value = yield(self)
end
-
+
if !@abort && !read_only
save_data(checksum, original_data_size, file)
end
@@ -349,19 +350,19 @@
ensure
@transaction = false
end
-
+
private
# Constant for relieving Ruby's garbage collector.
EMPTY_STRING = ""
EMPTY_MARSHAL_DATA = Marshal.dump({})
EMPTY_MARSHAL_CHECKSUM = Digest::MD5.digest(EMPTY_MARSHAL_DATA)
-
+
class DummyMutex
def synchronize
yield
end
end
-
+
#
# Open the specified filename (either in read-only mode or in
# read-write mode) and lock it for reading or writing.
@@ -391,7 +392,7 @@
return file
end
end
-
+
# Load the given PStore file.
# If +read_only+ is true, the unmarshalled Hash will be returned.
# If +read_only+ is false, a 3-tuple will be returned: the unmarshalled
@@ -427,18 +428,18 @@
[table, checksum, size]
end
end
-
+
def on_windows?
is_windows = RUBY_PLATFORM =~ /mswin/ ||
RUBY_PLATFORM =~ /mingw/ ||
- RUBY_PLATFORM =~ /bbcwin/ ||
+ RUBY_PLATFORM =~ /bccwin/ ||
RUBY_PLATFORM =~ /wince/
self.class.__send__(:define_method, :on_windows?) do
is_windows
end
is_windows
end
-
+
# Check whether Marshal.dump supports the 'canonical' option. This option
# makes sure that Marshal.dump always dumps data structures in the same order.
# This is important because otherwise, the checksums that we generate may differ.
@@ -454,7 +455,7 @@
end
result
end
-
+
def save_data(original_checksum, original_file_size, file)
# We only want to save the new data if the size or checksum has changed.
# This results in less filesystem calls, which is good for performance.
@@ -464,7 +465,7 @@
new_data = dump(@table)
end
new_checksum = Digest::MD5.digest(new_data)
-
+
if new_data.size != original_file_size || new_checksum != original_checksum
if @ultra_safe && !on_windows?
# Windows doesn't support atomic file renames.
@@ -473,10 +474,10 @@
save_data_with_fast_strategy(new_data, file)
end
end
-
+
new_data.replace(EMPTY_STRING)
end
-
+
def save_data_with_atomic_file_rename_strategy(data, file)
temp_filename = "#{@filename}.tmp.#{Process.pid}.#{rand 1000000}"
temp_file = File.new(temp_filename, WR_ACCESS)
@@ -492,7 +493,7 @@
temp_file.close
end
end
-
+
def save_data_with_fast_strategy(data, file)
file.rewind
file.truncate(0)
Modified: MacRuby/trunk/lib/rake/clean.rb
===================================================================
--- MacRuby/trunk/lib/rake/clean.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake/clean.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,3 @@
-#!/usr/bin/env ruby
-
# The 'rake/clean' file defines two file lists (CLEAN and CLOBBER) and
# two rake tasks (:clean and :clobber).
#
@@ -16,8 +14,8 @@
require 'rake'
CLEAN = Rake::FileList["**/*~", "**/*.bak", "**/core"]
-CLEAN.clear_exclude.exclude { |fn|
- fn.pathmap("%f") == 'core' && File.directory?(fn)
+CLEAN.clear_exclude.exclude { |fn|
+ fn.pathmap("%f") == 'core' && File.directory?(fn)
}
desc "Remove any temporary products."
Modified: MacRuby/trunk/lib/rake/gempackagetask.rb
===================================================================
--- MacRuby/trunk/lib/rake/gempackagetask.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake/gempackagetask.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,3 @@
-#!/usr/bin/env ruby
-
# Define a package task library to aid in the definition of GEM
# packages.
@@ -35,10 +33,10 @@
# s.files = PKG_FILES
# s.description = <<EOF
# Rake is a Make-like program implemented in Ruby. Tasks
- # and dependencies are specified in standard Ruby syntax.
+ # and dependencies are specified in standard Ruby syntax.
# EOF
# end
- #
+ #
# Rake::GemPackageTask.new(spec) do |pkg|
# pkg.need_zip = true
# pkg.need_tar = true
@@ -84,7 +82,7 @@
}
end
end
-
+
def gem_file
if @gem_spec.platform == Gem::Platform::RUBY
"#{package_name}.gem"
@@ -92,6 +90,6 @@
"#{package_name}-#{@gem_spec.platform}.gem"
end
end
-
+
end
end
Modified: MacRuby/trunk/lib/rake/loaders/makefile.rb
===================================================================
--- MacRuby/trunk/lib/rake/loaders/makefile.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake/loaders/makefile.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,19 +1,17 @@
-#!/usr/bin/env ruby
-
module Rake
# Makefile loader to be used with the import file loader.
class MakefileLoader
+ SPACE_MARK = "\0"
# Load the makefile dependencies in +fn+.
def load(fn)
- open(fn) do |mf|
- lines = mf.read
- lines.gsub!(/#[^\n]*\n/m, "")
- lines.gsub!(/\\\n/, ' ')
- lines.split("\n").each do |line|
- process_line(line)
- end
+ lines = open(fn) {|mf| mf.read}
+ lines.gsub!(/\\ /, SPACE_MARK)
+ lines.gsub!(/#[^\n]*\n/m, "")
+ lines.gsub!(/\\\n/, ' ')
+ lines.each_line do |line|
+ process_line(line)
end
end
@@ -21,13 +19,18 @@
# Process one logical line of makefile data.
def process_line(line)
- file_tasks, args = line.split(':')
+ file_tasks, args = line.split(':', 2)
return if args.nil?
- dependents = args.split
- file_tasks.strip.split.each do |file_task|
+ dependents = args.split.map {|arg| respace(arg)}
+ file_tasks.scan(/\S+/) do |file_task|
+ file_task = respace(file_task)
file file_task => dependents
end
end
+
+ def respace(str)
+ str.tr(SPACE_MARK, ' ')
+ end
end
# Install the handler
Modified: MacRuby/trunk/lib/rake/packagetask.rb
===================================================================
--- MacRuby/trunk/lib/rake/packagetask.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake/packagetask.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,6 +1,4 @@
-#!/usr/bin/env ruby
-
-# Define a package task libarary to aid in the definition of
+# Define a package task library to aid in the definition of
# redistributable package files.
require 'rake'
@@ -25,13 +23,13 @@
# of date.
#
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tgz"</b>]
- # Create a gzipped tar package (if <em>need_tar</em> is true).
+ # Create a gzipped tar package (if <em>need_tar</em> is true).
#
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.gz"</b>]
- # Create a gzipped tar package (if <em>need_tar_gz</em> is true).
+ # Create a gzipped tar package (if <em>need_tar_gz</em> is true).
#
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.bz2"</b>]
- # Create a bzip2'd tar package (if <em>need_tar_bz2</em> is true).
+ # Create a bzip2'd tar package (if <em>need_tar_bz2</em> is true).
#
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.zip"</b>]
# Create a zip package archive (if <em>need_zip</em> is true).
@@ -44,7 +42,7 @@
# end
#
class PackageTask < TaskLib
- # Name of the package.
+ # Name of the package (from the GEM Spec).
attr_accessor :name
# Version of the package (e.g. '1.3.2').
@@ -74,7 +72,7 @@
# Zip command for zipped archives. The default is 'zip'.
attr_accessor :zip_command
- # Create a Package Task with the given name and version.
+ # Create a Package Task with the given name and version.
def initialize(name=nil, version=nil)
init(name, version)
yield self if block_given?
@@ -102,11 +100,11 @@
desc "Build all the packages"
task :package
-
+
desc "Force a rebuild of the package files"
task :repackage => [:clobber_package, :package]
-
- desc "Remove package products"
+
+ desc "Remove package products"
task :clobber_package do
rm_r package_dir rescue nil
end
@@ -122,13 +120,12 @@
task :package => ["#{package_dir}/#{file}"]
file "#{package_dir}/#{file}" => [package_dir_path] + package_files do
chdir(package_dir) do
- sh %{env}
sh %{#{@tar_command} #{flag}cvf #{file} #{package_name}}
end
end
end
end
-
+
if need_zip
task :package => ["#{package_dir}/#{zip_file}"]
file "#{package_dir}/#{zip_file}" => [package_dir_path] + package_files do
@@ -160,7 +157,7 @@
def package_name
@version ? "#{@name}-#{@version}" : @name
end
-
+
def package_dir_path
"#{package_dir}/#{package_name}"
end
Modified: MacRuby/trunk/lib/rake/rdoctask.rb
===================================================================
--- MacRuby/trunk/lib/rake/rdoctask.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake/rdoctask.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,3 @@
-#!/usr/bin/env ruby
-
require 'rake'
require 'rake/tasklib'
@@ -10,8 +8,8 @@
#
# The RDocTask will create the following targets:
#
- # [<b><em>rdoc</em></b>]
- # Main task for this RDOC task.
+ # [<b>:<em>rdoc</em></b>]
+ # Main task for this RDOC task.
#
# [<b>:clobber_<em>rdoc</em></b>]
# Delete all the rdoc files. This target is automatically
@@ -28,6 +26,11 @@
# rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
# end
#
+ # The +rd+ object passed to the block is an RDocTask object. See the
+ # attributes list for the RDocTask class for available customization options.
+ #
+ # == Specifying different task names
+ #
# You may wish to give the task a different name, such as if you are
# generating two sets of documentation. For instance, if you want to have a
# development set of documentation including private methods:
@@ -41,6 +44,16 @@
# The tasks would then be named :<em>rdoc_dev</em>, :clobber_<em>rdoc_dev</em>, and
# :re<em>rdoc_dev</em>.
#
+ # If you wish to have completely different task names, then pass a Hash as
+ # first argument. With the <tt>:rdoc</tt>, <tt>:clobber_rdoc</tt> and
+ # <tt>:rerdoc</tt> options, you can customize the task names to your liking.
+ # For example:
+ #
+ # Rake::RDocTask.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean", :rerdoc => "rdoc:force")
+ #
+ # This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc_clean</tt> and
+ # <tt>:rdoc:force</tt>.
+ #
class RDocTask < TaskLib
# Name of the main, top level task. (default is :rdoc)
attr_accessor :name
@@ -48,7 +61,7 @@
# Name of directory to receive the html output files. (default is "html")
attr_accessor :rdoc_dir
- # Title of RDoc documentation. (default is none)
+ # Title of RDoc documentation. (defaults to rdoc's default)
attr_accessor :title
# Name of file to be used as the main, top level file of the
@@ -61,14 +74,24 @@
# List of files to be included in the rdoc generation. (default is [])
attr_accessor :rdoc_files
- # List of options to be passed rdoc. (default is [])
+ # Additional list of options to be passed rdoc. (default is [])
attr_accessor :options
- # Run the rdoc process as an external shell (default is false)
+ # Whether to run the rdoc process as an external shell (default is false)
attr_accessor :external
- # Create an RDoc task named <em>rdoc</em>. Default task name is +rdoc+.
- def initialize(name=:rdoc) # :yield: self
+ attr_accessor :inline_source
+
+ # Create an RDoc task with the given name. See the RDocTask class overview
+ # for documentation.
+ def initialize(name = :rdoc) # :yield: self
+ if name.is_a?(Hash)
+ invalid_options = name.keys.map { |k| k.to_sym } - [:rdoc, :clobber_rdoc, :rerdoc]
+ if !invalid_options.empty?
+ raise ArgumentError, "Invalid option(s) passed to RDocTask.new: #{invalid_options.join(", ")}"
+ end
+ end
+
@name = name
@rdoc_files = Rake::FileList.new
@rdoc_dir = 'html'
@@ -76,38 +99,40 @@
@title = nil
@template = nil
@external = false
+ @inline_source = true
@options = []
yield self if block_given?
define
end
-
+
# Create the tasks defined by this task lib.
def define
- if name.to_s != "rdoc"
+ if rdoc_task_name != "rdoc"
desc "Build the RDOC HTML Files"
+ else
+ desc "Build the #{rdoc_task_name} HTML Files"
end
+ task rdoc_task_name
- desc "Build the #{name} HTML Files"
- task name
-
desc "Force a rebuild of the RDOC files"
- task "re#{name}" => ["clobber_#{name}", name]
-
- desc "Remove rdoc products"
- task "clobber_#{name}" do
+ task rerdoc_task_name => [clobber_task_name, rdoc_task_name]
+
+ desc "Remove rdoc products"
+ task clobber_task_name do
rm_r rdoc_dir rescue nil
end
-
- task :clobber => ["clobber_#{name}"]
-
+
+ task :clobber => [clobber_task_name]
+
directory @rdoc_dir
- task name => [rdoc_target]
+ task rdoc_task_name => [rdoc_target]
file rdoc_target => @rdoc_files + [Rake.application.rakefile] do
rm_r @rdoc_dir rescue nil
+ @before_running_rdoc.call if @before_running_rdoc
args = option_list + @rdoc_files
if @external
argstring = args.join(' ')
- sh %{ruby -Ivendor vender/rd #{argstring}}
+ sh %{ruby -Ivendor vendor/rd #{argstring}}
else
require 'rdoc/rdoc'
RDoc::RDoc.new.document(args)
@@ -116,12 +141,14 @@
self
end
+ # List of options that will be supplied to RDoc
def option_list
result = @options.dup
result << "-o" << @rdoc_dir
result << "--main" << quote(main) if main
result << "--title" << quote(title) if title
result << "-T" << quote(template) if template
+ result << "--inline-source" if inline_source && !@options.include?("--inline-source") && !@options.include?("-S")
result
end
@@ -137,11 +164,45 @@
option_list.join(' ')
end
+ # The block passed to this method will be called just before running the
+ # RDoc generator. It is allowed to modify RDocTask attributes inside the
+ # block.
+ def before_running_rdoc(&block)
+ @before_running_rdoc = block
+ end
+
private
def rdoc_target
"#{rdoc_dir}/index.html"
end
+ def rdoc_task_name
+ case name
+ when Hash
+ (name[:rdoc] || "rdoc").to_s
+ else
+ name.to_s
+ end
+ end
+
+ def clobber_task_name
+ case name
+ when Hash
+ (name[:clobber_rdoc] || "clobber_rdoc").to_s
+ else
+ "clobber_#{name}"
+ end
+ end
+
+ def rerdoc_task_name
+ case name
+ when Hash
+ (name[:rerdoc] || "rerdoc").to_s
+ else
+ "re#{name}"
+ end
+ end
+
end
end
Modified: MacRuby/trunk/lib/rake/runtest.rb
===================================================================
--- MacRuby/trunk/lib/rake/runtest.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake/runtest.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,3 @@
-#!/usr/bin/env ruby
-
require 'test/unit'
require 'test/unit/assertions'
Modified: MacRuby/trunk/lib/rake/tasklib.rb
===================================================================
--- MacRuby/trunk/lib/rake/tasklib.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake/tasklib.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,3 @@
-#!/usr/bin/env ruby
-
require 'rake'
module Rake
Modified: MacRuby/trunk/lib/rake/testtask.rb
===================================================================
--- MacRuby/trunk/lib/rake/testtask.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake/testtask.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,3 @@
-#!/usr/bin/env ruby
-
# Define a task library for running unit tests.
require 'rake'
@@ -10,7 +8,7 @@
# Create a task that runs a set of tests.
#
# Example:
- #
+ #
# Rake::TestTask.new do |t|
# t.libs << "test"
# t.test_files = FileList['test/test*.rb']
@@ -63,7 +61,7 @@
# * :rake -- Rake provided test loading script (default).
# * :testrb -- Ruby provided test loading script.
# * :direct -- Load tests using command line loader.
- #
+ #
attr_accessor :loader
# Array of commandline options to pass to ruby when running test loader.
@@ -105,11 +103,11 @@
when :direct
"-e 'ARGV.each{|f| load f}'"
when :testrb
- "-S testrb #{fix}"
+ "-S testrb"
when :rake
rake_loader
end
- @ruby_opts.unshift( "-I#{lib_path}" )
+ @ruby_opts.unshift( "-I\"#{lib_path}\"" )
@ruby_opts.unshift( "-w" ) if @warning
ruby @ruby_opts.join(" ") +
" \"#{run_code}\" " +
@@ -135,15 +133,6 @@
end
end
- def fix # :nodoc:
- case RUBY_VERSION
- when '1.8.2'
- find_file 'rake/ruby182_test_unit_fix'
- else
- nil
- end || ''
- end
-
def rake_loader # :nodoc:
find_file('rake/rake_test_loader') or
fail "unable to find rake test loader"
Modified: MacRuby/trunk/lib/rake/win32.rb
===================================================================
--- MacRuby/trunk/lib/rake/win32.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake/win32.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -5,9 +5,10 @@
module Win32
class << self
# True if running on a windows system.
- def windows?
- # assume other DOSish systems are extinct.
- File::ALT_SEPARATOR == '\\'
+ if File::ALT_SEPARATOR == '\\' # assume other DOSish systems are extinct.
+ def windows?; true end
+ else
+ def windows?; false end
end
end
@@ -29,6 +30,17 @@
end
File.expand_path('Rake', win32_shared_path)
end
+
+ # Normalize a win32 path so that the slashes are all forward slashes.
+ def normalize(path)
+ path.tr('\\', '/')
+ end
end if windows?
end
+
+ if Win32.windows?
+ def standard_system_dir
+ Win32.win32_system_dir
+ end
+ end
end
Modified: MacRuby/trunk/lib/rake.rb
===================================================================
--- MacRuby/trunk/lib/rake.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rake.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,8 +1,6 @@
-#!/usr/bin/env ruby
-
#--
-# Copyright (c) 2003, 2004, 2005, 2006, 2007 Jim Weirich
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008 by Jim Weirich (jim at weirichhouse.org)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
@@ -29,7 +27,7 @@
# as a library via a require statement, but it can be distributed
# independently as an application.
-RAKEVERSION = '0.8.3'
+RAKEVERSION = '0.8.7'
require 'rbconfig'
require 'fileutils'
@@ -40,6 +38,8 @@
require 'rake/win32'
+$trace = false
+
######################################################################
# Rake extensions to Module.
#
@@ -74,7 +74,7 @@
#
class String
rake_extension("ext") do
- # Replace the file extension with +newext+. If there is no extenson on
+ # Replace the file extension with +newext+. If there is no extension on
# the string, append the new extension to the end. If the new extension
# is not given, or is the empty string, remove any existing extension.
#
@@ -115,7 +115,7 @@
File.join(partial_dirs)
end
protected :pathmap_partial
-
+
# Preform the pathmap replacement operations on the given path. The
# patterns take the form 'pat1,rep1;pat2,rep2...'.
def pathmap_replace(patterns, &block)
@@ -203,7 +203,7 @@
when '%f'
result << File.basename(self)
when '%n'
- result << File.basename(self, '.*')
+ result << File.basename(self).ext
when '%d'
result << File.dirname(self)
when '%x'
@@ -280,7 +280,7 @@
end
- # ##########################################################################
+ ####################################################################
# Mixin for creating easily cloned objects.
#
module Cloneable
@@ -305,6 +305,27 @@
end
####################################################################
+ # Exit status class for times the system just gives us a nil.
+ class PseudoStatus
+ attr_reader :exitstatus
+ def initialize(code=0)
+ @exitstatus = code
+ end
+ def to_i
+ @exitstatus << 8
+ end
+ def >>(n)
+ to_i >> n
+ end
+ def stopped?
+ false
+ end
+ def exited?
+ true
+ end
+ end
+
+ ####################################################################
# TaskAguments manage the arguments passed to a task.
#
class TaskArguments
@@ -362,9 +383,9 @@
def inspect
to_s
end
-
+
protected
-
+
def lookup(name)
if @hash.has_key?(name)
@hash[name]
@@ -434,7 +455,7 @@
module Rake
- # #########################################################################
+ ###########################################################################
# A Task is the basic unit of work in a Rakefile. Tasks have associated
# actions (possibly more than one) and a list of prerequisites. When
# invoked, a task will first ensure that all of its prerequisites have an
@@ -734,7 +755,7 @@
end # class Rake::Task
- # #########################################################################
+ ###########################################################################
# A FileTask is a task that includes time based dependencies. If any of a
# FileTask's prerequisites have a timestamp that is later than the file
# represented by this task, then the file must be rebuilt (using the
@@ -745,9 +766,7 @@
# Is this file task needed? Yes if it doesn't exist, or if its time stamp
# is out of date.
def needed?
- return true unless File.exist?(name)
- return true if out_of_date?(timestamp)
- false
+ ! File.exist?(name) || out_of_date?(timestamp)
end
# Time stamp for file task.
@@ -778,7 +797,7 @@
end
end # class Rake::FileTask
- # #########################################################################
+ ###########################################################################
# A FileCreationTask is a file task that when used as a dependency will be
# needed if and only if the file has not been created. Once created, it is
# not re-triggered if any of its dependencies are newer, nor does trigger
@@ -797,7 +816,7 @@
end
end
- # #########################################################################
+ ###########################################################################
# Same as a regular task, but the immediate prerequisites are done in
# parallel using Ruby threads.
#
@@ -812,7 +831,7 @@
end
end # module Rake
-# ###########################################################################
+## ###########################################################################
# Task Definition Functions ...
# Declare a basic task.
@@ -931,12 +950,18 @@
end
end
-# ###########################################################################
+#############################################################################
# This a FileUtils extension that defines several additional commands to be
# added to the FileUtils utility functions.
#
module FileUtils
- RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']).
+ RUBY_EXT = ((RbConfig::CONFIG['ruby_install_name'] =~ /\.(com|cmd|exe|bat|rb|sh)$/) ?
+ "" :
+ RbConfig::CONFIG['EXEEXT'])
+
+ RUBY = File.join(
+ RbConfig::CONFIG['bindir'],
+ RbConfig::CONFIG['ruby_install_name'] + RUBY_EXT).
sub(/.*\s.*/m, '"\&"')
OPT_TABLE['sh'] = %w(noop verbose)
@@ -962,14 +987,14 @@
options = (Hash === cmd.last) ? cmd.pop : {}
unless block_given?
show_command = cmd.join(" ")
- show_command = show_command[0,42] + "..."
+ show_command = show_command[0,42] + "..." unless $trace
# TODO code application logic heref show_command.length > 45
block = lambda { |ok, status|
ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
}
end
if RakeFileUtils.verbose_flag == :default
- options[:verbose] = false
+ options[:verbose] = true
else
options[:verbose] ||= RakeFileUtils.verbose_flag
end
@@ -978,7 +1003,9 @@
rake_output_message cmd.join(" ") if options[:verbose]
unless options[:noop]
res = rake_system(*cmd)
- block.call(res, $?)
+ status = $?
+ status = PseudoStatus.new(1) if !res && status.nil?
+ block.call(res, status)
end
end
@@ -1031,7 +1058,7 @@
end
end
-# ###########################################################################
+#############################################################################
# RakeFileUtils provides a custom version of the FileUtils methods that
# respond to the <tt>verbose</tt> and <tt>nowrite</tt> commands.
#
@@ -1162,7 +1189,7 @@
extend self
end
-# ###########################################################################
+#############################################################################
# Include the FileUtils file manipulation functions in the top level module,
# but mark them private so that they don't unintentionally define methods on
# other objects.
@@ -1175,7 +1202,7 @@
######################################################################
module Rake
- # #########################################################################
+ ###########################################################################
# A FileList is essentially an array with a few helper methods defined to
# make file manipulation a bit easier.
#
@@ -1211,7 +1238,7 @@
# List of array methods (that are not in +Object+) that need to be
# delegated.
- ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
+ ARRAY_METHODS = (Array.instance_methods - (Object.instance_methods - [:<=>])).map { |n| n.to_s }
# List of additional methods that must be delegated.
MUST_DEFINE = %w[to_a inspect]
@@ -1229,28 +1256,23 @@
]
DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
-
+
# Now do the delegation.
DELEGATING_METHODS.each_with_index do |sym, i|
if SPECIAL_RETURN.include?(sym)
- class_eval do
- define_method(sym) do |*args, &block|
- resolve
- result = @items.send(sym, *args, &block)
- FileList.new.import(result)
- end
+ define_method(sym) do |*args, &block|
+ resolve
+ result = @items.send(sym, *args, &block)
+ FileList.new.import(result)
end
else
- class_eval do
- define_method(sym) do |*args, &block|
- resolve
- result = @items.send(sym, *args, &block)
- result.object_id == @items.object_id ? self : result
- end
+ define_method(sym) do |*args, &block|
+ resolve
+ result = @items.send(sym, *args, &block)
+ result.object_id == @items.object_id ? self : result
end
end
end
-
# Create a file list from the globbable patterns given. If you wish to
# perform multiple includes or excludes at object build time, use the
@@ -1456,8 +1478,8 @@
collect { |fn| fn.pathmap(spec) }
end
- # Return a new array with <tt>String#ext</tt> method applied to each
- # member of the array.
+ # Return a new FileList with <tt>String#ext</tt> method applied
+ # to each member of the array.
#
# This method is a shortcut for:
#
@@ -1474,9 +1496,9 @@
# name, line number, and the matching line of text. If no block is given,
# a standard emac style file:linenumber:line message will be printed to
# standard out.
- def egrep(pattern, *opt)
+ def egrep(pattern, *options)
each do |fn|
- open(fn, "rb", *opt) do |inf|
+ open(fn, "rb", *options) do |inf|
count = 0
inf.each do |line|
count += 1
@@ -1582,7 +1604,7 @@
# Alias FileList to be available at the top level.
FileList = Rake::FileList
-# ###########################################################################
+#############################################################################
module Rake
# Default Rakefile loader used by +import+.
@@ -1609,7 +1631,7 @@
EARLY = EarlyTime.instance
end # module Rake
-# ###########################################################################
+#############################################################################
# Extensions to time to allow comparisons with an early time class.
#
class Time
@@ -1643,9 +1665,9 @@
@task_manager.lookup(name, @scope)
end
- # Return the list of tasks defined in this namespace.
+ # Return the list of tasks defined in this and nested namespaces.
def tasks
- @task_manager.tasks
+ @task_manager.tasks_in_scope(@scope)
end
end # NameSpace
@@ -1734,7 +1756,7 @@
[task_name, arg_names, []]
end
private :resolve_args_without_dependencies
-
+
# Resolve task arguments for a task or rule when there are
# dependencies declared.
#
@@ -1765,7 +1787,7 @@
[task_name, arg_names, deps]
end
private :resolve_args_with_dependencies
-
+
# If a rule can be found that matches the task name, enhance the
# task with the prerequisites and actions from the rule. Set the
# source attribute of the task appropriately for the rule. Return
@@ -1790,6 +1812,15 @@
@tasks.values.sort_by { |t| t.name }
end
+ # List of all the tasks defined in the given scope (and its
+ # sub-scopes).
+ def tasks_in_scope(scope)
+ prefix = scope.join(":")
+ tasks.select { |t|
+ /^#{prefix}:/ =~ t.name
+ }
+ end
+
# Clear all tasks in this application.
def clear
@tasks.clear
@@ -1957,18 +1988,17 @@
# application. The define any tasks. Finally, call +top_level+ to run your top
# level tasks.
def run
- standard_exception_handling do
- init
- load_rakefile
- top_level
- end
+ init
+ load_rakefile
+ top_level
end
# Initialize the command line parameters and app name.
def init(app_name='rake')
standard_exception_handling do
@name = app_name
- collect_tasks handle_options
+ handle_options
+ collect_tasks
end
end
@@ -2035,9 +2065,9 @@
exit(false)
rescue Exception => ex
# Exit with error message
- $stderr.puts "rake aborted!"
+ $stderr.puts "#{name} aborted!"
$stderr.puts ex.message
- if options.trace
+ if options.trace or true
$stderr.puts ex.backtrace.join("\n")
else
$stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
@@ -2051,7 +2081,10 @@
# If a match is found, it is copied into @rakefile.
def have_rakefile
@rakefiles.each do |fn|
- if File.exist?(fn) || fn == ''
+ if File.exist?(fn)
+ others = Dir.glob(fn, File::FNM_CASEFOLD)
+ return others.size == 1 ? others.first : fn
+ elsif fn == ''
return fn
end
end
@@ -2074,14 +2107,14 @@
tty_output? || ENV['RAKE_COLUMNS']
end
- # Display the tasks and dependencies.
+ # Display the tasks and comments.
def display_tasks_and_comments
displayable_tasks = tasks.select { |t|
t.comment && t.name =~ options.show_task_pattern
}
if options.full_description
displayable_tasks.each do |t|
- puts "rake #{t.name_with_args}"
+ puts "#{name} #{t.name_with_args}"
t.full_comment.split("\n").each do |line|
puts " #{line}"
end
@@ -2108,7 +2141,7 @@
80
end
- # Calculate the dynamic width of the
+ # Calculate the dynamic width of the
def dynamic_width
@dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
end
@@ -2124,7 +2157,7 @@
def unix?
RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
end
-
+
def windows?
Win32.windows?
end
@@ -2140,7 +2173,7 @@
# Display the tasks and prerequisites
def display_prerequisites
tasks.each do |t|
- puts "rake #{t.name}"
+ puts "#{name} #{t.name}"
t.prerequisites.each { |pre| puts " #{pre}" }
end
end
@@ -2184,7 +2217,7 @@
],
['--execute-continue', '-E CODE',
"Execute some Ruby code, then continue with normal task processing.",
- lambda { |value| eval(value) }
+ lambda { |value| eval(value) }
],
['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
lambda { |value| $:.push(value) }
@@ -2196,9 +2229,9 @@
lambda { |value| verbose(false) }
],
['--rakefile', '-f [FILE]', "Use FILE as the rakefile.",
- lambda { |value|
+ lambda { |value|
value ||= ''
- @rakefiles.clear
+ @rakefiles.clear
@rakefiles << value
}
],
@@ -2252,7 +2285,7 @@
verbose(true)
}
],
- ['--verbose', '-v', "Log message to standard output (default).",
+ ['--verbose', '-v', "Log message to standard output.",
lambda { |value| verbose(true) }
],
['--version', '-V', "Display the program version.",
@@ -2268,19 +2301,19 @@
def handle_options
options.rakelib = ['rakelib']
- opts = OptionParser.new
- opts.banner = "rake [-f rakefile] {options} targets..."
- opts.separator ""
- opts.separator "Options are ..."
-
- opts.on_tail("-h", "--help", "-H", "Display this help message.") do
- puts opts
- exit
- end
-
- standard_rake_options.each { |args| opts.on(*args) }
- parsed_argv = opts.parse(ARGV)
+ OptionParser.new do |opts|
+ opts.banner = "rake [-f rakefile] {options} targets..."
+ opts.separator ""
+ opts.separator "Options are ..."
+ opts.on_tail("-h", "--help", "-H", "Display this help message.") do
+ puts opts
+ exit
+ end
+
+ standard_rake_options.each { |args| opts.on(*args) }
+ end.parse!
+
# If class namespaces are requested, set the global options
# according to the values in the options structure.
if options.classic_namespace
@@ -2290,7 +2323,6 @@
$dryrun = options.dryrun
$silent = options.silent
end
- parsed_argv
end
# Similar to the regular Ruby +require+ command, but will check
@@ -2356,34 +2388,23 @@
# The directory path containing the system wide rakefiles.
def system_dir
- @system_dir ||=
- begin
- if ENV['RAKE_SYSTEM']
- ENV['RAKE_SYSTEM']
- else
- standard_system_dir
- end
- end
+ @system_dir ||= ENV['RAKE_SYSTEM'] || standard_system_dir
end
-
+
# The standard directory containing system wide rake files.
- if Win32.windows?
+ unless method_defined?(:standard_system_dir)
def standard_system_dir #:nodoc:
- Win32.win32_system_dir
+ File.expand_path('~/.rake')
end
- else
- def standard_system_dir #:nodoc:
- File.expand_path('.rake', '~')
- end
end
private :standard_system_dir
# Collect the list of tasks on the command line. If no tasks are
# given, return a list containing only the default task.
# Environmental assignments are processed at this time as well.
- def collect_tasks(argv)
+ def collect_tasks
@top_level_tasks = []
- argv.each do |arg|
+ ARGV.each do |arg|
if arg =~ /^(\w+)=(.*)$/
ENV[$1] = $2
else
Modified: MacRuby/trunk/lib/rational.rb
===================================================================
--- MacRuby/trunk/lib/rational.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rational.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +1,7 @@
+# :enddoc:
+
+warn('lib/rational.rb is deprecated') if $VERBOSE
+
class Fixnum
alias quof fdiv
@@ -3,5 +7,5 @@
alias rdiv quo
- alias power! ** unless defined?(0.power!)
+ alias power! ** unless method_defined? :power!
alias rpower **
@@ -13,7 +17,7 @@
alias quof fdiv
alias rdiv quo
- alias power! ** unless defined?(0.power!)
+ alias power! ** unless method_defined? :power!
alias rpower **
end
Modified: MacRuby/trunk/lib/resolv.rb
===================================================================
--- MacRuby/trunk/lib/resolv.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/resolv.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -9,10 +9,10 @@
end
# Resolv is a thread-aware DNS resolver library written in Ruby. Resolv can
-# handle multiple DNS requests concurrently without blocking. The ruby
+# handle multiple DNS requests concurrently without blocking the entire ruby
# interpreter.
#
-# See also resolv-replace.rb to replace the libc resolver with # Resolv.
+# See also resolv-replace.rb to replace the libc resolver with Resolv.
#
# Resolv can look up various DNS resources using the DNS module directly.
#
@@ -162,10 +162,10 @@
class ResolvTimeout < TimeoutError; end
##
- # DNS::Hosts is a hostname resolver that uses the system hosts file.
+ # Resolv::Hosts is a hostname resolver that uses the system hosts file.
class Hosts
- if /mswin32|mingw|bccwin/ =~ RUBY_PLATFORM
+ if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM
require 'win32/resolv'
DefaultFileName = Win32::Resolv.get_hosts_path
else
@@ -173,7 +173,7 @@
end
##
- # Creates a new DNS::Hosts, using +filename+ for its data source.
+ # Creates a new Resolv::Hosts, using +filename+ for its data source.
def initialize(filename = DefaultFileName)
@filename = filename
@@ -313,7 +313,17 @@
# nil:: Uses /etc/resolv.conf.
# String:: Path to a file using /etc/resolv.conf's format.
# Hash:: Must contain :nameserver, :search and :ndots keys.
+ # :nameserver_port can be used to specify port number of nameserver address.
#
+ # The value of :nameserver should be an address string or
+ # an array of address strings.
+ # - :nameserver => '8.8.8.8'
+ # - :nameserver => ['8.8.8.8', '8.8.4.4']
+ #
+ # The value of :nameserver_port should be an array of
+ # pair of nameserver address and port number.
+ # - :nameserver_port => [['8.8.8.8', 53], ['8.8.4.4', 53]]
+ #
# Example:
#
# Resolv::DNS.new(:nameserver => ['210.251.121.21'],
@@ -379,9 +389,21 @@
def each_address(name)
each_resource(name, Resource::IN::A) {|resource| yield resource.address}
- each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
+ if use_ipv6?
+ each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
+ end
end
+ def use_ipv6?
+ begin
+ list = Socket.ip_address_list
+ rescue NotImplementedError
+ return true
+ end
+ list.any? {|a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
+ end
+ private :use_ipv6?
+
##
# Gets the hostname for +address+ from the DNS resolver.
#
@@ -473,13 +495,13 @@
requester = make_requester
senders = {}
begin
- @config.resolv(name) {|candidate, tout, nameserver|
+ @config.resolv(name) {|candidate, tout, nameserver, port|
msg = Message.new
msg.rd = 1
msg.add_question(candidate, typeclass)
- unless sender = senders[[candidate, nameserver]]
- sender = senders[[candidate, nameserver]] =
- requester.sender(msg, candidate, nameserver)
+ unless sender = senders[[candidate, nameserver, port]]
+ sender = senders[[candidate, nameserver, port]] =
+ requester.sender(msg, candidate, nameserver, port)
end
reply, reply_name = requester.request(sender, tout)
case reply.rcode
@@ -498,10 +520,11 @@
end
def make_requester # :nodoc:
- if nameserver = @config.single?
- Requester::ConnectedUDP.new(nameserver)
+ nameserver_port = @config.nameserver_port
+ if nameserver_port.length == 1
+ Requester::ConnectedUDP.new(*nameserver_port[0])
else
- Requester::UnconnectedUDP.new
+ Requester::UnconnectedUDP.new(*nameserver_port)
end
end
@@ -587,10 +610,10 @@
}
end
- def self.bind_random_port(udpsock) # :nodoc:
+ def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
begin
port = rangerand(1024..65535)
- udpsock.bind("", port)
+ udpsock.bind(bind_host, port)
rescue Errno::EADDRINUSE
retry
end
@@ -599,18 +622,23 @@
class Requester # :nodoc:
def initialize
@senders = {}
- @sock = nil
+ @socks = nil
end
def request(sender, tout)
timelimit = Time.now + tout
sender.send
- while (now = Time.now) < timelimit
+ while true
+ now = Time.now
timeout = timelimit - now
- if !IO.select([@sock], nil, nil, timeout)
+ if timeout <= 0
raise ResolvTimeout
end
- reply, from = recv_reply
+ select_result = IO.select(@socks, nil, nil, timeout)
+ if !select_result
+ raise ResolvTimeout
+ end
+ reply, from = recv_reply(select_result[0])
begin
msg = Message.decode(reply)
rescue DecodeError
@@ -626,9 +654,11 @@
end
def close
- sock = @sock
- @sock = nil
- sock.close if sock
+ socks = @socks
+ @socks = nil
+ if socks
+ socks.each {|sock| sock.close }
+ end
end
class Sender # :nodoc:
@@ -640,15 +670,31 @@
end
class UnconnectedUDP < Requester # :nodoc:
- def initialize
+ def initialize(*nameserver_port)
super()
- @sock = UDPSocket.new
- @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
- DNS.bind_random_port(@sock)
+ @nameserver_port = nameserver_port
+ @socks_hash = {}
+ @socks = []
+ nameserver_port.each {|host, port|
+ if host.index(':')
+ bind_host = "::"
+ af = Socket::AF_INET6
+ else
+ bind_host = "0.0.0.0"
+ af = Socket::AF_INET
+ end
+ next if @socks_hash[bind_host]
+ sock = UDPSocket.new(af)
+ sock.do_not_reverse_lookup = true
+ sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
+ DNS.bind_random_port(sock, bind_host)
+ @socks << sock
+ @socks_hash[bind_host] = sock
+ }
end
- def recv_reply
- reply, from = @sock.recvfrom(UDPSize)
+ def recv_reply(readable_socks)
+ reply, from = readable_socks[0].recvfrom(UDPSize)
return reply, [from[3],from[1]]
end
@@ -657,8 +703,9 @@
id = DNS.allocate_request_id(host, port)
request = msg.encode
request[0,2] = [id].pack('n')
+ sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
return @senders[[service, id]] =
- Sender.new(request, data, @sock, host, port)
+ Sender.new(request, data, sock, host, port)
end
def close
@@ -687,14 +734,17 @@
super()
@host = host
@port = port
- @sock = UDPSocket.new(host.index(':') ? Socket::AF_INET6 : Socket::AF_INET)
- DNS.bind_random_port(@sock)
- @sock.connect(host, port)
- @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
+ is_ipv6 = host.index(':')
+ sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET)
+ @socks = [sock]
+ sock.do_not_reverse_lookup = true
+ sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
+ DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0")
+ sock.connect(host, port)
end
- def recv_reply
- reply = @sock.recv(UDPSize)
+ def recv_reply(readable_socks)
+ reply = readable_socks[0].recv(UDPSize)
return reply, nil
end
@@ -705,7 +755,7 @@
id = DNS.allocate_request_id(@host, @port)
request = msg.encode
request[0,2] = [id].pack('n')
- return @senders[[nil,id]] = Sender.new(request, data, @sock)
+ return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
end
def close
@@ -728,14 +778,15 @@
super()
@host = host
@port = port
- @sock = TCPSocket.new(@host, @port)
- @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
+ sock = TCPSocket.new(@host, @port)
+ @socks = [sock]
+ sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
@senders = {}
end
- def recv_reply
- len = @sock.read(2).unpack('n')[0]
- reply = @sock.read(len)
+ def recv_reply(readable_socks)
+ len = readable_socks[0].read(2).unpack('n')[0]
+ reply = @socks[0].read(len)
return reply, nil
end
@@ -746,7 +797,7 @@
id = DNS.allocate_request_id(@host, @port)
request = msg.encode
request[0,2] = [request.length, id].pack('nn')
- return @senders[[nil,id]] = Sender.new(request, data, @sock)
+ return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
end
class Sender < Requester::Sender # :nodoc:
@@ -817,7 +868,7 @@
if File.exist? filename
config_hash = Config.parse_resolv_conf(filename)
else
- if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
+ if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
require 'win32/resolv'
search, nameserver = Win32::Resolv.get_resolv_info
config_hash = {}
@@ -825,13 +876,13 @@
config_hash[:search] = [search].flatten if search
end
end
- config_hash
+ config_hash || {}
end
def lazy_initialize
@mutex.synchronize {
unless @initialized
- @nameserver = []
+ @nameserver_port = []
@search = nil
@ndots = 1
case @config_info
@@ -850,11 +901,18 @@
else
raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
end
- @nameserver = config_hash[:nameserver] if config_hash.include? :nameserver
+ if config_hash.include? :nameserver
+ @nameserver_port = config_hash[:nameserver].map {|ns| [ns, Port] }
+ end
+ if config_hash.include? :nameserver_port
+ @nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
+ end
@search = config_hash[:search] if config_hash.include? :search
@ndots = config_hash[:ndots] if config_hash.include? :ndots
- @nameserver = ['0.0.0.0'] if @nameserver.empty?
+ if @nameserver_port.empty?
+ @nameserver_port << ['0.0.0.0', Port]
+ end
if @search
@search = @search.map {|arg| Label.split(arg) }
else
@@ -866,9 +924,14 @@
end
end
- if !@nameserver.kind_of?(Array) ||
- !@nameserver.all? {|ns| String === ns }
- raise ArgumentError.new("invalid nameserver config: #{@nameserver.inspect}")
+ if !@nameserver_port.kind_of?(Array) ||
+ @nameserver_port.any? {|ns_port|
+ !(Array === ns_port) ||
+ ns_port.length != 2
+ !(String === ns_port[0]) ||
+ !(Integer === ns_port[1])
+ }
+ raise ArgumentError.new("invalid nameserver config: #{@nameserver_port.inspect}")
end
if !@search.kind_of?(Array) ||
@@ -888,13 +951,17 @@
def single?
lazy_initialize
- if @nameserver.length == 1
- return @nameserver[0]
+ if @nameserver_port.length == 1
+ return @nameserver_port[0]
else
return nil
end
end
+ def nameserver_port
+ @nameserver_port
+ end
+
def generate_candidates(name)
candidates = nil
name = Name.create(name)
@@ -915,7 +982,7 @@
def generate_timeouts
ts = [InitialTimeout]
- ts << ts[-1] * 2 / @nameserver.length
+ ts << ts[-1] * 2 / @nameserver_port.length
ts << ts[-1] * 2
ts << ts[-1] * 2
return ts
@@ -928,9 +995,9 @@
candidates.each {|candidate|
begin
timeouts.each {|tout|
- @nameserver.each {|nameserver|
+ @nameserver_port.each {|nameserver, port|
begin
- yield candidate, tout, nameserver
+ yield candidate, tout, nameserver, port
rescue ResolvTimeout
end
}
@@ -1348,6 +1415,10 @@
yield self
end
+ def inspect
+ "\#<#{self.class}: #{@data[0, @index].inspect} #{@data[@index..-1].inspect}>"
+ end
+
def get_length16
len, = self.get_unpack('n')
save_limit = @limit
@@ -2039,7 +2110,11 @@
##
# Regular expression IPv4 addresses must match.
- Regex = /\A(\d+)\.(\d+)\.(\d+)\.(\d+)\z/
+ Regex256 = /0
+ |1(?:[0-9][0-9]?)?
+ |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
+ |[3-9][0-9]?/x
+ Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
def self.create(arg)
case arg
@@ -2060,9 +2135,12 @@
end
def initialize(address) # :nodoc:
- unless address.kind_of?(String) && address.length == 4
- raise ArgumentError.new('IPv4 address must be 4 bytes')
+ unless address.kind_of?(String)
+ raise ArgumentError, 'IPv4 address must be a string'
end
+ unless address.length == 4
+ raise ArgumentError, "IPv4 address expects 4 bytes but #{address.length} bytes"
+ end
@address = address
end
Modified: MacRuby/trunk/lib/rexml/attlistdecl.rb
===================================================================
--- MacRuby/trunk/lib/rexml/attlistdecl.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/attlistdecl.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -31,7 +31,7 @@
@element_name, @pairs, @contents = *source
end
end
-
+
# Access the attlist attribute/value pairs.
# value = attlist_decl[ attribute_name ]
def [](key)
Modified: MacRuby/trunk/lib/rexml/attribute.rb
===================================================================
--- MacRuby/trunk/lib/rexml/attribute.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/attribute.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -14,7 +14,7 @@
attr_reader :element
# The normalized value of this attribute. That is, the attribute with
# entities intact.
- attr_writer :normalized
+ attr_writer :normalized
PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
@@ -22,18 +22,18 @@
# Constructor.
# FIXME: The parser doesn't catch illegal characters in attributes
#
- # first::
+ # first::
# Either: an Attribute, which this new attribute will become a
# clone of; or a String, which is the name of this attribute
# second::
# If +first+ is an Attribute, then this may be an Element, or nil.
# If nil, then the Element parent of this attribute is the parent
- # of the +first+ Attribute. If the first argument is a String,
- # then this must also be a String, and is the content of the attribute.
+ # of the +first+ Attribute. If the first argument is a String,
+ # then this must also be a String, and is the content of the attribute.
# If this is the content, it must be fully normalized (contain no
# illegal characters).
# parent::
- # Ignored unless +first+ is a String; otherwise, may be the Element
+ # Ignored unless +first+ is a String; otherwise, may be the Element
# parent of this attribute, or nil.
#
#
@@ -61,7 +61,7 @@
end
# Returns the namespace of the attribute.
- #
+ #
# e = Element.new( "elns:myelement" )
# e.add_attribute( "nsa:a", "aval" )
# e.add_attribute( "b", "bval" )
@@ -78,7 +78,7 @@
end
# Returns the namespace URL, if defined, or nil otherwise
- #
+ #
# e = Element.new("el")
# e.add_attributes({"xmlns:ns", "http://url"})
# e.namespace( "ns" ) # -> "http://url"
@@ -157,7 +157,7 @@
end
# Removes this Attribute from the tree, and returns true if successfull
- #
+ #
# This method is usually not called directly.
def remove
@element.attributes.delete self.name unless @element.nil?
Modified: MacRuby/trunk/lib/rexml/cdata.rb
===================================================================
--- MacRuby/trunk/lib/rexml/cdata.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/cdata.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -17,7 +17,7 @@
end
# Make a copy of this object
- #
+ #
# _Examples_
# c = CData.new( "Some text" )
# d = c.clone
Modified: MacRuby/trunk/lib/rexml/child.rb
===================================================================
--- MacRuby/trunk/lib/rexml/child.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/child.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -15,8 +15,8 @@
# if supplied, the parent of this child will be set to the
# supplied value, and self will be added to the parent
def initialize( parent = nil )
- @parent = nil
- # Declare @parent, but don't define it. The next line sets the
+ @parent = nil
+ # Declare @parent, but don't define it. The next line sets the
# parent.
parent.add( self ) if parent
end
@@ -68,7 +68,7 @@
parent.insert_after self, other
end
- # Sets the previous sibling of this child. This can be used to insert a
+ # Sets the previous sibling of this child. This can be used to insert a
# child before some other child.
# a = Element.new("a")
# b = a.add_element("b")
Modified: MacRuby/trunk/lib/rexml/comment.rb
===================================================================
--- MacRuby/trunk/lib/rexml/comment.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/comment.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -14,11 +14,11 @@
##
# Constructor. The first argument can be one of three types:
- # @param first If String, the contents of this comment are set to the
+ # @param first If String, the contents of this comment are set to the
# argument. If Comment, the argument is duplicated. If
# Source, the argument is scanned for a comment.
- # @param second If the first argument is a Source, this argument
- # should be nil, not supplied, or a Parent to be set as the parent
+ # @param second If the first argument is a Source, this argument
+ # should be nil, not supplied, or a Parent to be set as the parent
# of this object
def initialize( first, second = nil )
#puts "IN COMMENT CONSTRUCTOR; SECOND IS #{second.type}"
Modified: MacRuby/trunk/lib/rexml/doctype.rb
===================================================================
--- MacRuby/trunk/lib/rexml/doctype.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/doctype.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -15,11 +15,11 @@
STOP = ">"
SYSTEM = "SYSTEM"
PUBLIC = "PUBLIC"
- DEFAULT_ENTITIES = {
- 'gt'=>EntityConst::GT,
- 'lt'=>EntityConst::LT,
- 'quot'=>EntityConst::QUOT,
- "apos"=>EntityConst::APOS
+ DEFAULT_ENTITIES = {
+ 'gt'=>EntityConst::GT,
+ 'lt'=>EntityConst::LT,
+ 'quot'=>EntityConst::QUOT,
+ "apos"=>EntityConst::APOS
}
# name is the name of the doctype
@@ -33,7 +33,7 @@
# dt = DocType.new( doctype_to_clone )
# # Incomplete. Shallow clone of doctype
#
- # +Note+ that the constructor:
+ # +Note+ that the constructor:
#
# Doctype.new( Source.new( "<!DOCTYPE foo 'bar'>" ) )
#
@@ -139,8 +139,8 @@
@entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES
@entities[ child.name ] = child if child.kind_of? Entity
end
-
- # This method retrieves the public identifier identifying the document's
+
+ # This method retrieves the public identifier identifying the document's
# DTD.
#
# Method contributed by Henrik Martensson
@@ -152,7 +152,7 @@
strip_quotes(@long_name)
end
end
-
+
# This method retrieves the system identifier identifying the document's DTD
#
# Method contributed by Henrik Martensson
@@ -164,16 +164,16 @@
@uri.kind_of?(String) ? strip_quotes(@uri) : nil
end
end
-
+
# This method returns a list of notations that have been declared in the
- # _internal_ DTD subset. Notations in the external DTD subset are not
+ # _internal_ DTD subset. Notations in the external DTD subset are not
# listed.
#
# Method contributed by Henrik Martensson
def notations
children().select {|node| node.kind_of?(REXML::NotationDecl)}
end
-
+
# Retrieves a named notation. Only notations declared in the internal
# DTD subset can be retrieved.
#
@@ -183,9 +183,9 @@
notation_decl.name == name
}
end
-
+
private
-
+
# Method contributed by Henrik Martensson
def strip_quotes(quoted_string)
quoted_string =~ /^[\'\"].*[\'\"]$/ ?
@@ -217,7 +217,7 @@
output << to_s
end
end
-
+
public
class ElementDecl < Declaration
def initialize( src )
@@ -250,7 +250,7 @@
def to_s
"<!NOTATION #@name #@middle#{
- @public ? ' ' + public.inspect : ''
+ @public ? ' ' + public.inspect : ''
}#{
@system ? ' ' + at system.inspect : ''
}>"
@@ -259,7 +259,7 @@
def write( output, indent=-1 )
output << to_s
end
-
+
# This method retrieves the name of the notation.
#
# Method contributed by Henrik Martensson
Modified: MacRuby/trunk/lib/rexml/document.rb
===================================================================
--- MacRuby/trunk/lib/rexml/document.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/document.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -25,7 +25,7 @@
DECLARATION = XMLDecl.default
# Constructor
- # @param source if supplied, must be a Document, String, or IO.
+ # @param source if supplied, must be a Document, String, or IO.
# Documents have their context and Element attributes cloned.
# Strings are expected to be valid XML documents. IOs are expected
# to be sources of valid XML documents.
@@ -66,25 +66,27 @@
# of the document
def add( child )
if child.kind_of? XMLDecl
- @children.unshift child
+ if @children[0].kind_of? XMLDecl
+ @children[0] = child
+ else
+ @children.unshift child
+ end
child.parent = self
elsif child.kind_of? DocType
- # Find first Element or DocType node and insert the decl right
+ # Find first Element or DocType node and insert the decl right
# before it. If there is no such node, just insert the child at the
# end. If there is a child and it is an DocType, then replace it.
- insert_before_index = 0
- @children.find { |x|
- insert_before_index += 1
+ insert_before_index = @children.find_index { |x|
x.kind_of?(Element) || x.kind_of?(DocType)
}
- if @children[ insert_before_index ] # Not null = not end of list
- if @children[ insert_before_index ].kind_of DocType
+ if insert_before_index # Not null = not end of list
+ if @children[ insert_before_index ].kind_of? DocType
@children[ insert_before_index ] = child
else
- @children[ index_before_index-1, 0 ] = child
+ @children[ insert_before_index-1, 0 ] = child
end
else # Insert at end of list
- @children[insert_before_index] = child
+ @children << child
end
child.parent = self
else
@@ -167,7 +169,7 @@
# indent::
# An integer. If -1, no indenting will be used; otherwise, the
# indentation will be twice this number of spaces, and children will be
- # indented an additional amount. For a value of 3, every item will be
+ # indented an additional amount. For a value of 3, every item will be
# indented 3 more levels, or 6 more spaces (2 * 3). Defaults to -1
# transitive::
# If transitive is true and indent is >= 0, then the output will be
@@ -178,7 +180,7 @@
# Internet Explorer is the worst piece of crap to have ever been
# written, with the possible exception of Windows itself. Since IE is
# unable to parse proper XML, we have to provide a hack to generate XML
- # that IE's limited abilities can handle. This hack inserts a space
+ # that IE's limited abilities can handle. This hack inserts a space
# before the /> on empty tags. Defaults to false
def write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
@@ -197,7 +199,7 @@
formatter.write( self, output )
end
-
+
def Document::parse_stream( source, listener )
Parsers::StreamParser.new( source, listener ).parse
end
@@ -215,7 +217,7 @@
end
attr_reader :entity_expansion_count
-
+
def record_entity_expansion
@entity_expansion_count += 1
if @entity_expansion_count > @@entity_expansion_limit
Modified: MacRuby/trunk/lib/rexml/dtd/entitydecl.rb
===================================================================
--- MacRuby/trunk/lib/rexml/dtd/entitydecl.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/dtd/entitydecl.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -49,7 +49,7 @@
def EntityDecl.parse_source source, listener
md = source.match( PATTERN_RE, true )
thing = md[0].squeeze(" \t\n\r")
- listener.send inspect.downcase, thing
+ listener.send inspect.downcase, thing
end
end
end
Modified: MacRuby/trunk/lib/rexml/dtd/notationdecl.rb
===================================================================
--- MacRuby/trunk/lib/rexml/dtd/notationdecl.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/dtd/notationdecl.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -32,7 +32,7 @@
def NotationDecl.parse_source source, listener
md = source.match( PATTERN_RE, true )
thing = md[0].squeeze(" \t\n\r")
- listener.send inspect.downcase, thing
+ listener.send inspect.downcase, thing
end
end
end
Modified: MacRuby/trunk/lib/rexml/element.rb
===================================================================
--- MacRuby/trunk/lib/rexml/element.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/element.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -30,13 +30,13 @@
attr_accessor :context
# Constructor
- # arg::
+ # arg::
# if not supplied, will be set to the default value.
# If a String, the name of this object will be set to the argument.
- # If an Element, the object will be shallowly cloned; name,
+ # If an Element, the object will be shallowly cloned; name,
# attributes, and namespaces will be copied. Children will +not+ be
# copied.
- # parent::
+ # parent::
# if supplied, must be a Parent, and will be used as
# the parent of this object.
# context::
@@ -97,7 +97,7 @@
self.class.new self
end
- # Evaluates to the root node of the document that this element
+ # Evaluates to the root node of the document that this element
# belongs to. If this element doesn't belong to a document, but does
# belong to another Element, the parent's root will be returned, until the
# earliest ancestor is found.
@@ -137,8 +137,8 @@
# is the case if:
# 1. Neither :+respect_whitespace+ nor :+compress_whitespace+ has any value
# 2. The context has :+respect_whitespace+ set to :+all+ or
- # an array containing the name of this element, and
- # :+compress_whitespace+ isn't set to :+all+ or an array containing the
+ # an array containing the name of this element, and
+ # :+compress_whitespace+ isn't set to :+all+ or an array containing the
# name of this element.
# The evaluation is tested against +expanded_name+, and so is namespace
# sensitive.
@@ -162,7 +162,7 @@
@ignore_whitespace_nodes = false
if @context
if @context[:ignore_whitespace_nodes]
- @ignore_whitespace_nodes =
+ @ignore_whitespace_nodes =
(@context[:ignore_whitespace_nodes] == :all or
@context[:ignore_whitespace_nodes].include? expanded_name)
end
@@ -206,13 +206,13 @@
return namespaces
end
- # Evalutas to the URI for a prefix, or the empty string if no such
+ # Evalutas to the URI for a prefix, or the empty string if no such
# namespace is declared for this element. Evaluates recursively for
# ancestors. Returns the default namespace, if there is one.
- # prefix::
+ # prefix::
# the prefix to search for. If not supplied, returns the default
# namespace if one exists
- # Returns::
+ # Returns::
# the namespace URI as a String, or nil if no such namespace
# exists. If the namespace is undefined, returns an empty string
# doc = Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
@@ -235,10 +235,10 @@
end
# Adds a namespace to this element.
- # prefix::
+ # prefix::
# the prefix string, or the namespace URI if +uri+ is not
# supplied
- # uri::
+ # uri::
# the namespace URI. May be nil, in which +prefix+ is used as
# the URI
# Evaluates to: this Element
@@ -280,12 +280,12 @@
# Adds a child to this element, optionally setting attributes in
# the element.
- # element::
+ # element::
# optional. If Element, the element is added.
# Otherwise, a new Element is constructed with the argument (see
# Element.initialize).
- # attrs::
- # If supplied, must be a Hash containing String name,value
+ # attrs::
+ # If supplied, must be a Hash containing String name,value
# pairs, which will be used to set the attributes of the new Element.
# Returns:: the Element that was added
# el = doc.add_element 'my-tag'
@@ -302,9 +302,9 @@
end
# Deletes a child element.
- # element::
- # Must be an +Element+, +String+, or +Integer+. If Element,
- # the element is removed. If String, the element is found (via XPath)
+ # element::
+ # Must be an +Element+, +String+, or +Integer+. If Element,
+ # the element is removed. If String, the element is found (via XPath)
# and removed. <em>This means that any parent can remove any
# descendant.<em> If Integer, the Element indexed by that number will be
# removed.
@@ -327,14 +327,14 @@
# Iterates through the child elements, yielding for each Element that
# has a particular attribute set.
- # key::
+ # key::
# the name of the attribute to search for
- # value::
+ # value::
# the value of the attribute
- # max::
- # (optional) causes this method to return after yielding
+ # max::
+ # (optional) causes this method to return after yielding
# for this number of matching children
- # name::
+ # name::
# (optional) if supplied, this is an XPath that filters
# the children to check.
#
@@ -348,7 +348,7 @@
# # Yields d
# doc.root.each_element_with_attribute( 'id', '1', 0, 'd' ) {|e| p e}
def each_element_with_attribute( key, value=nil, max=0, name=nil, &block ) # :yields: Element
- each_with_something( proc {|child|
+ each_with_something( proc {|child|
if value.nil?
child.attributes[key] != nil
else
@@ -359,13 +359,13 @@
# Iterates through the children, yielding for each Element that
# has a particular text set.
- # text::
+ # text::
# the text to search for. If nil, or not supplied, will iterate
# over all +Element+ children that contain at least one +Text+ node.
- # max::
+ # max::
# (optional) causes this method to return after yielding
# for this number of matching children
- # name::
+ # name::
# (optional) if supplied, this is an XPath that filters
# the children to check.
#
@@ -379,7 +379,7 @@
# # Yields d
# doc.each_element_with_text(nil, 0, 'd'){|e|p e}
def each_element_with_text( text=nil, max=0, name=nil, &block ) # :yields: Element
- each_with_something( proc {|child|
+ each_with_something( proc {|child|
if text.nil?
child.has_text?
else
@@ -408,7 +408,7 @@
# doc.root.elements['c'].next_element #-> nil
def next_element
element = next_sibling
- element = element.next_sibling until element.nil? or element.kind_of? Element
+ element = element.next_sibling until element.nil? or element.kind_of? Element
return element
end
@@ -477,7 +477,7 @@
# this method with a nil argument. In this case, the next Text
# child becomes the first Text child. In no case is the order of
# any siblings disturbed.
- # text::
+ # text::
# If a String, a new Text child is created and added to
# this Element as the first Text child. If Text, the text is set
# as the first Child element. If nil, then any existing first Text
@@ -492,7 +492,7 @@
def text=( text )
if text.kind_of? String
text = Text.new( text, whitespace(), nil, raw() )
- elsif text and !text.kind_of? Text
+ elsif !text.nil? and !text.kind_of? Text
text = Text.new( text.to_s, whitespace(), nil, raw() )
end
old_text = get_text
@@ -520,7 +520,7 @@
# Note that at the end of this example, the branch has <b>3</b> nodes; the 'e'
# element and <b>2</b> Text node children.
def add_text( text )
- if text.kind_of? String
+ if text.kind_of? String
if @children[-1].kind_of? Text
@children[-1] << text
return
@@ -559,7 +559,7 @@
end
prefix = nil if prefix == 'xmlns'
- ret_val =
+ ret_val =
attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" )
return ret_val unless ret_val.nil?
@@ -586,7 +586,7 @@
# the attribute is added to the list of Element attributes. If String,
# the argument is used as the name of the new attribute, and the value
# parameter must be supplied.
- # value::
+ # value::
# Required if +key+ is a String, and ignored if the first argument is
# an Attribute. This is a String, and is used as the value
# of the new Attribute. This should be the unnormalized value of the
@@ -621,7 +621,7 @@
# either an Attribute or a String. In either case, the
# attribute is found by matching the attribute name to the argument,
# and then removed. If no attribute is found, no action is taken.
- # Returns::
+ # Returns::
# the attribute removed, or nil if this Element did not contain
# a matching attribute
# e = Element.new('E')
@@ -638,7 +638,7 @@
# Other Utilities #
#################################################
- # Get an array of all CData children.
+ # Get an array of all CData children.
# IMMUTABLE
def cdatas
find_all { |child| child.kind_of? CData }.freeze
@@ -681,7 +681,7 @@
# Internet Explorer is the worst piece of crap to have ever been
# written, with the possible exception of Windows itself. Since IE is
# unable to parse proper XML, we have to provide a hack to generate XML
- # that IE's limited abilities can handle. This hack inserts a space
+ # that IE's limited abilities can handle. This hack inserts a space
# before the /> on empty tags. Defaults to false
#
# out = ''
@@ -707,8 +707,8 @@
def __to_xpath_helper node
rv = node.expanded_name.clone
if node.parent
- results = node.parent.find_all {|n|
- n.kind_of?(REXML::Element) and n.expanded_name == node.expanded_name
+ results = node.parent.find_all {|n|
+ n.kind_of?(REXML::Element) and n.expanded_name == node.expanded_name
}
if results.length > 1
idx = results.index( node )
@@ -734,7 +734,7 @@
# A class which provides filtering of children for Elements, and
# XPath search support. You are expected to only encounter this class as
- # the <tt>element.elements</tt> object. Therefore, you are
+ # the <tt>element.elements</tt> object. Therefore, you are
# _not_ expected to instantiate this yourself.
class Elements
include Enumerable
@@ -746,7 +746,7 @@
# Fetches a child element. Filters only Element children, regardless of
# the XPath match.
- # index::
+ # index::
# the search parameter. This is either an Integer, which
# will be used to find the index'th child Element, or an XPath,
# which will be used to search for the Element. <em>Because
@@ -756,7 +756,7 @@
# child element is at index 1, not 0, and the +n+th element is at index
# +n+, not <tt>n-1</tt>. This is because XPath indexes element children
# starting from 1, not 0, and the indexes should be the same.
- # name::
+ # name::
# optional, and only used in the first argument is an
# Integer. In that case, the index'th child Element that has the
# supplied name will be returned. Note again that the indexes start at 1.
@@ -772,12 +772,12 @@
num = 0
@element.find { |child|
child.kind_of? Element and
- (name.nil? ? true : child.has_name?( name )) and
+ (name.nil? ? true : child.has_name?( name )) and
(num += 1) == index
}
else
return XPath::first( @element, index )
- #{ |element|
+ #{ |element|
# return element if element.kind_of? Element
#}
#return nil
@@ -787,7 +787,7 @@
# Sets an element, replacing any previous matching element. If no
# existing element is found ,the element is added.
# index:: Used to find a matching element to replace. See []().
- # element::
+ # element::
# The element to replace the existing element with
# the previous element
# Returns:: nil if no previous element was found.
@@ -812,12 +812,12 @@
@element.find{ |child| child.kind_of? Element}.nil?
end
- # Returns the index of the supplied child (starting at 1), or -1 if
+ # Returns the index of the supplied child (starting at 1), or -1 if
# the element is not a child
# element:: an +Element+ child
def index element
rv = 0
- found = @element.find do |child|
+ found = @element.find do |child|
child.kind_of? Element and
(rv += 1) and
child == element
@@ -827,7 +827,7 @@
end
# Deletes a child Element
- # element::
+ # element::
# Either an Element, which is removed directly; an
# xpath, where the first matching child is removed; or an Integer,
# where the n'th Element is removed.
@@ -854,7 +854,7 @@
# deleted = doc.elements.delete_all 'a/c' #-> [<c/>, <c/>, <c/>, <c/>]
def delete_all( xpath )
rv = []
- XPath::each( @element, xpath) {|element|
+ XPath::each( @element, xpath) {|element|
rv << element if element.kind_of? Element
}
rv.each do |element|
@@ -865,7 +865,7 @@
end
# Adds an element
- # element::
+ # element::
# if supplied, is either an Element, String, or
# Source (see Element.initialize). If not supplied or nil, a
# new, default Element will be constructed
@@ -890,8 +890,8 @@
# Iterates through all of the child Elements, optionally filtering
# them by a given XPath
- # xpath::
- # optional. If supplied, this is a String XPath, and is used to
+ # xpath::
+ # optional. If supplied, this is a String XPath, and is used to
# filter the children, so that only matching children are yielded. Note
# that XPaths are automatically filtered for Elements, so that
# non-Element children will not be yielded
@@ -908,8 +908,8 @@
def collect( xpath=nil, &block )
collection = []
- XPath::each( @element, xpath ) {|e|
- collection << yield(e) if e.kind_of?(Element)
+ XPath::each( @element, xpath ) {|e|
+ collection << yield(e) if e.kind_of?(Element)
}
collection
end
@@ -944,7 +944,7 @@
# supplied XPath matches non-Element children.
# doc = Document.new '<a>sean<b/>elliott<c/></a>'
# doc.root.elements.to_a #-> [ <b/>, <c/> ]
- # doc.root.elements.to_a("child::node()") #-> [ <b/>, <c/> ]
+ # doc.root.elements.to_a("child::node()") #-> [ <b/>, <c/> ]
# XPath.match(doc.root, "child::node()") #-> [ sean, <b/>, elliott, <c/> ]
def to_a( xpath=nil )
rv = XPath.match( @element, xpath )
@@ -964,7 +964,7 @@
# ATTRIBUTES #
########################################################################
- # A class that defines the set of Attributes of an Element and provides
+ # A class that defines the set of Attributes of an Element and provides
# operations for accessing elements in that set.
class Attributes < Hash
# Constructor
@@ -976,11 +976,11 @@
# Fetches an attribute value. If you want to get the Attribute itself,
# use get_attribute()
# name:: an XPath attribute name. Namespaces are relevant here.
- # Returns::
+ # Returns::
# the String value of the matching attribute, or +nil+ if no
# matching attribute was found. This is the unnormalized value
# (with entities expanded).
- #
+ #
# doc = Document.new "<a foo:att='1' bar:att='2' att='<'/>"
# doc.root.attributes['att'] #-> '<'
# doc.root.attributes['bar:att'] #-> '2'
@@ -1006,7 +1006,7 @@
# Iterates over the attributes of an Element. Yields actual Attribute
# nodes, not String values.
- #
+ #
# doc = Document.new '<a x="1" y="2"/>'
# doc.root.attributes.each_attribute {|attr|
# p attr.expanded_name+" => "+attr.value
@@ -1033,7 +1033,7 @@
end
# Fetches an attribute
- # name::
+ # name::
# the name by which to search for the attribute. Can be a
# <tt>prefix:name</tt> namespace name.
# Returns:: The first matching attribute, or nil if there was none. This
@@ -1077,10 +1077,10 @@
# Sets an attribute, overwriting any existing attribute value by the
# same name. Namespace is significant.
# name:: the name of the attribute
- # value::
+ # value::
# (optional) If supplied, the value of the attribute. If
# nil, any existing matching attribute is deleted.
- # Returns::
+ # Returns::
# Owning element
# doc = Document.new "<a x:foo='1' foo='3'/>"
# doc.root.attributes['y:foo'] = '2'
@@ -1109,13 +1109,13 @@
old_attr[value.prefix] = value
elsif old_attr.prefix != value.prefix
# Check for conflicting namespaces
- raise ParseException.new(
+ raise ParseException.new(
"Namespace conflict in adding attribute \"#{value.name}\": "+
"Prefix \"#{old_attr.prefix}\" = "+
"\"#{@element.namespace(old_attr.prefix)}\" and prefix "+
- "\"#{value.prefix}\" = \"#{@element.namespace(value.prefix)}\"") if
+ "\"#{value.prefix}\" = \"#{@element.namespace(value.prefix)}\"") if
value.prefix != "xmlns" and old_attr.prefix != "xmlns" and
- @element.namespace( old_attr.prefix ) ==
+ @element.namespace( old_attr.prefix ) ==
@element.namespace( value.prefix )
store value.name, { old_attr.prefix => old_attr,
value.prefix => value }
@@ -1125,7 +1125,7 @@
return @element
end
- # Returns an array of Strings containing all of the prefixes declared
+ # Returns an array of Strings containing all of the prefixes declared
# by this set of # attributes. The array does not include the default
# namespace declaration, if one exists.
# doc = Document.new("<a xmlns='foo' xmlns:x='bar' xmlns:y='twee' "+
@@ -1164,7 +1164,7 @@
end
# Removes an attribute
- # attribute::
+ # attribute::
# either a String, which is the name of the attribute to remove --
# namespaces are significant here -- or the attribute to remove.
# Returns:: the owning element
@@ -1212,12 +1212,12 @@
alias :<< :add
# Deletes all attributes matching a name. Namespaces are significant.
- # name::
+ # name::
# A String; all attributes that match this path will be removed
# Returns:: an Array of the Attributes that were removed
def delete_all( name )
rv = []
- each_attribute { |attribute|
+ each_attribute { |attribute|
rv << attribute if attribute.expanded_name == name
}
rv.each{ |attr| attr.remove }
@@ -1227,7 +1227,7 @@
# The +get_attribute_ns+ method retrieves a method by its namespace
# and name. Thus it is possible to reliably identify an attribute
# even if an XML processor has changed the prefix.
- #
+ #
# Method contributed by Henrik Martensson
def get_attribute_ns(namespace, name)
result = nil
@@ -1236,7 +1236,7 @@
namespace == attribute.namespace() &&
( !namespace.empty? || !attribute.fully_expanded_name.index(':') )
# foo will match xmlns:foo, but only if foo isn't also an attribute
- result = attribute if !result or !namespace.empty? or
+ result = attribute if !result or !namespace.empty? or
!attribute.fully_expanded_name.index(':')
end
}
Modified: MacRuby/trunk/lib/rexml/encoding.rb
===================================================================
--- MacRuby/trunk/lib/rexml/encoding.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/encoding.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -29,7 +29,7 @@
if enc and enc != UTF_8
@encoding = enc
raise ArgumentError, "Bad encoding name #@encoding" unless @encoding =~ /^[\w-]+$/
- @encoding.untaint
+ @encoding.untaint
begin
require 'rexml/encodings/ICONV.rb'
Encoding.apply(self, "ICONV")
Modified: MacRuby/trunk/lib/rexml/encodings/CP-1252.rb
===================================================================
--- MacRuby/trunk/lib/rexml/encodings/CP-1252.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/encodings/CP-1252.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -58,7 +58,7 @@
end
array_enc.pack('C*')
end
-
+
# Convert to UTF-8
def decode_cp1252(str)
array_latin9 = str.unpack('C*')
Modified: MacRuby/trunk/lib/rexml/encodings/ISO-8859-15.rb
===================================================================
--- MacRuby/trunk/lib/rexml/encodings/ISO-8859-15.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/encodings/ISO-8859-15.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -46,7 +46,7 @@
end
array_enc.pack('C*')
end
-
+
# Convert to UTF-8
def from_iso_8859_15(str)
array_latin9 = str.unpack('C*')
Modified: MacRuby/trunk/lib/rexml/encodings/UNILE.rb
===================================================================
--- MacRuby/trunk/lib/rexml/encodings/UNILE.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/encodings/UNILE.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -18,7 +18,7 @@
def decode_unile(str)
array_enc=str.unpack('C*')
array_utf8 = []
- 0.step(array_enc.size-1, 2){|i|
+ 0.step(array_enc.size-1, 2){|i|
array_utf8 << (array_enc.at(i) + array_enc.at(i+1)*0x100)
}
array_utf8.pack('U*')
Modified: MacRuby/trunk/lib/rexml/encodings/UTF-16.rb
===================================================================
--- MacRuby/trunk/lib/rexml/encodings/UTF-16.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/encodings/UTF-16.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -17,10 +17,11 @@
def decode_utf16(str)
# XXX macruby cannot compile this regexp
+ # It now compiles it but doesn't match it
#str = str[2..-1] if /^\376\377/n =~ str
array_enc=str.unpack('C*')
array_utf8 = []
- 0.step(array_enc.size-1, 2){|i|
+ 0.step(array_enc.size-1, 2){|i|
array_utf8 << (array_enc.at(i+1) + array_enc.at(i)*0x100)
}
array_utf8.pack('U*')
Modified: MacRuby/trunk/lib/rexml/entity.rb
===================================================================
--- MacRuby/trunk/lib/rexml/entity.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/entity.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -25,12 +25,12 @@
# Create a new entity. Simple entities can be constructed by passing a
# name, value to the constructor; this creates a generic, plain entity
# reference. For anything more complicated, you have to pass a Source to
- # the constructor with the entity definiton, or use the accessor methods.
+ # the constructor with the entity definition, or use the accessor methods.
# +WARNING+: There is no validation of entity state except when the entity
# is read from a stream. If you start poking around with the accessors,
# you can easily create a non-conformant Entity. The best thing to do is
# dump the stupid DTDs and use XMLSchema instead.
- #
+ #
# e = Entity.new( 'amp', '&' )
def initialize stream, value=nil, parent=nil, reference=false
super(parent)
@@ -38,7 +38,7 @@
if stream.kind_of? Array
@name = stream[1]
if stream[-1] == '%'
- @reference = true
+ @reference = true
stream.pop
else
@reference = false
Modified: MacRuby/trunk/lib/rexml/formatters/default.rb
===================================================================
--- MacRuby/trunk/lib/rexml/formatters/default.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/formatters/default.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -21,7 +21,7 @@
def write( node, output )
case node
- when Document
+ when Document
if node.xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
output = Output.new( output, node.xml_decl.encoding )
end
@@ -63,14 +63,16 @@
def write_element( node, output )
output << "<#{node.expanded_name}"
- node.attributes.to_a.sort_by {|attr| attr.name}.each do |attr|
+ node.attributes.to_a.map { |a|
+ Hash === a ? a.values : a
+ }.flatten.sort_by {|attr| attr.name}.each do |attr|
output << " "
attr.write( output )
end unless node.attributes.empty?
if node.children.empty?
output << " " if @ie_hack
- output << "/"
+ output << "/"
else
output << ">"
node.children.each { |child|
Modified: MacRuby/trunk/lib/rexml/formatters/pretty.rb
===================================================================
--- MacRuby/trunk/lib/rexml/formatters/pretty.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/formatters/pretty.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -48,7 +48,7 @@
if @ie_hack
output << " "
end
- output << "/"
+ output << "/"
else
output << ">"
# If compact and all children are text, and if the formatted output
Modified: MacRuby/trunk/lib/rexml/formatters/transitive.rb
===================================================================
--- MacRuby/trunk/lib/rexml/formatters/transitive.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/formatters/transitive.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -31,7 +31,7 @@
output << ' '*@level
if node.children.empty?
output << " " if @ie_hack
- output << "/"
+ output << "/"
else
output << ">"
# If compact and all children are text, and if the formatted output
Modified: MacRuby/trunk/lib/rexml/functions.rb
===================================================================
--- MacRuby/trunk/lib/rexml/functions.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/functions.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -48,7 +48,7 @@
# UNTESTED
def Functions::local_name( node_set=nil )
get_namespace( node_set ) do |node|
- return node.local_name
+ return node.local_name
end
end
@@ -57,7 +57,7 @@
end
def Functions::name( node_set=nil )
- get_namespace( node_set ) do |node|
+ get_namespace( node_set ) do |node|
node.expanded_name
end
end
@@ -66,7 +66,7 @@
def Functions::get_namespace( node_set = nil )
if node_set == nil
yield @@context[:node] if defined? @@context[:node].namespace
- else
+ else
if node_set.respond_to? :each
node_set.each { |node| yield node if defined? node.namespace }
elsif node_set.respond_to? :namespace
@@ -81,15 +81,15 @@
#
# A number is converted to a string as follows
#
- # NaN is converted to the string NaN
+ # NaN is converted to the string NaN
#
- # positive zero is converted to the string 0
+ # positive zero is converted to the string 0
#
- # negative zero is converted to the string 0
+ # negative zero is converted to the string 0
#
- # positive infinity is converted to the string Infinity
+ # positive infinity is converted to the string Infinity
#
- # negative infinity is converted to the string -Infinity
+ # negative infinity is converted to the string -Infinity
#
# if the number is an integer, the number is represented in decimal form
# as a Number with no decimal point and no leading zeros, preceded by a
@@ -156,7 +156,7 @@
string(string).include?(string(test))
end
- # Kouhei fixed this
+ # Kouhei fixed this
def Functions::substring_before( string, test )
ruby_string = string(string)
ruby_index = ruby_string.index(string(test))
@@ -166,7 +166,7 @@
ruby_string[ 0...ruby_index ]
end
end
-
+
# Kouhei fixed this too
def Functions::substring_after( string, test )
ruby_string = string(string)
@@ -175,11 +175,11 @@
""
end
- # Take equal portions of Mike Stok and Sean Russell; mix
+ # Take equal portions of Mike Stok and Sean Russell; mix
# vigorously, and pour into a tall, chilled glass. Serves 10,000.
def Functions::substring( string, start, length=nil )
ruby_string = string(string)
- ruby_length = if length.nil?
+ ruby_length = if length.nil?
ruby_string.length.to_f
else
number(length)
@@ -188,15 +188,15 @@
# Handle the special cases
return '' if (
- ruby_length.nan? or
+ ruby_length.nan? or
ruby_start.nan? or
ruby_start.infinite?
)
infinite_length = ruby_length.infinite? == 1
ruby_length = ruby_string.length if infinite_length
-
- # Now, get the bounds. The XPath bounds are 1..length; the ruby bounds
+
+ # Now, get the bounds. The XPath bounds are 1..length; the ruby bounds
# are 0..length. Therefore, we have to offset the bounds by one.
ruby_start = ruby_start.round - 1
ruby_length = ruby_length.round
@@ -247,7 +247,7 @@
0.upto(from.length - 1) { |pos|
from_char = from[pos]
unless map.has_key? from_char
- map[from_char] =
+ map[from_char] =
if pos < to.length
to[pos]
else
@@ -359,7 +359,7 @@
nodes = [nodes] unless nodes.kind_of? Array
nodes.inject(0) { |r,n| r += number(string(n)) }
end
-
+
def Functions::floor( number )
number(number).floor
end
Modified: MacRuby/trunk/lib/rexml/instruction.rb
===================================================================
--- MacRuby/trunk/lib/rexml/instruction.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/instruction.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -13,7 +13,7 @@
attr_accessor :target, :content
# Constructs a new Instruction
- # @param target can be one of a number of things. If String, then
+ # @param target can be one of a number of things. If String, then
# the target of this instruction is set to this. If an Instruction,
# then the Instruction is shallowly cloned (target and content are
# copied). If a Source, then the source is scanned and parsed for
@@ -37,7 +37,7 @@
def clone
Instruction.new self
end
-
+
# == DEPRECATED
# See the rexml/formatters package
#
Modified: MacRuby/trunk/lib/rexml/namespace.rb
===================================================================
--- MacRuby/trunk/lib/rexml/namespace.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/namespace.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -40,7 +40,7 @@
# source file.
def fully_expanded_name
ns = prefix
- return "#{ns}:#@name" if ns.size > 0
+ return "#{ns}:#@name" if ns.size > 0
return @name
end
end
Modified: MacRuby/trunk/lib/rexml/node.rb
===================================================================
--- MacRuby/trunk/lib/rexml/node.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/node.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -57,7 +57,7 @@
}
end
- # Find (and return) first subnode (recursively) for which the block
+ # Find (and return) first subnode (recursively) for which the block
# evaluates to true. Returns +nil+ if none was found.
def find_first_recursive(&block) # :yields: node
each_recursive {|node|
Modified: MacRuby/trunk/lib/rexml/output.rb
===================================================================
--- MacRuby/trunk/lib/rexml/output.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/output.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -3,7 +3,7 @@
module REXML
class Output
include Encoding
-
+
attr_reader :encoding
def initialize real_IO, encd="iso-8859-1"
Modified: MacRuby/trunk/lib/rexml/parent.rb
===================================================================
--- MacRuby/trunk/lib/rexml/parent.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/parent.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -6,14 +6,14 @@
# object.
class Parent < Child
include Enumerable
-
+
# Constructor
# @param parent if supplied, will be set as the parent of this object
def initialize parent=nil
super(parent)
@children = []
end
-
+
def add( object )
#puts "PARENT GOTS #{size} CHILDREN"
object.parent = self
@@ -21,47 +21,48 @@
#puts "PARENT NOW GOTS #{size} CHILDREN"
object
end
-
+
alias :push :add
alias :<< :push
-
+
def unshift( object )
object.parent = self
@children.unshift object
end
-
+
def delete( object )
found = false
@children.delete_if {|c| c.equal?(object) and found = true }
object.parent = nil if found
+ found ? object : nil
end
-
+
def each(&block)
@children.each(&block)
end
-
+
def delete_if( &block )
@children.delete_if(&block)
end
-
+
def delete_at( index )
@children.delete_at index
end
-
+
def each_index( &block )
@children.each_index(&block)
end
-
+
# Fetches a child at a given index
# @param index the Integer index of the child to fetch
def []( index )
@children[index]
end
-
+
alias :each_child :each
-
-
-
+
+
+
# Set an index entry. See Array.[]=
# @param index the index of the element to set
# @param opt either the object to set, or an Integer length
@@ -71,7 +72,7 @@
args[-1].parent = self
@children[*args[0..-2]] = args[-1]
end
-
+
# Inserts an child before another child
# @param child1 this is either an xpath or an Element. If an Element,
# child2 will be inserted before child1 in the child list of the parent.
@@ -91,7 +92,7 @@
end
self
end
-
+
# Inserts an child after another child
# @param child1 this is either an xpath or an Element. If an Element,
# child2 will be inserted after child1 in the child list of the parent.
@@ -111,11 +112,11 @@
end
self
end
-
+
def to_a
@children.dup
end
-
+
# Fetches the index of a given child
# @param child the child to get the index of
# @return the index of the child, or nil if the object is not a child
@@ -125,24 +126,24 @@
@children.find { |i| count += 1 ; i.hash == child.hash }
count
end
-
+
# @return the number of children of this parent
def size
@children.size
end
-
+
alias :length :size
-
+
# Replaces one child with another, making sure the nodelist is correct
# @param to_replace the child to replace (must be a Child)
- # @param replacement the child to insert into the nodelist (must be a
+ # @param replacement the child to insert into the nodelist (must be a
# Child)
def replace_child( to_replace, replacement )
@children.map! {|c| c.equal?( to_replace ) ? replacement : c }
to_replace.parent = nil
replacement.parent = self
end
-
+
# Deeply clones this object. This creates a complete duplicate of this
# Parent, including all descendants.
def deep_clone
@@ -156,9 +157,9 @@
end
cl
end
-
+
alias :children :to_a
-
+
def parent?
true
end
Modified: MacRuby/trunk/lib/rexml/parseexception.rb
===================================================================
--- MacRuby/trunk/lib/rexml/parseexception.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/parseexception.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -30,7 +30,7 @@
err << "Last 80 unconsumed characters:\n"
err << @source.buffer[0..80].gsub(/\n/, ' ')
end
-
+
err
end
@@ -40,12 +40,12 @@
end
def line
- @source.current_line[2] if @source and defined? @source.current_line and
+ @source.current_line[2] if @source and defined? @source.current_line and
@source.current_line
end
def context
@source.current_line
end
- end
+ end
end
Modified: MacRuby/trunk/lib/rexml/parsers/baseparser.rb
===================================================================
--- MacRuby/trunk/lib/rexml/parsers/baseparser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/parsers/baseparser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -25,24 +25,17 @@
#
# Nat Price gave me some good ideas for the API.
class BaseParser
- if String.method_defined? :encode
- # Oniguruma / POSIX [understands unicode]
- LETTER = '[[:alpha:]]'
- DIGIT = '[[:digit:]]'
- else
- # Ruby < 1.9 [doesn't understand unicode]
- LETTER = 'a-zA-Z'
- DIGIT = '\d'
- end
+ LETTER = '[:alpha:]'
+ DIGIT = '[:digit:]'
COMBININGCHAR = '' # TODO
EXTENDER = '' # TODO
- NCNAME_STR= "[#{LETTER}_:][-#{LETTER}#{DIGIT}._:#{COMBININGCHAR}#{EXTENDER}]*"
+ NCNAME_STR= "[#{LETTER}_:][-[:alnum:]._:#{COMBININGCHAR}#{EXTENDER}]*"
NAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})"
UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
- NAMECHAR = '[\-\w\d\.:]'
+ NAMECHAR = '[\-\w\.:]'
NAME = "([\\w:]#{NAMECHAR}*)"
NMTOKEN = "(?:#{NAMECHAR})+"
NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*"
@@ -66,7 +59,7 @@
VERSION = /\bversion\s*=\s*["'](.*?)['"]/um
ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um
- STANDALONE = /\bstandalone\s*=\s["'](.*?)['"]/um
+ STANDALONE = /\bstandalone\s*=\s*["'](.*?)['"]/um
ENTITY_START = /^\s*<!ENTITY/
IDENTITY = /^([!\*\w\-]+)(\s+#{NCNAME_STR})?(\s+["'](.*?)['"])?(\s+['"](.*?)["'])?/u
@@ -105,11 +98,11 @@
EREFERENCE = /&(?!#{NAME};)/
- DEFAULT_ENTITIES = {
- 'gt' => [/>/, '>', '>', />/],
- 'lt' => [/</, '<', '<', /</],
- 'quot' => [/"/, '"', '"', /"/],
- "apos" => [/'/, "'", "'", /'/]
+ DEFAULT_ENTITIES = {
+ 'gt' => [/>/, '>', '>', />/],
+ 'lt' => [/</, '<', '<', /</],
+ 'quot' => [/"/, '"', '"', /"/],
+ "apos" => [/'/, "'", "'", /'/]
}
@@ -180,9 +173,9 @@
# Peek at the +depth+ event in the stack. The first element on the stack
# is at depth 0. If +depth+ is -1, will parse to the end of the input
# stream and return the last event, which is always :end_document.
- # Be aware that this causes the stream to be parsed up to the +depth+
- # event, so you can effectively pre-parse the entire document (pull the
- # entire thing into memory) using this method.
+ # Be aware that this causes the stream to be parsed up to the +depth+
+ # event, so you can effectively pre-parse the entire document (pull the
+ # entire thing into memory) using this method.
def peek depth=0
raise %Q[Illegal argument "#{depth}"] if depth < -1
temp = []
@@ -265,7 +258,7 @@
if @document_status == :in_doctype
md = @source.match(/\s*(.*?>)/um)
case md[1]
- when SYSTEMENTITY
+ when SYSTEMENTITY
match = @source.match( SYSTEMENTITY, true )[1]
return [ :externalentity, match ]
@@ -344,7 +337,7 @@
#md = @source.match_to_consume( '>', CLOSE_MATCH)
md = @source.match( CLOSE_MATCH, true )
raise REXML::ParseException.new( "Missing end tag for "+
- "'#{last_tag}' (got \"#{md[1]}\")",
+ "'#{last_tag}' (got \"#{md[1]}\")",
@source) unless last_tag == md[1]
return [ :end_element, last_tag ]
elsif @source.buffer[1] == ?!
@@ -377,7 +370,7 @@
unless md
# Check for missing attribute quotes
raise REXML::ParseException.new("missing attribute quote", @source) if @source.match(MISSING_ATTRIBUTE_QUOTES )
- raise REXML::ParseException.new("malformed XML: missing tag start", @source)
+ raise REXML::ParseException.new("malformed XML: missing tag start", @source)
end
attributes = {}
prefixes = Set.new
@@ -386,7 +379,7 @@
if md[4].size > 0
attrs = md[4].scan( ATTRIBUTE_PATTERN )
raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0
- attrs.each { |a,b,c,d,e|
+ attrs.each { |a,b,c,d,e|
if b == "xmlns"
if c == "xml"
if d != "http://www.w3.org/XML/1998/namespace"
@@ -409,10 +402,10 @@
raise REXML::ParseException.new( msg, @source, self)
end
- attributes[a] = e
+ attributes[a] = e
}
end
-
+
# Verify that all of the prefixes have been defined
for prefix in prefixes
unless @nsstack.find{|k| k.member?(prefix)}
@@ -466,7 +459,7 @@
# Doing it like this rather than in a loop improves the speed
copy.gsub!( EREFERENCE, '&' )
entities.each do |key, value|
- copy.gsub!( value, "&#{key};" ) unless entity_filter and
+ copy.gsub!( value, "&#{key};" ) unless entity_filter and
entity_filter.include?(entity)
end if entities
copy.gsub!( EREFERENCE, '&' )
Modified: MacRuby/trunk/lib/rexml/parsers/pullparser.rb
===================================================================
--- MacRuby/trunk/lib/rexml/parsers/pullparser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/parsers/pullparser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -68,7 +68,7 @@
event = @parser.pull
case event[0]
when :entitydecl
- @entities[ event[1] ] =
+ @entities[ event[1] ] =
event[2] unless event[2] =~ /PUBLIC|SYSTEM/
when :text
unnormalized = @parser.unnormalize( event[1], @entities )
Modified: MacRuby/trunk/lib/rexml/parsers/sax2parser.rb
===================================================================
--- MacRuby/trunk/lib/rexml/parsers/sax2parser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/parsers/sax2parser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -20,7 +20,7 @@
def source
@parser.source
end
-
+
def add_listener( listener )
@parser.add_listener( listener )
end
@@ -44,7 +44,7 @@
# :entitydecl, :notationdecl, :cdata, :xmldecl, :comment
#
# There is an additional symbol that can be listened for: :progress.
- # This will be called for every event generated, passing in the current
+ # This will be called for every event generated, passing in the current
# stream position.
#
# Array contains regular expressions or strings which will be matched
@@ -72,7 +72,7 @@
add([nil, nil, args[0]])
end
end
-
+
def deafen( listener=nil, &blok )
if listener
@listeners.delete_if {|item| item[-1] == listener }
@@ -81,10 +81,10 @@
@procs.delete_if {|item| item[-1] == blok }
end
end
-
+
def parse
@procs.each { |sym,match,block| block.call if sym == :start_document }
- @listeners.each { |sym,match,block|
+ @listeners.each { |sym,match,block|
block.start_document if sym == :start_document or sym.nil?
}
root = context = []
@@ -126,8 +126,8 @@
listeners = get_listeners( :start_element, event[1] )
# notify observers
procs.each { |ob| ob.call( uri, local, event[1], event[2] ) } if procs
- listeners.each { |ob|
- ob.start_element( uri, local, event[1], event[2] )
+ listeners.each { |ob|
+ ob.start_element( uri, local, event[1], event[2] )
} if listeners
when :end_element
@tag_stack.pop
@@ -140,8 +140,8 @@
listeners = get_listeners( :end_element, event[1] )
# notify observers
procs.each { |ob| ob.call( uri, local, event[1] ) } if procs
- listeners.each { |ob|
- ob.end_element( uri, local, event[1] )
+ listeners.each { |ob|
+ ob.end_element( uri, local, event[1] )
} if listeners
namespace_mapping = @namespace_stack.pop
@@ -160,7 +160,7 @@
#handle( :characters, normalized )
copy = event[1].clone
- esub = proc { |match|
+ esub = proc { |match|
if @entities.has_key?($1)
@entities[$1].gsub(Text::REFERENCE, &esub)
else
@@ -178,7 +178,7 @@
when :entitydecl
@entities[ event[1] ] = event[2] if event.size == 3
handle( *event )
- when :processing_instruction, :comment, :attlistdecl,
+ when :processing_instruction, :comment, :attlistdecl,
:elementdecl, :cdata, :notationdecl, :xmldecl
handle( *event )
end
@@ -193,8 +193,8 @@
listeners = get_listeners( symbol, tag )
# notify observers
procs.each { |ob| ob.call( *arguments ) } if procs
- listeners.each { |l|
- l.send( symbol.to_s, *arguments )
+ listeners.each { |l|
+ l.send( symbol.to_s, *arguments )
} if listeners
end
@@ -205,7 +205,7 @@
@procs.find_all do |sym, match, block|
#puts sym.inspect+"=="+symbol.inspect+ "\t"+match.inspect+"=="+name.inspect+ "\t"+( (sym.nil? or symbol == sym) and ((name.nil? and match.nil?) or match.nil? or ( (name == match) or (match.kind_of? Regexp and name =~ match)))).to_s
(
- (sym.nil? or symbol == sym) and
+ (sym.nil? or symbol == sym) and
((name.nil? and match.nil?) or match.nil? or (
(name == match) or
(match.kind_of? Regexp and name =~ match)
@@ -218,7 +218,7 @@
return nil if @listeners.size == 0
@listeners.find_all do |sym, match, block|
(
- (sym.nil? or symbol == sym) and
+ (sym.nil? or symbol == sym) and
((name.nil? and match.nil?) or match.nil? or (
(name == match) or
(match.kind_of? Regexp and name =~ match)
@@ -237,7 +237,7 @@
end
end
- def get_namespace( prefix )
+ def get_namespace( prefix )
uris = (@namespace_stack.find_all { |ns| not ns[prefix].nil? }) ||
(@namespace_stack.find { |ns| not ns[nil].nil? })
uris[-1][prefix] unless uris.nil? or 0 == uris.size
Modified: MacRuby/trunk/lib/rexml/parsers/streamparser.rb
===================================================================
--- MacRuby/trunk/lib/rexml/parsers/streamparser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/parsers/streamparser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -5,11 +5,11 @@
@listener = listener
@parser = BaseParser.new( source )
end
-
+
def add_listener( listener )
@parser.add_listener( listener )
end
-
+
def parse
# entity string
while true
Modified: MacRuby/trunk/lib/rexml/parsers/treeparser.rb
===================================================================
--- MacRuby/trunk/lib/rexml/parsers/treeparser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/parsers/treeparser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -42,8 +42,8 @@
if @build_context[-1].instance_of? Text
@build_context[-1] << event[1]
else
- @build_context.add(
- Text.new(event[1], @build_context.whitespace, nil, true)
+ @build_context.add(
+ Text.new(event[1], @build_context.whitespace, nil, true)
) unless (
@build_context.ignore_whitespace_nodes and
event[1].strip.size==0
Modified: MacRuby/trunk/lib/rexml/parsers/xpathparser.rb
===================================================================
--- MacRuby/trunk/lib/rexml/parsers/xpathparser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/parsers/xpathparser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -53,8 +53,8 @@
string << "*"
when :text
string << "text()"
- when :following, :following_sibling,
- :ancestor, :ancestor_or_self, :descendant,
+ when :following, :following_sibling,
+ :ancestor, :ancestor_or_self, :descendant,
:namespace, :preceding, :preceding_sibling
string << "/" unless string.size == 0
string << op.to_s.tr("_", "-")
@@ -97,7 +97,7 @@
case op
when :node
string << "node()"
- when :attribute, :child, :following, :following_sibling,
+ when :attribute, :child, :following, :following_sibling,
:ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
:namespace, :preceding, :preceding_sibling, :self, :parent
string << "/" unless string.size == 0
@@ -249,7 +249,7 @@
parsed.concat(n)
end
-
+
if path.size > 0
if path[0] == ?/
if path[1] == ?/
@@ -332,12 +332,12 @@
predicates << expr[1..-2] if expr
end
#puts "PREDICATES = #{predicates.inspect}"
- predicates.each{ |pred|
+ predicates.each{ |pred|
#puts "ORING #{pred}"
preds = []
parsed << :predicate
parsed << preds
- OrExpr(pred, preds)
+ OrExpr(pred, preds)
}
#puts "PREDICATES = #{predicates.inspect}"
path
@@ -551,7 +551,7 @@
end
end
#puts "BEFORE WITH '#{rest}'"
- rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w_*]/
+ rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/
parsed.concat(n)
return rest
end
@@ -600,13 +600,13 @@
#puts "LITERAL or NUMBER: #$1"
varname = $1.nil? ? $2 : $1
path = $'
- parsed << :literal
+ parsed << :literal
parsed << (varname.include?('.') ? varname.to_f : varname.to_i)
when LITERAL
#puts "LITERAL or NUMBER: #$1"
varname = $1.nil? ? $2 : $1
path = $'
- parsed << :literal
+ parsed << :literal
parsed << varname
when /^\(/ #/
path, contents = get_group(path)
@@ -649,7 +649,7 @@
return nil unless depth==0
[string[ind..-1], string[0..ind-1]]
end
-
+
def parse_args( string )
arguments = []
ind = 0
@@ -683,7 +683,7 @@
s = string[0,ind].strip
arguments << s unless s == ""
string = string[ind+1..-1]
- ind = -1
+ ind = -1
end
end
end
Modified: MacRuby/trunk/lib/rexml/quickpath.rb
===================================================================
--- MacRuby/trunk/lib/rexml/quickpath.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/quickpath.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -68,7 +68,7 @@
ns = $1
rest = $'
elements.delete_if do |element|
- !(element.kind_of? Element and
+ !(element.kind_of? Element and
(element.expanded_name == name or
(element.name == name and
element.namespace == Functions.namespace_context[ns])))
@@ -135,16 +135,17 @@
matches = filter(elements.collect{|element| element.next_sibling}.uniq,
rest)
when "previous-sibling"
- matches = filter(elements.collect{|element|
+ matches = filter(elements.collect{|element|
element.previous_sibling}.uniq, rest )
end
return matches.uniq
end
+ OPERAND_ = '((?=(?:(?!and|or).)*[^\s<>=])[^\s<>=]+)'
# A predicate filters a node-set with respect to an axis to produce a
- # new node-set. For each node in the node-set to be filtered, the
- # PredicateExpr is evaluated with that node as the context node, with
- # the number of nodes in the node-set as the context size, and with the
+ # new node-set. For each node in the node-set to be filtered, the
+ # PredicateExpr is evaluated with that node as the context node, with
+ # the number of nodes in the node-set as the context size, and with the
# proximity position of the node in the node-set with respect to the
# axis as the context position; if PredicateExpr evaluates to true for
# that node, the node is included in the new node-set; otherwise, it is
@@ -157,7 +158,7 @@
# number, then the result will be converted as if by a call to the
# boolean function. Thus a location path para[3] is equivalent to
# para[position()=3].
- def QuickPath::predicate( elements, path )
+ def QuickPath::predicate( elements, path )
ind = 1
bcount = 1
while bcount > 0
@@ -170,18 +171,20 @@
rest = path[ind+1..-1]
# have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c'
- predicate.gsub!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/u,
+ #
+ predicate.gsub!(
+ /#{OPERAND_}\s*([<>=])\s*#{OPERAND_}\s*([<>=])\s*#{OPERAND_}/u,
'\1 \2 \3 and \3 \4 \5' )
# Let's do some Ruby trickery to avoid some work:
predicate.gsub!( /&/u, "&&" )
predicate.gsub!( /=/u, "==" )
- predicate.gsub!( /@(\w[-\w.]*)/u, 'attribute("\1")' )
+ predicate.gsub!( /@(\w[-\w.]*)/u, 'attribute("\1")' )
predicate.gsub!( /\bmod\b/u, "%" )
predicate.gsub!( /\b(\w[-\w.]*\()/u ) {
fname = $1
fname.gsub( /-/u, "_" )
}
-
+
Functions.pair = [ 0, elements.size ]
results = []
elements.each do |element|
Modified: MacRuby/trunk/lib/rexml/rexml.rb
===================================================================
--- MacRuby/trunk/lib/rexml/rexml.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/rexml.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -5,26 +5,26 @@
# non-validating[http://www.w3.org/TR/2004/REC-xml-20040204/#sec-conformance]
# toolkit with an intuitive API. REXML passes 100% of the non-validating Oasis
# tests[http://www.oasis-open.org/committees/xml-conformance/xml-test-suite.shtml],
-# and provides tree, stream, SAX2, pull, and lightweight APIs. REXML also
-# includes a full XPath[http://www.w3c.org/tr/xpath] 1.0 implementation. Since
+# and provides tree, stream, SAX2, pull, and lightweight APIs. REXML also
+# includes a full XPath[http://www.w3c.org/tr/xpath] 1.0 implementation. Since
# Ruby 1.8, REXML is included in the standard Ruby distribution.
#
# Main page:: http://www.germane-software.com/software/rexml
# Author:: Sean Russell <serATgermaneHYPHENsoftwareDOTcom>
# Date:: 2008/019
# Version:: 3.1.7.3
-#
+#
# This API documentation can be downloaded from the REXML home page, or can
# be accessed online[http://www.germane-software.com/software/rexml_doc]
#
# A tutorial is available in the REXML distribution in docs/tutorial.html,
-# or can be accessed
+# or can be accessed
# online[http://www.germane-software.com/software/rexml/docs/tutorial.html]
module REXML
COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser at germane-software.com>"
DATE = "2008/019"
VERSION = "3.1.7.3"
- REVISION = "$Revision: 15141 $".gsub(/\$Revision:|\$/,'').strip
+ REVISION = %w$Revision: 26193 $[1] || ''
Copyright = COPYRIGHT
Version = VERSION
Modified: MacRuby/trunk/lib/rexml/sax2listener.rb
===================================================================
--- MacRuby/trunk/lib/rexml/sax2listener.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/sax2listener.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,11 +1,11 @@
module REXML
# A template for stream parser listeners.
# Note that the declarations (attlistdecl, elementdecl, etc) are trivially
- # processed; REXML doesn't yet handle doctype entity declarations, so you
+ # processed; REXML doesn't yet handle doctype entity declarations, so you
# have to parse them out yourself.
# === Missing methods from SAX2
# ignorable_whitespace
- # === Methods extending SAX2
+ # === Methods extending SAX2
# +WARNING+
# These methods are certainly going to change, until DTDs are fully
# supported. Be aware of this.
@@ -58,7 +58,7 @@
# The argument passed to this method is an array of the entity
# declaration. It can be in a number of formats, but in general it
# returns (example, result):
- # <!ENTITY % YN '"Yes"'>
+ # <!ENTITY % YN '"Yes"'>
# ["%", "YN", "'\"Yes\"'", "\""]
# <!ENTITY % YN 'Yes'>
# ["%", "YN", "'Yes'", "s"]
@@ -93,5 +93,5 @@
end
def progress position
end
- end
+ end
end
Modified: MacRuby/trunk/lib/rexml/source.rb
===================================================================
--- MacRuby/trunk/lib/rexml/source.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/source.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -69,9 +69,9 @@
# usual scan() method. For one thing, the pattern argument has some
# requirements; for another, the source can be consumed. You can easily
# confuse this method. Originally, the patterns were easier
- # to construct and this method more robust, because this method
- # generated search regexes on the fly; however, this was
- # computationally expensive and slowed down the entire REXML package
+ # to construct and this method more robust, because this method
+ # generated search regexes on the fly; however, this was
+ # computationally expensive and slowed down the entire REXML package
# considerably, since this is by far the most commonly called method.
# @param pattern must be a Regexp, and must be in the form of
# /^\s*(#{your pattern, with no groups})(.*)/. The first group
@@ -162,6 +162,15 @@
@line_break = ">"
end
super( @source.eof? ? str : str+ at source.readline( @line_break ) )
+
+ if !@to_utf and
+ @buffer.respond_to?(:force_encoding) and
+ @source.respond_to?(:external_encoding) and
+ @source.external_encoding != ::Encoding::UTF_8
+ @force_utf8 = true
+ else
+ @force_utf8 = false
+ end
end
def scan(pattern, cons=false)
@@ -174,11 +183,7 @@
if rv.size == 0
until @buffer =~ pattern or @source.nil?
begin
- # READLINE OPT
- #str = @source.read(@block_size)
- str = @source.readline(@line_break)
- str = decode(str) if @to_utf and str
- @buffer << str
+ @buffer << readline
rescue Iconv::IllegalSequence
raise
rescue
@@ -193,12 +198,7 @@
def read
begin
- str = @source.readline(@line_break)
- str = decode(str) if @to_utf and str
- @buffer << str
- if not @to_utf and @buffer.respond_to? :force_encoding
- @buffer.force_encoding Encoding::UTF_8
- end
+ @buffer << readline
rescue Exception, NameError
@source = nil
end
@@ -213,9 +213,7 @@
@buffer = $' if cons and rv
while !rv and @source
begin
- str = @source.readline(@line_break)
- str = decode(str) if @to_utf and str
- @buffer << str
+ @buffer << readline
rv = pattern.match(@buffer)
@buffer = $' if cons and rv
rescue
@@ -225,7 +223,7 @@
rv.taint
rv
end
-
+
def empty?
super and ( @source.nil? || @source.eof? )
end
@@ -254,5 +252,18 @@
end
[pos, lineno, line]
end
+
+ private
+ def readline
+ str = @source.readline(@line_break)
+ return nil if str.nil?
+
+ if @to_utf
+ decode(str)
+ else
+ str.force_encoding(::Encoding::UTF_8) if @force_utf8
+ str
+ end
+ end
end
end
Modified: MacRuby/trunk/lib/rexml/streamlistener.rb
===================================================================
--- MacRuby/trunk/lib/rexml/streamlistener.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/streamlistener.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,14 +1,14 @@
module REXML
# A template for stream parser listeners.
# Note that the declarations (attlistdecl, elementdecl, etc) are trivially
- # processed; REXML doesn't yet handle doctype entity declarations, so you
+ # processed; REXML doesn't yet handle doctype entity declarations, so you
# have to parse them out yourself.
module StreamListener
# Called when a tag is encountered.
# @p name the tag name
# @p attrs an array of arrays of attribute/value pairs, suitable for
# use with assoc or rassoc. IE, <tag attr1="value1" attr2="value2">
- # will result in
+ # will result in
# tag_start( "tag", # [["attr1","value1"],["attr2","value2"]])
def tag_start name, attrs
end
@@ -56,7 +56,7 @@
# The argument passed to this method is an array of the entity
# declaration. It can be in a number of formats, but in general it
# returns (example, result):
- # <!ENTITY % YN '"Yes"'>
+ # <!ENTITY % YN '"Yes"'>
# ["%", "YN", "'\"Yes\"'", "\""]
# <!ENTITY % YN 'Yes'>
# ["%", "YN", "'Yes'", "s"]
Modified: MacRuby/trunk/lib/rexml/text.rb
===================================================================
--- MacRuby/trunk/lib/rexml/text.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/text.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -19,7 +19,7 @@
attr_accessor :raw
NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
- NUMERICENTITY = /�*((?:\d+)|(?:x[a-fA-F0-9]+));/
+ NUMERICENTITY = /�*((?:\d+)|(?:x[a-fA-F0-9]+));/
VALID_CHAR = [
0x9, 0xA, 0xD,
(0x20..0xD7FF),
@@ -50,25 +50,25 @@
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
- )*$/nx;
+ )*$/nx;
end
# Constructor
# +arg+ if a String, the content is set to the String. If a Text,
- # the object is shallowly cloned.
+ # the object is shallowly cloned.
#
# +respect_whitespace+ (boolean, false) if true, whitespace is
# respected
#
# +parent+ (nil) if this is a Parent object, the parent
- # will be set to this.
+ # will be set to this.
#
# +raw+ (nil) This argument can be given three values.
- # If true, then the value of used to construct this object is expected to
- # contain no unescaped XML markup, and REXML will not change the text. If
+ # If true, then the value of used to construct this object is expected to
+ # contain no unescaped XML markup, and REXML will not change the text. If
# this value is false, the string may contain any characters, and REXML will
# escape any and all defined entities whose values are contained in the
- # text. If this value is nil (the default), then the raw value of the
+ # text. If this value is nil (the default), then the raw value of the
# parent will be used as the raw value for this node. If there is no raw
# value for the parent, and no value is supplied, the default is false.
# Use this field if you have entities defined for some text, and you don't
@@ -88,17 +88,16 @@
# Text.new( "sean russell", false, nil, true, ["s"] ) #-> "sean russell"
# In the last example, the +entity_filter+ argument is ignored.
#
- # +pattern+ INTERNAL USE ONLY
- def initialize(arg, respect_whitespace=false, parent=nil, raw=nil,
+ # +illegal+ INTERNAL USE ONLY
+ def initialize(arg, respect_whitespace=false, parent=nil, raw=nil,
entity_filter=nil, illegal=NEEDS_A_SECOND_CHECK )
@raw = false
+ @parent = nil
if parent
super( parent )
- @raw = parent.raw
- else
- @parent = nil
+ @raw = parent.raw
end
@raw = raw unless raw.nil?
@@ -117,7 +116,7 @@
@string.gsub!( /\r\n?/, "\n" )
- Text.check(@string, NEEDS_A_SECOND_CHECK, doctype) if @raw and @parent
+ Text.check(@string, illegal, doctype) if @raw
end
def parent= parent
@@ -160,10 +159,11 @@
else
raise "Illegal character '#{$1}' in raw string \"#{string}\""
end
- elsif $3 and !SUBSTITUTES.include?($1)
- if !doctype or !doctype.entities.has_key?($3)
- raise "Undeclared entity '#{$1}' in raw string \"#{string}\""
- end
+ # FIXME: below can't work but this needs API change.
+ # elsif @parent and $3 and !SUBSTITUTES.include?($1)
+ # if !doctype or !doctype.entities.has_key?($3)
+ # raise "Undeclared entity '#{$1}' in raw string \"#{string}\""
+ # end
end
end
end
@@ -208,12 +208,12 @@
# escaped, meaning that it is a valid XML text node string, and all
# entities that can be escaped, have been inserted. This method respects
# the entity filter set in the constructor.
- #
- # # Assume that the entity "s" is defined to be "sean", and that the
+ #
+ # # Assume that the entity "s" is defined to be "sean", and that the
# # entity "r" is defined to be "russell"
- # t = Text.new( "< & sean russell", false, nil, false, ['s'] )
+ # t = Text.new( "< & sean russell", false, nil, false, ['s'] )
# t.to_s #-> "< & &s; russell"
- # t = Text.new( "< & &s; russell", false, nil, false )
+ # t = Text.new( "< & &s; russell", false, nil, false )
# t.to_s #-> "< & &s; russell"
# u = Text.new( "sean russell", false, nil, true )
# u.to_s #-> "sean russell"
@@ -233,9 +233,9 @@
# console. This ignores the 'raw' attribute setting, and any
# entity_filter.
#
- # # Assume that the entity "s" is defined to be "sean", and that the
+ # # Assume that the entity "s" is defined to be "sean", and that the
# # entity "r" is defined to be "russell"
- # t = Text.new( "< & sean russell", false, nil, false, ['s'] )
+ # t = Text.new( "< & sean russell", false, nil, false, ['s'] )
# t.value #-> "< & sean russell"
# t = Text.new( "< & &s; russell", false, nil, false )
# t.value #-> "< & sean russell"
@@ -246,7 +246,7 @@
@unnormalized = Text::unnormalize( @string, doctype )
end
- # Sets the contents of this text node. This expects the text to be
+ # Sets the contents of this text node. This expects the text to be
# unnormalized. It returns self.
#
# e = Element.new( "a" )
@@ -259,7 +259,7 @@
@normalized = nil
@raw = false
end
-
+
def wrap(string, width, addnewline=false)
# Recursively wrap string at width.
return string if string.length <= width
@@ -274,7 +274,7 @@
def indent_text(string, level=1, style="\t", indentfirstline=true)
return string if level < 0
new_string = ''
- string.each { |line|
+ string.each_line { |line|
indent_string = style * level
new_line = (indent_string + line).sub(/[\s]+$/,'')
new_string << new_line
@@ -282,11 +282,11 @@
new_string.strip! unless indentfirstline
return new_string
end
-
+
# == DEPRECATED
# See REXML::Formatters
#
- def write( writer, indent=-1, transitive=false, ie_hack=false )
+ def write( writer, indent=-1, transitive=false, ie_hack=false )
Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters")
formatter = if indent > -1
REXML::Formatters::Pretty.new( indent )
@@ -337,7 +337,7 @@
if copy =~ illegal
raise ParseException.new( "malformed text: Illegal character #$& in \"#{copy}\"" )
end if illegal
-
+
copy.gsub!( /\r\n?/, "\n" )
if copy.include? ?&
copy.gsub!( SETUTITSBUS[0], SLAICEPS[0] )
@@ -365,8 +365,8 @@
if doctype
# Replace all ampersands that aren't part of an entity
doctype.entities.each_value do |entity|
- copy = copy.gsub( entity.value,
- "&#{entity.name};" ) if entity.value and
+ copy = copy.gsub( entity.value,
+ "&#{entity.name};" ) if entity.value and
not( entity_filter and entity_filter.include?(entity) )
end
else
Modified: MacRuby/trunk/lib/rexml/validation/relaxng.rb
===================================================================
--- MacRuby/trunk/lib/rexml/validation/relaxng.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/validation/relaxng.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -79,7 +79,7 @@
when "mixed"
states << Interleave.new( self )
states[-2] << states[-1]
- states[-1] << TEXT
+ states[-1] << TEXT
when "define"
states << [ event[2]["name"] ]
when "ref"
@@ -102,7 +102,7 @@
case event[1]
when "element", "attribute"
states[-1] << event
- when "zeroOrMore", "oneOrMore", "choice", "optional",
+ when "zeroOrMore", "oneOrMore", "choice", "optional",
"interleave", "group", "mixed"
states.pop
when "define"
@@ -139,7 +139,7 @@
@events.each {|s| s.reset if s.kind_of? State }
end
- def previous=( previous )
+ def previous=( previous )
@previous << previous
end
@@ -183,7 +183,7 @@
end
def inspect
- "< #{to_s} #{@events.collect{|e|
+ "< #{to_s} #{@events.collect{|e|
pre = e == @events[@current] ? '#' : ''
pre + e.inspect unless self == e
}.join(', ')} >"
@@ -201,15 +201,15 @@
protected
def expand_ref_in( arry, ind )
new_events = []
- @references[ arry[ind].to_s ].each{ |evt|
+ @references[ arry[ind].to_s ].each{ |evt|
add_event_to_arry(new_events,evt)
}
arry[ind,1] = new_events
end
- def add_event_to_arry( arry, evt )
+ def add_event_to_arry( arry, evt )
evt = generate_event( evt )
- if evt.kind_of? String
+ if evt.kind_of? String
arry[-1].event_arg = evt if arry[-1].kind_of? Event and @value
@value = false
else
@@ -272,7 +272,7 @@
end
def matches?(event)
- @events[@current].matches?(event) ||
+ @events[@current].matches?(event) ||
(@current == 0 and @previous[-1].matches?(event))
end
@@ -319,7 +319,7 @@
end
def reset
- super
+ super
@ord = 0
end
@@ -345,7 +345,7 @@
end
def matches?( event )
- @events[@current].matches?(event) ||
+ @events[@current].matches?(event) ||
(@current == 0 and @ord > 0 and @previous[-1].matches?(event))
end
@@ -412,7 +412,7 @@
#puts "IN CHOICE EXPECTED"
#puts "EVENTS = #{@events.inspect}"
return [@events[@current]] if @events.size > 0
- return @choices.collect do |x|
+ return @choices.collect do |x|
if x[0].kind_of? State
x[0].expected
else
@@ -426,12 +426,12 @@
end
protected
- def add_event_to_arry( arry, evt )
+ def add_event_to_arry( arry, evt )
if evt.kind_of? State or evt.class == Ref
arry << [evt]
- elsif evt[0] == :text
+ elsif evt[0] == :text
if arry[-1] and
- arry[-1][-1].kind_of?( Event ) and
+ arry[-1][-1].kind_of?( Event ) and
arry[-1][-1].event_type == :text and @value
arry[-1][-1].event_arg = evt[1]
@@ -478,7 +478,7 @@
@choices[idx] = old
@choice += 1
end
-
+
#puts "In next with #{event.inspect}."
#puts "events is #{@events.inspect}"
@events = [] unless @events
@@ -490,7 +490,7 @@
next_current(event) unless @events[@current]
return nil unless @events[@current]
- expand_ref_in( @events, @current ) if @events[@current].class == Ref
+ expand_ref_in( @events, @current ) if @events[@current].class == Ref
#puts "In next with #{event.inspect}."
#puts "Next (#@current) is #{@events[@current]}"
if ( @events[@current].kind_of? State )
@@ -530,7 +530,7 @@
#puts "IN CHOICE EXPECTED"
#puts "EVENTS = #{@events.inspect}"
return [@events[@current]] if @events[@current]
- return @choices[@choice..-1].collect do |x|
+ return @choices[@choice..-1].collect do |x|
if x[0].kind_of? State
x[0].expected
else
Modified: MacRuby/trunk/lib/rexml/validation/validation.rb
===================================================================
--- MacRuby/trunk/lib/rexml/validation/validation.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/validation/validation.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -14,7 +14,7 @@
def dump
puts @root.inspect
end
- def validate( event )
+ def validate( event )
#puts "Current: #@current"
#puts "Event: #{event.inspect}"
@attr_stack = [] unless defined? @attr_stack
@@ -33,12 +33,12 @@
sattr = [:start_attribute, nil]
eattr = [:end_attribute]
text = [:text, nil]
- k,v = event[2].find { |key,value|
+ k,v = event[2].find { |key,value|
sattr[1] = key
#puts "Looking for #{sattr.inspect}"
m = @current.next( sattr )
#puts "Got #{m.inspect}"
- if m
+ if m
# If the state has text children...
#puts "Looking for #{eattr.inspect}"
#puts "Expect #{m.expected}"
Modified: MacRuby/trunk/lib/rexml/xmltokens.rb
===================================================================
--- MacRuby/trunk/lib/rexml/xmltokens.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/xmltokens.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -2,10 +2,10 @@
# Defines a number of tokens used for parsing XML. Not for general
# consumption.
module XMLTokens
- NCNAME_STR= '[\w:][\-\w\d.]*'
+ NCNAME_STR= '[\w:][\-\w.]*'
NAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
- NAMECHAR = '[\-\w\d\.:]'
+ NAMECHAR = '[\-\w\.:]'
NAME = "([\\w:]#{NAMECHAR}*)"
NMTOKEN = "(?:#{NAMECHAR})+"
NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*"
Modified: MacRuby/trunk/lib/rexml/xpath.rb
===================================================================
--- MacRuby/trunk/lib/rexml/xpath.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/xpath.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -64,7 +64,7 @@
parser.parse(path, element).each( &block )
end
- # Returns an array of nodes matching a given XPath.
+ # Returns an array of nodes matching a given XPath.
def XPath::match element, path=nil, namespaces=nil, variables={}
parser = XPathParser.new
parser.namespaces = namespaces
Modified: MacRuby/trunk/lib/rexml/xpath_parser.rb
===================================================================
--- MacRuby/trunk/lib/rexml/xpath_parser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rexml/xpath_parser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -88,7 +88,7 @@
case path[0]
when :document
- # do nothing
+ # do nothing
return first( path[1..-1], node )
when :child
for c in node.children
@@ -123,7 +123,7 @@
end
- def match( path_stack, nodeset )
+ def match( path_stack, nodeset )
#puts "MATCH: path_stack = #{path_stack.inspect}"
#puts "MATCH: nodeset = #{nodeset.inspect}"
r = expr( path_stack, nodeset )
@@ -136,7 +136,7 @@
# Returns a String namespace for a node, given a prefix
# The rules are:
- #
+ #
# 1. Use the supplied namespace mapping first.
# 2. If no mapping was supplied, use the context node to look up the namespace
def get_namespace( node, prefix )
@@ -187,8 +187,8 @@
#puts "node.namespace == #{ns.inspect} => #{node.namespace == ns}"
end
end
- !(node.node_type == :element and
- node.name == name and
+ !(node.node_type == :element and
+ node.name == name and
node.namespace == ns )
end
node_types = ELEMENTS
@@ -205,7 +205,7 @@
when :processing_instruction
target = path_stack.shift
nodeset.delete_if do |node|
- (node.node_type != :processing_instruction) or
+ (node.node_type != :processing_instruction) or
( target!='' and ( node.target != target ) )
end
@@ -231,7 +231,7 @@
when :literal
return path_stack.shift
-
+
when :attribute
new_nodeset = []
case path_stack.shift
@@ -481,23 +481,23 @@
when :function
func_name = path_stack.shift.tr('-','_')
arguments = path_stack.shift
- #puts "FUNCTION 0: #{func_name}(#{arguments.collect{|a|a.inspect}.join(', ')})"
+ #puts "FUNCTION 0: #{func_name}(#{arguments.collect{|a|a.inspect}.join(', ')})"
subcontext = context ? nil : { :size => nodeset.size }
res = []
cont = context
- nodeset.each_with_index { |n, i|
+ nodeset.each_with_index { |n, i|
if subcontext
subcontext[:node] = n
subcontext[:index] = i
cont = subcontext
end
arg_clone = arguments.dclone
- args = arg_clone.collect { |arg|
+ args = arg_clone.collect { |arg|
#puts "FUNCTION 1: Calling expr( #{arg.inspect}, [#{n.inspect}] )"
- expr( arg, [n], cont )
+ expr( arg, [n], cont )
}
- #puts "FUNCTION 2: #{func_name}(#{args.collect{|a|a.inspect}.join(', ')})"
+ #puts "FUNCTION 2: #{func_name}(#{args.collect{|a|a.inspect}.join(', ')})"
Functions.context = cont
res << Functions.send( func_name, *args )
#puts "FUNCTION 3: #{res[-1].inspect}"
@@ -515,10 +515,10 @@
# FIXME
# The next two methods are BAD MOJO!
# This is my achilles heel. If anybody thinks of a better
- # way of doing this, be my guest. This really sucks, but
+ # way of doing this, be my guest. This really sucks, but
# it is a wonder it works at all.
# ########################################################
-
+
def descendant_or_self( path_stack, nodeset )
rs = []
#puts "#"*80
@@ -547,7 +547,7 @@
# Reorders an array of nodes so that they are in document order
# It tries to do this efficiently.
#
- # FIXME: I need to get rid of this, but the issue is that most of the XPath
+ # FIXME: I need to get rid of this, but the issue is that most of the XPath
# interpreter functions as a filter, which means that we lose context going
# in and out of function calls. If I knew what the index of the nodes was,
# I wouldn't have to do this. Maybe add a document IDX for each node?
@@ -555,7 +555,7 @@
def document_order( array_of_nodes )
new_arry = []
array_of_nodes.each { |node|
- node_idx = []
+ node_idx = []
np = node.node_type == :attribute ? node.element : node
while np.parent and np.parent.node_type == :element
node_idx << np.parent.index( np )
@@ -579,7 +579,7 @@
# Builds a nodeset of all of the preceding nodes of the supplied node,
# in reverse document order
- # preceding:: includes every element in the document that precedes this node,
+ # preceding:: includes every element in the document that precedes this node,
# except for ancestors
def preceding( node )
#puts "IN PRECEDING"
@@ -609,9 +609,9 @@
#puts "NODE: #{node.inspect}"
#puts "PREVIOUS NODE: #{node.previous_sibling_node.inspect}"
#puts "PARENT NODE: #{node.parent}"
- psn = node.previous_sibling_node
+ psn = node.previous_sibling_node
if psn.nil?
- if node.parent.nil? or node.parent.class == Document
+ if node.parent.nil? or node.parent.class == Document
return nil
end
return node.parent
@@ -647,9 +647,9 @@
end
def next_sibling_node(node)
- psn = node.next_sibling_node
+ psn = node.next_sibling_node
while psn.nil?
- if node.parent.nil? or node.parent.class == Document
+ if node.parent.nil? or node.parent.class == Document
return nil
end
node = node.parent
Modified: MacRuby/trunk/lib/rinda/rinda.rb
===================================================================
--- MacRuby/trunk/lib/rinda/rinda.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rinda/rinda.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -58,7 +58,7 @@
##
# The number of elements in the tuple.
-
+
def size
@tuple.size
end
@@ -162,7 +162,7 @@
end
return true
end
-
+
##
# Alias for #match.
@@ -171,7 +171,7 @@
end
end
-
+
##
# <i>Documentation?</i>
@@ -184,7 +184,7 @@
@drb_uri = uri
@drb_ref = ref
end
-
+
##
# This DRbObjectTemplate matches +ro+ if the remote object's drburi and
# drbref are the same. +nil+ is used as a wildcard.
@@ -213,14 +213,14 @@
def initialize(ts)
@ts = ts
end
-
+
##
# Adds +tuple+ to the proxied TupleSpace. See TupleSpace#write.
def write(tuple, sec=nil)
@ts.write(tuple, sec)
end
-
+
##
# Takes +tuple+ from the proxied TupleSpace. See TupleSpace#take.
@@ -229,14 +229,14 @@
@ts.move(DRbObject.new(port), tuple, sec, &block)
port[0]
end
-
+
##
# Reads +tuple+ from the proxied TupleSpace. See TupleSpace#read.
def read(tuple, sec=nil, &block)
@ts.read(tuple, sec, &block)
end
-
+
##
# Reads all tuples matching +tuple+ from the proxied TupleSpace. See
# TupleSpace#read_all.
@@ -244,7 +244,7 @@
def read_all(tuple)
@ts.read_all(tuple)
end
-
+
##
# Registers for notifications of event +ev+ on the proxied TupleSpace.
# See TupleSpace#notify
Modified: MacRuby/trunk/lib/rinda/ring.rb
===================================================================
--- MacRuby/trunk/lib/rinda/ring.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rinda/ring.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -49,7 +49,7 @@
end
end
end
-
+
##
# Extracts the response URI from +msg+ and adds it to TupleSpace where it
# will be picked up by +reply_service+ for notification.
@@ -74,7 +74,7 @@
end
end
end
-
+
##
# Pulls lookup tuples out of the TupleSpace and sends their DRb object the
# address of the local TupleSpace.
@@ -104,7 +104,7 @@
# created RingFinger.
def self.finger
- unless @@finger
+ unless @@finger
@@finger = self.new
@@finger.lookup_ring_any
end
@@ -207,7 +207,7 @@
@rings.push(it)
end
end
-
+
@primary = queue.pop
raise('RingNotFound') if @primary.nil?
@primary
Modified: MacRuby/trunk/lib/rinda/tuplespace.rb
===================================================================
--- MacRuby/trunk/lib/rinda/tuplespace.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rinda/tuplespace.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -73,14 +73,14 @@
end
##
- # Reset the expiry time according to +sec_or_renewer+.
+ # Reset the expiry time according to +sec_or_renewer+.
#
# +nil+:: it is set to expire in the far future.
# +false+:: it has expired.
# Numeric:: it will expire in that many seconds.
#
# Otherwise the argument refers to some kind of renewer object
- # which will reset its expiry time.
+ # which will reset its expiry time.
def renew(sec_or_renewer)
sec, @renewer = get_renewer(sec_or_renewer)
@@ -168,7 +168,7 @@
def match(tuple)
@tuple.match(tuple)
end
-
+
alias === match
def make_tuple(ary) # :nodoc:
@@ -224,11 +224,11 @@
#
# ts = Rinda::TupleSpace.new
# observer = ts.notify 'write', [nil]
- #
+ #
# Thread.start do
# observer.each { |t| p t }
# end
- #
+ #
# 3.times { |i| ts.write [i] }
#
# Outputs:
@@ -276,7 +276,7 @@
it = pop
yield(it)
end
- rescue
+ rescue
ensure
cancel
end
@@ -295,16 +295,16 @@
def initialize
@bin = []
end
-
+
def add(tuple)
@bin.push(tuple)
end
-
+
def delete(tuple)
idx = @bin.rindex(tuple)
@bin.delete_at(idx) if idx
end
-
+
def find(&blk)
@bin.reverse_each do |x|
return x if yield(x)
Modified: MacRuby/trunk/lib/rss/0.9.rb
===================================================================
--- MacRuby/trunk/lib/rss/0.9.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/0.9.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -8,7 +8,7 @@
def self.append_features(klass)
super
-
+
klass.install_must_call_validator('', "")
end
end
@@ -123,7 +123,7 @@
def not_need_to_call_setup_maker_variables
%w(image textInput)
end
-
+
class SkipDays < Element
include RSS09
@@ -146,11 +146,11 @@
self.content = args[0]
end
end
-
+
end
-
+
end
-
+
class SkipHours < Element
include RSS09
@@ -174,13 +174,13 @@
end
end
end
-
+
end
-
+
class Image < Element
include RSS09
-
+
%w(url title link).each do |name|
install_text_element(name, "", nil)
end
@@ -239,9 +239,9 @@
end
end
end
-
+
class Item < Element
-
+
include RSS09
[
@@ -269,7 +269,7 @@
@enclosure.setup_maker(item) if @enclosure
@source.setup_maker(item) if @source
end
-
+
class Source < Element
include RSS09
@@ -279,7 +279,7 @@
].each do |name, uri, required|
install_get_attribute(name, uri, required)
end
-
+
content_setup
def initialize(*args)
@@ -341,7 +341,7 @@
class Category < Element
include RSS09
-
+
[
["domain", "", false]
].each do |name, uri, required|
@@ -369,11 +369,11 @@
category.domain = domain
category.content = content
end
-
+
end
end
-
+
class TextInput < Element
include RSS09
@@ -399,9 +399,9 @@
maker.textinput
end
end
-
+
end
-
+
end
RSS09::ELEMENTS.each do |name|
@@ -411,8 +411,8 @@
module ListenerMixin
private
def initial_start_rss(tag_name, prefix, attrs, ns)
- check_ns(tag_name, prefix, ns, "")
-
+ check_ns(tag_name, prefix, ns, "", false)
+
@rss = Rss.new(attrs['version'], @version, @encoding, @standalone)
@rss.do_validate = @do_validate
@rss.xml_stylesheets = @xml_stylesheets
@@ -422,7 +422,7 @@
end
@proc_stack.push(pr)
end
-
+
end
end
Modified: MacRuby/trunk/lib/rss/1.0.rb
===================================================================
--- MacRuby/trunk/lib/rss/1.0.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/1.0.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -8,7 +8,7 @@
def self.append_features(klass)
super
-
+
klass.install_must_call_validator('', ::RSS::URI)
end
@@ -64,13 +64,13 @@
URI
end
end
-
+
[
["resource", [URI, ""], true]
].each do |name, uri, required|
install_get_attribute(name, uri, required)
end
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -98,10 +98,10 @@
end
@tag_name = 'Seq'
-
+
install_have_children_element("li", URI, "*")
install_must_call_validator('rdf', ::RSS::RDF::URI)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -114,7 +114,7 @@
def full_name
tag_name_with_prefix(PREFIX)
end
-
+
def setup_maker(target)
lis.each do |li|
target << li.resource
@@ -135,10 +135,10 @@
end
@tag_name = 'Bag'
-
+
install_have_children_element("li", URI, "*")
install_must_call_validator('rdf', URI)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -151,7 +151,7 @@
def full_name
tag_name_with_prefix(PREFIX)
end
-
+
def setup_maker(target)
lis.each do |li|
target << li.resource
@@ -162,7 +162,7 @@
class Channel < Element
include RSS10
-
+
class << self
def required_uri
@@ -202,17 +202,17 @@
def maker_target(maker)
maker.channel
end
-
+
def setup_maker_attributes(channel)
channel.about = about
end
class Image < Element
-
+
include RSS10
class << self
-
+
def required_uri
::RSS::URI
end
@@ -225,7 +225,7 @@
install_get_attribute(name, uri, required, nil, nil,
"#{PREFIX}:#{name}")
end
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -237,11 +237,11 @@
end
class Textinput < Element
-
+
include RSS10
class << self
-
+
def required_uri
::RSS::URI
end
@@ -254,7 +254,7 @@
install_get_attribute(name, uri, required, nil, nil,
"#{PREFIX}:#{name}")
end
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -264,7 +264,7 @@
end
end
end
-
+
class Items < Element
include RSS10
@@ -272,16 +272,16 @@
Seq = ::RSS::RDF::Seq
class << self
-
+
def required_uri
::RSS::URI
end
-
+
end
install_have_child_element("Seq", URI, nil)
install_must_call_validator('rdf', URI)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -309,7 +309,7 @@
include RSS10
class << self
-
+
def required_uri
::RSS::URI
end
@@ -351,7 +351,7 @@
def required_uri
::RSS::URI
end
-
+
end
@@ -436,7 +436,7 @@
module ListenerMixin
private
def initial_start_RDF(tag_name, prefix, attrs, ns)
- check_ns(tag_name, prefix, ns, RDF::URI)
+ check_ns(tag_name, prefix, ns, RDF::URI, false)
@rss = RDF.new(@version, @encoding, @standalone)
@rss.do_validate = @do_validate
Modified: MacRuby/trunk/lib/rss/2.0.rb
===================================================================
--- MacRuby/trunk/lib/rss/2.0.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/2.0.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -29,7 +29,7 @@
Category = Item::Category
class Item
-
+
[
["comments", "?"],
["author", "?"],
@@ -57,9 +57,9 @@
_setup_maker_element(item)
@guid.setup_maker(item) if @guid
end
-
+
class Guid < Element
-
+
include RSS09
[
Modified: MacRuby/trunk/lib/rss/atom.rb
===================================================================
--- MacRuby/trunk/lib/rss/atom.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/atom.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -716,7 +716,7 @@
module ListenerMixin
private
def initial_start_feed(tag_name, prefix, attrs, ns)
- check_ns(tag_name, prefix, ns, Atom::URI)
+ check_ns(tag_name, prefix, ns, Atom::URI, false)
@rss = Atom::Feed.new(@version, @encoding, @standalone)
@rss.do_validate = @do_validate
@@ -731,7 +731,7 @@
end
def initial_start_entry(tag_name, prefix, attrs, ns)
- check_ns(tag_name, prefix, ns, Atom::URI)
+ check_ns(tag_name, prefix, ns, Atom::URI, false)
@rss = Atom::Entry.new(@version, @encoding, @standalone)
@rss.do_validate = @do_validate
Modified: MacRuby/trunk/lib/rss/content/1.0.rb
===================================================================
--- MacRuby/trunk/lib/rss/content/1.0.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/content/1.0.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,4 @@
require 'rss/1.0'
-require 'rss/content'
module RSS
RDF.install_ns(CONTENT_PREFIX, CONTENT_URI)
Modified: MacRuby/trunk/lib/rss/content/2.0.rb
===================================================================
--- MacRuby/trunk/lib/rss/content/2.0.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/content/2.0.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,4 @@
require "rss/2.0"
-require "rss/content"
module RSS
Rss.install_ns(CONTENT_PREFIX, CONTENT_URI)
Modified: MacRuby/trunk/lib/rss/converter.rb
===================================================================
--- MacRuby/trunk/lib/rss/converter.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/converter.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -3,7 +3,7 @@
module RSS
class Converter
-
+
include Utils
def initialize(to_enc, from_enc=nil)
@@ -63,11 +63,11 @@
raise UnknownConversionMethodError.new(to_enc, from_enc)
end
end
-
+
def def_else_enc(to_enc, from_enc)
def_iconv_convert(to_enc, from_enc, 0)
end
-
+
def def_same_enc()
def_convert do |value|
value
@@ -101,40 +101,40 @@
def def_to_euc_jp_from_utf_8
def_uconv_convert_if_can('u8toeuc', 'EUC-JP', 'UTF-8', '-We')
end
-
+
def def_to_utf_8_from_euc_jp
def_uconv_convert_if_can('euctou8', 'UTF-8', 'EUC-JP', '-Ew')
end
-
+
def def_to_shift_jis_from_utf_8
def_uconv_convert_if_can('u8tosjis', 'Shift_JIS', 'UTF-8', '-Ws')
end
-
+
def def_to_utf_8_from_shift_jis
def_uconv_convert_if_can('sjistou8', 'UTF-8', 'Shift_JIS', '-Sw')
end
-
+
def def_to_euc_jp_from_shift_jis
require "nkf"
def_convert do |value|
"NKF.nkf('-Se', #{value})"
end
end
-
+
def def_to_shift_jis_from_euc_jp
require "nkf"
def_convert do |value|
"NKF.nkf('-Es', #{value})"
end
end
-
+
def def_to_euc_jp_from_iso_2022_jp
require "nkf"
def_convert do |value|
"NKF.nkf('-Je', #{value})"
end
end
-
+
def def_to_iso_2022_jp_from_euc_jp
require "nkf"
def_convert do |value|
@@ -147,7 +147,7 @@
"#{value}.unpack('C*').pack('U*')"
end
end
-
+
def def_to_iso_8859_1_from_utf_8
def_convert do |value|
<<-EOC
@@ -164,7 +164,7 @@
EOC
end
end
-
+
end
-
+
end
Modified: MacRuby/trunk/lib/rss/dublincore/1.0.rb
===================================================================
--- MacRuby/trunk/lib/rss/dublincore/1.0.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/dublincore/1.0.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,4 @@
require "rss/1.0"
-require "rss/dublincore"
module RSS
RDF.install_ns(DC_PREFIX, DC_URI)
Modified: MacRuby/trunk/lib/rss/dublincore/2.0.rb
===================================================================
--- MacRuby/trunk/lib/rss/dublincore/2.0.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/dublincore/2.0.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,4 @@
require "rss/2.0"
-require "rss/dublincore"
module RSS
Rss.install_ns(DC_PREFIX, DC_URI)
Modified: MacRuby/trunk/lib/rss/dublincore/atom.rb
===================================================================
--- MacRuby/trunk/lib/rss/dublincore/atom.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/dublincore/atom.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,4 @@
require "rss/atom"
-require "rss/dublincore"
module RSS
module Atom
Modified: MacRuby/trunk/lib/rss/dublincore.rb
===================================================================
--- MacRuby/trunk/lib/rss/dublincore.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/dublincore.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -25,7 +25,7 @@
def #{full_name}
@#{full_name}.first and @#{full_name}.first.value
end
-
+
def #{full_name}=(new_value)
@#{full_name}[0] = Utils.new_with_value_if_need(#{klass_name}, new_value)
end
@@ -50,7 +50,7 @@
EOC
end
end
-
+
module DublinCoreModel
extend BaseModel
@@ -76,26 +76,26 @@
DATE_ELEMENTS = {
"date" => "w3cdtf",
}
-
+
ELEMENT_NAME_INFOS = DublinCoreModel::TEXT_ELEMENTS.to_a
DublinCoreModel::DATE_ELEMENTS.each do |name, |
ELEMENT_NAME_INFOS << [name, nil]
end
-
+
ELEMENTS = TEXT_ELEMENTS.keys + DATE_ELEMENTS.keys
ELEMENTS.each do |name, plural_name|
module_eval(<<-EOC, *get_file_and_line_from_caller(0))
class DublinCore#{Utils.to_class_name(name)} < Element
include RSS10
-
+
content_setup
class << self
def required_prefix
DC_PREFIX
end
-
+
def required_uri
DC_URI
end
@@ -105,7 +105,7 @@
alias_method(:value, :content)
alias_method(:value=, :content=)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -114,7 +114,7 @@
self.content = args[0]
end
end
-
+
def full_name
tag_name_with_prefix(DC_PREFIX)
end
Modified: MacRuby/trunk/lib/rss/image.rb
===================================================================
--- MacRuby/trunk/lib/rss/image.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/image.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -15,7 +15,7 @@
BaseListener.install_class_name(IMAGE_URI, name, "Image#{class_name}")
IMAGE_ELEMENTS << "#{IMAGE_PREFIX}_#{name}"
end
-
+
module ImageModelUtils
def validate_one_tag_name(ignore_unknown_element, name, tags)
if !ignore_unknown_element
@@ -25,7 +25,7 @@
raise TooMuchTagError.new(name, tag_name) if tags.size > 1
end
end
-
+
module ImageItemModel
include ImageModelUtils
extend BaseModel
@@ -43,12 +43,12 @@
include DublinCoreModel
@tag_name = "item"
-
+
class << self
def required_prefix
IMAGE_PREFIX
end
-
+
def required_uri
IMAGE_URI
end
@@ -102,11 +102,11 @@
end
end
end
-
+
module ImageFaviconModel
include ImageModelUtils
extend BaseModel
-
+
def self.append_features(klass)
super
@@ -122,12 +122,12 @@
include DublinCoreModel
@tag_name = "favicon"
-
+
class << self
def required_prefix
IMAGE_PREFIX
end
-
+
def required_uri
IMAGE_URI
end
@@ -154,7 +154,7 @@
end
set_size(new_value)
end
-
+
alias image_size= size=
alias image_size size
Modified: MacRuby/trunk/lib/rss/maker/0.9.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/0.9.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/0.9.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -4,14 +4,14 @@
module RSS
module Maker
-
+
class RSS09 < RSSBase
-
- def initialize(feed_version="0.92")
+
+ def initialize(feed_version)
super
@feed_type = "rss"
end
-
+
private
def make_feed
Rss.new(@feed_version, @version, @encoding, @standalone)
@@ -38,20 +38,20 @@
raise NotSetError.new("maker.channel", _not_set_required_variables)
end
end
-
+
private
def setup_items(rss)
@maker.items.to_feed(rss)
end
-
+
def setup_image(rss)
@maker.image.to_feed(rss)
end
-
+
def setup_textinput(rss)
@maker.textinput.to_feed(rss)
end
-
+
def variables
super + ["pubDate"]
end
@@ -78,7 +78,7 @@
end
end
end
-
+
class Day < DayBase
def to_feed(rss, days)
day = Rss::Channel::SkipDays::Day.new
@@ -96,7 +96,7 @@
end
end
end
-
+
class SkipHours < SkipHoursBase
def to_feed(rss, channel)
unless @hours.empty?
@@ -108,7 +108,7 @@
end
end
end
-
+
class Hour < HourBase
def to_feed(rss, hours)
hour = Rss::Channel::SkipHours::Hour.new
@@ -126,7 +126,7 @@
end
end
end
-
+
class Cloud < CloudBase
def to_feed(*args)
end
@@ -243,7 +243,7 @@
true
end
end
-
+
class Items < ItemsBase
def to_feed(rss)
if rss.channel
@@ -253,7 +253,7 @@
setup_other_elements(rss, rss.items)
end
end
-
+
class Item < ItemBase
def to_feed(rss)
item = Rss::Channel::Item.new
@@ -439,7 +439,7 @@
end
end
end
-
+
class Textinput < TextinputBase
def to_feed(rss)
textInput = Rss::Channel::TextInput.new
@@ -457,11 +457,52 @@
end
end
end
-
- add_maker("0.9", "0.92", RSS09)
- add_maker("0.91", "0.91", RSS09)
- add_maker("0.92", "0.92", RSS09)
- add_maker("rss0.91", "0.91", RSS09)
- add_maker("rss0.92", "0.92", RSS09)
+
+ class RSS091 < RSS09
+ def initialize(feed_version="0.91")
+ super
+ end
+
+ class Channel < RSS09::Channel
+ end
+
+ class Items < RSS09::Items
+ class Item < RSS09::Items::Item
+ end
+ end
+
+ class Image < RSS09::Image
+ end
+
+ class Textinput < RSS09::Textinput
+ end
+ end
+
+ class RSS092 < RSS09
+ def initialize(feed_version="0.92")
+ super
+ end
+
+ class Channel < RSS09::Channel
+ end
+
+ class Items < RSS09::Items
+ class Item < RSS09::Items::Item
+ end
+ end
+
+ class Image < RSS09::Image
+ end
+
+ class Textinput < RSS09::Textinput
+ end
+ end
+
+ add_maker("0.9", "0.92", RSS092)
+ add_maker("0.91", "0.91", RSS091)
+ add_maker("0.92", "0.92", RSS092)
+ add_maker("rss0.9", "0.92", RSS092)
+ add_maker("rss0.91", "0.91", RSS091)
+ add_maker("rss0.92", "0.92", RSS092)
end
end
Modified: MacRuby/trunk/lib/rss/maker/1.0.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/1.0.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/1.0.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -25,6 +25,7 @@
end
class Channel < ChannelBase
+ include SetupDefaultLanguage
def to_feed(rss)
set_default_values do
@@ -60,7 +61,7 @@
rss.channel.items = items
set_parent(rss.channel, items)
end
-
+
def setup_image(rss)
if @maker.image.have_required_values?
image = RDF::Channel::Image.new(@maker.image.url)
@@ -91,11 +92,11 @@
class SkipDays < SkipDaysBase
def to_feed(*args)
end
-
+
class Day < DayBase
end
end
-
+
class SkipHours < SkipHoursBase
def to_feed(*args)
end
@@ -103,7 +104,7 @@
class Hour < HourBase
end
end
-
+
class Cloud < CloudBase
def to_feed(*args)
end
@@ -403,7 +404,7 @@
end
end
end
-
+
class Textinput < TextinputBase
def to_feed(rss)
if @link
Modified: MacRuby/trunk/lib/rss/maker/2.0.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/2.0.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/2.0.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -4,9 +4,9 @@
module RSS
module Maker
-
+
class RSS20 < RSS09
-
+
def initialize(feed_version="2.0")
super
end
@@ -17,17 +17,17 @@
def required_variable_names
%w(link)
end
-
+
class SkipDays < RSS09::Channel::SkipDays
class Day < RSS09::Channel::SkipDays::Day
end
end
-
+
class SkipHours < RSS09::Channel::SkipHours
class Hour < RSS09::Channel::SkipHours::Hour
end
end
-
+
class Cloud < RSS09::Channel::Cloud
def to_feed(rss, channel)
cloud = Rss::Channel::Cloud.new
@@ -51,7 +51,7 @@
category.to_feed(rss, channel)
end
end
-
+
class Category < RSS09::Channel::Categories::Category
def to_feed(rss, channel)
category = Rss::Channel::Category.new
@@ -81,14 +81,14 @@
end
end
end
-
+
class Image < RSS09::Image
private
def required_element?
false
end
end
-
+
class Items < RSS09::Items
class Item < RSS09::Items::Item
private
@@ -179,7 +179,7 @@
category.to_feed(rss, item)
end
end
-
+
class Category < RSS09::Items::Item::Categories::Category
def to_feed(rss, item)
category = Rss::Channel::Item::Category.new
@@ -212,11 +212,11 @@
end
end
end
-
+
class Textinput < RSS09::Textinput
end
end
-
+
add_maker("2.0", "2.0", RSS20)
add_maker("rss2.0", "2.0", RSS20)
end
Modified: MacRuby/trunk/lib/rss/maker/base.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/base.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/base.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -238,7 +238,7 @@
setter = "#{var}="
if target.respond_to?(setter)
value = __send__(var)
- if value
+ unless value.nil?
target.__send__(setter, value)
set = true
end
@@ -358,7 +358,7 @@
:date => date,
:dc_dates => dc_dates.to_a.dup,
}
- _date = date
+ _date = _parse_date_if_needed(date)
if _date and !dc_dates.any? {|dc_date| dc_date.value == _date}
dc_date = self.class::DublinCoreDates::DublinCoreDate.new(self)
dc_date.value = _date.dup
@@ -370,12 +370,36 @@
date = keep[:date]
dc_dates.replace(keep[:dc_dates])
end
+
+ def _parse_date_if_needed(date_value)
+ date_value = Time.parse(date_value) if date_value.is_a?(String)
+ date_value
+ end
end
+ module SetupDefaultLanguage
+ private
+ def _set_default_values(&block)
+ keep = {
+ :dc_languages => dc_languages.to_a.dup,
+ }
+ _language = language
+ if _language and
+ !dc_languages.any? {|dc_language| dc_language.value == _language}
+ dc_language = self.class::DublinCoreLanguages::DublinCoreLanguage.new(self)
+ dc_language.value = _language.dup
+ dc_languages.unshift(dc_language)
+ end
+ super(&block)
+ ensure
+ dc_languages.replace(keep[:dc_languages])
+ end
+ end
+
class RSSBase < Base
class << self
- def make(version, &block)
- new(version).make(&block)
+ def make(*args, &block)
+ new(*args).make(&block)
end
end
@@ -384,7 +408,7 @@
add_need_initialize_variable(element) do |object|
object.send("make_#{element}")
end
- module_eval(<<-EOC, __FILE__, __LINE__)
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
private
def setup_#{element}(feed)
@#{element}.to_feed(feed)
@@ -395,7 +419,7 @@
end
EOC
end
-
+
attr_reader :feed_version
alias_method(:rss_version, :feed_version)
attr_accessor :version, :encoding, :standalone
@@ -409,7 +433,7 @@
@encoding = "UTF-8"
@standalone = nil
end
-
+
def make
yield(self)
to_feed
@@ -423,7 +447,7 @@
feed.validate
feed
end
-
+
private
remove_method :make_xml_stylesheets
def make_xml_stylesheets
@@ -440,7 +464,7 @@
attr_accessor attribute
add_need_initialize_variable(attribute)
end
-
+
def to_feed(feed)
xss = ::RSS::XMLStyleSheet.new
guess_type_if_need(xss)
@@ -463,7 +487,7 @@
end
end
end
-
+
class ChannelBase < Base
include SetupDefaultDate
@@ -484,12 +508,24 @@
end
%w(id about language
- managingEditor webMaster rating docs date
- lastBuildDate ttl).each do |element|
+ managingEditor webMaster rating docs ttl).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
+ %w(date lastBuildDate).each do |date_element|
+ attr_reader date_element
+ add_need_initialize_variable(date_element)
+ end
+
+ def date=(_date)
+ @date = _parse_date_if_needed(_date)
+ end
+
+ def lastBuildDate=(_date)
+ @lastBuildDate = _parse_date_if_needed(_date)
+ end
+
def pubDate
date
end
@@ -538,7 +574,7 @@
end
end
end
-
+
class SkipHoursBase < Base
def_array_element("hour")
@@ -549,7 +585,7 @@
end
end
end
-
+
class CloudBase < Base
%w(domain port path registerProcedure protocol).each do |element|
attr_accessor element
@@ -619,7 +655,7 @@
include AtomTextConstructBase
end
end
-
+
class ImageBase < Base
%w(title url width height description).each do |element|
attr_accessor element
@@ -630,18 +666,18 @@
@maker.channel.link
end
end
-
+
class ItemsBase < Base
def_array_element("item")
attr_accessor :do_sort, :max_size
-
+
def initialize(maker)
super
@do_sort = false
@max_size = -1
end
-
+
def normalize
if @max_size >= 0
sort_if_need[0... at max_size]
@@ -684,11 +720,20 @@
def_classed_elements(name, attribute)
end
- %w(date comments id published).each do |element|
+ %w(comments id published).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
+ %w(date).each do |date_element|
+ attr_reader date_element
+ add_need_initialize_variable(date_element)
+ end
+
+ def date=(_date)
+ @date = _parse_date_if_needed(_date)
+ end
+
def pubDate
date
end
@@ -727,6 +772,14 @@
attr_accessor element
add_need_initialize_variable(element)
end
+
+ def permanent_link?
+ isPermaLink
+ end
+
+ def permanent_link=(bool)
+ self.isPermaLink = bool
+ end
end
class EnclosureBase < Base
@@ -737,6 +790,8 @@
end
class SourceBase < Base
+ include SetupDefaultDate
+
%w(authors categories contributors generator icon
logo rights subtitle title).each do |name|
def_classed_element(name)
@@ -748,7 +803,7 @@
def_classed_elements(name, attribute)
end
- %w(id content date).each do |element|
+ %w(id content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
@@ -756,6 +811,15 @@
alias_method(:url, :link)
alias_method(:url=, :link=)
+ %w(date).each do |date_element|
+ attr_reader date_element
+ add_need_initialize_variable(date_element)
+ end
+
+ def date=(_date)
+ @date = _parse_date_if_needed(_date)
+ end
+
def updated
date
end
Modified: MacRuby/trunk/lib/rss/maker/dublincore.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/dublincore.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/dublincore.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -90,7 +90,7 @@
class ChannelBase
include DublinCoreModel
end
-
+
class ImageBase; include DublinCoreModel; end
class ItemsBase
class ItemBase
Modified: MacRuby/trunk/lib/rss/maker/entry.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/entry.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/entry.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -135,7 +135,7 @@
self.id = keep[:id]
@rights = keep[:rights]
@title = keep[:title]
- self.updated = keep[:prev_updated]
+ self.updated = keep[:updated]
end
Guid = Feed::Items::Item::Guid
Modified: MacRuby/trunk/lib/rss/maker/feed.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/feed.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/feed.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -22,6 +22,8 @@
end
class Channel < ChannelBase
+ include SetupDefaultLanguage
+
def to_feed(feed)
set_default_values do
setup_values(feed)
@@ -71,14 +73,11 @@
def _set_default_values(&block)
keep = {
:id => id,
- :updated => updated,
}
self.id ||= about
- self.updated ||= dc_date
super(&block)
ensure
self.id = keep[:id]
- self.updated = keep[:updated]
end
class SkipDays < SkipDaysBase
@@ -182,6 +181,7 @@
set_default_values do
entry = feed.class::Entry.new
set = setup_values(entry)
+ entry.dc_dates.clear
setup_other_elements(feed, entry)
if set
feed.entries << entry
@@ -216,14 +216,11 @@
def _set_default_values(&block)
keep = {
:id => id,
- :updated => updated,
}
self.id ||= link
- self.updated ||= dc_date
super(&block)
ensure
self.id = keep[:id]
- self.updated = keep[:updated]
end
class Guid < GuidBase
Modified: MacRuby/trunk/lib/rss/maker/image.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/image.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/image.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -89,7 +89,7 @@
end
class ChannelBase; include Maker::ImageFaviconModel; end
-
+
class ItemsBase
class ItemBase; include Maker::ImageItemModel; end
end
Modified: MacRuby/trunk/lib/rss/maker/taxonomy.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/taxonomy.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/taxonomy.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -72,12 +72,12 @@
class TaxonomyTopicBase < Base
include DublinCoreModel
include TaxonomyTopicsModel
-
+
attr_accessor :value
add_need_initialize_variable("value")
alias_method(:taxo_link, :value)
alias_method(:taxo_link=, :value=)
-
+
def have_required_values?
@value
end
@@ -88,11 +88,11 @@
class RSSBase
include TaxonomyTopicModel
end
-
+
class ChannelBase
include TaxonomyTopicsModel
end
-
+
class ItemsBase
class ItemBase
include TaxonomyTopicsModel
Modified: MacRuby/trunk/lib/rss/maker/trackback.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker/trackback.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker/trackback.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -19,7 +19,7 @@
class TrackBackAboutBase < Base
attr_accessor :value
add_need_initialize_variable("value")
-
+
alias_method(:resource, :value)
alias_method(:resource=, :value=)
alias_method(:content, :value)
Modified: MacRuby/trunk/lib/rss/maker.rb
===================================================================
--- MacRuby/trunk/lib/rss/maker.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/maker.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -6,13 +6,13 @@
class << self
def make(version, &block)
- m = maker(version)
- raise UnsupportedMakerVersionError.new(version) if m.nil?
- m[:maker].make(m[:version], &block)
+ self[version].make(&block)
end
- def maker(version)
- MAKERS[version]
+ def [](version)
+ maker_info = maker(version)
+ raise UnsupportedMakerVersionError.new(version) if maker_info.nil?
+ maker_info[:maker]
end
def add_maker(version, normalized_version, maker)
@@ -26,6 +26,16 @@
def makers
MAKERS.values.collect {|info| info[:maker]}.uniq
end
+
+ def supported?(version)
+ versions.include?(version)
+ end
+
+ private
+ # Can I remove this method?
+ def maker(version)
+ MAKERS[version]
+ end
end
end
end
Modified: MacRuby/trunk/lib/rss/parser.rb
===================================================================
--- MacRuby/trunk/lib/rss/parser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/parser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -98,7 +98,7 @@
return rss if maybe_xml?(rss)
uri = to_uri(rss)
-
+
if uri.respond_to?(:read)
uri.read
elsif !rss.tainted? and File.readable?(rss)
@@ -133,7 +133,7 @@
listener.raise_for_undefined_entity?
end
end
-
+
def initialize(rss)
@listener = self.class.listener.new
@rss = rss
@@ -196,13 +196,13 @@
def available_tags(uri)
(@@accessor_bases[uri] || {}).keys
end
-
+
# register uri against this name.
def register_uri(uri, name)
@@registered_uris[name] ||= {}
@@registered_uris[name][uri] = nil
end
-
+
# test if this uri is registered against this name
def uri_registered?(uri, name)
@@registered_uris[name].has_key?(uri)
@@ -228,11 +228,11 @@
install_accessor_base(uri, name, accessor_base)
def_get_text_element(uri, name, *get_file_and_line_from_caller(1))
end
-
+
def raise_for_undefined_entity?
true
end
-
+
private
# set the accessor for the uri, tag_name pair
def install_accessor_base(uri, tag_name, accessor_base)
@@ -279,7 +279,7 @@
@xml_element = nil
@last_xml_element = nil
end
-
+
# set instance vars for version, encoding, standalone
def xmldecl(version, encoding, standalone)
@version, @encoding, @standalone = version, encoding, standalone
@@ -392,7 +392,7 @@
start_have_something_element(local, prefix, attrs, ns, next_class)
else
if !@do_validate or @ignore_unknown_element
- @proc_stack.push(nil)
+ @proc_stack.push(setup_next_element_in_unknown_element)
else
parent = "ROOT ELEMENT???"
if current_class.tag_name
@@ -417,19 +417,28 @@
end
end
- NAMESPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/
+ NAMESPLIT = /^(?:([\w:][-\w.]*):)?([\w:][-\w.]*)/
def split_name(name)
name =~ NAMESPLIT
[$1 || '', $2]
end
- def check_ns(tag_name, prefix, ns, require_uri)
- unless _ns(ns, prefix) == require_uri
- if @do_validate
+ def check_ns(tag_name, prefix, ns, require_uri, ignore_unknown_element=nil)
+ if _ns(ns, prefix) == require_uri
+ true
+ else
+ if ignore_unknown_element.nil?
+ ignore_unknown_element = @ignore_unknown_element
+ end
+
+ if ignore_unknown_element
+ false
+ elsif @do_validate
raise NSError.new(tag_name, prefix, require_uri)
else
# Force bind required URI with prefix
@ns_stack.last[prefix] = require_uri
+ true
end
end
end
@@ -437,7 +446,7 @@
def start_get_text_element(tag_name, prefix, ns, required_uri)
pr = Proc.new do |text, tags|
setter = self.class.setter(required_uri, tag_name)
- if @last_element.respond_to?(setter)
+ if setter and @last_element.respond_to?(setter)
if @do_validate
getter = self.class.getter(required_uri, tag_name)
if @last_element.__send__(getter)
@@ -456,9 +465,12 @@
end
def start_have_something_element(tag_name, prefix, attrs, ns, klass)
- check_ns(tag_name, prefix, ns, klass.required_uri)
- attributes = collect_attributes(tag_name, prefix, attrs, ns, klass)
- @proc_stack.push(setup_next_element(tag_name, klass, attributes))
+ if check_ns(tag_name, prefix, ns, klass.required_uri)
+ attributes = collect_attributes(tag_name, prefix, attrs, ns, klass)
+ @proc_stack.push(setup_next_element(tag_name, klass, attributes))
+ else
+ @proc_stack.push(setup_next_element_in_unknown_element)
+ end
end
def collect_attributes(tag_name, prefix, attrs, ns, klass)
@@ -525,6 +537,11 @@
@last_element = previous
end
end
+
+ def setup_next_element_in_unknown_element
+ current_element, @last_element = @last_element, nil
+ Proc.new {@last_element = current_element}
+ end
end
unless const_defined? :AVAILABLE_PARSER_LIBRARIES
Modified: MacRuby/trunk/lib/rss/rexmlparser.rb
===================================================================
--- MacRuby/trunk/lib/rss/rexmlparser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/rexmlparser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -7,7 +7,7 @@
end
module RSS
-
+
class REXMLParser < BaseParser
class << self
@@ -15,7 +15,7 @@
REXMLListener
end
end
-
+
private
def _parse
begin
@@ -28,9 +28,9 @@
raise NotWellFormedError.new(line){e.message}
end
end
-
+
end
-
+
class REXMLListener < BaseListener
include REXML::StreamListener
@@ -41,7 +41,7 @@
false
end
end
-
+
def xmldecl(version, encoding, standalone)
super(version, encoding, standalone == "yes")
# Encoding is converted to UTF-8 when REXML parse XML.
Modified: MacRuby/trunk/lib/rss/rss.rb
===================================================================
--- MacRuby/trunk/lib/rss/rss.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/rss.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -53,7 +53,7 @@
module RSS
- VERSION = "0.2.5"
+ VERSION = "0.2.7"
URI = "http://purl.org/rss/1.0/"
@@ -249,7 +249,7 @@
# accessor
convert_attr_reader name
date_writer(name, type, disp_name)
-
+
install_element(name) do |n, elem_name|
<<-EOC
if @#{n}
@@ -634,7 +634,7 @@
include SetupMaker
INDENT = " "
-
+
MUST_CALL_VALIDATORS = {}
MODELS = []
GET_ATTRIBUTES = []
@@ -830,7 +830,7 @@
def full_name
tag_name
end
-
+
def converter=(converter)
@converter = converter
targets = children.dup
@@ -865,7 +865,7 @@
ensure
@do_validate = do_validate
end
-
+
def validate_for_stream(tags, ignore_unknown_element=true)
validate_attribute
__validate(ignore_unknown_element, tags, false)
@@ -985,7 +985,7 @@
end_tag = "\n#{indent}</#{full_name}>"
end
end
-
+
start_tag + content.join("\n") + end_tag
end
@@ -1010,7 +1010,7 @@
end
attrs
end
-
+
def tag_name_with_prefix(prefix)
"#{prefix}:#{tag_name}"
end
@@ -1210,7 +1210,7 @@
module RootElementMixin
include XMLStyleSheetMixin
-
+
attr_reader :output_encoding
attr_reader :feed_type, :feed_subtype, :feed_version
attr_accessor :version, :encoding, :standalone
@@ -1296,7 +1296,7 @@
rv << "?>\n"
rv
end
-
+
def ns_declarations
decls = {}
self.class::NSPOOL.collect do |prefix, uri|
Modified: MacRuby/trunk/lib/rss/syndication.rb
===================================================================
--- MacRuby/trunk/lib/rss/syndication.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/syndication.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -8,11 +8,11 @@
RDF.install_ns(SY_PREFIX, SY_URI)
module SyndicationModel
-
+
extend BaseModel
-
+
ELEMENTS = []
-
+
def self.append_features(klass)
super
Modified: MacRuby/trunk/lib/rss/taxonomy.rb
===================================================================
--- MacRuby/trunk/lib/rss/taxonomy.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/taxonomy.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -24,7 +24,7 @@
module TaxonomyTopicsModel
extend BaseModel
-
+
def self.append_features(klass)
super
@@ -37,21 +37,21 @@
class TaxonomyTopics < Element
include RSS10
-
+
Bag = ::RSS::RDF::Bag
class << self
def required_prefix
TAXO_PREFIX
end
-
+
def required_uri
TAXO_URI
end
end
@tag_name = "topics"
-
+
install_have_child_element("Bag", RDF::URI, nil)
install_must_call_validator('rdf', RDF::URI)
@@ -84,10 +84,10 @@
end
end
end
-
+
module TaxonomyTopicModel
extend BaseModel
-
+
def self.append_features(klass)
super
var_name = "#{TAXO_PREFIX}_topic"
@@ -99,12 +99,12 @@
include DublinCoreModel
include TaxonomyTopicsModel
-
+
class << self
def required_prefix
TAXO_PREFIX
end
-
+
def required_uri
TAXO_URI
end
@@ -115,7 +115,7 @@
install_get_attribute("about", ::RSS::RDF::URI, true, nil, nil,
"#{RDF::PREFIX}:about")
install_text_element("link", TAXO_URI, "?", "#{TAXO_PREFIX}_link")
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
Modified: MacRuby/trunk/lib/rss/trackback.rb
===================================================================
--- MacRuby/trunk/lib/rss/trackback.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/trackback.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -23,7 +23,7 @@
module BaseTrackBackModel
ELEMENTS = %w(ping about)
-
+
def append_features(klass)
super
@@ -47,7 +47,7 @@
end
EOC
end
-
+
[%w(about s)].each do |name, postfix|
var_name = "#{TRACKBACK_PREFIX}_#{name}"
klass_name = "TrackBack#{Utils.to_class_name(name)}"
@@ -105,7 +105,7 @@
def required_prefix
TRACKBACK_PREFIX
end
-
+
def required_uri
TRACKBACK_URI
end
@@ -141,17 +141,17 @@
include RSS10
class << self
-
+
def required_prefix
TRACKBACK_PREFIX
end
-
+
def required_uri
TRACKBACK_URI
end
end
-
+
@tag_name = "about"
[
@@ -163,7 +163,7 @@
alias_method(:value, :resource)
alias_method(:value=, :resource=)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -185,7 +185,7 @@
def setup_maker_attributes(about)
about.resource = self.resource
end
-
+
end
end
@@ -197,7 +197,7 @@
include RSS09
@tag_name = "ping"
-
+
content_setup
class << self
@@ -205,13 +205,13 @@
def required_prefix
TRACKBACK_PREFIX
end
-
+
def required_uri
TRACKBACK_URI
end
end
-
+
alias_method(:value, :content)
alias_method(:value=, :content=)
@@ -223,26 +223,26 @@
self.content = args[0]
end
end
-
+
def full_name
tag_name_with_prefix(TRACKBACK_PREFIX)
end
-
+
end
class TrackBackAbout < Element
include RSS09
@tag_name = "about"
-
+
content_setup
class << self
-
+
def required_prefix
TRACKBACK_PREFIX
end
-
+
def required_uri
TRACKBACK_URI
end
@@ -260,11 +260,11 @@
self.content = args[0]
end
end
-
+
def full_name
tag_name_with_prefix(TRACKBACK_PREFIX)
end
-
+
end
end
Modified: MacRuby/trunk/lib/rss/utils.rb
===================================================================
--- MacRuby/trunk/lib/rss/utils.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/utils.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -8,11 +8,9 @@
"#{part[0, 1].upcase}#{part[1..-1]}"
end.join("")
end
-
+
def get_file_and_line_from_caller(i=0)
- bt = caller
- i = bt.size - 1 if i >= bt.size
- file, line, = bt[i].split(':')
+ file, line, = caller[i].split(':')
line = line.to_i
line += 1 if i.zero?
[file, line]
@@ -23,7 +21,7 @@
s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<")
end
alias h html_escape
-
+
# If +value+ is an instance of class +klass+, return it, else
# create a new instance of +klass+ with value +value+.
def new_with_value_if_need(klass, value)
Modified: MacRuby/trunk/lib/rss/xml-stylesheet.rb
===================================================================
--- MacRuby/trunk/lib/rss/xml-stylesheet.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/xml-stylesheet.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -8,7 +8,7 @@
super
@xml_stylesheets = []
end
-
+
private
def xml_stylesheet_pi
xsss = @xml_stylesheets.collect do |xss|
@@ -94,7 +94,7 @@
xss.__send__("#{attr}=", __send__(attr))
end
end
-
+
private
def guess_type(filename)
/\.([^.]+)$/ =~ filename
Modified: MacRuby/trunk/lib/rss/xmlparser.rb
===================================================================
--- MacRuby/trunk/lib/rss/xmlparser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/xmlparser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -26,9 +26,9 @@
end
module RSS
-
+
class REXMLLikeXMLParser < ::XML::Parser
-
+
include ::XML::Encoding_ja
def listener=(listener)
@@ -38,7 +38,7 @@
def startElement(name, attrs)
@listener.tag_start(name, attrs)
end
-
+
def endElement(name)
@listener.tag_end(name)
end
@@ -64,7 +64,7 @@
XMLParserListener
end
end
-
+
private
def _parse
begin
@@ -75,13 +75,13 @@
raise NotWellFormedError.new(parser.line){e.message}
end
end
-
+
end
-
+
class XMLParserListener < BaseListener
include ListenerMixin
-
+
def xmldecl(version, encoding, standalone)
super
# Encoding is converted to UTF-8 when XMLParser parses XML.
Modified: MacRuby/trunk/lib/rss/xmlscanner.rb
===================================================================
--- MacRuby/trunk/lib/rss/xmlscanner.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/rss/xmlscanner.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -2,15 +2,15 @@
require 'stringio'
module RSS
-
+
class XMLScanParser < BaseParser
-
+
class << self
def listener
XMLScanListener
end
end
-
+
private
def _parse
begin
@@ -26,11 +26,11 @@
raise NotWellFormedError.new(lineno){e.message}
end
end
-
+
end
class XMLScanListener < BaseListener
-
+
include XMLScan::Visitor
include ListenerMixin
Modified: MacRuby/trunk/lib/securerandom.rb
===================================================================
--- MacRuby/trunk/lib/securerandom.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/securerandom.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -46,6 +46,11 @@
# If n is not specified, 16 is assumed.
# It may be larger in future.
#
+ # The result may contain any byte: "\x00" - "\xff".
+ #
+ # p SecureRandom.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6"
+ # p SecureRandom.random_bytes #=> "m\xDC\xFC/\a\x00Uf\xB2\xB2P\xBD\xFF6S\x97"
+ #
# If secure random number generator is not available,
# NotImplementedError is raised.
def self.random_bytes(n=nil)
@@ -59,7 +64,6 @@
flags = File::RDONLY
flags |= File::NONBLOCK if defined? File::NONBLOCK
flags |= File::NOCTTY if defined? File::NOCTTY
- flags |= File::NOFOLLOW if defined? File::NOFOLLOW
begin
File.open("/dev/urandom", flags) {|f|
unless f.stat.chardev?
@@ -99,7 +103,7 @@
end
end
if @has_win32
- bytes = " " * n
+ bytes = " ".force_encoding("ASCII-8BIT") * n
if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
raise SystemCallError, "CryptGenRandom failed: #{lastWin32ErrorMessage}"
end
@@ -117,6 +121,11 @@
# If n is not specified, 16 is assumed.
# It may be larger in future.
#
+ # The result may contain 0-9 and a-f.
+ #
+ # p SecureRandom.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"
+ # p SecureRandom.hex #=> "91dc3bfb4de5b11d029d376634589b61"
+ #
# If secure random number generator is not available,
# NotImplementedError is raised.
def self.hex(n=nil)
@@ -131,21 +140,69 @@
# If n is not specified, 16 is assumed.
# It may be larger in future.
#
+ # The result may contain A-Z, a-z, 0-9, "+", "/" and "=".
+ #
+ # p SecureRandom.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A=="
+ # p SecureRandom.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
+ #
# If secure random number generator is not available,
# NotImplementedError is raised.
+ #
+ # See RFC 3548 for base64.
def self.base64(n=nil)
[random_bytes(n)].pack("m*").delete("\n")
end
+ # SecureRandom.urlsafe_base64 generates a random URL-safe base64 string.
+ #
+ # The argument _n_ specifies the length of the random length.
+ # The length of the result string is about 4/3 of _n_.
+ #
+ # If _n_ is not specified, 16 is assumed.
+ # It may be larger in future.
+ #
+ # The boolean argument _padding_ specifies the padding.
+ # If it is false or nil, padding is not generated.
+ # Otherwise padding is generated.
+ # By default, padding is not generated because "=" may be used as a URL delimiter.
+ #
+ # The result may contain A-Z, a-z, 0-9, "-" and "_".
+ # "=" is also used if _padding_ is true.
+ #
+ # p SecureRandom.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg"
+ # p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
+ #
+ # p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
+ # p SecureRandom.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="
+ #
+ # If secure random number generator is not available,
+ # NotImplementedError is raised.
+ #
+ # See RFC 3548 for URL-safe base64.
+ def self.urlsafe_base64(n=nil, padding=false)
+ s = [random_bytes(n)].pack("m*")
+ s.delete!("\n")
+ s.tr!("+/", "-_")
+ s.delete!("=") if !padding
+ s
+ end
+
# SecureRandom.random_number generates a random number.
#
# If an positive integer is given as n,
# SecureRandom.random_number returns an integer:
# 0 <= SecureRandom.random_number(n) < n.
#
+ # p SecureRandom.random_number(100) #=> 15
+ # p SecureRandom.random_number(100) #=> 88
+ #
# If 0 is given or an argument is not given,
# SecureRandom.random_number returns an float:
# 0.0 <= SecureRandom.random_number() < 1.0.
+ #
+ # p SecureRandom.random_number #=> 0.596506046187744
+ # p SecureRandom.random_number #=> 0.350621695741409
+ #
def self.random_number(n=0)
if 0 < n
hex = n.to_s(16)
@@ -167,6 +224,24 @@
end
end
+ # SecureRandom.uuid generates a v4 random UUID (Universally Unique IDentifier).
+ #
+ # p SecureRandom.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
+ # p SecureRandom.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
+ # p SecureRandom.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"
+ #
+ # The version 4 UUID is purely random (except the version).
+ # It doesn't contain meaningful information such as MAC address, time, etc.
+ #
+ # See RFC 4122 for details of UUID.
+ #
+ def self.uuid
+ ary = self.random_bytes(16).unpack("NnnnnN")
+ ary[2] = (ary[2] & 0x0fff) | 0x4000
+ ary[3] = (ary[3] & 0x3fff) | 0x8000
+ "%08x-%04x-%04x-%04x-%04x%08x" % ary
+ end
+
# Following code is based on David Garamond's GUID library for Ruby.
def self.lastWin32ErrorMessage # :nodoc:
get_last_error = Win32API.new("kernel32", "GetLastError", '', 'L')
Modified: MacRuby/trunk/lib/set.rb
===================================================================
--- MacRuby/trunk/lib/set.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/set.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -9,7 +9,7 @@
# All rights reserved. You can redistribute and/or modify it under the same
# terms as Ruby.
#
-# $Id: set.rb 25189 2009-10-02 12:04:37Z akr $
+# $Id: set.rb 26648 2010-02-11 17:38:05Z knu $
#
# == Overview
#
@@ -70,12 +70,23 @@
enum.nil? and return
if block
- enum.each { |o| add(block[o]) }
+ do_with_enum(enum) { |o| add(block[o]) }
else
merge(enum)
end
end
+ def do_with_enum(enum, &block)
+ if enum.respond_to?(:each_entry)
+ enum.each_entry(&block)
+ elsif enum.respond_to?(:each)
+ enum.each(&block)
+ else
+ raise ArgumentError, "value must be enumerable"
+ end
+ end
+ private :do_with_enum
+
# Copy internal hash.
def initialize_copy(orig)
@hash = orig.instance_eval{@hash}.dup
@@ -123,7 +134,7 @@
@hash.replace(enum.instance_eval { @hash })
else
clear
- enum.each { |o| add(o) }
+ merge(enum)
end
self
@@ -279,7 +290,7 @@
if enum.instance_of?(self.class)
@hash.update(enum.instance_variable_get(:@hash))
else
- enum.each { |o| add(o) }
+ do_with_enum(enum) { |o| add(o) }
end
self
@@ -288,7 +299,7 @@
# Deletes every element that appears in the given enumerable object
# and returns self.
def subtract(enum)
- enum.each { |o| delete(o) }
+ do_with_enum(enum) { |o| delete(o) }
self
end
@@ -311,7 +322,7 @@
# given enumerable object.
def &(enum)
n = self.class.new
- enum.each { |o| n.add(o) if include?(o) }
+ do_with_enum(enum) { |o| n.add(o) if include?(o) }
n
end
alias intersection & ##
@@ -509,7 +520,7 @@
end
def add(o)
- o.respond_to?(:<=>) or raise ArgumentError, "value must repond to <=>"
+ o.respond_to?(:<=>) or raise ArgumentError, "value must respond to <=>"
super
end
alias << add
@@ -637,14 +648,16 @@
# end
#
# def replace(enum)
+# enum.respond_to?(:each) or raise ArgumentError, "value must be enumerable"
# clear
-# enum.each { |o| add(o) }
+# enum.each_entry { |o| add(o) }
#
# self
# end
#
# def merge(enum)
-# enum.each { |o| add(o) }
+# enum.respond_to?(:each) or raise ArgumentError, "value must be enumerable"
+# enum.each_entry { |o| add(o) }
#
# self
# end
@@ -711,10 +724,10 @@
Set.new([1,2])
Set.new('a'..'c')
}
- assert_raises(NoMethodError) {
+ assert_raises(ArgumentError) {
Set.new(false)
}
- assert_raises(NoMethodError) {
+ assert_raises(ArgumentError) {
Set.new(1)
}
assert_raises(ArgumentError) {
Modified: MacRuby/trunk/lib/shell/builtin-command.rb
===================================================================
--- MacRuby/trunk/lib/shell/builtin-command.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/shell/builtin-command.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,13 +1,13 @@
#
-# shell/builtin-command.rb -
+# shell/builtin-command.rb -
# $Release Version: 0.7 $
-# $Revision: 14912 $
+# $Revision: 25189 $
# by Keiju ISHITSUKA(keiju at ruby-lang.org)
#
# --
#
-#
#
+#
require "shell/filter"
@@ -25,7 +25,7 @@
def initialize(sh, *opts)
super sh
end
-
+
def each(rs = nil)
# do nothing
end
@@ -36,7 +36,7 @@
super sh
@strings = strings
end
-
+
def each(rs = nil)
rs = @shell.record_separator unless rs
for str in @strings
@@ -70,7 +70,7 @@
end
def each(rs = nil)
- if @pattern[0] == ?/
+ if @pattern[0] == ?/
@files = Dir[@pattern]
else
prefix = @shell.pwd+"/"
Modified: MacRuby/trunk/lib/shell/command-processor.rb
===================================================================
--- MacRuby/trunk/lib/shell/command-processor.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/shell/command-processor.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,13 +1,13 @@
#
-# shell/command-controller.rb -
+# shell/command-controller.rb -
# $Release Version: 0.7 $
-# $Revision: 20880 $
+# $Revision: 26986 $
# by Keiju ISHITSUKA(keiju at ruby-lang.org)
#
# --
#
-#
#
+#
require "e2mmap"
require "thread"
@@ -35,11 +35,11 @@
install_builtin_commands
- # define CommandProccessor#methods to Shell#methods and Filter#methods
+ # define CommandProcessor#methods to Shell#methods and Filter#methods
for m in CommandProcessor.instance_methods(false) - NoDelegateMethods
add_delegate_command_to_shell(m)
end
-
+
def self.method_added(id)
add_delegate_command_to_shell(id)
end
@@ -84,7 +84,7 @@
# Shell#test
#
# -
- #
+ #
# CommandProcessor#foreach(path, rs)
# path: String
# rs: String - record separator
@@ -168,7 +168,7 @@
# sh["e", "foo"]
# sh[:exists?, "foo"]
# sh["exists?", "foo"]
- #
+ #
alias top_level_test test
def test(command, file1, file2=nil)
file1 = expand_path(file1)
@@ -211,11 +211,11 @@
# CommandProcessor#mkdir(*path)
# path: String
# same as Dir.mkdir()
- #
+ #
def mkdir(*path)
@shell.check_point
notify("mkdir #{path.join(' ')}")
-
+
perm = nil
if path.last.kind_of?(Integer)
perm = path.pop
@@ -236,7 +236,7 @@
# CommandProcessor#rmdir(*path)
# path: String
# same as Dir.rmdir()
- #
+ #
def rmdir(*path)
@shell.check_point
notify("rmdir #{path.join(' ')}")
@@ -256,7 +256,7 @@
# example:
# print sh.system("ls", "-l")
# sh.system("ls", "-l") | sh.head > STDOUT
- #
+ #
def system(command, *opts)
if opts.empty?
if command =~ /\*|\?|\{|\}|\[|\]|<|>|\(|\)|~|&|\||\\|\$|;|'|`|"|\n/
@@ -338,7 +338,7 @@
def notify(*opts, &block)
Shell.notify(*opts) {|mes|
yield mes if iterator?
-
+
mes.gsub!("%pwd", "#{@cwd}")
mes.gsub!("%cwd", "#{@cwd}")
}
@@ -383,10 +383,10 @@
SystemCommand.new(@shell, '#{path}', *opts)
end]), nil, __FILE__, __LINE__ - 1)
rescue SyntaxError
- Shell.notify "warn: Can't define #{command} path: #{path}."
+ Shell.notify "warn: Can't define #{command} path: #{path}."
end
Shell.notify "Define #{command} path: #{path}.", Shell.debug?
- Shell.notify("Definition of #{command}: ", d,
+ Shell.notify("Definition of #{command}: ", d,
Shell.debug.kind_of?(Integer) && Shell.debug > 1)
end
@@ -418,7 +418,7 @@
@shell.__send__(:#{command},
*(CommandProcessor.alias_map[:#{ali}].call *opts))
end]), nil, __FILE__, __LINE__ - 1)
-
+
else
args = opts.collect{|opt| '"' + opt + '"'}.join(",")
eval((d = %Q[def #{ali}(*opts)
@@ -426,22 +426,22 @@
end]), nil, __FILE__, __LINE__ - 1)
end
rescue SyntaxError
- Shell.notify "warn: Can't alias #{ali} command: #{command}."
+ Shell.notify "warn: Can't alias #{ali} command: #{command}."
Shell.notify("Definition of #{ali}: ", d)
raise
end
Shell.notify "Define #{ali} command: #{command}.", Shell.debug?
- Shell.notify("Definition of #{ali}: ", d,
+ Shell.notify("Definition of #{ali}: ", d,
Shell.debug.kind_of?(Integer) && Shell.debug > 1)
self
end
-
+
def self.unalias_command(ali)
ali = ali.id2name if ali.kind_of?(Symbol)
@alias_map.delete ali.intern
undef_system_command(ali)
end
-
+
#
# CommandProcessor.def_builtin_commands(delegation_class, command_specs)
# delegation_class: Class or Module
@@ -472,7 +472,7 @@
#{delegation_class}.#{meth}(#{call_arg_str})
end]
Shell.notify "Define #{meth}(#{arg_str})", Shell.debug?
- Shell.notify("Definition of #{meth}: ", d,
+ Shell.notify("Definition of #{meth}: ", d,
Shell.debug.kind_of?(Integer) && Shell.debug > 1)
eval d
end
@@ -513,14 +513,14 @@
#----------------------------------------------------------------------
#
- # class initializing methods -
+ # class initializing methods -
#
#----------------------------------------------------------------------
def self.add_delegate_command_to_shell(id)
id = id.intern if id.kind_of?(String)
name = id.id2name
if Shell.method_defined?(id)
- Shell.notify "warn: override definnition of Shell##{name}."
+ Shell.notify "warn: override definition of Shell##{name}."
Shell.notify "warn: alias Shell##{name} to Shell##{name}_org.\n"
Shell.module_eval "alias #{name}_org #{name}"
end
@@ -536,7 +536,7 @@
end], __FILE__, __LINE__)
if Shell::Filter.method_defined?(id)
- Shell.notify "warn: override definnition of Shell::Filter##{name}."
+ Shell.notify "warn: override definition of Shell::Filter##{name}."
Shell.notify "warn: alias Shell##{name} to Shell::Filter##{name}_org."
Filter.module_eval "alias #{name}_org #{name}"
end
@@ -561,7 +561,7 @@
normal_delegation_file_methods = [
["atime", ["FILENAME"]],
["basename", ["fn", "*opts"]],
- ["chmod", ["mode", "*FILENAMES"]],
+ ["chmod", ["mode", "*FILENAMES"]],
["chown", ["owner", "group", "*FILENAME"]],
["ctime", ["FILENAMES"]],
["delete", ["*FILENAMES"]],
@@ -584,7 +584,7 @@
alias_method :rm, :delete
# method related FileTest
- def_builtin_commands(FileTest,
+ def_builtin_commands(FileTest,
FileTest.singleton_methods(false).collect{|m| [m, ["FILENAME"]]})
end
Modified: MacRuby/trunk/lib/shell/error.rb
===================================================================
--- MacRuby/trunk/lib/shell/error.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/shell/error.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,13 +1,13 @@
#
-# shell/error.rb -
+# shell/error.rb -
# $Release Version: 0.7 $
-# $Revision: 14912 $
+# $Revision: 25189 $
# by Keiju ISHITSUKA(keiju at ruby-lang.org)
#
# --
#
-#
#
+#
require "e2mmap"
Modified: MacRuby/trunk/lib/shell/filter.rb
===================================================================
--- MacRuby/trunk/lib/shell/filter.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/shell/filter.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,13 +1,13 @@
#
-# shell/filter.rb -
+# shell/filter.rb -
# $Release Version: 0.7 $
-# $Revision: 14912 $
+# $Revision: 25189 $
# by Keiju ISHITSUKA(keiju at ruby-lang.org)
#
# --
#
-#
#
+#
class Shell
#
@@ -28,7 +28,7 @@
def input=(filter)
@input = filter
end
-
+
def each(rs = nil)
rs = @shell.record_separator unless rs
if @input
Modified: MacRuby/trunk/lib/shell/process-controller.rb
===================================================================
--- MacRuby/trunk/lib/shell/process-controller.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/shell/process-controller.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,13 +1,13 @@
#
-# shell/process-controller.rb -
+# shell/process-controller.rb -
# $Release Version: 0.7 $
-# $Revision: 20880 $
+# $Revision: 26986 $
# by Keiju ISHITSUKA(keiju at ruby-lang.org)
#
# --
#
-#
#
+#
require "forwardable"
require "thread"
@@ -26,7 +26,7 @@
class<<self
extend Forwardable
- def_delegator("@ProcessControllersMonitor",
+ def_delegator("@ProcessControllersMonitor",
"synchronize", "process_controllers_exclusive")
def active_process_controllers
@@ -118,7 +118,7 @@
def waiting_jobs
@waiting_jobs
end
-
+
def jobs_exist?
@jobs_sync.synchronize(:SH) do
@active_jobs.empty? or @waiting_jobs.empty?
@@ -158,7 +158,7 @@
else
command = @waiting_jobs.shift
# command.notify "job(%id) pre-start.", @shell.debug?
-
+
return unless command
end
@active_jobs.push command
@@ -191,7 +191,7 @@
@active_jobs.delete command
ProcessController.inactivate(self)
if @active_jobs.empty?
- command.notify("start_jon in ierminate_jon(%id)", Shell::debug?)
+ command.notify("start_job in terminate_job(%id)", Shell::debug?)
start_job
end
end
@@ -253,7 +253,7 @@
end
pid = fork {
- Thread.list.each do |th|
+ Thread.list.each do |th|
# th.kill unless [Thread.main, Thread.current].include?(th)
th.kill unless Thread.current == th
end
@@ -261,7 +261,7 @@
STDIN.reopen(pipe_peer_in)
STDOUT.reopen(pipe_peer_out)
- ObjectSpace.each_object(IO) do |io|
+ ObjectSpace.each_object(IO) do |io|
if ![STDIN, STDOUT, STDERR].include?(io)
io.close unless io.closed?
end
@@ -281,13 +281,13 @@
command.notify("job(%id) start to waiting finish.", @shell.debug?)
_pid = Process.waitpid(pid, nil)
rescue Errno::ECHILD
- command.notify "warn: job(%id) was done already waitipd."
+ command.notify "warn: job(%id) was done already waitpid."
_pid = true
# rescue
# STDERR.puts $!
ensure
command.notify("Job(%id): Wait to finish when Process finished.", @shell.debug?)
- # when the process ends, wait until the command termintes
+ # when the process ends, wait until the command terminates
if USING_AT_EXIT_WHEN_PROCESS_EXIT or _pid
else
command.notify("notice: Process finishing...",
@@ -295,9 +295,9 @@
"You can use Shell#transact or Shell#check_point for more safe execution.")
redo
end
-
+
# command.notify "job(%id) pre-pre-finish.", @shell.debug?
- @job_monitor.synchronize do
+ @job_monitor.synchronize do
# command.notify "job(%id) pre-finish.", @shell.debug?
terminate_job(command)
# command.notify "job(%id) pre-finish2.", @shell.debug?
Modified: MacRuby/trunk/lib/shell/system-command.rb
===================================================================
--- MacRuby/trunk/lib/shell/system-command.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/shell/system-command.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,13 +1,13 @@
#
-# shell/system-command.rb -
+# shell/system-command.rb -
# $Release Version: 0.7 $
-# $Revision: 14912 $
+# $Revision: 25189 $
# by Keiju ISHITSUKA(keiju at ruby-lang.org)
#
# --
#
-#
#
+#
require "shell/filter"
@@ -20,7 +20,7 @@
super(sh)
@command = command
@opts = opts
-
+
@input_queue = Queue.new
@pid = nil
@@ -140,9 +140,9 @@
end
# ex)
- # if you wish to output:
+ # if you wish to output:
# "shell: job(#{@command}:#{@pid}) close pipe-out."
- # then
+ # then
# mes: "job(%id) close pipe-out."
# yorn: Boolean(@shell.debug? or @shell.verbose?)
def notify(*opts, &block)
Modified: MacRuby/trunk/lib/shell/version.rb
===================================================================
--- MacRuby/trunk/lib/shell/version.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/shell/version.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,13 +1,13 @@
#
# version.rb - shell version definition file
# $Release Version: 0.7$
-# $Revision: 14912 $
+# $Revision: 25189 $
# by Keiju ISHITSUKA(keiju at ruby-lang.org)
#
# --
#
-#
#
+#
class Shell
@RELEASE_VERSION = "0.7"
Modified: MacRuby/trunk/lib/shell.rb
===================================================================
--- MacRuby/trunk/lib/shell.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/shell.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,13 +1,13 @@
#
-# shell.rb -
+# shell.rb -
# $Release Version: 0.7 $
# $Revision: 1.9 $
# by Keiju ISHITSUKA(keiju at ruby-lang.org)
#
# --
#
-#
#
+#
require "e2mmap"
Modified: MacRuby/trunk/lib/sync.rb
===================================================================
--- MacRuby/trunk/lib/sync.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/sync.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,7 +1,7 @@
#
# sync.rb - 2 phase lock with counter
# $Release Version: 1.0$
-# $Revision: 19280 $
+# $Revision: 25189 $
# by Keiju ISHITSUKA(keiju at ishitsuka.com)
#
# --
@@ -34,34 +34,34 @@
# Sync#lock(mode) -- mode = :EX, :SH, :UN
# Sync#unlock
# Sync#synchronize(mode) {...}
-#
#
+#
unless defined? Thread
raise "Thread not available for this ruby interpreter"
end
module Sync_m
- RCS_ID='-$Header$-'
-
+ RCS_ID='-$Id: sync.rb 25189 2009-10-02 12:04:37Z akr $-'
+
# lock mode
UN = :UN
SH = :SH
EX = :EX
-
+
# exceptions
class Err < StandardError
def Err.Fail(*opt)
fail self, sprintf(self::Message, *opt)
end
-
+
class UnknownLocker < Err
Message = "Thread(%s) not locked."
def UnknownLocker.Fail(th)
super(th.inspect)
end
end
-
+
class LockModeFailer < Err
Message = "Unknown lock mode(%s)"
def LockModeFailer.Fail(mode)
@@ -72,7 +72,7 @@
end
end
end
-
+
def Sync_m.define_aliases(cl)
cl.module_eval %q{
alias locked? sync_locked?
@@ -84,7 +84,7 @@
alias synchronize sync_synchronize
}
end
-
+
def Sync_m.append_features(cl)
super
# do nothing for Modules
@@ -92,12 +92,12 @@
define_aliases(cl) unless cl.instance_of?(Module)
self
end
-
+
def Sync_m.extend_object(obj)
super
obj.sync_extend
end
-
+
def sync_extend
unless (defined? locked? and
defined? shared? and
@@ -115,15 +115,15 @@
def sync_locked?
sync_mode != UN
end
-
+
def sync_shared?
sync_mode == SH
end
-
+
def sync_exclusive?
sync_mode == EX
end
-
+
# locking methods.
def sync_try_lock(mode = EX)
return unlock if mode == UN
@@ -132,7 +132,7 @@
end
ret
end
-
+
def sync_lock(m = EX)
return unlock if m == UN
@@ -153,21 +153,21 @@
end
self
end
-
+
def sync_unlock(m = EX)
wakeup_threads = []
@sync_mutex.synchronize do
if sync_mode == UN
Err::UnknownLocker.Fail(Thread.current)
end
-
+
m = sync_mode if m == EX and sync_mode == SH
-
+
runnable = false
case m
when UN
Err::UnknownLocker.Fail(Thread.current)
-
+
when EX
if sync_ex_locker == Thread.current
if (self.sync_ex_count = sync_ex_count - 1) == 0
@@ -182,12 +182,12 @@
else
Err::UnknownLocker.Fail(Thread.current)
end
-
+
when SH
if (count = sync_sh_locker[Thread.current]).nil?
Err::UnknownLocker.Fail(Thread.current)
else
- if (sync_sh_locker[Thread.current] = count - 1) == 0
+ if (sync_sh_locker[Thread.current] = count - 1) == 0
sync_sh_locker.delete(Thread.current)
if sync_sh_locker.empty? and sync_ex_count == 0
self.sync_mode = UN
@@ -196,7 +196,7 @@
end
end
end
-
+
if runnable
if sync_upgrade_waiting.size > 0
th, count = sync_upgrade_waiting.shift
@@ -218,7 +218,7 @@
end
self
end
-
+
def sync_synchronize(mode = EX)
sync_lock(mode)
begin
@@ -229,7 +229,7 @@
end
attr_accessor :sync_mode
-
+
attr_accessor :sync_waiting
attr_accessor :sync_upgrade_waiting
attr_accessor :sync_sh_locker
@@ -258,7 +258,7 @@
super
sync_initialize
end
-
+
def sync_try_lock_sub(m)
case m
when SH
@@ -282,7 +282,7 @@
end
when EX
if sync_mode == UN or
- sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
+ sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
self.sync_mode = m
self.sync_ex_locker = Thread.current
self.sync_ex_count = 1
Modified: MacRuby/trunk/lib/tempfile.rb
===================================================================
--- MacRuby/trunk/lib/tempfile.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/tempfile.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,102 +1,166 @@
#
# tempfile - manipulates temporary files
#
-# $Id: tempfile.rb 19833 2008-10-18 10:32:26Z matz $
+# $Id: tempfile.rb 27578 2010-05-01 13:54:01Z nobu $
#
require 'delegate'
require 'tmpdir'
require 'thread'
-# A class for managing temporary files. This library is written to be
-# thread safe.
+# A utility class for managing temporary files. When you create a Tempfile
+# object, it will create a temporary file with a unique filename. A Tempfile
+# objects behaves just like a File object, and you can perform all the usual
+# file operations on it: reading data, writing data, changing its permissions,
+# etc. So although this class does not explicitly document all instance methods
+# supported by File, you can in fact call any File instance method on a
+# Tempfile object.
+#
+# == Synopsis
+#
+# require 'tempfile'
+#
+# file = Tempfile.new('foo')
+# file.path # => A unique filename in the OS's temp directory,
+# # e.g.: "/tmp/foo.24722.0"
+# # This filename contains 'foo' in its basename.
+# file.write("hello world")
+# file.rewind
+# file.read # => "hello world"
+# file.close
+# file.unlink # deletes the temp file
+#
+# == Good practices
+#
+# === Explicit close
+#
+# When a Tempfile object is garbage collected, or when the Ruby interpreter
+# exits, its associated temporary file is automatically deleted. This means
+# that's it's unnecessary to explicitly delete a Tempfile after use, though
+# it's good practice to do so: not explicitly deleting unused Tempfiles can
+# potentially leave behind large amounts of tempfiles on the filesystem
+# until they're garbage collected. The existance of these temp files can make
+# it harder to determine a new Tempfile filename.
+#
+# Therefore, one should always call #unlink or close in an ensure block, like
+# this:
+#
+# file = Tempfile.new('foo')
+# begin
+# ...do something with file...
+# ensure
+# file.close
+# file.unlink # deletes the temp file
+# end
+#
+# === Unlink after creation
+#
+# On POSIX systems, it's possible to unlink a file right after creating it,
+# and before closing it. This removes the filesystem entry without closing
+# the file handle, so it ensures that only the processes that already had
+# the file handle open can access the file's contents. It's strongly
+# recommended that you do this if you do not want any other processes to
+# be able to read from or write to the Tempfile, and you do not need to
+# know the Tempfile's filename either.
+#
+# For example, a practical use case for unlink-after-creation would be this:
+# you need a large byte buffer that's too large to comfortably fit in RAM,
+# e.g. when you're writing a web server and you want to buffer the client's
+# file upload data.
+#
+# Please refer to #unlink for more information and a code example.
+#
+# == Minor notes
+#
+# Tempfile's filename picking method is both thread-safe and inter-process-safe:
+# it guarantees that no other threads or processes will pick the same filename.
+#
+# Tempfile itself however may not be entirely thread-safe. If you access the
+# same Tempfile object from multiple threads then you should protect it with a
+# mutex.
class Tempfile < DelegateClass(File)
- MAX_TRY = 10
- @@cleanlist = []
- @@lock = Mutex.new
+ MAX_TRY = 10 # :nodoc:
+ include Dir::Tmpname
- # Creates a temporary file of mode 0600 in the temporary directory,
- # opens it with mode "w+", and returns a Tempfile object which
- # represents the created temporary file. A Tempfile object can be
- # treated just like a normal File object.
+ # call-seq:
+ # new(basename, [tmpdir = Dir.tmpdir], [options])
#
- # The basename parameter is used to determine the name of a
- # temporary file. If an Array is given, the first element is used
- # as prefix string and the second as suffix string, respectively.
- # Otherwise it is treated as prefix string.
+ # Creates a temporary file with permissions 0600 (= only readable and
+ # writable by the owner) and opens it with mode "w+".
#
- # If tmpdir is omitted, the temporary directory is determined by
- # Dir::tmpdir provided by 'tmpdir.rb'.
- # When $SAFE > 0 and the given tmpdir is tainted, it uses
- # /tmp. (Note that ENV values are tainted by default)
+ # The +basename+ parameter is used to determine the name of the
+ # temporary file. You can either pass a String or an Array with
+ # 2 String elements. In the former form, the temporary file's base
+ # name will begin with the given string. In the latter form,
+ # the temporary file's base name will begin with the array's first
+ # element, and end with the second element. For example:
+ #
+ # file = Tempfile.new('hello')
+ # file.path # => something like: "/tmp/foo2843-8392-92849382--0"
+ #
+ # # Use the Array form to enforce an extension in the filename:
+ # file = Tempfile.new(['hello', '.jpg'])
+ # file.path # => something like: "/tmp/foo2843-8392-92849382--0.jpg"
+ #
+ # The temporary file will be placed in the directory as specified
+ # by the +tmpdir+ parameter. By default, this is +Dir.tmpdir+.
+ # When $SAFE > 0 and the given +tmpdir+ is tainted, it uses
+ # '/tmp' as the temporary directory. Please note that ENV values
+ # are tainted by default, and +Dir.tmpdir+'s return value might
+ # come from environment variables (e.g. <tt>$TMPDIR</tt>).
+ #
+ # file = Tempfile.new('hello', '/home/aisaka')
+ # file.path # => something like: "/home/aisaka/foo2843-8392-92849382--0"
+ #
+ # You can also pass an options hash. Under the hood, Tempfile creates
+ # the temporary file using +File.open+. These options will be passed to
+ # +File.open+. This is mostly useful for specifying encoding
+ # options, e.g.:
+ #
+ # Tempfile.new('hello', '/home/aisaka', :encoding => 'ascii-8bit')
+ #
+ # # You can also omit the 'tmpdir' parameter:
+ # Tempfile.new('hello', :encoding => 'ascii-8bit')
+ #
+ # === Exceptions
+ #
+ # If Tempfile.new cannot find a unique filename within a limited
+ # number of tries, then it will raise an exception.
def initialize(basename, *rest)
- # I wish keyword argument settled soon.
- if opts = Hash.try_convert(rest[-1])
- rest.pop
- end
- tmpdir = rest[0] || Dir::tmpdir
- if $SAFE > 0 and tmpdir.tainted?
- tmpdir = '/tmp'
- end
+ @data = []
+ @clean_proc = Remover.new(@data)
+ ObjectSpace.define_finalizer(self, @clean_proc)
- lock = tmpname = nil
- n = failure = 0
- @@lock.synchronize {
+ create(basename, *rest) do |tmpname, n, opts|
+ lock = tmpname + '.lock'
+ mode = File::RDWR|File::CREAT|File::EXCL
+ perm = 0600
+ if opts
+ mode |= opts.delete(:mode) || 0
+ opts[:perm] = perm
+ perm = nil
+ else
+ opts = perm
+ end
+ self.class.mkdir(lock)
begin
- begin
- tmpname = File.join(tmpdir, make_tmpname(basename, n))
- lock = tmpname + '.lock'
- n += 1
- end while @@cleanlist.include?(tmpname) or
- File.exist?(lock) or File.exist?(tmpname)
- Dir.mkdir(lock)
- rescue
- failure += 1
- retry if failure < MAX_TRY
- raise "cannot generate tempfile `%s'" % tmpname
+ @data[1] = @tmpfile = File.open(tmpname, mode, opts)
+ @data[0] = @tmpname = tmpname
+ ensure
+ self.class.rmdir(lock)
end
- }
-
- @data = [tmpname]
- @clean_proc = Tempfile.callback(@data)
- ObjectSpace.define_finalizer(self, @clean_proc)
-
- if opts.nil?
- opts = []
- else
- opts = [opts]
+ @mode = mode & ~(File::CREAT|File::EXCL)
+ perm or opts.freeze
+ @opts = opts
end
- @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600, *opts)
- @tmpname = tmpname
- @@cleanlist << @tmpname
- @data[1] = @tmpfile
- @data[2] = @@cleanlist
super(@tmpfile)
-
- # Now we have all the File/IO methods defined, you must not
- # carelessly put bare puts(), etc. after this.
-
- Dir.rmdir(lock)
end
- def make_tmpname(basename, n)
- case basename
- when Array
- prefix, suffix = *basename
- else
- prefix, suffix = basename, ''
- end
-
- t = Time.now.strftime("%Y%m%d")
- path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-#{n}#{suffix}"
- end
- private :make_tmpname
-
# Opens or reopens the file with mode "r+".
def open
@tmpfile.close if @tmpfile
- @tmpfile = File.open(@tmpname, 'r+')
+ @tmpfile = File.open(@tmpname, @mode, @opts)
@data[1] = @tmpfile
__setobj__(@tmpfile)
end
@@ -108,8 +172,9 @@
end
protected :_close
- #Closes the file. If the optional flag is true, unlinks the file
- # after closing.
+ # Closes the file. If +unlink_now+ is true, then the file will be unlinked
+ # (deleted) after closing. Of course, you can choose to later call #unlink
+ # if you do not unlink it now.
#
# If you don't explicitly unlink the temporary file, the removal
# will be delayed until the object is finalized.
@@ -121,25 +186,57 @@
end
end
- # Closes and unlinks the file.
+ # Closes and unlinks (deletes) the file. Has the same effect as called
+ # <tt>close(true)</tt>.
def close!
_close
- @clean_proc.call
+ unlink
ObjectSpace.undefine_finalizer(self)
- @data = @tmpname = nil
end
- # Unlinks the file. On UNIX-like systems, it is often a good idea
- # to unlink a temporary file immediately after creating and opening
- # it, because it leaves other programs zero chance to access the
- # file.
+ # Unlinks (deletes) the file from the filesystem. One should always unlink
+ # the file after using it, as is explained in the "Explicit close" good
+ # practice section in the Tempfile overview:
+ #
+ # file = Tempfile.new('foo')
+ # begin
+ # ...do something with file...
+ # ensure
+ # file.close
+ # file.unlink # deletes the temp file
+ # end
+ #
+ # === Unlink-before-close
+ #
+ # On POSIX systems it's possible to unlink a file before closing it. This
+ # practice is explained in detail in the Tempfile overview (section
+ # "Unlink after creation"); please refer there for more information.
+ #
+ # However, unlink-before-close may not be supported on non-POSIX operating
+ # systems. Microsoft Windows is the most notable case: unlinking a non-closed
+ # file will result in an error, which this method will silently ignore. If
+ # you want to practice unlink-before-close whenever possible, then you should
+ # write code like this:
+ #
+ # file = Tempfile.new('foo')
+ # file.unlink # On Windows this silently fails.
+ # begin
+ # ... do something with file ...
+ # ensure
+ # file.close! # Closes the file handle. If the file wasn't unlinked
+ # # because #unlink failed, then this method will attempt
+ # # to do so again.
+ # end
def unlink
# keep this order for thread safeness
+ return unless @tmpname
begin
- File.unlink(@tmpname) if File.exist?(@tmpname)
- @@cleanlist.delete(@tmpname)
+ if File.exist?(@tmpname)
+ File.unlink(@tmpname)
+ end
+ # remove tmpname from remover
+ @data[0] = @data[2] = nil
@data = @tmpname = nil
- ObjectSpace.undefine_finalizer(self)
rescue Errno::EACCES
# may not be able to unlink on Windows; just ignore
end
@@ -147,6 +244,7 @@
alias delete unlink
# Returns the full path name of the temporary file.
+ # This will be nil if #unlink has been called.
def path
@tmpname
end
@@ -157,37 +255,63 @@
if @tmpfile
@tmpfile.flush
@tmpfile.stat.size
+ elsif @tmpname
+ File.size(@tmpname)
else
0
end
end
alias length size
- class << self
- def callback(data) # :nodoc:
- pid = $$
- Proc.new {
- if pid == $$
- path, tmpfile, cleanlist = *data
+ # :stopdoc:
+ class Remover
+ def initialize(data)
+ @pid = $$
+ @data = data
+ end
- print "removing ", path, "..." if $DEBUG
+ def call(*args)
+ if @pid == $$
+ path, tmpfile = *@data
- tmpfile.close if tmpfile
+ STDERR.print "removing ", path, "..." if $DEBUG
- # keep this order for thread safeness
- File.unlink(path) if File.exist?(path)
- cleanlist.delete(path) if cleanlist
+ tmpfile.close if tmpfile
- print "done\n" if $DEBUG
- end
- }
+ # keep this order for thread safeness
+ if path
+ File.unlink(path) if File.exist?(path)
+ end
+
+ STDERR.print "done\n" if $DEBUG
+ end
end
+ end
+ # :startdoc:
- # If no block is given, this is a synonym for new().
+ class << self
+ # Creates a new Tempfile.
#
- # If a block is given, it will be passed tempfile as an argument,
- # and the tempfile will automatically be closed when the block
- # terminates. In this case, open() returns nil.
+ # If no block is given, this is a synonym for Tempfile.new.
+ #
+ # If a block is given, then a Tempfile object will be constructed,
+ # and the block is run with said object as argument. The Tempfile
+ # oject will be automatically closed after the block terminates.
+ # The call returns the value of the block.
+ #
+ # In any case, all arguments (+*args+) will be passed to Tempfile.new.
+ #
+ # Tempfile.open('foo', '/home/temp') do |f|
+ # ... do something with f ...
+ # end
+ #
+ # # Equivalent:
+ # f = Tempfile.open('foo', '/home/temp')
+ # begin
+ # ... do something with f ...
+ # ensure
+ # f.close
+ # end
def open(*args)
tempfile = new(*args)
@@ -201,6 +325,13 @@
tempfile
end
end
+
+ def mkdir(*args)
+ Dir.mkdir(*args)
+ end
+ def rmdir(*args)
+ Dir.rmdir(*args)
+ end
end
end
Modified: MacRuby/trunk/lib/test/unit/assertions.rb
===================================================================
--- MacRuby/trunk/lib/test/unit/assertions.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/test/unit/assertions.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -10,6 +10,15 @@
obj.pretty_inspect.chomp
end
+ def assert(test, msg = (nomsg = true; nil))
+ unless nomsg or msg.instance_of?(String) or msg.instance_of?(Proc) or
+ (bt = caller).first.rindex(MiniTest::MINI_DIR, 0)
+ bt.delete_if {|s| s.rindex(MiniTest::MINI_DIR, 0)}
+ raise ArgumentError, "assertion message must be String or Proc, but #{msg.class} was given.", bt
+ end
+ super
+ end
+
def assert_raise(*args, &b)
assert_raises(*args, &b)
end
@@ -28,7 +37,7 @@
as = e.instance_of?(MiniTest::Assertion)
if as
ans = /\A#{Regexp.quote(__FILE__)}:#{line}:in /o
- bt.reject! {|line| ans =~ line}
+ bt.reject! {|ln| ans =~ ln}
end
if ((args.empty? && !as) ||
args.any? {|a| a.instance_of?(Module) ? e.is_a?(a) : e.class == a })
@@ -67,8 +76,20 @@
exp_str = "%\#.#{Float::DIG+2}g" % exp
act_str = "%\#.#{Float::DIG+2}g" % act
elsif exp.is_a?(Time) && act.is_a?(Time)
- exp_comment = " (nsec=#{exp.nsec})"
- act_comment = " (nsec=#{act.nsec})"
+ if exp.subsec * 1000_000_000 == exp.nsec
+ exp_comment = " (#{exp.nsec}[ns])"
+ else
+ exp_comment = " (subsec=#{exp.subsec})"
+ end
+ if act.subsec * 1000_000_000 == act.nsec
+ act_comment = " (#{act.nsec}[ns])"
+ else
+ act_comment = " (subsec=#{act.subsec})"
+ end
+ elsif exp.class != act.class
+ # a subclass of Range, for example.
+ exp_comment = " (#{exp.class})"
+ act_comment = " (#{act.class})"
end
elsif !Encoding.compatible?(exp_str, act_str)
if exp.is_a?(String) && act.is_a?(String)
@@ -113,6 +134,17 @@
assert(!actual.equal?(expected), msg)
end
+ # get rid of overcounting
+ def assert_respond_to obj, meth, msg = nil
+ super if !caller[0].rindex(MiniTest::MINI_DIR, 0) || !obj.respond_to?(meth)
+ end
+
+ ms = instance_methods(true).map {|sym| sym.to_s }
+ ms.grep(/\Arefute_/) do |m|
+ mname = ('assert_not_' << m.to_s[/.*?_(.*)/, 1])
+ alias_method(mname, m) unless ms.include? mname
+ end
+
def build_message(head, template=nil, *arguments)
template &&= template.chomp
template.gsub(/\?/) { mu_pp(arguments.shift) }
Modified: MacRuby/trunk/lib/test/unit/testcase.rb
===================================================================
--- MacRuby/trunk/lib/test/unit/testcase.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/test/unit/testcase.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -2,6 +2,9 @@
module Test
module Unit
+ # remove silly TestCase class
+ remove_const(:TestCase) if defined?(self::TestCase)
+
class TestCase < MiniTest::Unit::TestCase
include Assertions
def self.test_order
Modified: MacRuby/trunk/lib/test/unit.rb
===================================================================
--- MacRuby/trunk/lib/test/unit.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/test/unit.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -16,12 +16,12 @@
while arg = original_argv.shift
case arg
when '-v'
- minitest_argv << '-v'
- when '-n', '--name'
minitest_argv << arg
- minitest_argv << original_argv.shift
- when '-x'
- reject << original_argv.shift
+ when /\A(-n)(.+)?/, /\A(--name)=?\b(.+)?/
+ minitest_argv << $1
+ minitest_argv << ($2 || original_argv.shift)
+ when /\A-x(.+)?/
+ reject << ($1 || original_argv.shift)
else
files << arg
end
@@ -32,7 +32,7 @@
end
files.map! {|f|
- f = f.gsub(Regexp.compile(Regexp.quote(File::ALT_SEPARATOR)), File::SEPARATOR) if File::ALT_SEPARATOR
+ f = f.tr(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
if File.directory? f
Dir["#{f}/**/test_*.rb"]
elsif File.file? f
@@ -45,14 +45,14 @@
reject_pat = Regexp.union(reject.map {|r| /#{r}/ })
files.reject! {|f| reject_pat =~ f }
-
+
files.each {|f|
- d = File.dirname(File.expand_path(f))
+ d = File.dirname(path = File.expand_path(f))
unless $:.include? d
$: << d
end
begin
- require f
+ require path
rescue LoadError
puts "#{f}: #{$!}"
end
Modified: MacRuby/trunk/lib/thread.rb
===================================================================
--- MacRuby/trunk/lib/thread.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/thread.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -20,7 +20,7 @@
Thread.abort_on_exception = true
end
-#
+#
# ConditionVariable objects augment class Mutex. Using condition variables,
# it is possible to suspend while in the middle of a critical section until a
# resource becomes available.
@@ -31,7 +31,7 @@
#
# mutex = Mutex.new
# resource = ConditionVariable.new
-#
+#
# a = Thread.new {
# mutex.synchronize {
# # Thread 'a' now needs the resource
@@ -39,7 +39,7 @@
# # 'a' can now have the resource
# }
# }
-#
+#
# b = Thread.new {
# mutex.synchronize {
# # Thread 'b' has finished using the resource
@@ -55,20 +55,28 @@
@waiters = []
@waiters_mutex = Mutex.new
end
-
+
#
# Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
#
- def wait(mutex)
+ # If +timeout+ is given, this method returns after +timeout+ seconds passed,
+ # even if no other thread doesn't signal.
+ #
+ def wait(mutex, timeout=nil)
begin
# TODO: mutex should not be used
@waiters_mutex.synchronize do
@waiters.push(Thread.current)
end
- mutex.sleep
+ mutex.sleep timeout
+ ensure
+ @waiters_mutex.synchronize do
+ @waiters.delete(Thread.current)
+ end
end
+ self
end
-
+
#
# Wakes up the first thread in line waiting for this lock.
#
@@ -79,8 +87,9 @@
rescue ThreadError
retry
end
+ self
end
-
+
#
# Wakes up all threads waiting for this lock.
#
@@ -93,10 +102,11 @@
end
for t in waiters0
begin
- t.run
+ t.run
rescue ThreadError
end
end
+ self
end
end
@@ -106,9 +116,9 @@
# Example:
#
# require 'thread'
-#
+#
# queue = Queue.new
-#
+#
# producer = Thread.new do
# 5.times do |i|
# sleep rand(i) # simulate expense
@@ -116,7 +126,7 @@
# puts "#{i} produced"
# end
# end
-#
+#
# consumer = Thread.new do
# 5.times do |i|
# value = queue.pop
@@ -124,7 +134,7 @@
# puts "consumed #{value}"
# end
# end
-#
+#
# consumer.join
#
class Queue
@@ -144,7 +154,6 @@
# Pushes +obj+ to the queue.
#
def push(obj)
- t = nil
@mutex.synchronize{
@que.push obj
begin
@@ -154,10 +163,6 @@
retry
end
}
- begin
- t.run if t
- rescue ThreadError
- end
end
#
@@ -176,8 +181,8 @@
# thread isn't suspended, and an exception is raised.
#
def pop(non_block=false)
- while true
- @mutex.synchronize{
+ @mutex.synchronize{
+ while true
if @que.empty?
raise ThreadError, "queue empty" if non_block
@waiting.push Thread.current
@@ -185,8 +190,8 @@
else
return @que.shift
end
- }
- end
+ end
+ }
end
#
@@ -289,14 +294,13 @@
# until space becomes available.
#
def push(obj)
- t = nil
@mutex.synchronize{
while true
- break if @que.length <= @max
+ break if @que.length < @max
@queue_wait.push Thread.current
@mutex.sleep
end
-
+
@que.push obj
begin
t = @waiting.shift
@@ -305,11 +309,6 @@
retry
end
}
-
- begin
- t.run if t
- rescue ThreadError
- end
end
#
@@ -327,7 +326,6 @@
#
def pop(*args)
retval = super
- t = nil
@mutex.synchronize {
if @que.length < @max
begin
@@ -338,10 +336,6 @@
end
end
}
- begin
- t.run if t
- rescue ThreadError
- end
retval
end
Modified: MacRuby/trunk/lib/thwait.rb
===================================================================
--- MacRuby/trunk/lib/thwait.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/thwait.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -2,38 +2,7 @@
# thwait.rb - thread synchronization class
# $Release Version: 0.9 $
# $Revision: 1.3 $
-# by Keiju ISHITSUKA(Nihpon Rational Software Co.,Ltd.)
-#
-# --
-# feature:
-# provides synchronization for multiple threads.
-#
-# class methods:
-# * ThreadsWait.all_waits(thread1,...)
-# waits until all of specified threads are terminated.
-# if a block is supplied for the method, evaluates it for
-# each thread termination.
-# * th = ThreadsWait.new(thread1,...)
-# creates synchronization object, specifying thread(s) to wait.
-#
-# methods:
-# * th.threads
-# list threads to be synchronized
-# * th.empty?
-# is there any thread to be synchronized.
-# * th.finished?
-# is there already terminated thread.
-# * th.join(thread1,...)
-# wait for specified thread(s).
-# * th.join_nowait(threa1,...)
-# specifies thread(s) to wait. non-blocking.
-# * th.next_wait
-# waits until any of specified threads is terminated.
-# * th.all_waits
-# waits until all of specified threads are terminated.
-# if a block is supplied for the method, evaluates it for
-# each thread termination.
-#
+# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd.)
require "thread.rb"
require "e2mmap.rb"
@@ -50,16 +19,21 @@
# STDERR.puts "Thread #{t} has terminated."
# end
#
+#
+# th = ThreadsWait.new(thread1,...)
+# th.next_wait # next one to be done
+#
+#
class ThreadsWait
RCS_ID='-$Id: thwait.rb,v 1.3 1998/06/26 03:19:34 keiju Exp keiju $-'
-
+
extend Exception2MessageMapper
def_exception("ErrNoWaitingThread", "No threads for waiting.")
def_exception("ErrNoFinishedThread", "No finished threads.")
-
+
#
# Waits until all specified threads have terminated. If a block is provided,
- # it is executed for each thread termination.
+ # it is executed for each thread as they terminate.
#
def ThreadsWait.all_waits(*threads) # :yield: thread
tw = ThreadsWait.new(*threads)
@@ -71,7 +45,7 @@
tw.all_waits
end
end
-
+
#
# Creates a ThreadsWait object, specifying the threads to wait on.
# Non-blocking.
@@ -81,32 +55,33 @@
@wait_queue = Queue.new
join_nowait(*threads) unless threads.empty?
end
-
- # Returns the array of threads in the wait queue.
+
+ # Returns the array of threads that have not terminated yet.
attr :threads
-
+
#
- # Returns +true+ if there are no threads to be synchronized.
+ # Returns +true+ if there are no threads in the pool still running.
#
def empty?
@threads.empty?
end
-
+
#
- # Returns +true+ if any thread has terminated.
+ # Returns +true+ if any thread has terminated and is ready to be collected.
#
def finished?
!@wait_queue.empty?
end
-
+
#
- # Waits for specified threads to terminate.
+ # Waits for specified threads to terminate, and returns when one of
+ # the threads terminated.
#
def join(*threads)
join_nowait(*threads)
next_wait
end
-
+
#
# Specifies the threads that this object will wait for, but does not actually
# wait.
@@ -124,7 +99,7 @@
end
end
end
-
+
#
# Waits until any of the specified threads has terminated, and returns the one
# that does.
@@ -141,7 +116,7 @@
ThreadsWait.fail ErrNoFinishedThread
end
end
-
+
#
# Waits until all of the specified threads are terminated. If a block is
# supplied for the method, it is executed for each thread termination.
Modified: MacRuby/trunk/lib/time.rb
===================================================================
--- MacRuby/trunk/lib/time.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/time.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -35,10 +35,6 @@
# %z is required to generate zone in date-time of RFC 2822
# but it is not portable.
#
-# == Revision Information
-#
-# $Id$
-#
require 'date/format'
@@ -102,7 +98,7 @@
# In RFC 3339, -00:00 is used for the time in UTC is known,
# but the offset to local time is unknown.
# They are not appropriate for specific time zone such as
- # Europe/London because time zone neutral,
+ # Europe/London because time zone neutral,
# So -00:00 and -0000 are treated as UTC.
if /\A(?:-00:00|-0000|-00|UTC|Z|UT)\z/i =~ zone
true
@@ -210,7 +206,7 @@
# If a block is given, the year described in +date+ is converted by the
# block. For example:
#
- # Time.parse(...) {|y| y < 100 ? (y >= 69 ? y + 1900 : y + 2000) : y}
+ # Time.parse(...) {|y| 0 <= y && y < 100 ? (y >= 69 ? y + 1900 : y + 2000) : y}
#
# If the upper components of the given time are broken or missing, they are
# supplied with those of +now+. For the lower components, the minimum
@@ -218,9 +214,11 @@
#
# # Suppose it is "Thu Nov 29 14:33:20 GMT 2001" now and
# # your timezone is GMT:
- # Time.parse("16:30") #=> Thu Nov 29 16:30:00 GMT 2001
- # Time.parse("7/23") #=> Mon Jul 23 00:00:00 GMT 2001
- # Time.parse("Aug 31") #=> Fri Aug 31 00:00:00 GMT 2001
+ # now = Time.parse("Thu Nov 29 14:33:20 GMT 2001")
+ # Time.parse("16:30", now) #=> 2001-11-29 16:30:00 +0900
+ # Time.parse("7/23", now) #=> 2001-07-23 00:00:00 +0900
+ # Time.parse("Aug 31", now) #=> 2001-08-31 00:00:00 +0900
+ # Time.parse("Aug 2000", now) #=> 2000-08-01 00:00:00 +0900
#
# Since there are numerous conflicts among locally defined timezone
# abbreviations all over the world, this method is not made to
@@ -254,10 +252,18 @@
#
# A failure for Time.parse should be checked, though.
#
+ # time library should be required to use this method as follows.
+ #
+ # require 'time'
+ #
def parse(date, now=self.now)
- d = Date._parse(date, false)
+ comp = !block_given?
+ d = Date._parse(date, comp)
+ if !d[:year] && !d[:mon] && !d[:mday] && !d[:hour] && !d[:min] && !d[:sec] && !d[:sec_fraction]
+ raise ArgumentError, "no time information in #{date.inspect}"
+ end
year = d[:year]
- year = yield(year) if year && block_given?
+ year = yield(year) if year && !comp
make_time(year, d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now)
end
@@ -291,6 +297,10 @@
#
# See #rfc2822 for more information on this format.
#
+ # time library should be required to use this method as follows.
+ #
+ # require 'time'
+ #
def rfc2822(date)
if /\A\s*
(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*,\s*)?
@@ -340,6 +350,10 @@
#
# See #httpdate for more information on this format.
#
+ # time library should be required to use this method as follows.
+ #
+ # require 'time'
+ #
def httpdate(date)
if /\A\s*
(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\x20
@@ -387,6 +401,10 @@
#
# See #xmlschema for more information on this format.
#
+ # time library should be required to use this method as follows.
+ #
+ # require 'time'
+ #
def xmlschema(date)
if /\A\s*
(-?\d+)-(\d\d)-(\d\d)
@@ -429,10 +447,14 @@
#
# If +self+ is a UTC time, -0000 is used as zone.
#
+ # time library should be required to use this method as follows.
+ #
+ # require 'time'
+ #
def rfc2822
- sprintf('%s, %02d %s %d %02d:%02d:%02d ',
+ sprintf('%s, %02d %s %0*d %02d:%02d:%02d ',
RFC2822_DAY_NAME[wday],
- day, RFC2822_MONTH_NAME[mon-1], year,
+ day, RFC2822_MONTH_NAME[mon-1], year < 0 ? 5 : 4, year,
hour, min, sec) +
if utc?
'-0000'
@@ -460,11 +482,15 @@
#
# Note that the result is always UTC (GMT).
#
+ # time library should be required to use this method as follows.
+ #
+ # require 'time'
+ #
def httpdate
t = dup.utc
- sprintf('%s, %02d %s %d %02d:%02d:%02d GMT',
+ sprintf('%s, %02d %s %0*d %02d:%02d:%02d GMT',
RFC2822_DAY_NAME[t.wday],
- t.day, RFC2822_MONTH_NAME[t.mon-1], t.year,
+ t.day, RFC2822_MONTH_NAME[t.mon-1], t.year < 0 ? 5 : 4, t.year,
t.hour, t.min, t.sec)
end
@@ -482,15 +508,17 @@
# +fractional_seconds+ specifies a number of digits of fractional seconds.
# Its default value is 0.
#
+ # time library should be required to use this method as follows.
+ #
+ # require 'time'
+ #
def xmlschema(fraction_digits=0)
- sprintf('%d-%02d-%02dT%02d:%02d:%02d',
- year, mon, day, hour, min, sec) +
+ sprintf('%0*d-%02d-%02dT%02d:%02d:%02d',
+ year < 0 ? 5 : 4, year, mon, day, hour, min, sec) +
if fraction_digits == 0
''
- elsif fraction_digits <= 9
- '.' + sprintf('%09d', nsec)[0, fraction_digits]
else
- '.' + sprintf('%09d', nsec) + '0' * (fraction_digits - 9)
+ '.' + sprintf('%0*d', fraction_digits, (subsec * 10**fraction_digits).floor)
end +
if utc?
'Z'
@@ -503,367 +531,3 @@
alias iso8601 xmlschema
end
-if __FILE__ == $0
- require 'test/unit'
-
- class TimeExtentionTest < Test::Unit::TestCase # :nodoc:
- def test_rfc822
- assert_equal(Time.utc(1976, 8, 26, 14, 30) + 4 * 3600,
- Time.rfc2822("26 Aug 76 14:30 EDT"))
- assert_equal(Time.utc(1976, 8, 27, 9, 32) + 7 * 3600,
- Time.rfc2822("27 Aug 76 09:32 PDT"))
- end
-
- def test_rfc2822
- assert_equal(Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600,
- Time.rfc2822("Fri, 21 Nov 1997 09:55:06 -0600"))
- assert_equal(Time.utc(2003, 7, 1, 10, 52, 37) - 2 * 3600,
- Time.rfc2822("Tue, 1 Jul 2003 10:52:37 +0200"))
- assert_equal(Time.utc(1997, 11, 21, 10, 1, 10) + 6 * 3600,
- Time.rfc2822("Fri, 21 Nov 1997 10:01:10 -0600"))
- assert_equal(Time.utc(1997, 11, 21, 11, 0, 0) + 6 * 3600,
- Time.rfc2822("Fri, 21 Nov 1997 11:00:00 -0600"))
- assert_equal(Time.utc(1997, 11, 24, 14, 22, 1) + 8 * 3600,
- Time.rfc2822("Mon, 24 Nov 1997 14:22:01 -0800"))
- begin
- Time.at(-1)
- rescue ArgumentError
- # ignore
- else
- assert_equal(Time.utc(1969, 2, 13, 23, 32, 54) + 3 * 3600 + 30 * 60,
- Time.rfc2822("Thu, 13 Feb 1969 23:32:54 -0330"))
- assert_equal(Time.utc(1969, 2, 13, 23, 32, 0) + 3 * 3600 + 30 * 60,
- Time.rfc2822(" Thu,
- 13
- Feb
- 1969
- 23:32
- -0330 (Newfoundland Time)"))
- end
- assert_equal(Time.utc(1997, 11, 21, 9, 55, 6),
- Time.rfc2822("21 Nov 97 09:55:06 GMT"))
- assert_equal(Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600,
- Time.rfc2822("Fri, 21 Nov 1997 09 : 55 : 06 -0600"))
- assert_raise(ArgumentError) {
- # inner comment is not supported.
- Time.rfc2822("Fri, 21 Nov 1997 09(comment): 55 : 06 -0600")
- }
- end
-
- def test_rfc2616
- t = Time.utc(1994, 11, 6, 8, 49, 37)
- assert_equal(t, Time.httpdate("Sun, 06 Nov 1994 08:49:37 GMT"))
- assert_equal(t, Time.httpdate("Sunday, 06-Nov-94 08:49:37 GMT"))
- assert_equal(t, Time.httpdate("Sun Nov 6 08:49:37 1994"))
- assert_equal(Time.utc(1995, 11, 15, 6, 25, 24),
- Time.httpdate("Wed, 15 Nov 1995 06:25:24 GMT"))
- assert_equal(Time.utc(1995, 11, 15, 4, 58, 8),
- Time.httpdate("Wed, 15 Nov 1995 04:58:08 GMT"))
- assert_equal(Time.utc(1994, 11, 15, 8, 12, 31),
- Time.httpdate("Tue, 15 Nov 1994 08:12:31 GMT"))
- assert_equal(Time.utc(1994, 12, 1, 16, 0, 0),
- Time.httpdate("Thu, 01 Dec 1994 16:00:00 GMT"))
- assert_equal(Time.utc(1994, 10, 29, 19, 43, 31),
- Time.httpdate("Sat, 29 Oct 1994 19:43:31 GMT"))
- assert_equal(Time.utc(1994, 11, 15, 12, 45, 26),
- Time.httpdate("Tue, 15 Nov 1994 12:45:26 GMT"))
- assert_equal(Time.utc(1999, 12, 31, 23, 59, 59),
- Time.httpdate("Fri, 31 Dec 1999 23:59:59 GMT"))
-
- assert_equal(Time.utc(2007, 12, 23, 11, 22, 33),
- Time.httpdate('Sunday, 23-Dec-07 11:22:33 GMT'))
- end
-
- def test_rfc3339
- t = Time.utc(1985, 4, 12, 23, 20, 50, 520000)
- s = "1985-04-12T23:20:50.52Z"
- assert_equal(t, Time.iso8601(s))
- assert_equal(s, t.iso8601(2))
-
- t = Time.utc(1996, 12, 20, 0, 39, 57)
- s = "1996-12-19T16:39:57-08:00"
- assert_equal(t, Time.iso8601(s))
- # There is no way to generate time string with arbitrary timezone.
- s = "1996-12-20T00:39:57Z"
- assert_equal(t, Time.iso8601(s))
- assert_equal(s, t.iso8601)
-
- t = Time.utc(1990, 12, 31, 23, 59, 60)
- s = "1990-12-31T23:59:60Z"
- assert_equal(t, Time.iso8601(s))
- # leap second is representable only if timezone file has it.
- s = "1990-12-31T15:59:60-08:00"
- assert_equal(t, Time.iso8601(s))
-
- begin
- Time.at(-1)
- rescue ArgumentError
- # ignore
- else
- t = Time.utc(1937, 1, 1, 11, 40, 27, 870000)
- s = "1937-01-01T12:00:27.87+00:20"
- assert_equal(t, Time.iso8601(s))
- end
- end
-
- # http://www.w3.org/TR/xmlschema-2/
- def test_xmlschema
- assert_equal(Time.utc(1999, 5, 31, 13, 20, 0) + 5 * 3600,
- Time.xmlschema("1999-05-31T13:20:00-05:00"))
- assert_equal(Time.local(2000, 1, 20, 12, 0, 0),
- Time.xmlschema("2000-01-20T12:00:00"))
- assert_equal(Time.utc(2000, 1, 20, 12, 0, 0),
- Time.xmlschema("2000-01-20T12:00:00Z"))
- assert_equal(Time.utc(2000, 1, 20, 12, 0, 0) - 12 * 3600,
- Time.xmlschema("2000-01-20T12:00:00+12:00"))
- assert_equal(Time.utc(2000, 1, 20, 12, 0, 0) + 13 * 3600,
- Time.xmlschema("2000-01-20T12:00:00-13:00"))
- assert_equal(Time.utc(2000, 3, 4, 23, 0, 0) - 3 * 3600,
- Time.xmlschema("2000-03-04T23:00:00+03:00"))
- assert_equal(Time.utc(2000, 3, 4, 20, 0, 0),
- Time.xmlschema("2000-03-04T20:00:00Z"))
- assert_equal(Time.local(2000, 1, 15, 0, 0, 0),
- Time.xmlschema("2000-01-15T00:00:00"))
- assert_equal(Time.local(2000, 2, 15, 0, 0, 0),
- Time.xmlschema("2000-02-15T00:00:00"))
- assert_equal(Time.local(2000, 1, 15, 12, 0, 0),
- Time.xmlschema("2000-01-15T12:00:00"))
- assert_equal(Time.utc(2000, 1, 16, 12, 0, 0),
- Time.xmlschema("2000-01-16T12:00:00Z"))
- assert_equal(Time.local(2000, 1, 1, 12, 0, 0),
- Time.xmlschema("2000-01-01T12:00:00"))
- assert_equal(Time.utc(1999, 12, 31, 23, 0, 0),
- Time.xmlschema("1999-12-31T23:00:00Z"))
- assert_equal(Time.local(2000, 1, 16, 12, 0, 0),
- Time.xmlschema("2000-01-16T12:00:00"))
- assert_equal(Time.local(2000, 1, 16, 0, 0, 0),
- Time.xmlschema("2000-01-16T00:00:00"))
- assert_equal(Time.utc(2000, 1, 12, 12, 13, 14),
- Time.xmlschema("2000-01-12T12:13:14Z"))
- assert_equal(Time.utc(2001, 4, 17, 19, 23, 17, 300000),
- Time.xmlschema("2001-04-17T19:23:17.3Z"))
- assert_raise(ArgumentError) { Time.xmlschema("2000-01-01T00:00:00.+00:00") }
- end
-
- def test_encode_xmlschema
- t = Time.utc(2001, 4, 17, 19, 23, 17, 300000)
- assert_equal("2001-04-17T19:23:17Z", t.xmlschema)
- assert_equal("2001-04-17T19:23:17.3Z", t.xmlschema(1))
- assert_equal("2001-04-17T19:23:17.300000Z", t.xmlschema(6))
- assert_equal("2001-04-17T19:23:17.3000000Z", t.xmlschema(7))
-
- t = Time.utc(2001, 4, 17, 19, 23, 17, 123456)
- assert_equal("2001-04-17T19:23:17.1234560Z", t.xmlschema(7))
- assert_equal("2001-04-17T19:23:17.123456Z", t.xmlschema(6))
- assert_equal("2001-04-17T19:23:17.12345Z", t.xmlschema(5))
- assert_equal("2001-04-17T19:23:17.1Z", t.xmlschema(1))
-
- begin
- Time.at(-1)
- rescue ArgumentError
- # ignore
- else
- t = Time.utc(1960, 12, 31, 23, 0, 0, 123456)
- assert_equal("1960-12-31T23:00:00.123456Z", t.xmlschema(6))
- end
-
- assert_equal(249, Time.xmlschema("2008-06-05T23:49:23.000249+09:00").usec)
- end
-
- def test_completion
- now = Time.local(2001,11,29,21,26,35)
- assert_equal(Time.local( 2001,11,29,21,12),
- Time.parse("2001/11/29 21:12", now))
- assert_equal(Time.local( 2001,11,29),
- Time.parse("2001/11/29", now))
- assert_equal(Time.local( 2001,11,29),
- Time.parse( "11/29", now))
- #assert_equal(Time.local(2001,11,1), Time.parse("Nov", now))
- assert_equal(Time.local( 2001,11,29,10,22),
- Time.parse( "10:22", now))
- end
-
- def test_invalid
- # They were actually used in some web sites.
- assert_raise(ArgumentError) { Time.httpdate("1 Dec 2001 10:23:57 GMT") }
- assert_raise(ArgumentError) { Time.httpdate("Sat, 1 Dec 2001 10:25:42 GMT") }
- assert_raise(ArgumentError) { Time.httpdate("Sat, 1-Dec-2001 10:53:55 GMT") }
- assert_raise(ArgumentError) { Time.httpdate("Saturday, 01-Dec-2001 10:15:34 GMT") }
- assert_raise(ArgumentError) { Time.httpdate("Saturday, 01-Dec-101 11:10:07 GMT") }
- assert_raise(ArgumentError) { Time.httpdate("Fri, 30 Nov 2001 21:30:00 JST") }
-
- # They were actually used in some mails.
- assert_raise(ArgumentError) { Time.rfc2822("01-5-20") }
- assert_raise(ArgumentError) { Time.rfc2822("7/21/00") }
- assert_raise(ArgumentError) { Time.rfc2822("2001-8-28") }
- assert_raise(ArgumentError) { Time.rfc2822("00-5-6 1:13:06") }
- assert_raise(ArgumentError) { Time.rfc2822("2001-9-27 9:36:49") }
- assert_raise(ArgumentError) { Time.rfc2822("2000-12-13 11:01:11") }
- assert_raise(ArgumentError) { Time.rfc2822("2001/10/17 04:29:55") }
- assert_raise(ArgumentError) { Time.rfc2822("9/4/2001 9:23:19 PM") }
- assert_raise(ArgumentError) { Time.rfc2822("01 Nov 2001 09:04:31") }
- assert_raise(ArgumentError) { Time.rfc2822("13 Feb 2001 16:4 GMT") }
- assert_raise(ArgumentError) { Time.rfc2822("01 Oct 00 5:41:19 PM") }
- assert_raise(ArgumentError) { Time.rfc2822("2 Jul 00 00:51:37 JST") }
- assert_raise(ArgumentError) { Time.rfc2822("01 11 2001 06:55:57 -0500") }
- assert_raise(ArgumentError) { Time.rfc2822("18 \343\366\356\341\370 2000") }
- assert_raise(ArgumentError) { Time.rfc2822("Fri, Oct 2001 18:53:32") }
- assert_raise(ArgumentError) { Time.rfc2822("Fri, 2 Nov 2001 03:47:54") }
- assert_raise(ArgumentError) { Time.rfc2822("Fri, 27 Jul 2001 11.14.14 +0200") }
- assert_raise(ArgumentError) { Time.rfc2822("Thu, 2 Nov 2000 04:13:53 -600") }
- assert_raise(ArgumentError) { Time.rfc2822("Wed, 5 Apr 2000 22:57:09 JST") }
- assert_raise(ArgumentError) { Time.rfc2822("Mon, 11 Sep 2000 19:47:33 00000") }
- assert_raise(ArgumentError) { Time.rfc2822("Fri, 28 Apr 2000 20:40:47 +-900") }
- assert_raise(ArgumentError) { Time.rfc2822("Fri, 19 Jan 2001 8:15:36 AM -0500") }
- assert_raise(ArgumentError) { Time.rfc2822("Thursday, Sep 27 2001 7:42:35 AM EST") }
- assert_raise(ArgumentError) { Time.rfc2822("3/11/2001 1:31:57 PM Pacific Daylight Time") }
- assert_raise(ArgumentError) { Time.rfc2822("Mi, 28 Mrz 2001 11:51:36") }
- assert_raise(ArgumentError) { Time.rfc2822("P, 30 sept 2001 23:03:14") }
- assert_raise(ArgumentError) { Time.rfc2822("fr, 11 aug 2000 18:39:22") }
- assert_raise(ArgumentError) { Time.rfc2822("Fr, 21 Sep 2001 17:44:03 -1000") }
- assert_raise(ArgumentError) { Time.rfc2822("Mo, 18 Jun 2001 19:21:40 -1000") }
- assert_raise(ArgumentError) { Time.rfc2822("l\366, 12 aug 2000 18:53:20") }
- assert_raise(ArgumentError) { Time.rfc2822("l\366, 26 maj 2001 00:15:58") }
- assert_raise(ArgumentError) { Time.rfc2822("Dom, 30 Sep 2001 17:36:30") }
- assert_raise(ArgumentError) { Time.rfc2822("%&, 31 %2/ 2000 15:44:47 -0500") }
- assert_raise(ArgumentError) { Time.rfc2822("dom, 26 ago 2001 03:57:07 -0300") }
- assert_raise(ArgumentError) { Time.rfc2822("ter, 04 set 2001 16:27:58 -0300") }
- assert_raise(ArgumentError) { Time.rfc2822("Wen, 3 oct 2001 23:17:49 -0400") }
- assert_raise(ArgumentError) { Time.rfc2822("Wen, 3 oct 2001 23:17:49 -0400") }
- assert_raise(ArgumentError) { Time.rfc2822("ele, 11 h: 2000 12:42:15 -0500") }
- assert_raise(ArgumentError) { Time.rfc2822("Tue, 14 Aug 2001 3:55:3 +0200") }
- assert_raise(ArgumentError) { Time.rfc2822("Fri, 25 Aug 2000 9:3:48 +0800") }
- assert_raise(ArgumentError) { Time.rfc2822("Fri, 1 Dec 2000 0:57:50 EST") }
- assert_raise(ArgumentError) { Time.rfc2822("Mon, 7 May 2001 9:39:51 +0200") }
- assert_raise(ArgumentError) { Time.rfc2822("Wed, 1 Aug 2001 16:9:15 +0200") }
- assert_raise(ArgumentError) { Time.rfc2822("Wed, 23 Aug 2000 9:17:36 +0800") }
- assert_raise(ArgumentError) { Time.rfc2822("Fri, 11 Aug 2000 10:4:42 +0800") }
- assert_raise(ArgumentError) { Time.rfc2822("Sat, 15 Sep 2001 13:22:2 +0300") }
- assert_raise(ArgumentError) { Time.rfc2822("Wed,16 \276\305\324\302 2001 20:06:25 +0800") }
- assert_raise(ArgumentError) { Time.rfc2822("Wed,7 \312\256\322\273\324\302 2001 23:47:22 +0800") }
- assert_raise(ArgumentError) { Time.rfc2822("=?iso-8859-1?Q?(=C5=DA),?= 10 2 2001 23:32:26 +0900 (JST)") }
- assert_raise(ArgumentError) { Time.rfc2822("\307\341\314\343\332\311, 30 \344\346\335\343\310\321 2001 10:01:06") }
- assert_raise(ArgumentError) { Time.rfc2822("=?iso-8859-1?Q?(=BF=E5),?= 12 =?iso-8859-1?Q?9=B7=EE?= 2001 14:52:41\n+0900 (JST)") }
- end
-
- def test_zone_0000
- assert_equal(true, Time.parse("2000-01-01T00:00:00Z").utc?)
- assert_equal(true, Time.parse("2000-01-01T00:00:00-00:00").utc?)
- assert_equal(false, Time.parse("2000-01-01T00:00:00+00:00").utc?)
- assert_equal(false, Time.parse("Sat, 01 Jan 2000 00:00:00 GMT").utc?)
- assert_equal(true, Time.parse("Sat, 01 Jan 2000 00:00:00 -0000").utc?)
- assert_equal(false, Time.parse("Sat, 01 Jan 2000 00:00:00 +0000").utc?)
- assert_equal(false, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 GMT").utc?)
- assert_equal(true, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 -0000").utc?)
- assert_equal(false, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 +0000").utc?)
- assert_equal(true, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 UTC").utc?)
- end
-
- def test_rfc2822_utc_roundtrip_winter
- t1 = Time.local(2008,12,1)
- t2 = Time.rfc2822(t1.rfc2822)
- assert_equal(t1.utc?, t2.utc?, "[ruby-dev:37126]")
- end
-
- def test_rfc2822_utc_roundtrip_summer
- t1 = Time.local(2008,8,1)
- t2 = Time.rfc2822(t1.rfc2822)
- assert_equal(t1.utc?, t2.utc?)
- end
-
- def test_parse_leap_second
- t = Time.utc(1998,12,31,23,59,59)
- assert_equal(t, Time.parse("Thu Dec 31 23:59:59 UTC 1998"))
- assert_equal(t, Time.parse("Fri Dec 31 23:59:59 -0000 1998"));t.localtime
- assert_equal(t, Time.parse("Fri Jan 1 08:59:59 +0900 1999"))
- assert_equal(t, Time.parse("Fri Jan 1 00:59:59 +0100 1999"))
- assert_equal(t, Time.parse("Fri Dec 31 23:59:59 +0000 1998"))
- assert_equal(t, Time.parse("Fri Dec 31 22:59:59 -0100 1998"));t.utc
- t += 1
- assert_equal(t, Time.parse("Thu Dec 31 23:59:60 UTC 1998"))
- assert_equal(t, Time.parse("Fri Dec 31 23:59:60 -0000 1998"));t.localtime
- assert_equal(t, Time.parse("Fri Jan 1 08:59:60 +0900 1999"))
- assert_equal(t, Time.parse("Fri Jan 1 00:59:60 +0100 1999"))
- assert_equal(t, Time.parse("Fri Dec 31 23:59:60 +0000 1998"))
- assert_equal(t, Time.parse("Fri Dec 31 22:59:60 -0100 1998"));t.utc
- t += 1 if t.sec == 60
- assert_equal(t, Time.parse("Thu Jan 1 00:00:00 UTC 1999"))
- assert_equal(t, Time.parse("Fri Jan 1 00:00:00 -0000 1999"));t.localtime
- assert_equal(t, Time.parse("Fri Jan 1 09:00:00 +0900 1999"))
- assert_equal(t, Time.parse("Fri Jan 1 01:00:00 +0100 1999"))
- assert_equal(t, Time.parse("Fri Jan 1 00:00:00 +0000 1999"))
- assert_equal(t, Time.parse("Fri Dec 31 23:00:00 -0100 1998"))
- end
-
- def test_rfc2822_leap_second
- t = Time.utc(1998,12,31,23,59,59)
- assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:59 UTC"))
- assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 -0000"));t.localtime
- assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 08:59:59 +0900"))
- assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:59:59 +0100"))
- assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 +0000"))
- assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:59 -0100"));t.utc
- t += 1
- assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:60 UTC"))
- assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 -0000"));t.localtime
- assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 08:59:60 +0900"))
- assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:59:60 +0100"))
- assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 +0000"))
- assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:60 -0100"));t.utc
- t += 1 if t.sec == 60
- assert_equal(t, Time.rfc2822("Thu, 1 Jan 1999 00:00:00 UTC"))
- assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:00:00 -0000"));t.localtime
- assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 09:00:00 +0900"))
- assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 01:00:00 +0100"))
- assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:00:00 +0000"))
- assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:00:00 -0100"))
- end
-
- def test_xmlschema_leap_second
- t = Time.utc(1998,12,31,23,59,59)
- assert_equal(t, Time.xmlschema("1998-12-31T23:59:59Z"))
- assert_equal(t, Time.xmlschema("1998-12-31T23:59:59-00:00"));t.localtime
- assert_equal(t, Time.xmlschema("1999-01-01T08:59:59+09:00"))
- assert_equal(t, Time.xmlschema("1999-01-01T00:59:59+01:00"))
- assert_equal(t, Time.xmlschema("1998-12-31T23:59:59+00:00"))
- assert_equal(t, Time.xmlschema("1998-12-31T22:59:59-01:00"));t.utc
- t += 1
- assert_equal(t, Time.xmlschema("1998-12-31T23:59:60Z"))
- assert_equal(t, Time.xmlschema("1998-12-31T23:59:60-00:00"));t.localtime
- assert_equal(t, Time.xmlschema("1999-01-01T08:59:60+09:00"))
- assert_equal(t, Time.xmlschema("1999-01-01T00:59:60+01:00"))
- assert_equal(t, Time.xmlschema("1998-12-31T23:59:60+00:00"))
- assert_equal(t, Time.xmlschema("1998-12-31T22:59:60-01:00"));t.utc
- t += 1 if t.sec == 60
- assert_equal(t, Time.xmlschema("1999-01-01T00:00:00Z"))
- assert_equal(t, Time.xmlschema("1999-01-01T00:00:00-00:00"));t.localtime
- assert_equal(t, Time.xmlschema("1999-01-01T09:00:00+09:00"))
- assert_equal(t, Time.xmlschema("1999-01-01T01:00:00+01:00"))
- assert_equal(t, Time.xmlschema("1999-01-01T00:00:00+00:00"))
- assert_equal(t, Time.xmlschema("1998-12-31T23:00:00-01:00"))
- end
-
- def test_xmlschema_fraction
- assert_equal(500000, Time.xmlschema("2000-01-01T00:00:00.5+00:00").tv_usec)
- end
-
- def test_ruby_talk_152866
- t = Time::xmlschema('2005-08-30T22:48:00-07:00')
- assert_equal(31, t.day)
- assert_equal(8, t.mon)
- end
-
- def test_parse_fraction
- assert_equal(500000, Time.parse("2000-01-01T00:00:00.5+00:00").tv_usec)
- end
-
- def test_strptime
- assert_equal(Time.utc(2005, 8, 28, 06, 54, 20), Time.strptime("28/Aug/2005:06:54:20 +0000", "%d/%b/%Y:%T %z"))
- end
-
- def test_nsec
- assert_equal(123456789, Time.xmlschema("2000-01-01T00:00:00.123456789+00:00").tv_nsec)
- assert_equal(123456789, Time.parse("2000-01-01T00:00:00.123456789+00:00").tv_nsec)
- end
- end
-end
Modified: MacRuby/trunk/lib/timeout.rb
===================================================================
--- MacRuby/trunk/lib/timeout.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/timeout.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -46,8 +46,13 @@
begin
x = Thread.current
y = Thread.start {
- sleep sec
- x.raise exception, "execution expired" if x.alive?
+ begin
+ sleep sec
+ rescue => e
+ x.raise e
+ else
+ x.raise exception, "execution expired" if x.alive?
+ end
}
return yield(sec)
rescue exception => e
@@ -63,7 +68,7 @@
raise Error, e.message, e.backtrace
ensure
if y and y.alive?
- y.kill
+ y.kill
y.join # make sure y is dead.
end
end
@@ -85,24 +90,3 @@
# Another name for Timeout::Error, defined for backwards compatibility with
# earlier versions of timeout.rb.
TimeoutError = Timeout::Error
-
-if __FILE__ == $0
- p timeout(5) {
- 45
- }
- p timeout(5, TimeoutError) {
- 45
- }
- p timeout(nil) {
- 54
- }
- p timeout(0) {
- 54
- }
- p timeout(5) {
- loop {
- p 10
- sleep 1
- }
- }
-end
Modified: MacRuby/trunk/lib/tmpdir.rb
===================================================================
--- MacRuby/trunk/lib/tmpdir.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/tmpdir.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,38 +1,19 @@
#
# tmpdir - retrieve temporary directory path
#
-# $Id: tmpdir.rb 19513 2008-09-24 05:39:39Z usa $
+# $Id: tmpdir.rb 27667 2010-05-08 03:25:17Z nobu $
#
require 'fileutils'
+begin
+ require 'etc.so'
+rescue LoadError
+end
class Dir
- @@systmpdir = '/tmp'
+ @@systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp'
- begin
- require 'Win32API'
- CSIDL_LOCAL_APPDATA = 0x001c
- max_pathlen = 260
- windir = "\0"*(max_pathlen+1)
- begin
- getdir = Win32API.new('shell32', 'SHGetFolderPath', 'LLLLP', 'L')
- raise RuntimeError if getdir.call(0, CSIDL_LOCAL_APPDATA, 0, 0, windir) != 0
- windir = File.expand_path(windir.rstrip)
- rescue RuntimeError
- begin
- getdir = Win32API.new('kernel32', 'GetSystemWindowsDirectory', 'PL', 'L')
- rescue RuntimeError
- getdir = Win32API.new('kernel32', 'GetWindowsDirectory', 'PL', 'L')
- end
- len = getdir.call(windir, windir.size)
- windir = File.expand_path(windir[0, len])
- end
- temp = File.join(windir.untaint, 'temp')
- @@systmpdir = temp if File.directory?(temp) and File.writable?(temp)
- rescue LoadError
- end
-
##
# Returns the operating system's temporary file path.
@@ -41,12 +22,11 @@
if $SAFE > 0
tmp = @@systmpdir
else
- for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'],
- ENV['USERPROFILE'], @@systmpdir, '/tmp']
- if dir and File.directory?(dir) and File.writable?(dir)
+ for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp']
+ if dir and stat = File.stat(dir) and stat.directory? and stat.writable?
tmp = dir
break
- end
+ end rescue nil
end
File.expand_path(tmp)
end
@@ -96,41 +76,67 @@
# FileUtils.remove_entry_secure dir
# end
#
- def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil)
- case prefix_suffix
- when nil
- prefix = "d"
- suffix = ""
- when String
- prefix = prefix_suffix
- suffix = ""
- when Array
- prefix = prefix_suffix[0]
- suffix = prefix_suffix[1]
+ def Dir.mktmpdir(prefix_suffix=nil, *rest)
+ path = Tmpname.create(prefix_suffix || "d", *rest) {|n| mkdir(n, 0700)}
+ if block_given?
+ begin
+ yield path
+ ensure
+ FileUtils.remove_entry_secure path
+ end
else
- raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
+ path
end
- tmpdir ||= Dir.tmpdir
- t = Time.now.strftime("%Y%m%d")
- n = nil
- begin
- path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
+ end
+
+ module Tmpname # :nodoc:
+ module_function
+
+ def tmpdir
+ Dir.tmpdir
+ end
+
+ def make_tmpname(prefix_suffix, n)
+ case prefix_suffix
+ when String
+ prefix = prefix_suffix
+ suffix = ""
+ when Array
+ prefix = prefix_suffix[0]
+ suffix = prefix_suffix[1]
+ else
+ raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
+ end
+ t = Time.now.strftime("%Y%m%d")
+ path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
path << "-#{n}" if n
path << suffix
- Dir.mkdir(path, 0700)
- rescue Errno::EEXIST
- n ||= 0
- n += 1
- retry
end
- if block_given?
+ def create(basename, *rest)
+ if opts = Hash.try_convert(rest[-1])
+ opts = opts.dup if rest.pop.equal?(opts)
+ max_try = opts.delete(:max_try)
+ opts = [opts]
+ else
+ opts = []
+ end
+ tmpdir, = *rest
+ if $SAFE > 0 and tmpdir.tainted?
+ tmpdir = '/tmp'
+ else
+ tmpdir ||= tmpdir()
+ end
+ n = nil
begin
- yield path
- ensure
- FileUtils.remove_entry_secure path
+ path = File.expand_path(make_tmpname(basename, n), tmpdir)
+ yield(path, n, *opts)
+ rescue Errno::EEXIST
+ n ||= 0
+ n += 1
+ retry if !max_try or n < max_try
+ raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'"
end
- else
path
end
end
Modified: MacRuby/trunk/lib/tracer.rb
===================================================================
--- MacRuby/trunk/lib/tracer.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/tracer.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,38 +1,57 @@
-#
# tracer.rb -
-# $Release Version: 0.2$
-# $Revision: 1.8 $
-# by Keiju ISHITSUKA(Nippon Rational Inc.)
+# $Release Version: 0.3$
+# $Revision: 1.12 $
+# by Keiju ISHITSUKA(keiju at ishitsuka.com)
#
# --
#
#
#
+require "thread"
#
# tracer main class
#
class Tracer
- @RCS_ID='-$Id: tracer.rb,v 1.8 1998/05/19 03:42:49 keiju Exp keiju $-'
-
- @stdout = STDOUT
- @verbose = false
class << self
attr_accessor :verbose
alias verbose? verbose
+
attr_accessor :stdout
+ attr_reader :stdout_mutex
+
+ # display process id?
+ attr_accessor :display_process_id
+ alias display_process_id? display_process_id
+
+ # display thread id?
+ attr_accessor :display_thread_id
+ alias display_thread_id? display_thread_id
+
+ # display builtin method call?
+ attr_accessor :display_c_call
+ alias display_c_call? display_c_call
end
-
+ Tracer::stdout = STDOUT
+ Tracer::verbose = false
+ Tracer::display_process_id = false
+ Tracer::display_thread_id = true
+ Tracer::display_c_call = false
+
+ @stdout_mutex = Mutex.new
+
EVENT_SYMBOL = {
"line" => "-",
"call" => ">",
"return" => "<",
"class" => "C",
"end" => "E",
- "c-call" => ">",
- "c-return" => "<",
+ "raise" => "^",
+ "c-call" => "}",
+ "c-return" => "{",
+ "unknown" => "?"
}
-
+
def initialize
@threads = Hash.new
if defined? Thread.main
@@ -45,7 +64,7 @@
@filters = []
end
-
+
def stdout
Tracer.stdout
end
@@ -63,7 +82,7 @@
stdout.print "Trace on\n" if Tracer.verbose?
end
end
-
+
def off
set_trace_func nil
stdout.print "Trace off\n" if Tracer.verbose?
@@ -76,7 +95,7 @@
def set_get_line_procs(file, p = proc)
@get_line_procs[file] = p
end
-
+
def get_line(file, line)
if p = @get_line_procs[file]
return p.call(line)
@@ -84,8 +103,8 @@
unless list = SCRIPT_LINES__[file]
begin
- f = open(file)
- begin
+ f = File::open(file)
+ begin
SCRIPT_LINES__[file] = list = f.readlines
ensure
f.close
@@ -101,7 +120,7 @@
"-\n"
end
end
-
+
def get_thread_no
if no = @threads[Thread.current.object_id]
no
@@ -109,24 +128,35 @@
@threads[Thread.current.object_id] = @threads.size
end
end
-
+
def trace_func(event, file, line, id, binding, klass, *)
return if file == __FILE__
-
+
for p in @filters
return unless p.call event, file, line, id, binding, klass
end
-
- # saved_crit = Thread.critical
- # Thread.critical = true
- stdout.printf("#%d:%s:%d:%s:%s: %s",
- get_thread_no,
- file,
- line,
- klass || '',
- EVENT_SYMBOL[event],
- get_line(file, line))
- # Thread.critical = saved_crit
+
+ return unless Tracer::display_c_call? or
+ event != "c-call" && event != "c-return"
+
+ Tracer::stdout_mutex.synchronize do
+ if EVENT_SYMBOL[event]
+ stdout.printf("<%d>", $$) if Tracer::display_process_id?
+ stdout.printf("#%d:", get_thread_no) if Tracer::display_thread_id?
+ if line == 0
+ source = "?\n"
+ else
+ source = get_line(file, line)
+ end
+ printf("%s:%d:%s:%s: %s",
+ file,
+ line,
+ klass || '',
+ EVENT_SYMBOL[event],
+ source)
+ end
+ end
+
end
Single = new
@@ -137,11 +167,11 @@
Single.on
end
end
-
+
def Tracer.off
Single.off
end
-
+
def Tracer.set_get_line_procs(file_name, p = proc)
Single.set_get_line_procs(file_name, p)
end
@@ -149,18 +179,17 @@
def Tracer.add_filter(p = proc)
Single.add_filter(p)
end
-
end
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
if $0 == __FILE__
# direct call
-
+
$0 = ARGV[0]
ARGV.shift
Tracer.on
require $0
-elsif caller(0).size == 1
+elsif caller.size <= 1
Tracer.on
end
Modified: MacRuby/trunk/lib/tsort.rb
===================================================================
--- MacRuby/trunk/lib/tsort.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/tsort.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,4 +1,3 @@
-#!/usr/bin/env ruby
#--
# tsort.rb - provides a module for topological sorting and strongly connected components.
#++
@@ -241,50 +240,3 @@
raise NotImplementedError.new
end
end
-
-if __FILE__ == $0
- require 'test/unit'
-
- class TSortHash < Hash # :nodoc:
- include TSort
- alias tsort_each_node each_key
- def tsort_each_child(node, &block)
- fetch(node).each(&block)
- end
- end
-
- class TSortArray < Array # :nodoc:
- include TSort
- alias tsort_each_node each_index
- def tsort_each_child(node, &block)
- fetch(node).each(&block)
- end
- end
-
- class TSortTest < Test::Unit::TestCase # :nodoc:
- def test_dag
- h = TSortHash[{1=>[2, 3], 2=>[3], 3=>[]}]
- assert_equal([3, 2, 1], h.tsort)
- assert_equal([[3], [2], [1]], h.strongly_connected_components)
- end
-
- def test_cycle
- h = TSortHash[{1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}]
- assert_equal([[4], [2, 3], [1]],
- h.strongly_connected_components.map {|nodes| nodes.sort})
- assert_raise(TSort::Cyclic) { h.tsort }
- end
-
- def test_array
- a = TSortArray[[1], [0], [0], [2]]
- assert_equal([[0, 1], [2], [3]],
- a.strongly_connected_components.map {|nodes| nodes.sort})
-
- a = TSortArray[[], [0]]
- assert_equal([[0], [1]],
- a.strongly_connected_components.map {|nodes| nodes.sort})
- end
- end
-
-end
-
Modified: MacRuby/trunk/lib/un.rb
===================================================================
--- MacRuby/trunk/lib/un.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/un.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,11 +1,11 @@
-#
+#
# = un.rb
-#
+#
# Copyright (c) 2003 WATANABE Hirofumi <eban at ruby-lang.org>
-#
+#
# This program is free software.
# You can distribute/modify this program under the same terms of Ruby.
-#
+#
# == Utilities to replace common UNIX commands in Makefiles etc
#
# == SYNOPSIS
@@ -21,6 +21,7 @@
# ruby -run -e touch -- [OPTION] FILE
# ruby -run -e wait_writable -- [OPTION] FILE
# ruby -run -e mkmf -- [OPTION] EXTNAME [OPTION]
+# ruby -run -e httpd -- [OPTION] DocumentRoot
# ruby -run -e help [COMMAND]
require "fileutils"
@@ -43,7 +44,7 @@
end
long_options.each do |s|
opt_name = s[/\A(?:--)?([^\s=]+)/, 1].intern
- o.on(s.sub(/\A(?!--)/, '--')) do |val|
+ o.on(s.gsub(/([a-z])([A-Z])/){$1+"-"+$2.downcase}.sub(/\A(?!--)/, '--')) do |val|
opt_hash[opt_name] = val
end
end
@@ -283,6 +284,43 @@
end
##
+# Run WEBrick HTTP server.
+#
+# ruby -run -e httpd -- [OPTION] DocumentRoot
+#
+# --bind-address=ADDR address to bind
+# --port=NUM listening port number
+# --max-clients=MAX max number of simultaneous clients
+# --temp-dir=DIR temporary directory
+# --do-not-reverse-lookup disable reverse lookup
+# --request-timeout=SECOND request timeout in seconds
+# --http-version=VERSION HTTP version
+# -v verbose
+#
+
+def httpd
+ setup("", "BindAddress=ADDR", "Port=PORT", "MaxClients=NUM", "TempDir=DIR",
+ "DoNotReverseLookup", "RequestTimeout=SECOND", "HTTPVersion=VERSION") do
+ |argv, options|
+ require 'webrick'
+ opt = options[:RequestTimeout] and options[:RequestTimeout] = opt.to_i
+ opt = options[:Port] and (options[:Port] = Integer(opt)) rescue nil
+ unless argv.empty?
+ options[:DocumentRoot] = argv.shift
+ end
+ s = WEBrick::HTTPServer.new(options)
+ shut = proc {s.shutdown}
+ Signal.trap("TERM", shut)
+ Signal.trap("QUIT", shut)
+ if STDIN.tty?
+ Signal.trap("HUP", shut)
+ Signal.trap("INT", shut)
+ end
+ s.start
+ end
+end
+
+##
# Display help message.
#
# ruby -run -e help [COMMAND]
Modified: MacRuby/trunk/lib/uri/common.rb
===================================================================
--- MacRuby/trunk/lib/uri/common.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/uri/common.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,8 +1,8 @@
# = uri/common.rb
#
# Author:: Akira Yamada <akira at ruby-lang.org>
-# Revision:: $Id: common.rb 19413 2008-09-18 11:05:09Z mame $
-# License::
+# Revision:: $Id: common.rb 27285 2010-04-10 22:05:02Z naruse $
+# License::
# You can redistribute it and/or modify it under the same term as Ruby.
#
@@ -34,7 +34,7 @@
UNRESERVED = "-_.!~*'()#{ALNUM}"
# reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
# "$" | ","
- # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+ # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
# "$" | "," | "[" | "]" (RFC 2732)
RESERVED = ";/?:@&=+$,\\[\\]"
@@ -103,7 +103,7 @@
# null uri
when @regexp[:ABS_URI]
- scheme, opaque, userinfo, host, port,
+ scheme, opaque, userinfo, host, port,
registry, path, query, fragment = $~[1..-1]
# URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
@@ -119,19 +119,19 @@
# server = [ [ userinfo "@" ] hostport ]
if !scheme
- raise InvalidURIError,
+ raise InvalidURIError,
"bad URI(absolute but no scheme): #{uri}"
end
if !opaque && (!path && (!host && !registry))
raise InvalidURIError,
- "bad URI(absolute but no path): #{uri}"
+ "bad URI(absolute but no path): #{uri}"
end
when @regexp[:REL_URI]
scheme = nil
opaque = nil
- userinfo, host, port, registry,
+ userinfo, host, port, registry,
rel_segment, abs_path, query, fragment = $~[1..-1]
if rel_segment && abs_path
path = rel_segment + abs_path
@@ -158,7 +158,7 @@
path = '' if !path && !opaque # (see RFC2396 Section 5.2)
ret = [
- scheme,
+ scheme,
userinfo, host, port, # X
registry, # X
path, # Y
@@ -170,16 +170,16 @@
end
def parse(uri)
- scheme, userinfo, host, port,
+ scheme, userinfo, host, port,
registry, path, opaque, query, fragment = self.split(uri)
if scheme && URI.scheme_list.include?(scheme.upcase)
- URI.scheme_list[scheme.upcase].new(scheme, userinfo, host, port,
- registry, path, opaque, query,
+ URI.scheme_list[scheme.upcase].new(scheme, userinfo, host, port,
+ registry, path, opaque, query,
fragment, self)
else
- Generic.new(scheme, userinfo, host, port,
- registry, path, opaque, query,
+ Generic.new(scheme, userinfo, host, port,
+ registry, path, opaque, query,
fragment, self)
end
end
@@ -223,11 +223,11 @@
tmp << sprintf('%%%02X', uc)
end
tmp
- end
+ end.force_encoding(Encoding::US_ASCII)
end
def unescape(str, escaped = @regexp[:ESCAPED])
- str.gsub(escaped) { [$&[1, 2].hex].pack('U') }
+ str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(str.encoding)
end
@@to_s = Kernel.instance_method(:to_s)
@@ -397,8 +397,8 @@
ret = {}
# for URI::split
- ret[:ABS_URI] = Regexp.new('^' + pattern[:X_ABS_URI] + '$', Regexp::EXTENDED)
- ret[:REL_URI] = Regexp.new('^' + pattern[:X_REL_URI] + '$', Regexp::EXTENDED)
+ ret[:ABS_URI] = Regexp.new('\A\s*' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
+ ret[:REL_URI] = Regexp.new('\A\s*' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
# for URI::extract
ret[:URI_REF] = Regexp.new(pattern[:URI_REF])
@@ -457,7 +457,7 @@
end
end
else
- raise ArgumentError,
+ raise ArgumentError,
"expected Array of or Hash of components of #{klass.to_s} (#{klass.component[1..-1].join(', ')})"
end
tmp[:scheme] = klass.to_s.sub(/\A.*::/, '').downcase
@@ -501,6 +501,7 @@
# # => "@%3F@%21"
#
def escape(*arg)
+ warn "#{caller(1)[0]}: warning: URI.escape is obsolete" if $VERBOSE
DEFAULT_PARSER.escape(*arg)
end
alias encode escape
@@ -526,6 +527,7 @@
# # => "http://example.com/?a=\t\r"
#
def unescape(*arg)
+ warn "#{caller(1)[0]}: warning: URI.unescape is obsolete" if $VERBOSE
DEFAULT_PARSER.unescape(*arg)
end
alias decode unescape
@@ -538,7 +540,7 @@
def self.scheme_list
@@schemes
end
-
+
#
# Base class for all URI exceptions.
#
@@ -579,7 +581,7 @@
# * Opaque
# * Query
# * Fragment
- #
+ #
# == Usage
#
# require 'uri'
@@ -604,7 +606,7 @@
# == Description
#
# Creates one of the URI's subclasses instance from the string.
- #
+ #
# == Raises
#
# URI::InvalidURIError
@@ -617,11 +619,11 @@
# uri = URI.parse("http://www.ruby-lang.org/")
# p uri
# # => #<URI::HTTP:0x202281be URL:http://www.ruby-lang.org/>
- # p uri.scheme
- # # => "http"
- # p uri.host
- # # => "www.ruby-lang.org"
- #
+ # p uri.scheme
+ # # => "http"
+ # p uri.host
+ # # => "www.ruby-lang.org"
+ #
def self.parse(uri)
DEFAULT_PARSER.parse(uri)
end
@@ -658,7 +660,7 @@
#
# == Args
#
- # +str+::
+ # +str+::
# String to extract URIs from.
# +schemes+::
# Limit URI matching to a specific schemes.
@@ -686,25 +688,25 @@
#
# == Args
#
- # +match_schemes+::
+ # +match_schemes+::
# Array of schemes. If given, resulting regexp matches to URIs
# whose scheme is one of the match_schemes.
- #
+ #
# == Description
# Returns a Regexp object which matches to URI-like strings.
# The Regexp object returned by this method includes arbitrary
# number of capture group (parentheses). Never rely on it's number.
- #
+ #
# == Usage
#
# require 'uri'
#
# # extract first URI from html_string
# html_string.slice(URI.regexp)
- #
+ #
# # remove ftp URIs
# html_string.sub(URI.regexp(['ftp'])
- #
+ #
# # You should not rely on the number of parentheses
# html_string.scan(URI.regexp) do |*matches|
# p $&
@@ -714,6 +716,124 @@
DEFAULT_PARSER.make_regexp(schemes)
end
+ TBLENCWWWCOMP_ = {} # :nodoc:
+ TBLDECWWWCOMP_ = {} # :nodoc:
+ HTML5ASCIIINCOMPAT = [Encoding::UTF_16BE, Encoding::UTF_16LE,
+ Encoding::UTF_32BE, Encoding::UTF_32LE] # :nodoc:
+
+ # Encode given +str+ to URL-encoded form data.
+ #
+ # This doesn't convert *, -, ., 0-9, A-Z, _, a-z,
+ # does convert SP to +, and convert others to %XX.
+ #
+ # This refers http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
+ #
+ # See URI.decode_www_form_component, URI.encode_www_form
+ def self.encode_www_form_component(str)
+ if TBLENCWWWCOMP_.empty?
+ 256.times do |i|
+ TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
+ end
+ TBLENCWWWCOMP_[' '] = '+'
+ TBLENCWWWCOMP_.freeze
+ end
+ str = str.to_s
+ if HTML5ASCIIINCOMPAT.include?(str.encoding)
+ str = str.encode(Encoding::UTF_8)
+ else
+ str = str.dup
+ end
+ str.force_encoding(Encoding::ASCII_8BIT)
+ str.gsub!(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_)
+ str.force_encoding(Encoding::US_ASCII)
+ end
+
+ # Decode given +str+ of URL-encoded form data.
+ #
+ # This decods + to SP.
+ #
+ # See URI.encode_www_form_component, URI.decode_www_form
+ def self.decode_www_form_component(str, enc=Encoding::UTF_8)
+ if TBLDECWWWCOMP_.empty?
+ 256.times do |i|
+ h, l = i>>4, i&15
+ TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
+ TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
+ TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
+ TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
+ end
+ TBLDECWWWCOMP_['+'] = ' '
+ TBLDECWWWCOMP_.freeze
+ end
+ raise ArgumentError, "invalid %-encoding (#{str})" unless /\A(?:%\h\h|[^%]+)*\z/ =~ str
+ str.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
+ end
+
+ # Generate URL-encoded form data from given +enum+.
+ #
+ # This generates application/x-www-form-urlencoded data defined in HTML5
+ # from given an Enumerable object.
+ #
+ # This internally uses URI.encode_www_form_component(str).
+ #
+ # This doesn't convert encodings of give items, so convert them before call
+ # this method if you want to send data as other than original encoding or
+ # mixed encoding data. (strings which is encoded in HTML5 ASCII incompatible
+ # encoding is converted to UTF-8)
+ #
+ # This doesn't treat files. When you send a file, use multipart/form-data.
+ #
+ # This refers http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
+ #
+ # See URI.encode_www_form_component, URI.decode_www_form
+ def self.encode_www_form(enum)
+ str = nil
+ enum.each do |k,v|
+ if str
+ str << '&'
+ else
+ str = nil.to_s
+ end
+ str << encode_www_form_component(k)
+ str << '='
+ str << encode_www_form_component(v)
+ end
+ str
+ end
+
+ WFKV_ = '(?:%\h\h|[^%#=;&]+)' # :nodoc:
+
+ # Decode URL-encoded form data from given +str+.
+ #
+ # This decodes application/x-www-form-urlencoded data
+ # and returns array of key-value array.
+ # This internally uses URI.decode_www_form_component.
+ #
+ # _charset_ hack is not supported now because the mapping from given charset
+ # to Ruby's encoding is not clear yet.
+ # see also http://www.w3.org/TR/html5/syntax.html#character-encodings-0
+ #
+ # This refers http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
+ #
+ # ary = URI.decode_www_form("a=1&a=2&b=3")
+ # p ary #=> [['a', '1'], ['a', '2'], ['b', '3']]
+ # p ary.assoc('a').last #=> '1'
+ # p ary.assoc('b').last #=> '3'
+ # p ary.rassoc('a').last #=> '2'
+ # p Hash[ary] # => {"a"=>"2", "b"=>"3"}
+ #
+ # See URI.decode_www_form_component, URI.encode_www_form
+ def self.decode_www_form(str, enc=Encoding::UTF_8)
+ return [] if str.empty?
+ unless /\A#{WFKV_}*=#{WFKV_}*(?:[;&]#{WFKV_}*=#{WFKV_}*)*\z/o =~ str
+ raise ArgumentError, "invalid data of application/x-www-form-urlencoded (#{str})"
+ end
+ ary = []
+ $&.scan(/([^=;&]+)=([^;&]*)/) do
+ ary << [decode_www_form_component($1, enc), decode_www_form_component($2, enc)]
+ end
+ ary
+ end
end
module Kernel
Modified: MacRuby/trunk/lib/uri/ftp.rb
===================================================================
--- MacRuby/trunk/lib/uri/ftp.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/uri/ftp.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -3,7 +3,7 @@
#
# Author:: Akira Yamada <akira at ruby-lang.org>
# License:: You can redistribute it and/or modify it under the same term as Ruby.
-# Revision:: $Id: ftp.rb 11708 2007-02-12 23:01:19Z shyouhei $
+# Revision:: $Id: ftp.rb 27350 2010-04-15 13:41:19Z mame $
#
require 'uri/generic'
@@ -13,16 +13,21 @@
#
# FTP URI syntax is defined by RFC1738 section 3.2.
#
+ # This class will be redesigned because of difference of implementations;
+ # the structure of its path. draft-hoffman-ftp-uri-04 is a draft but it
+ # is a good summary about the de facto spec.
+ # http://tools.ietf.org/html/draft-hoffman-ftp-uri-04
+ #
class FTP < Generic
DEFAULT_PORT = 21
COMPONENT = [
- :scheme,
+ :scheme,
:userinfo, :host, :port,
:path, :typecode
].freeze
#
- # Typecode is "a", "i" or "d".
+ # Typecode is "a", "i" or "d".
#
# * "a" indicates a text file (the FTP command was ASCII)
# * "i" indicates a binary file (FTP command IMAGE)
@@ -31,7 +36,7 @@
TYPECODE = ['a', 'i', 'd'].freeze
TYPECODE_PREFIX = ';type='.freeze
- def self.new2(user, password, host, port, path,
+ def self.new2(user, password, host, port, path,
typecode = nil, arg_check = true)
typecode = nil if typecode.size == 0
if typecode && !TYPECODE.include?(typecode)
@@ -42,22 +47,22 @@
# do escape
self.new('ftp',
- [user, password],
- host, port, nil,
- typecode ? path + TYPECODE_PREFIX + typecode : path,
+ [user, password],
+ host, port, nil,
+ typecode ? path + TYPECODE_PREFIX + typecode : path,
nil, nil, nil, arg_check)
end
#
# == Description
#
- # Creates a new URI::FTP object from components, with syntax checking.
+ # Creates a new URI::FTP object from components, with syntax checking.
#
- # The components accepted are +userinfo+, +host+, +port+, +path+ and
+ # The components accepted are +userinfo+, +host+, +port+, +path+ and
# +typecode+.
#
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
+ # The components should be provided either as an Array, or as a Hash
+ # with keys formed by preceding the component names with a colon.
#
# If an Array is used, the components must be passed in the order
# [userinfo, host, port, path, typecode]
@@ -67,11 +72,11 @@
#
# require 'uri'
#
- # uri = URI::FTP.build(['user:password', 'ftp.example.com', nil,
+ # uri = URI::FTP.build(['user:password', 'ftp.example.com', nil,
# '/path/file.> zip', 'i'])
# puts uri.to_s -> ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=a
#
- # uri2 = URI::FTP.build({:host => 'ftp.example.com',
+ # uri2 = URI::FTP.build({:host => 'ftp.example.com',
# :path => 'ruby/src'})
# puts uri2.to_s -> ftp://ftp.example.com/ruby/src
#
@@ -92,7 +97,7 @@
if tmp[:typecode]
if tmp[:typecode].size == 1
- tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode]
+ tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode]
end
tmp[:path] << tmp[:typecode]
end
@@ -109,17 +114,18 @@
# Unlike build(), this method does not escape the path component as
# required by RFC1738; instead it is treated as per RFC2396.
#
- # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
+ # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
# +opaque+, +query+ and +fragment+, in that order.
#
def initialize(*arg)
+ arg[5] = arg[5].sub(/^\//,'').sub(/^%2F/,'/')
super(*arg)
@typecode = nil
tmp = @path.index(TYPECODE_PREFIX)
if tmp
typecode = @path[tmp + TYPECODE_PREFIX.size..-1]
- self.set_path(@path[0..tmp - 1])
-
+ @path = @path[0..tmp - 1]
+
if arg[-1]
self.typecode = typecode
else
@@ -164,9 +170,9 @@
# RFC 1738 specifically states that the path for an FTP URI does not
# include the / which separates the URI path from the URI host. Example:
#
- # ftp://ftp.example.com/pub/ruby
+ # ftp://ftp.example.com/pub/ruby
#
- # The above URI indicates that the client should connect to
+ # The above URI indicates that the client should connect to
# ftp.example.com then cd pub/ruby from the initial login directory.
#
# If you want to cd to an absolute directory, you must include an
@@ -180,6 +186,11 @@
return @path.sub(/^\//,'').sub(/^%2F/,'/')
end
+ def set_path(v)
+ super("/" + v.sub(/^\//, "%2F"))
+ end
+ protected :set_path
+
def to_s
save_path = nil
if @typecode
Modified: MacRuby/trunk/lib/uri/generic.rb
===================================================================
--- MacRuby/trunk/lib/uri/generic.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/uri/generic.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -3,13 +3,13 @@
#
# Author:: Akira Yamada <akira at ruby-lang.org>
# License:: You can redistribute it and/or modify it under the same term as Ruby.
-# Revision:: $Id: generic.rb 20258 2008-11-18 16:46:16Z yugui $
+# Revision:: $Id: generic.rb 27350 2010-04-15 13:41:19Z mame $
#
require 'uri/common'
module URI
-
+
#
# Base class for all URI classes.
# Implements generic URI syntax as per RFC 2396.
@@ -31,10 +31,10 @@
end
COMPONENT = [
- :scheme,
- :userinfo, :host, :port, :registry,
- :path, :opaque,
- :query,
+ :scheme,
+ :userinfo, :host, :port, :registry,
+ :path, :opaque,
+ :query,
:fragment
].freeze
@@ -62,7 +62,7 @@
# == Description
#
# At first, tries to create a new URI::Generic instance using
- # URI::Generic::build. But, if exception URI::InvalidComponentError is raised,
+ # URI::Generic::build. But, if exception URI::InvalidComponentError is raised,
# then it URI::Escape.escape all URI components and tries again.
#
#
@@ -71,9 +71,9 @@
return self.build(args)
rescue InvalidComponentError
if args.kind_of?(Array)
- return self.build(args.collect{|x|
+ return self.build(args.collect{|x|
if x
- @parser.escape(x)
+ parser.escape(x)
else
x
end
@@ -82,7 +82,7 @@
tmp = {}
args.each do |key, value|
tmp[key] = if value
- @parser.escape(value)
+ parser.escape(value)
else
value
end
@@ -117,11 +117,11 @@
end
end
else
- raise ArgumentError,
+ raise ArgumentError,
"expected Array of or Hash of components of #{self.class} (#{self.class.component.join(', ')})"
end
- tmp << DEFAULT_PARSER
+ tmp << nil
tmp << true
return self.new(*tmp)
end
@@ -155,10 +155,10 @@
#
# Creates a new URI::Generic instance from ``generic'' components without check.
#
- def initialize(scheme,
- userinfo, host, port, registry,
- path, opaque,
- query,
+ def initialize(scheme,
+ userinfo, host, port, registry,
+ path, opaque,
+ query,
fragment,
parser = DEFAULT_PARSER,
arg_check = false)
@@ -172,7 +172,7 @@
@opaque = nil
@registry = nil
@fragment = nil
- @parser = parser
+ @parser = parser == DEFAULT_PARSER ? nil : parser
if arg_check
self.scheme = scheme
@@ -196,10 +196,10 @@
self.set_fragment(fragment)
end
if @registry && !self.class.use_registry
- raise InvalidURIError,
+ raise InvalidURIError,
"the scheme #{@scheme} does not accept registry part: #{@registry} (or bad hostname?)"
end
-
+
@scheme.freeze if @scheme
self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2)
self.set_port(self.default_port) if self.default_port && !@port
@@ -212,8 +212,15 @@
attr_reader :query
attr_reader :opaque
attr_reader :fragment
- attr_reader :parser
+ def parser
+ if !defined?(@parser) || !@parser
+ DEFAULT_PARSER
+ else
+ @parser || DEFAULT_PARSER
+ end
+ end
+
# replace self by other URI object
def replace!(oth)
if self.class != oth.class
@@ -231,7 +238,7 @@
end
def check_scheme(v)
- if v && @parser.regexp[:SCHEME] !~ v
+ if v && parser.regexp[:SCHEME] !~ v
raise InvalidComponentError,
"bad component(expected scheme component): #{v}"
end
@@ -264,13 +271,13 @@
def check_user(v)
if @registry || @opaque
- raise InvalidURIError,
+ raise InvalidURIError,
"can not set user with registry or opaque"
end
return v unless v
- if @parser.regexp[:USERINFO] !~ v
+ if parser.regexp[:USERINFO] !~ v
raise InvalidComponentError,
"bad component(expected userinfo component or user component): #{v}"
end
@@ -281,7 +288,7 @@
def check_password(v, user = @user)
if @registry || @opaque
- raise InvalidURIError,
+ raise InvalidURIError,
"can not set password with registry or opaque"
end
return v unless v
@@ -291,7 +298,7 @@
"password component depends user component"
end
- if @parser.regexp[:USERINFO] !~ v
+ if parser.regexp[:USERINFO] !~ v
raise InvalidComponentError,
"bad component(expected user component): #{v}"
end
@@ -317,7 +324,7 @@
set_user(user)
# returns user
end
-
+
def password=(password)
check_password(password)
set_password(password)
@@ -325,7 +332,7 @@
end
def set_userinfo(user, password = nil)
- unless password
+ unless password
user, password = split_userinfo(user)
end
@user = user
@@ -356,7 +363,7 @@
private :split_userinfo
def escape_userpass(v)
- v = @parser.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
+ v = parser.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
end
private :escape_userpass
@@ -382,9 +389,9 @@
return v unless v
if @registry || @opaque
- raise InvalidURIError,
+ raise InvalidURIError,
"can not set host with registry or opaque"
- elsif @parser.regexp[:HOST] !~ v
+ elsif parser.regexp[:HOST] !~ v
raise InvalidComponentError,
"bad component(expected host component): #{v}"
end
@@ -408,9 +415,9 @@
return v unless v
if @registry || @opaque
- raise InvalidURIError,
+ raise InvalidURIError,
"can not set port with registry or opaque"
- elsif !v.kind_of?(Fixnum) && @parser.regexp[:PORT] !~ v
+ elsif !v.kind_of?(Fixnum) && parser.regexp[:PORT] !~ v
raise InvalidComponentError,
"bad component(expected port component): #{v}"
end
@@ -444,9 +451,9 @@
# authority = server | reg_name
# server = [ [ userinfo "@" ] hostport ]
if @host || @port || @user # userinfo = @user + ':' + @password
- raise InvalidURIError,
+ raise InvalidURIError,
"can not set registry with host, port, or userinfo"
- elsif v && @parser.regexp[:REGISTRY] !~ v
+ elsif v && parser.regexp[:REGISTRY] !~ v
raise InvalidComponentError,
"bad component(expected registry component): #{v}"
end
@@ -471,18 +478,20 @@
# absoluteURI = scheme ":" ( hier_part | opaque_part )
# hier_part = ( net_path | abs_path ) [ "?" query ]
if v && @opaque
- raise InvalidURIError,
+ raise InvalidURIError,
"path conflicts with opaque"
end
- if @scheme
- if v && v != '' && @parser.regexp[:ABS_PATH] !~ v
- raise InvalidComponentError,
+ # If scheme is ftp, path may be relative.
+ # See RFC 1738 section 3.2.2, and RFC 2396.
+ if @scheme && @scheme != "ftp"
+ if v && v != '' && parser.regexp[:ABS_PATH] !~ v
+ raise InvalidComponentError,
"bad component(expected absolute path component): #{v}"
end
else
- if v && v != '' && @parser.regexp[:ABS_PATH] !~ v && @parser.regexp[:REL_PATH] !~ v
- raise InvalidComponentError,
+ if v && v != '' && parser.regexp[:ABS_PATH] !~ v && parser.regexp[:REL_PATH] !~ v
+ raise InvalidComponentError,
"bad component(expected relative path component): #{v}"
end
end
@@ -509,12 +518,12 @@
# absoluteURI = scheme ":" ( hier_part | opaque_part )
# hier_part = ( net_path | abs_path ) [ "?" query ]
if @opaque
- raise InvalidURIError,
+ raise InvalidURIError,
"query conflicts with opaque"
end
- if v && v != '' && @parser.regexp[:QUERY] !~ v
- raise InvalidComponentError,
+ if v && v != '' && parser.regexp[:QUERY] !~ v
+ raise InvalidComponentError,
"bad component(expected query component): #{v}"
end
@@ -540,9 +549,9 @@
# absoluteURI = scheme ":" ( hier_part | opaque_part )
# hier_part = ( net_path | abs_path ) [ "?" query ]
if @host || @port || @user || @path # userinfo = @user + ':' + @password
- raise InvalidURIError,
+ raise InvalidURIError,
"can not set opaque with host, port, userinfo or path"
- elsif v && @parser.regexp[:OPAQUE] !~ v
+ elsif v && parser.regexp[:OPAQUE] !~ v
raise InvalidComponentError,
"bad component(expected opaque component): #{v}"
end
@@ -565,8 +574,8 @@
def check_fragment(v)
return v unless v
- if v && v != '' && @parser.regexp[:FRAGMENT] !~ v
- raise InvalidComponentError,
+ if v && v != '' && parser.regexp[:FRAGMENT] !~ v
+ raise InvalidComponentError,
"bad component(expected fragment component): #{v}"
end
@@ -777,19 +786,19 @@
case oth
when Generic
when String
- oth = @parser.parse(oth)
+ oth = parser.parse(oth)
else
raise ArgumentError,
"bad argument(expected URI object or URI string)"
end
if self.relative? && oth.relative?
- raise BadURIError,
+ raise BadURIError,
"both URI are relative"
end
if self.absolute? && oth.absolute?
- #raise BadURIError,
+ #raise BadURIError,
# "both URI are absolute"
# hmm... should return oth for usability?
return oth, oth
@@ -810,7 +819,7 @@
src_path = split_path(src)
dst_path = split_path(dst)
- # hmm... dst has abnormal absolute path,
+ # hmm... dst has abnormal absolute path,
# like "/./", "/../", "/x/../", ...
if dst_path.include?('..') ||
dst_path.include?('.')
@@ -848,18 +857,18 @@
case oth
when Generic
when String
- oth = @parser.parse(oth)
+ oth = parser.parse(oth)
else
raise ArgumentError,
"bad argument(expected URI object or URI string)"
end
if self.relative?
- raise BadURIError,
+ raise BadURIError,
"relative URI: #{self}"
end
if oth.relative?
- raise BadURIError,
+ raise BadURIError,
"relative URI: #{oth}"
end
@@ -867,9 +876,9 @@
return self, self.dup
end
rel = URI::Generic.new(nil, # it is relative URI
- self.userinfo, self.host, self.port,
+ self.userinfo, self.host, self.port,
self.registry, self.path, self.opaque,
- self.query, self.fragment, @parser)
+ self.query, self.fragment, parser)
if rel.userinfo != oth.userinfo ||
rel.host.to_s.downcase != oth.host.to_s.downcase ||
@@ -955,12 +964,12 @@
# uri = URI.parse('http://my.example.com')
# p uri.route_to('http://my.example.com/main.rbx?page=1')
# #=> #<URI::Generic:0x2020c2f6 URL:/main.rbx?page=1>
- #
+ #
def route_to(oth)
case oth
when Generic
when String
- oth = @parser.parse(oth)
+ oth = parser.parse(oth)
else
raise ArgumentError,
"bad argument(expected URI object or URI string)"
@@ -971,7 +980,7 @@
#
# Returns normalized URI
- #
+ #
def normalize
uri = dup
uri.normalize!
@@ -985,9 +994,12 @@
if path && path == ''
set_path('/')
end
+ if scheme && scheme != scheme.downcase
+ set_scheme(self.scheme.downcase)
+ end
if host && host != host.downcase
set_host(self.host.downcase)
- end
+ end
end
def path_query
@@ -1001,7 +1013,7 @@
#
# Constructs String from URI
- #
+ #
def to_s
str = ''
if @scheme
@@ -1059,7 +1071,8 @@
end
def eql?(oth)
- @parser == oth.parser &&
+ self.class == oth.class &&
+ parser == oth.parser &&
self.component_ary.eql?(oth.component_ary)
end
@@ -1103,7 +1116,7 @@
if component.include?(c)
self.send(c)
else
- raise ArgumentError,
+ raise ArgumentError,
"expected of components of #{self.class} (#{self.class.component.join(', ')})"
end
end
@@ -1117,7 +1130,7 @@
def coerce(oth)
case oth
when String
- oth = @parser.parse(oth)
+ oth = parser.parse(oth)
else
super
end
Modified: MacRuby/trunk/lib/uri/http.rb
===================================================================
--- MacRuby/trunk/lib/uri/http.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/uri/http.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -3,7 +3,7 @@
#
# Author:: Akira Yamada <akira at ruby-lang.org>
# License:: You can redistribute it and/or modify it under the same term as Ruby.
-# Revision:: $Id: http.rb 11708 2007-02-12 23:01:19Z shyouhei $
+# Revision:: $Id: http.rb 25189 2009-10-02 12:04:37Z akr $
#
require 'uri/generic'
@@ -14,18 +14,18 @@
# The syntax of HTTP URIs is defined in RFC1738 section 3.3.
#
# Note that the Ruby URI library allows HTTP URLs containing usernames and
- # passwords. This is not legal as per the RFC, but used to be
- # supported in Internet Explorer 5 and 6, before the MS04-004 security
+ # passwords. This is not legal as per the RFC, but used to be
+ # supported in Internet Explorer 5 and 6, before the MS04-004 security
# update. See <URL:http://support.microsoft.com/kb/834489>.
#
class HTTP < Generic
DEFAULT_PORT = 80
COMPONENT = [
- :scheme,
- :userinfo, :host, :port,
- :path,
- :query,
+ :scheme,
+ :userinfo, :host, :port,
+ :path,
+ :query,
:fragment
].freeze
@@ -37,21 +37,21 @@
# The components accepted are userinfo, host, port, path, query and
# fragment.
#
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
+ # The components should be provided either as an Array, or as a Hash
+ # with keys formed by preceding the component names with a colon.
#
# If an Array is used, the components must be passed in the order
# [userinfo, host, port, path, query, fragment].
#
# Example:
#
- # newuri = URI::HTTP.build({:host => 'www.example.com',
+ # newuri = URI::HTTP.build({:host => 'www.example.com',
# :path> => '/foo/bar'})
#
- # newuri = URI::HTTP.build([nil, "www.example.com", nil, "/path",
+ # newuri = URI::HTTP.build([nil, "www.example.com", nil, "/path",
# "query", 'fragment'])
#
- # Currently, if passed userinfo components this method generates
+ # Currently, if passed userinfo components this method generates
# invalid HTTP URIs as per RFC 1738.
#
def self.build(args)
@@ -63,10 +63,10 @@
# == Description
#
# Create a new URI::HTTP object from generic URI components as per
- # RFC 2396. No HTTP-specific syntax checking (as per RFC 1738) is
+ # RFC 2396. No HTTP-specific syntax checking (as per RFC 1738) is
# performed.
#
- # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
+ # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
# +opaque+, +query+ and +fragment+, in that order.
#
# Example:
Modified: MacRuby/trunk/lib/uri/https.rb
===================================================================
--- MacRuby/trunk/lib/uri/https.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/uri/https.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -3,7 +3,7 @@
#
# Author:: Akira Yamada <akira at ruby-lang.org>
# License:: You can redistribute it and/or modify it under the same term as Ruby.
-# Revision:: $Id: https.rb 11708 2007-02-12 23:01:19Z shyouhei $
+# Revision:: $Id: https.rb 25189 2009-10-02 12:04:37Z akr $
#
require 'uri/http'
Modified: MacRuby/trunk/lib/uri/ldap.rb
===================================================================
--- MacRuby/trunk/lib/uri/ldap.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/uri/ldap.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,13 +1,13 @@
#
# = uri/ldap.rb
#
-# Author::
+# Author::
# Takaaki Tateishi <ttate at jaist.ac.jp>
# Akira Yamada <akira at ruby-lang.org>
-# License::
+# License::
# URI::LDAP is copyrighted free software by Takaaki Tateishi and Akira Yamada.
# You can redistribute it and/or modify it under the same term as Ruby.
-# Revision:: $Id: ldap.rb 11708 2007-02-12 23:01:19Z shyouhei $
+# Revision:: $Id: ldap.rb 25189 2009-10-02 12:04:37Z akr $
#
require 'uri/generic'
@@ -21,7 +21,7 @@
class LDAP < Generic
DEFAULT_PORT = 389
-
+
COMPONENT = [
:scheme,
:host, :port,
Modified: MacRuby/trunk/lib/uri/mailto.rb
===================================================================
--- MacRuby/trunk/lib/uri/mailto.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/uri/mailto.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -3,7 +3,7 @@
#
# Author:: Akira Yamada <akira at ruby-lang.org>
# License:: You can redistribute it and/or modify it under the same term as Ruby.
-# Revision:: $Id: mailto.rb 19495 2008-09-23 18:16:08Z drbrain $
+# Revision:: $Id: mailto.rb 27731 2010-05-11 04:49:56Z marcandre $
#
require 'uri/generic'
@@ -38,7 +38,7 @@
# hvalue = *urlc
# header = hname "=" hvalue
HEADER_PATTERN = "(?:[^?=&]*=[^?=&]*)".freeze
- HEADER_REGEXP = Regexp.new(HEADER_PATTERN, 'N').freeze
+ HEADER_REGEXP = Regexp.new(HEADER_PATTERN).freeze
# headers = "?" header *( "&" header )
# to = #mailbox
# mailtoURL = "mailto:" [ to ] [ headers ]
@@ -68,20 +68,20 @@
#
# If a Hash is used, the keys are the component names preceded by colons.
#
- # The headers can be supplied as a pre-encoded string, such as
+ # The headers can be supplied as a pre-encoded string, such as
# "subject=subscribe&cc=address", or as an Array of Arrays like
# [['subject', 'subscribe'], ['cc', 'address']]
#
# Examples:
- #
+ #
# require 'uri'
- #
+ #
# m1 = URI::MailTo.build(['joe at example.com', 'subject=Ruby'])
# puts m1.to_s -> mailto:joe at example.com?subject=Ruby
- #
+ #
# m2 = URI::MailTo.build(['john at example.com', [['Subject', 'Ruby'], ['Cc', 'jack at example.com']]])
# puts m2.to_s -> mailto:john at example.com?Subject=Ruby&Cc=jack at example.com
- #
+ #
# m3 = URI::MailTo.build({:to => 'listman at example.com', :headers => [['subject', 'subscribe']]})
# puts m3.to_s -> mailto:listman at example.com?subject=subscribe
#
@@ -159,7 +159,7 @@
return true unless v
return true if v.size == 0
- if @parser.regexp[:OPAQUE] !~ v || /\A#{MAILBOX_PATTERN}*\z/o !~ v
+ if parser.regexp[:OPAQUE] !~ v || /\A#{MAILBOX_PATTERN}*\z/o !~ v
raise InvalidComponentError,
"bad component(expected opaque component): #{v}"
end
@@ -183,7 +183,7 @@
return true unless v
return true if v.size == 0
- if @parser.regexp[:OPAQUE] !~ v ||
+ if parser.regexp[:OPAQUE] !~ v ||
/\A(#{HEADER_PATTERN}(?:\&#{HEADER_PATTERN})*)\z/o !~ v
raise InvalidComponentError,
"bad component(expected opaque component): #{v}"
@@ -210,12 +210,12 @@
end
def to_s
- @scheme + ':' +
- if @to
+ @scheme + ':' +
+ if @to
@to
else
''
- end +
+ end +
if @headers.size > 0
'?' + @headers.collect{|x| x.join('=')}.join('&')
else
@@ -227,7 +227,7 @@
''
end
end
-
+
# Returns the RFC822 e-mail text equivalent of the URL, as a String.
#
# Example:
@@ -239,18 +239,18 @@
# # => "To: ruby-list at ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n"
#
def to_mailtext
- to = @parser.unescape(@to)
+ to = parser.unescape(@to)
head = ''
body = ''
@headers.each do |x|
case x[0]
when 'body'
- body = @parser.unescape(x[1])
+ body = parser.unescape(x[1])
when 'to'
- to << ', ' + @parser.unescape(x[1])
+ to << ', ' + parser.unescape(x[1])
else
- head << @parser.unescape(x[0]).capitalize + ': ' +
- @parser.unescape(x[1]) + "\n"
+ head << parser.unescape(x[0]).capitalize + ': ' +
+ parser.unescape(x[1]) + "\n"
end
end
Modified: MacRuby/trunk/lib/uri.rb
===================================================================
--- MacRuby/trunk/lib/uri.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/uri.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -3,11 +3,11 @@
#
# Author:: Akira Yamada <akira at ruby-lang.org>
# Documentation:: Akira Yamada <akira at ruby-lang.org>, Dmitry V. Sabanin <sdmitry at lrn.ru>
-# License::
+# License::
# Copyright (c) 2001 akira yamada <akira at ruby-lang.org>
# You can redistribute it and/or modify it under the same term as Ruby.
-# Revision:: $Id: uri.rb 13772 2007-10-25 00:53:34Z akira $
-#
+# Revision:: $Id: uri.rb 25189 2009-10-02 12:04:37Z akr $
+#
# See URI for documentation
#
Modified: MacRuby/trunk/lib/xmlrpc/base64.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/base64.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/base64.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -9,19 +9,19 @@
= XMLRPC::Base64
== Description
-This class is necessary for (('xmlrpc4r')) to determine that a string should
-be transmitted base64-encoded and not as a raw-string.
-You can use (({XMLRPC::Base64})) on the client and server-side as a
+This class is necessary for (('xmlrpc4r')) to determine that a string should
+be transmitted base64-encoded and not as a raw-string.
+You can use (({XMLRPC::Base64})) on the client and server-side as a
parameter and/or return-value.
== Class Methods
--- XMLRPC::Base64.new( str, state = :dec )
Creates a new (({XMLRPC::Base64})) instance with string ((|str|)) as the
- internal string. When ((|state|)) is (({:dec})) it assumes that the
- string ((|str|)) is not in base64 format (perhaps already decoded),
- otherwise if ((|state|)) is (({:enc})) it decodes ((|str|))
+ internal string. When ((|state|)) is (({:dec})) it assumes that the
+ string ((|str|)) is not in base64 format (perhaps already decoded),
+ otherwise if ((|state|)) is (({:enc})) it decodes ((|str|))
and stores it as the internal string.
-
+
--- XMLRPC::Base64.decode( str )
Decodes string ((|str|)) with base64 and returns that value.
@@ -40,7 +40,7 @@
module XMLRPC
class Base64
-
+
def initialize(str, state = :dec)
case state
when :enc
@@ -51,11 +51,11 @@
raise ArgumentError, "wrong argument; either :enc or :dec"
end
end
-
+
def decoded
- @str
+ @str
end
-
+
def encoded
Base64.encode(@str)
end
@@ -77,5 +77,5 @@
=begin
= History
- $Id: base64.rb 11708 2007-02-12 23:01:19Z shyouhei $
+ $Id: base64.rb 25189 2009-10-02 12:04:37Z akr $
=end
Modified: MacRuby/trunk/lib/xmlrpc/client.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/client.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/client.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -26,7 +26,7 @@
or
require "xmlrpc/client"
-
+
server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
ok, param = server.call2("michael.add", 4, 5)
if ok then
@@ -40,14 +40,14 @@
== Description
Class (({XMLRPC::Client})) provides remote procedure calls to a XML-RPC server.
After setting the connection-parameters with ((<XMLRPC::Client.new>)) which
-creates a new (({XMLRPC::Client})) instance, you can execute a remote procedure
+creates a new (({XMLRPC::Client})) instance, you can execute a remote procedure
by sending the ((<call|XMLRPC::Client#call>)) or ((<call2|XMLRPC::Client#call2>))
-message to this new instance. The given parameters indicate which method to
+message to this new instance. The given parameters indicate which method to
call on the remote-side and of course the parameters for the remote procedure.
== Class Methods
--- XMLRPC::Client.new( host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=false, timeout =nil)
- Creates an object which represents the remote XML-RPC server on the
+ Creates an object which represents the remote XML-RPC server on the
given host ((|host|)). If the server is CGI-based, ((|path|)) is the
path to the CGI-script, which will be called, otherwise (in the
case of a standalone server) ((|path|)) should be (({"/RPC2"})).
@@ -59,8 +59,8 @@
Default values for ((|host|)), ((|path|)) and ((|port|)) are 'localhost', '/RPC2' and
'80' respectively using SSL '443'.
- If ((|user|)) and ((|password|)) are given, each time a request is send,
- a Authorization header is send. Currently only Basic Authentification is
+ If ((|user|)) and ((|password|)) are given, each time a request is send,
+ a Authorization header is send. Currently only Basic Authentification is
implemented no Digest.
If ((|use_ssl|)) is set to (({true})), comunication over SSL is enabled.
@@ -76,9 +76,9 @@
: proxy
Is of the form "host:port".
-
+
: timeout
- Defaults to 30.
+ Defaults to 30.
--- XMLRPC::Client.new3( hash={} )
--- XMLRPC::Client.new_from_hash( hash={} )
@@ -97,10 +97,10 @@
== Instance Methods
--- XMLRPC::Client#call( method, *args )
- Invokes the method named ((|method|)) with the parameters given by
+ Invokes the method named ((|method|)) with the parameters given by
((|args|)) on the XML-RPC server.
- The parameter ((|method|)) is converted into a (({String})) and should
- be a valid XML-RPC method-name.
+ The parameter ((|method|)) is converted into a (({String})) and should
+ be a valid XML-RPC method-name.
Each parameter of ((|args|)) must be of one of the following types,
where (({Hash})), (({Struct})) and (({Array})) can contain any of these listed ((:types:)):
* (({Fixnum})), (({Bignum}))
@@ -110,31 +110,31 @@
* (({Hash})), (({Struct}))
* (({Array}))
* (({Date})), (({Time})), (({XMLRPC::DateTime}))
- * (({XMLRPC::Base64}))
- * A Ruby object which class includes XMLRPC::Marshallable (only if Config::ENABLE_MARSHALLABLE is (({true}))).
+ * (({XMLRPC::Base64}))
+ * A Ruby object which class includes XMLRPC::Marshallable (only if Config::ENABLE_MARSHALLABLE is (({true}))).
That object is converted into a hash, with one additional key/value pair "___class___" which contains the class name
for restoring later that object.
-
- The method returns the return-value from the RPC
- ((-stands for Remote Procedure Call-)).
+
+ The method returns the return-value from the RPC
+ ((-stands for Remote Procedure Call-)).
The type of the return-value is one of the above shown,
only that a (({Bignum})) is only allowed when it fits in 32-bit and
that a XML-RPC (('dateTime.iso8601')) type is always returned as
- a ((<(({XMLRPC::DateTime}))|URL:datetime.html>)) object and
+ a ((<(({XMLRPC::DateTime}))|URL:datetime.html>)) object and
a (({Struct})) is never returned, only a (({Hash})), the same for a (({Symbol})), where
- always a (({String})) is returned.
+ always a (({String})) is returned.
A (({XMLRPC::Base64})) is returned as a (({String})) from xmlrpc4r version 1.6.1 on.
-
- If the remote procedure returned a fault-structure, then a
+
+ If the remote procedure returned a fault-structure, then a
(({XMLRPC::FaultException})) exception is raised, which has two accessor-methods
(({faultCode})) and (({faultString})) of type (({Integer})) and (({String})).
--- XMLRPC::Client#call2( method, *args )
The difference between this method and ((<call|XMLRPC::Client#call>)) is, that
this method do ((*not*)) raise a (({XMLRPC::FaultException})) exception.
- The method returns an array of two values. The first value indicates if
+ The method returns an array of two values. The first value indicates if
the second value is a return-value ((({true}))) or an object of type
- (({XMLRPC::FaultException})).
+ (({XMLRPC::FaultException})).
Both are explained in ((<call|XMLRPC::Client#call>)).
Simple to remember: The "2" in "call2" denotes the number of values it returns.
@@ -151,19 +151,19 @@
# => [7, -1]
--- XMLRPC::Client#multicall2( *methods )
- Same as ((<XMLRPC::Client#multicall>)), but returns like ((<XMLRPC::Client#call2>)) two parameters
+ Same as ((<XMLRPC::Client#multicall>)), but returns like ((<XMLRPC::Client#call2>)) two parameters
instead of raising an (({XMLRPC::FaultException})).
--- XMLRPC::Client#proxy( prefix, *args )
Returns an object of class (({XMLRPC::Client::Proxy})), initialized with
((|prefix|)) and ((|args|)). A proxy object returned by this method behaves
like ((<XMLRPC::Client#call>)), i.e. a call on that object will raise a
- (({XMLRPC::FaultException})) when a fault-structure is returned by that call.
+ (({XMLRPC::FaultException})) when a fault-structure is returned by that call.
--- XMLRPC::Client#proxy2( prefix, *args )
Almost the same like ((<XMLRPC::Client#proxy>)) only that a call on the returned
(({XMLRPC::Client::Proxy})) object behaves like ((<XMLRPC::Client#call2>)), i.e.
- a call on that object will return two parameters.
+ a call on that object will return two parameters.
@@ -175,22 +175,22 @@
--- XMLRPC::Client#proxy_async(...)
--- XMLRPC::Client#proxy2_async(...)
In contrast to corresponding methods without "_async", these can be
- called concurrently and use for each request a new connection, where the
+ called concurrently and use for each request a new connection, where the
non-asynchronous counterparts use connection-alive (one connection for all requests)
- if possible.
+ if possible.
- Note, that you have to use Threads to call these methods concurrently.
+ Note, that you have to use Threads to call these methods concurrently.
The following example calls two methods concurrently:
-
+
Thread.new {
p client.call_async("michael.add", 4, 5)
}
-
+
Thread.new {
p client.call_async("michael.div", 7, 9)
}
-
+
--- XMLRPC::Client#timeout
--- XMLRPC::Client#user
--- XMLRPC::Client#password
@@ -200,12 +200,12 @@
--- XMLRPC::Client#user= (new_user)
--- XMLRPC::Client#password= (new_password)
Set the corresponding attributes.
-
+
--- XMLRPC::Client#set_writer( writer )
Sets the XML writer to use for generating XML output.
Should be an instance of a class from module (({XMLRPC::XMLWriter})).
- If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used.
+ If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used.
--- XMLRPC::Client#set_parser( parser )
Sets the XML parser to use for parsing XML documents.
@@ -220,7 +220,7 @@
Set extra HTTP headers that are included in the request.
--- XMLRPC::Client#http_header_extra
- Access the via ((<XMLRPC::Client#http_header_extra=>)) assigned header.
+ Access the via ((<XMLRPC::Client#http_header_extra=>)) assigned header.
--- XMLRPC::Client#http_last_response
Returns the (({Net::HTTPResponse})) object of the last RPC.
@@ -240,35 +240,35 @@
== Description
Class (({XMLRPC::Client::Proxy})) makes XML-RPC calls look nicer!
-You can call any method onto objects of that class - the object handles
+You can call any method onto objects of that class - the object handles
(({method_missing})) and will forward the method call to a XML-RPC server.
Don't use this class directly, but use instead method ((<XMLRPC::Client#proxy>)) or
((<XMLRPC::Client#proxy2>)).
== Class Methods
---- XMLRPC::Client::Proxy.new( server, prefix, args=[], meth=:call, delim="." )
+--- XMLRPC::Client::Proxy.new( server, prefix, args=[], meth=:call, delim="." )
Creates an object which provides (({method_missing})).
((|server|)) must be of type (({XMLRPC::Client})), which is the XML-RPC server to be used
for a XML-RPC call. ((|prefix|)) and ((|delim|)) will be prepended to the methodname
- called onto this object.
+ called onto this object.
Parameter ((|meth|)) is the method (call, call2, call_async, call2_async) to use for
a RPC.
((|args|)) are arguments which are automatically given
to every XML-RPC call before the arguments provides through (({method_missing})).
-
+
== Instance Methods
Every method call is forwarded to the XML-RPC server defined in ((<new|XMLRPC::Client::Proxy#new>)).
-
+
Note: Inherited methods from class (({Object})) cannot be used as XML-RPC names, because they get around
-(({method_missing})).
-
+(({method_missing})).
+
= History
- $Id: client.rb 19657 2008-10-01 13:46:53Z mame $
+ $Id: client.rb 25189 2009-10-02 12:04:37Z akr $
=end
@@ -283,7 +283,7 @@
module XMLRPC
class Client
-
+
USER_AGENT = "XMLRPC::Client (Ruby #{RUBY_VERSION})"
include ParserWriterChooseMixin
@@ -292,11 +292,11 @@
# Constructors -------------------------------------------------------------------
- def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil,
+ def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil,
user=nil, password=nil, use_ssl=nil, timeout=nil)
@http_header_extra = nil
- @http_last_response = nil
+ @http_last_response = nil
@cookie = nil
@host = host || "localhost"
@@ -325,7 +325,7 @@
# HTTP object for synchronous calls
Net::HTTP.version_1_2
- @http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
+ @http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
@http.use_ssl = @use_ssl if @use_ssl
@http.read_timeout = @timeout
@http.open_timeout = @timeout
@@ -341,7 +341,7 @@
if match = /^([^:]+):\/\/(([^@]+)@)?([^\/]+)(\/.*)?$/.match(uri)
proto = match[1]
user, passwd = (match[3] || "").split(":")
- host, port = match[4].split(":")
+ host, port = match[4].split(":")
path = match[5]
if proto != "http" and proto != "https"
@@ -351,7 +351,7 @@
else
raise "Wrong URI as parameter!"
end
-
+
proxy_host, proxy_port = (proxy || "").split(":")
self.new(host, path, port, proxy_host, proxy_port, user, passwd, (proto == "https"), timeout)
@@ -384,8 +384,8 @@
# Cookie support
attr_accessor :cookie
-
+
attr_reader :timeout, :user, :password
def timeout=(new_timeout)
@@ -407,13 +407,13 @@
# Call methods --------------------------------------------------------------
def call(method, *args)
- ok, param = call2(method, *args)
+ ok, param = call2(method, *args)
if ok
param
else
raise param
end
- end
+ end
def call2(method, *args)
request = create().methodCall(method, *args)
@@ -422,13 +422,13 @@
end
def call_async(method, *args)
- ok, param = call2_async(method, *args)
+ ok, param = call2_async(method, *args)
if ok
param
else
raise param
end
- end
+ end
def call2_async(method, *args)
request = create().methodCall(method, *args)
@@ -467,7 +467,7 @@
# Proxy generating methods ------------------------------------------
-
+
def proxy(prefix=nil, *args)
Proxy.new(self, prefix, args, :call)
end
@@ -498,10 +498,10 @@
end
def do_rpc(request, async=false)
- header = {
+ header = {
"User-Agent" => USER_AGENT,
"Content-Type" => "text/xml; charset=utf-8",
- "Content-Length" => request.size.to_s,
+ "Content-Length" => request.size.to_s,
"Connection" => (async ? "close" : "keep-alive")
}
@@ -512,41 +512,41 @@
# add authorization header
header["Authorization"] = @auth
end
-
+
resp = nil
@http_last_response = nil
if async
- # use a new HTTP object for each call
+ # use a new HTTP object for each call
Net::HTTP.version_1_2
- http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
+ http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
http.use_ssl = @use_ssl if @use_ssl
http.read_timeout = @timeout
http.open_timeout = @timeout
-
+
# post request
http.start {
- resp = http.post2(@path, request, header)
+ resp = http.post2(@path, request, header)
}
else
# reuse the HTTP object for each call => connection alive is possible
# we must start connection explicitely first time so that http.request
# does not assume that we don't want keepalive
@http.start if not @http.started?
-
+
# post request
- resp = @http.post2(@path, request, header)
+ resp = @http.post2(@path, request, header)
end
-
+
@http_last_response = resp
data = resp.body
if resp.code == "401"
# Authorization Required
- raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}"
+ raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}"
elsif resp.code[0,1] != "2"
- raise "HTTP-Error: #{resp.code} #{resp.message}"
+ raise "HTTP-Error: #{resp.code} #{resp.message}"
end
ct = parse_content_type(resp["Content-Type"]).first
@@ -559,8 +559,8 @@
end
expected = resp["Content-Length"] || "<unknown>"
- if data.nil? or data.size == 0
- raise "Wrong size. Was #{data.size}, should be #{expected}"
+ if data.nil? or data.size == 0
+ raise "Wrong size. Was #{data.size}, should be #{expected}"
elsif expected != "<unknown>" and expected.to_i != data.size and resp["Transfer-Encoding"].nil?
raise "Wrong size. Was #{data.size}, should be #{expected}"
end
@@ -581,11 +581,11 @@
meth = :call2
meth = :call2_async if async
- ok, params = self.send(meth, "system.multicall",
+ ok, params = self.send(meth, "system.multicall",
methods.collect {|m| {'methodName' => m[0], 'params' => m[1..-1]} }
)
- if ok
+ if ok
params = params.collect do |param|
if param.is_a? Array
param[0]
@@ -593,7 +593,7 @@
XMLRPC::FaultException.new(param["faultCode"], param["faultString"])
else
raise "Wrong multicall return value"
- end
+ end
end
end
@@ -607,7 +607,7 @@
def initialize(server, prefix, args=[], meth=:call, delim=".")
@server = server
@prefix = prefix ? prefix + delim : ""
- @args = args
+ @args = args
@meth = meth
end
Modified: MacRuby/trunk/lib/xmlrpc/config.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/config.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/config.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +1,5 @@
#
-# $Id: config.rb 11708 2007-02-12 23:01:19Z shyouhei $
+# $Id: config.rb 25189 2009-10-02 12:04:37Z akr $
# Configuration file for XML-RPC for Ruby
#
@@ -8,7 +8,7 @@
module Config
DEFAULT_WRITER = XMLWriter::Simple # or XMLWriter::XMLParser
-
+
# available parser:
# * XMLParser::NQXMLTreeParser
# * XMLParser::NQXMLStreamParser
@@ -21,16 +21,16 @@
# enable <nil/> tag
ENABLE_NIL_CREATE = false
ENABLE_NIL_PARSER = false
-
+
# allows integers greater than 32-bit if true
ENABLE_BIGINT = false
# enable marshalling ruby objects which include XMLRPC::Marshallable
- ENABLE_MARSHALLING = true
+ ENABLE_MARSHALLING = true
# enable multiCall extension by default
ENABLE_MULTICALL = false
-
+
# enable Introspection extension by default
ENABLE_INTROSPECTION = false
Modified: MacRuby/trunk/lib/xmlrpc/create.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/create.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/create.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,9 +1,9 @@
#
# Creates XML-RPC call/response documents
-#
+#
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann at ntecs.de)
#
-# $Id: create.rb 19657 2008-10-01 13:46:53Z mame $
+# $Id: create.rb 25189 2009-10-02 12:04:37Z akr $
#
require "date"
@@ -41,7 +41,7 @@
def element(name, attrs, *children)
raise "attributes not yet implemented" unless attrs.nil?
if children.empty?
- "<#{name}/>"
+ "<#{name}/>"
else
"<#{name}>" + children.join("") + "</#{name}>"
end
@@ -69,7 +69,7 @@
end
def document(*params)
- XML::SimpleTree::Document.new(*params)
+ XML::SimpleTree::Document.new(*params)
end
def pi(name, *params)
@@ -120,9 +120,9 @@
tree = @writer.document(
@writer.pi("xml", 'version="1.0"'),
- @writer.ele("methodCall",
+ @writer.ele("methodCall",
@writer.tag("methodName", name),
- @writer.ele("params", *parameter)
+ @writer.ele("params", *parameter)
)
)
@@ -137,29 +137,29 @@
# if is_ret == false then the params array must
# contain only one element, which is a structure
# of a fault return-value.
- #
- # if is_ret == true then a normal
+ #
+ # if is_ret == true then a normal
# return-value of all the given params is created.
#
def methodResponse(is_ret, *params)
- if is_ret
+ if is_ret
resp = params.collect do |param|
@writer.ele("param", conv2value(param))
end
-
+
resp = [@writer.ele("params", *resp)]
else
- if params.size != 1 or params[0] === XMLRPC::FaultException
+ if params.size != 1 or params[0] === XMLRPC::FaultException
raise ArgumentError, "no valid fault-structure given"
end
resp = @writer.ele("fault", conv2value(params[0].to_h))
end
-
+
tree = @writer.document(
@writer.pi("xml", 'version="1.0"'),
- @writer.ele("methodResponse", resp)
+ @writer.ele("methodResponse", resp)
)
@writer.document_to_str(tree) + "\n"
@@ -178,7 +178,7 @@
def conv2value(param)
val = case param
- when Fixnum
+ when Fixnum
@writer.tag("i4", param.to_s)
when Bignum
@@ -194,10 +194,10 @@
when TrueClass, FalseClass
@writer.tag("boolean", param ? "1" : "0")
- when Symbol
+ when Symbol
@writer.tag("string", param.to_s)
- when String
+ when String
@writer.tag("string", param)
when NilClass
@@ -211,51 +211,51 @@
@writer.tag("double", param.to_s)
when Struct
- h = param.members.collect do |key|
+ h = param.members.collect do |key|
value = param[key]
- @writer.ele("member",
+ @writer.ele("member",
@writer.tag("name", key.to_s),
- conv2value(value)
+ conv2value(value)
)
end
- @writer.ele("struct", *h)
+ @writer.ele("struct", *h)
when Hash
# TODO: can a Hash be empty?
-
+
h = param.collect do |key, value|
- @writer.ele("member",
+ @writer.ele("member",
@writer.tag("name", key.to_s),
- conv2value(value)
+ conv2value(value)
)
end
- @writer.ele("struct", *h)
+ @writer.ele("struct", *h)
when Array
# TODO: can an Array be empty?
a = param.collect {|v| conv2value(v) }
-
- @writer.ele("array",
+
+ @writer.ele("array",
@writer.ele("data", *a)
)
when Time, Date, ::DateTime
- @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S"))
+ @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S"))
when XMLRPC::DateTime
- @writer.tag("dateTime.iso8601",
+ @writer.tag("dateTime.iso8601",
format("%.4d%02d%02dT%02d:%02d:%02d", *param.to_a))
-
+
when XMLRPC::Base64
- @writer.tag("base64", param.encoded)
+ @writer.tag("base64", param.encoded)
- else
+ else
if Config::ENABLE_MARSHALLING and param.class.included_modules.include? XMLRPC::Marshallable
# convert Ruby object into Hash
ret = {"___class___" => param.class.name}
- param.instance_variables.each {|v|
+ param.instance_variables.each {|v|
name = v[1..-1]
val = param.instance_variable_get(v)
@@ -266,16 +266,16 @@
end
}
return conv2value(ret)
- else
+ else
ok, pa = wrong_type(param)
if ok
return conv2value(pa)
- else
+ else
raise "Wrong type!"
end
end
end
-
+
@writer.ele("value", val)
end
@@ -283,7 +283,7 @@
false
end
-
+
end # class Create
end # module XMLRPC
Modified: MacRuby/trunk/lib/xmlrpc/datetime.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/datetime.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/datetime.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -10,19 +10,19 @@
= XMLRPC::DateTime
== Description
This class is important to handle XMLRPC (('dateTime.iso8601')) values,
-correcly, because normal UNIX-dates (class (({Date}))) only handle dates
+correcly, because normal UNIX-dates (class (({Date}))) only handle dates
from year 1970 on, and class (({Time})) handles dates without the time
-component. (({XMLRPC::DateTime})) is able to store a XMLRPC
+component. (({XMLRPC::DateTime})) is able to store a XMLRPC
(('dateTime.iso8601')) value correctly.
== Class Methods
--- XMLRPC::DateTime.new( year, month, day, hour, min, sec )
Creates a new (({XMLRPC::DateTime})) instance with the
- parameters ((|year|)), ((|month|)), ((|day|)) as date and
+ parameters ((|year|)), ((|month|)), ((|day|)) as date and
((|hour|)), ((|min|)), ((|sec|)) as time.
Raises (({ArgumentError})) if a parameter is out of range, or ((|year|)) is not
of type (({Integer})).
-
+
== Instance Methods
--- XMLRPC::DateTime#year
--- XMLRPC::DateTime#month
@@ -50,7 +50,7 @@
--- XMLRPC::DateTime#to_time
Return a (({Time})) object of the date/time which (({self})) represents.
- If the (('year')) is below 1970, this method returns (({nil})),
+ If the (('year')) is below 1970, this method returns (({nil})),
because (({Time})) cannot handle years below 1970.
The used timezone is GMT.
@@ -68,7 +68,7 @@
module XMLRPC
class DateTime
-
+
attr_reader :year, :month, :day, :hour, :min, :sec
def year= (value)
@@ -102,14 +102,14 @@
end
alias mon month
- alias mon= month=
-
+ alias mon= month=
+
def initialize(year, month, day, hour, min, sec)
self.year, self.month, self.day = year, month, day
self.hour, self.min, self.sec = hour, min, sec
end
-
+
def to_time
if @year >= 1970
Time.gm(*to_a)
@@ -138,5 +138,5 @@
=begin
= History
- $Id: datetime.rb 11708 2007-02-12 23:01:19Z shyouhei $
+ $Id: datetime.rb 25189 2009-10-02 12:04:37Z akr $
=end
Modified: MacRuby/trunk/lib/xmlrpc/httpserver.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/httpserver.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/httpserver.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,10 +1,10 @@
#
-# Implements a simple HTTP-server by using John W. Small's (jsmall at laser.net)
+# Implements a simple HTTP-server by using John W. Small's (jsmall at laser.net)
# ruby-generic-server.
-#
+#
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann at ntecs.de)
#
-# $Id: httpserver.rb 19657 2008-10-01 13:46:53Z mame $
+# $Id: httpserver.rb 25189 2009-10-02 12:04:37Z akr $
#
@@ -14,8 +14,8 @@
##
# handle_obj specifies the object, that receives calls to request_handler
- # and ip_auth_handler
- def initialize(handle_obj, port = 8080, host = DEFAULT_HOST, maxConnections = 4,
+ # and ip_auth_handler
+ def initialize(handle_obj, port = 8080, host = DEFAULT_HOST, maxConnections = 4,
stdlog = $stdout, audit = true, debug = true)
@handler = handle_obj
super(port, host, maxConnections, stdlog, audit, debug)
@@ -24,7 +24,7 @@
private
# Constants -----------------------------------------------
-
+
CRLF = "\r\n"
HTTP_PROTO = "HTTP/1.0"
SERVER_NAME = "HttpServer (Ruby #{RUBY_VERSION})"
@@ -46,27 +46,27 @@
}
# Classes -------------------------------------------------
-
+
class Request
attr_reader :data, :header, :method, :path, :proto
-
+
def initialize(data, method=nil, path=nil, proto=nil)
@header, @data = Table.new, data
@method, @path, @proto = method, path, proto
end
-
+
def content_length
len = @header['Content-Length']
return nil if len.nil?
- return len.to_i
+ return len.to_i
end
-
+
end
-
+
class Response
attr_reader :header
attr_accessor :body, :status, :status_message
-
+
def initialize(status=200)
@status = status
@status_message = nil
@@ -82,7 +82,7 @@
include Enumerable
def initialize(hash={})
- @hash = hash
+ @hash = hash
update(hash)
end
@@ -113,7 +113,7 @@
def http_header(header=nil)
new_header = Table.new(DEFAULT_HEADER)
- new_header.update(header) unless header.nil?
+ new_header.update(header) unless header.nil?
new_header["Connection"] = "close"
new_header["Date"] = http_date(Time.now)
@@ -127,7 +127,7 @@
def http_resp(status_code, status_message=nil, header=nil, body=nil)
status_message ||= StatusCodeMapping[status_code]
-
+
str = ""
str << "#{HTTP_PROTO} #{status_code} #{status_message}" << CRLF
http_header(header).writeTo(str)
@@ -137,8 +137,8 @@
end
# Main Serve Loop -----------------------------------------
-
- def serve(io)
+
+ def serve(io)
# perform IP authentification
unless @handler.ip_auth_handler(io)
io << http_resp(403, "Forbidden")
@@ -149,10 +149,10 @@
if io.gets =~ /^(\S+)\s+(\S+)\s+(\S+)/
request = Request.new(io, $1, $2, $3)
else
- io << http_resp(400, "Bad Request")
+ io << http_resp(400, "Bad Request")
return
end
-
+
# parse HTTP headers
while (line=io.gets) !~ /^(\n|\r)/
if line =~ /^([\w-]+):\s*(.*)$/
@@ -160,15 +160,15 @@
end
end
- io.binmode
+ io.binmode
response = Response.new
# execute request handler
@handler.request_handler(request, response)
-
+
# write response back to the client
io << http_resp(response.status, response.status_message,
- response.header, response.body)
+ response.header, response.body)
rescue Exception => e
io << http_resp(500, "Internal Server Error")
Modified: MacRuby/trunk/lib/xmlrpc/marshal.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/marshal.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/marshal.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,9 +1,9 @@
#
# Marshalling of XML-RPC methodCall and methodResponse
-#
+#
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann at ntecs.de)
#
-# $Id: marshal.rb 11708 2007-02-12 23:01:19Z shyouhei $
+# $Id: marshal.rb 25189 2009-10-02 12:04:37Z akr $
#
require "xmlrpc/parser"
@@ -17,7 +17,7 @@
include ParserWriterChooseMixin
# class methods -------------------------------
-
+
class << self
def dump_call( methodName, *params )
@@ -52,7 +52,7 @@
create.methodCall( methodName, *params )
end
- def dump_response( param )
+ def dump_response( param )
create.methodResponse( ! param.kind_of?( XMLRPC::FaultException ) , param )
end
Modified: MacRuby/trunk/lib/xmlrpc/parser.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/parser.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/parser.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,9 +1,9 @@
#
# Parser for XML-RPC call and response
-#
+#
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann at ntecs.de)
#
-# $Id: parser.rb 19657 2008-10-01 13:46:53Z mame $
+# $Id: parser.rb 27235 2010-04-06 03:01:52Z naruse $
#
@@ -60,7 +60,7 @@
@faultCode = faultCode
@faultString = faultString
end
-
+
# returns a hash
def to_h
{"faultCode" => @faultCode, "faultString" => @faultString}
@@ -77,7 +77,7 @@
when "0" then false
when "1" then true
else
- raise "RPC-value of type boolean is wrong"
+ raise "RPC-value of type boolean is wrong"
end
end
@@ -122,7 +122,7 @@
def self.struct(hash)
# convert to marhalled object
klass = hash["___class___"]
- if klass.nil? or Config::ENABLE_MARSHALLING == false
+ if klass.nil? or Config::ENABLE_MARSHALLING == false
hash
else
begin
@@ -130,10 +130,10 @@
klass.split("::").each {|const| mod = mod.const_get(const.strip)}
obj = mod.allocate
-
+
hash.delete "___class___"
- hash.each {|key, value|
- obj.instance_variable_set("@#{ key }", value) if key =~ /^([\w_][\w_0-9]*)$/
+ hash.each {|key, value|
+ obj.instance_variable_set("@#{ key }", value) if key =~ /^([a-zA-Z_]\w*)$/
}
obj
rescue
@@ -143,11 +143,11 @@
end
def self.fault(hash)
- if hash.kind_of? Hash and hash.size == 2 and
- hash.has_key? "faultCode" and hash.has_key? "faultString" and
+ if hash.kind_of? Hash and hash.size == 2 and
+ hash.has_key? "faultCode" and hash.has_key? "faultString" and
hash["faultCode"].kind_of? Integer and hash["faultString"].kind_of? String
- XMLRPC::FaultException.new(hash["faultCode"], hash["faultString"])
+ XMLRPC::FaultException.new(hash["faultCode"], hash["faultString"])
else
raise "wrong fault-structure: #{hash.inspect}"
end
@@ -182,9 +182,9 @@
# TODO: add nil?
unless %w(i4 int boolean string double dateTime.iso8601 base64).include? node.nodeName
- if node.nodeName == "value"
+ if node.nodeName == "value"
if not node.childNodes.to_a.detect {|n| _nodeType(n) == :ELEMENT}.nil?
- remove << nd if nd.nodeValue.strip == ""
+ remove << nd if nd.nodeValue.strip == ""
end
else
remove << nd if nd.nodeValue.strip == ""
@@ -194,7 +194,7 @@
remove << nd
else
removeWhitespacesAndComments(nd)
- end
+ end
end
remove.each { |i| node.removeChild(i) }
@@ -203,13 +203,13 @@
def nodeMustBe(node, name)
cmp = case name
- when Array
+ when Array
name.include?(node.nodeName)
when String
name == node.nodeName
else
raise "error"
- end
+ end
if not cmp then
raise "wrong xml-rpc (name)"
@@ -233,7 +233,7 @@
def assert(b)
if not b then
- raise "assert-fail"
+ raise "assert-fail"
end
end
@@ -249,21 +249,21 @@
raise "wrong xml-rpc (size)"
end
end
-
+
def integer(node)
#TODO: check string for float because to_i returnsa
# 0 when wrong string
- nodeMustBe(node, %w(i4 int))
+ nodeMustBe(node, %w(i4 int))
hasOnlyOneChild(node)
-
+
Convert.int(text(node.firstChild))
end
def boolean(node)
- nodeMustBe(node, "boolean")
+ nodeMustBe(node, "boolean")
hasOnlyOneChild(node)
-
+
Convert.boolean(text(node.firstChild))
end
@@ -274,36 +274,36 @@
end
def string(node)
- nodeMustBe(node, "string")
+ nodeMustBe(node, "string")
text_zero_one(node)
end
def double(node)
#TODO: check string for float because to_f returnsa
# 0.0 when wrong string
- nodeMustBe(node, "double")
+ nodeMustBe(node, "double")
hasOnlyOneChild(node)
-
+
Convert.double(text(node.firstChild))
end
def dateTime(node)
nodeMustBe(node, "dateTime.iso8601")
hasOnlyOneChild(node)
-
+
Convert.dateTime( text(node.firstChild) )
end
def base64(node)
nodeMustBe(node, "base64")
#hasOnlyOneChild(node)
-
+
Convert.base64(text_zero_one(node))
end
def member(node)
nodeMustBe(node, "member")
- assert( node.childNodes.to_a.size == 2 )
+ assert( node.childNodes.to_a.size == 2 )
[ name(node[0]), value(node[1]) ]
end
@@ -311,13 +311,13 @@
def name(node)
nodeMustBe(node, "name")
#hasOnlyOneChild(node)
- text_zero_one(node)
+ text_zero_one(node)
end
def array(node)
nodeMustBe(node, "array")
- hasOnlyOneChild(node, "data")
- data(node.firstChild)
+ hasOnlyOneChild(node, "data")
+ data(node.firstChild)
end
def data(node)
@@ -325,15 +325,15 @@
node.childNodes.to_a.collect do |val|
value(val)
- end
+ end
end
def param(node)
nodeMustBe(node, "param")
hasOnlyOneChild(node, "value")
- value(node.firstChild)
+ value(node.firstChild)
end
-
+
def methodResponse(node)
nodeMustBe(node, "methodResponse")
hasOnlyOneChild(node, %w(params fault))
@@ -341,7 +341,7 @@
case child.nodeName
when "params"
- [ true, params(child,false) ]
+ [ true, params(child,false) ]
when "fault"
[ false, fault(child) ]
else
@@ -353,13 +353,13 @@
def methodName(node)
nodeMustBe(node, "methodName")
hasOnlyOneChild(node)
- text(node.firstChild)
+ text(node.firstChild)
end
def params(node, call=true)
nodeMustBe(node, "params")
- if call
+ if call
node.childNodes.to_a.collect do |n|
param(n)
end
@@ -372,7 +372,7 @@
def fault(node)
nodeMustBe(node, "fault")
hasOnlyOneChild(node, "value")
- f = value(node.firstChild)
+ f = value(node.firstChild)
Convert.fault(f)
end
@@ -388,13 +388,13 @@
end
def struct(node)
- nodeMustBe(node, "struct")
+ nodeMustBe(node, "struct")
hash = {}
node.childNodes.to_a.each do |me|
- n, v = member(me)
+ n, v = member(me)
hash[n] = v
- end
+ end
Convert.struct(hash)
end
@@ -403,9 +403,9 @@
def value(node)
nodeMustBe(node, "value")
nodes = node.childNodes.to_a.size
- if nodes == 0
+ if nodes == 0
return ""
- elsif nodes > 1
+ elsif nodes > 1
raise "wrong xml-rpc (size)"
end
@@ -423,14 +423,14 @@
when "dateTime.iso8601" then dateTime(child)
when "base64" then base64(child)
when "struct" then struct(child)
- when "array" then array(child)
- when "nil"
+ when "array" then array(child)
+ when "nil"
if Config::ENABLE_NIL_PARSER
v_nil(child)
else
raise "wrong/unknown XML-RPC type 'nil'"
end
- else
+ else
raise "wrong/unknown XML-RPC type"
end
else
@@ -441,7 +441,7 @@
def methodCall(node)
nodeMustBe(node, "methodCall")
- assert( (1..2).include?( node.childNodes.to_a.size ) )
+ assert( (1..2).include?( node.childNodes.to_a.size ) )
name = methodName(node[0])
if node.childNodes.to_a.size == 2 then
@@ -461,7 +461,7 @@
raise "No valid method response!" if parser.method_name != nil
if parser.fault != nil
# is a fault structure
- [false, parser.fault]
+ [false, parser.fault]
else
# is a normal return value
raise "Missing return value!" if parser.params.size == 0
@@ -508,7 +508,7 @@
@value = nil
when "nil"
raise "wrong/unknown XML-RPC type 'nil'" unless Config::ENABLE_NIL_PARSER
- @value = :nil
+ @value = :nil
when "array"
@val_stack << @values
@values = []
@@ -517,7 +517,7 @@
@name = []
@structs << @struct
- @struct = {}
+ @struct = {}
end
end
@@ -538,7 +538,7 @@
@value = Convert.base64(@data)
when "value"
@value = @data if @value.nil?
- @values << (@value == :nil ? nil : @value)
+ @values << (@value == :nil ? nil : @value)
when "array"
@value = @values
@values = @val_stack.pop
@@ -548,9 +548,9 @@
@name = @names.pop
@struct = @structs.pop
when "name"
- @name[0] = @data
+ @name[0] = @data
when "member"
- @struct[@name[0]] = @values.pop
+ @struct[@name[0]] = @values.pop
when "param"
@params << @values[0]
@@ -560,7 +560,7 @@
@fault = Convert.fault(@values[0])
when "methodName"
- @method_name = @data
+ @method_name = @data
end
@data = nil
@@ -592,7 +592,7 @@
@parser_class = XMLRPCParser
end
- class XMLRPCParser
+ class XMLRPCParser
include StreamParserMixin
def parse(str)
@@ -620,9 +620,9 @@
def initialize
require "xmltreebuilder"
- # The new XMLParser library (0.6.2+) uses a slightly different DOM implementation.
+ # The new XMLParser library (0.6.2+) uses a slightly different DOM implementation.
# The following code removes the differences between both versions.
- if defined? XML::DOM::Builder
+ if defined? XML::DOM::Builder
return if defined? XML::DOM::Node::DOCUMENT # code below has been already executed
klass = XML::DOM::Node
klass.const_set("DOCUMENT", klass::DOCUMENT_NODE)
@@ -637,8 +637,8 @@
def _nodeType(node)
tp = node.nodeType
if tp == XML::SimpleTree::Node::TEXT then :TEXT
- elsif tp == XML::SimpleTree::Node::COMMENT then :COMMENT
- elsif tp == XML::SimpleTree::Node::ELEMENT then :ELEMENT
+ elsif tp == XML::SimpleTree::Node::COMMENT then :COMMENT
+ elsif tp == XML::SimpleTree::Node::ELEMENT then :ELEMENT
else :ELSE
end
end
@@ -647,14 +647,14 @@
def methodResponse_document(node)
assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT )
hasOnlyOneChild(node, "methodResponse")
-
+
methodResponse(node.firstChild)
end
def methodCall_document(node)
assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT )
hasOnlyOneChild(node, "methodCall")
-
+
methodCall(node.firstChild)
end
@@ -688,7 +688,7 @@
end
def createCleanedTree(str)
- doc = ::NQXML::TreeParser.new(str).document.rootNode
+ doc = ::NQXML::TreeParser.new(str).document.rootNode
removeWhitespacesAndComments(doc)
doc
end
@@ -701,7 +701,7 @@
@parser_class = StreamListener
end
- class StreamListener
+ class StreamListener
include StreamParserMixin
alias :tag_start :startElement
@@ -716,7 +716,7 @@
def parse(str)
parser = REXML::Document.parse_stream(str, self)
end
- end
+ end
end
# ---------------------------------------------------------------------------
@@ -751,7 +751,7 @@
startElement(name)
endElement(name)
end
-
+
def on_chardata(str)
character(str)
end
@@ -784,7 +784,7 @@
# valid_name?
# valid_chardata?
# valid_char?
- # parse_error
+ # parse_error
end
end
@@ -792,8 +792,8 @@
XMLParser = XMLTreeParser
NQXMLParser = NQXMLTreeParser
- Classes = [XMLStreamParser, XMLTreeParser,
- NQXMLStreamParser, NQXMLTreeParser,
+ Classes = [XMLStreamParser, XMLTreeParser,
+ NQXMLStreamParser, NQXMLTreeParser,
REXMLStreamParser, XMLScanStreamParser]
# yields an instance of each installed parser
Modified: MacRuby/trunk/lib/xmlrpc/server.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/server.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/server.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -14,23 +14,23 @@
= XMLRPC::BasicServer
== Description
Is the base class for all XML-RPC server-types (CGI, standalone).
-You can add handler and set a default handler.
+You can add handler and set a default handler.
Do not use this server, as this is/should be an abstract class.
=== How the method to call is found
-The arity (number of accepted arguments) of a handler (method or (({Proc})) object) is
-compared to the given arguments submitted by the client for a RPC ((-Remote Procedure Call-)).
-A handler is only called if it accepts the number of arguments, otherwise the search
-for another handler will go on. When at the end no handler was found,
+The arity (number of accepted arguments) of a handler (method or (({Proc})) object) is
+compared to the given arguments submitted by the client for a RPC ((-Remote Procedure Call-)).
+A handler is only called if it accepts the number of arguments, otherwise the search
+for another handler will go on. When at the end no handler was found,
the ((<default_handler|XMLRPC::BasicServer#set_default_handler>)) will be called.
With this technique it is possible to do overloading by number of parameters, but
only for (({Proc})) handler, because you cannot define two methods of the same name in
-the same class.
+the same class.
== Class Methods
--- XMLRPC::BasicServer.new( class_delim="." )
- Creates a new (({XMLRPC::BasicServer})) instance, which should not be
+ Creates a new (({XMLRPC::BasicServer})) instance, which should not be
done, because (({XMLRPC::BasicServer})) is an abstract class. This
method should be called from a subclass indirectly by a (({super})) call
in the method (({initialize})). The paramter ((|class_delim|)) is used
@@ -40,24 +40,24 @@
== Instance Methods
--- XMLRPC::BasicServer#add_handler( name, signature=nil, help=nil ) { aBlock }
Adds ((|aBlock|)) to the list of handlers, with ((|name|)) as the name of the method.
- Parameters ((|signature|)) and ((|help|)) are used by the Introspection method if specified,
- where ((|signature|)) is either an Array containing strings each representing a type of it's
- signature (the first is the return value) or an Array of Arrays if the method has multiple
+ Parameters ((|signature|)) and ((|help|)) are used by the Introspection method if specified,
+ where ((|signature|)) is either an Array containing strings each representing a type of it's
+ signature (the first is the return value) or an Array of Arrays if the method has multiple
signatures. Value type-names are "int, boolean, double, string, dateTime.iso8601, base64, array, struct".
Parameter ((|help|)) is a String with informations about how to call this method etc.
A handler method or code-block can return the types listed at
- ((<XMLRPC::Client#call|URL:client.html#index:0>)).
- When a method fails, it can tell it the client by throwing an
+ ((<XMLRPC::Client#call|URL:client.html#index:0>)).
+ When a method fails, it can tell it the client by throwing an
(({XMLRPC::FaultException})) like in this example:
s.add_handler("michael.div") do |a,b|
if b == 0
raise XMLRPC::FaultException.new(1, "division by zero")
else
- a / b
+ a / b
end
- end
+ end
The client gets in the case of (({b==0})) an object back of type
(({XMLRPC::FaultException})) that has a ((|faultCode|)) and ((|faultString|))
field.
@@ -67,10 +67,10 @@
To add an object write:
server.add_handler("michael", MyHandlerClass.new)
All public methods of (({MyHandlerClass})) are accessible to
- the XML-RPC clients by (('michael."name of method"')). This is
- where the ((|class_delim|)) in ((<new|XMLRPC::BasicServer.new>))
- has it's role, a XML-RPC method-name is defined by
- ((|prefix|)) + ((|class_delim|)) + (('"name of method"')).
+ the XML-RPC clients by (('michael."name of method"')). This is
+ where the ((|class_delim|)) in ((<new|XMLRPC::BasicServer.new>))
+ has it's role, a XML-RPC method-name is defined by
+ ((|prefix|)) + ((|class_delim|)) + (('"name of method"')).
--- XMLRPC::BasicServer#add_handler( interface, obj )
This is the third form of ((<add_handler|XMLRPC::BasicServer#add_handler>)).
@@ -91,11 +91,11 @@
It is a (({Proc})) object or (({nil})).
--- XMLRPC::BasicServer#set_default_handler ( &handler )
- Sets ((|handler|)) as the default-handler, which is called when
+ Sets ((|handler|)) as the default-handler, which is called when
no handler for a method-name is found. ((|handler|)) is a code-block.
The default-handler is called with the (XML-RPC) method-name as first argument, and
the other arguments are the parameters given by the client-call.
-
+
If no block is specified the default of (({XMLRPC::BasicServer})) is used, which raises a
XMLRPC::FaultException saying "method missing".
@@ -103,7 +103,7 @@
--- XMLRPC::BasicServer#set_writer( writer )
Sets the XML writer to use for generating XML output.
Should be an instance of a class from module (({XMLRPC::XMLWriter})).
- If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used.
+ If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used.
--- XMLRPC::BasicServer#set_parser( parser )
Sets the XML parser to use for parsing XML documents.
@@ -111,7 +111,7 @@
If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used.
--- XMLRPC::BasicServer#add_introspection
- Adds the introspection handlers "system.listMethods", "system.methodSignature" and "system.methodHelp",
+ Adds the introspection handlers "system.listMethods", "system.methodSignature" and "system.methodHelp",
where only the first one works.
--- XMLRPC::BasicServer#add_multicall
@@ -123,7 +123,7 @@
--- XMLRPC::BasicServer#set_service_hook ( &handler )
A service-hook is called for each service request (RPC).
You can use a service-hook for example to wrap existing methods and catch exceptions of them or
- convert values to values recognized by XMLRPC. You can disable it by passing (({nil})) as parameter
+ convert values to values recognized by XMLRPC. You can disable it by passing (({nil})) as parameter
((|handler|)) .
The service-hook is called with a (({Proc})) object and with the parameters for this (({Proc})).
@@ -132,8 +132,8 @@
server.set_service_hook {|obj, *args|
begin
ret = obj.call(*args) # call the original service-method
- # could convert the return value
- resuce
+ # could convert the return value
+ rescue
# rescue exceptions
end
}
@@ -157,7 +157,7 @@
include ParserWriterChooseMixin
include ParseContentType
- ERR_METHOD_MISSING = 1
+ ERR_METHOD_MISSING = 1
ERR_UNCAUGHT_EXCEPTION = 2
ERR_MC_WRONG_PARAM = 3
ERR_MC_MISSING_PARAMS = 4
@@ -169,7 +169,7 @@
def initialize(class_delim=".")
@handler = []
- @default_handler = nil
+ @default_handler = nil
@service_hook = nil
@class_delim = class_delim
@@ -183,7 +183,7 @@
def add_handler(prefix, obj_or_signature=nil, help=nil, &block)
if block_given?
# proc-handler
- @handler << [prefix, block, obj_or_signature, help]
+ @handler << [prefix, block, obj_or_signature, help]
else
if prefix.kind_of? String
# class-handler
@@ -208,7 +208,7 @@
@service_hook = handler
self
end
-
+
def get_default_handler
@default_handler
end
@@ -216,18 +216,18 @@
def set_default_handler (&handler)
@default_handler = handler
self
- end
+ end
def add_multicall
add_handler("system.multicall", %w(array array), "Multicall Extension") do |arrStructs|
- unless arrStructs.is_a? Array
+ unless arrStructs.is_a? Array
raise XMLRPC::FaultException.new(ERR_MC_WRONG_PARAM, "system.multicall expects an array")
end
arrStructs.collect {|call|
if call.is_a? Hash
methodName = call["methodName"]
- params = call["params"]
+ params = call["params"]
if params.nil?
multicall_fault(ERR_MC_MISSING_PARAMS, "Missing params")
@@ -246,16 +246,16 @@
[val]
else
# exception
- multicall_fault(val.faultCode, val.faultString)
+ multicall_fault(val.faultCode, val.faultString)
end
end
end
- end
-
+ end
+
else
multicall_fault(ERR_MC_EXPECTED_STRUCT, "system.multicall expected struct")
end
- }
+ }
end # end add_handler
self
end
@@ -284,7 +284,7 @@
sig.each {|s| sigs << s}
else
# sig is a single signature, e.g. ["array"]
- sigs << sig
+ sigs << sig
end
end
end
@@ -292,11 +292,11 @@
end
add_handler("system.methodHelp", %w(string string), "Returns help on using this method") do |meth|
- help = nil
+ help = nil
@handler.each do |name, obj, sig, hlp|
- if obj.kind_of? Proc and name == meth
+ if obj.kind_of? Proc and name == meth
help = hlp
- break
+ break
end
end
help || ""
@@ -306,18 +306,18 @@
end
-
+
def process(data)
- method, params = parser().parseMethodCall(data)
+ method, params = parser().parseMethodCall(data)
handle(method, *params)
end
-
+
private # --------------------------------------------------------------
def multicall_fault(nr, str)
{"faultCode" => nr, "faultString" => str}
end
-
+
#
# method dispatch
#
@@ -333,17 +333,17 @@
if check_arity(obj, args.size)
if @service_hook.nil?
- return obj.call(*args)
+ return obj.call(*args)
else
return @service_hook.call(obj, *args)
end
end
- end
-
+ end
+
if @default_handler.nil?
raise XMLRPC::FaultException.new(ERR_METHOD_MISSING, "Method #{methodname} missing or wrong number of parameters!")
else
- @default_handler.call(methodname, *args)
+ @default_handler.call(methodname, *args)
end
end
@@ -357,7 +357,7 @@
if ary >= 0
n_args == ary
else
- n_args >= (ary+1).abs
+ n_args >= (ary+1).abs
end
end
@@ -366,8 +366,8 @@
def call_method(methodname, *args)
begin
[true, dispatch(methodname, *args)]
- rescue XMLRPC::FaultException => e
- [false, e]
+ rescue XMLRPC::FaultException => e
+ [false, e]
rescue Exception => e
[false, XMLRPC::FaultException.new(ERR_UNCAUGHT_EXCEPTION, "Uncaught exception #{e.message} in method #{methodname}")]
end
@@ -388,9 +388,9 @@
= XMLRPC::CGIServer
== Synopsis
require "xmlrpc/server"
-
- s = XMLRPC::CGIServer.new
+ s = XMLRPC::CGIServer.new
+
s.add_handler("michael.add") do |a,b|
a + b
end
@@ -399,15 +399,15 @@
if b == 0
raise XMLRPC::FaultException.new(1, "division by zero")
else
- a / b
+ a / b
end
- end
+ end
s.set_default_handler do |name, *args|
raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
" or wrong number of parameters!")
end
-
+
s.serve
== Description
@@ -419,7 +419,7 @@
== Class Methods
--- XMLRPC::CGIServer.new( *a )
Creates a new (({XMLRPC::CGIServer})) instance. All parameters given
- are by-passed to ((<XMLRPC::BasicServer.new>)). You can only create
+ are by-passed to ((<XMLRPC::BasicServer.new>)). You can only create
((*one*)) (({XMLRPC::CGIServer})) instance, because more than one makes
no sense.
@@ -427,7 +427,7 @@
--- XMLRPC::CGIServer#serve
Call this after you have added all you handlers to the server.
This method processes a XML-RPC methodCall and sends the answer
- back to the client.
+ back to the client.
Make sure that you don't write to standard-output in a handler, or in
any other part of your program, this would case a CGI-based server to fail!
=end
@@ -443,14 +443,14 @@
def initialize(*a)
super(*a)
end
-
+
def serve
catch(:exit_serve) {
length = ENV['CONTENT_LENGTH'].to_i
- http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST"
+ http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST"
http_error(400, "Bad Request") unless parse_content_type(ENV['CONTENT_TYPE']).first == "text/xml"
- http_error(411, "Length Required") unless length > 0
+ http_error(411, "Length Required") unless length > 0
# TODO: do we need a call to binmode?
$stdin.binmode if $stdin.respond_to? :binmode
@@ -467,7 +467,7 @@
def http_error(status, message)
err = "#{status} #{message}"
- msg = <<-"MSGEND"
+ msg = <<-"MSGEND"
<html>
<head>
<title>#{err}</title>
@@ -487,7 +487,7 @@
h = {}
header.each {|key, value| h[key.to_s.capitalize] = value}
h['Status'] ||= "200 OK"
- h['Content-length'] ||= body.size.to_s
+ h['Content-length'] ||= body.size.to_s
str = ""
h.each {|key, value| str << "#{key}: #{value}\r\n"}
@@ -507,7 +507,7 @@
== Superclass
((<XMLRPC::BasicServer>))
-=end
+=end
class ModRubyServer < BasicServer
@@ -523,9 +523,9 @@
length = header['Content-length'].to_i
- http_error(405, "Method Not Allowed") unless @ap.request_method == "POST"
+ http_error(405, "Method Not Allowed") unless @ap.request_method == "POST"
http_error(400, "Bad Request") unless parse_content_type(header['Content-type']).first == "text/xml"
- http_error(411, "Length Required") unless length > 0
+ http_error(411, "Length Required") unless length > 0
# TODO: do we need a call to binmode?
@ap.binmode
@@ -542,7 +542,7 @@
def http_error(status, message)
err = "#{status} #{message}"
- msg = <<-"MSGEND"
+ msg = <<-"MSGEND"
<html>
<head>
<title>#{err}</title>
@@ -562,12 +562,12 @@
h = {}
header.each {|key, value| h[key.to_s.capitalize] = value}
h['Status'] ||= "200 OK"
- h['Content-length'] ||= body.size.to_s
+ h['Content-length'] ||= body.size.to_s
h.each {|key, value| @ap.headers_out[key] = value }
- @ap.content_type = h["Content-type"]
- @ap.status = status.to_i
- @ap.send_http_header
+ @ap.content_type = h["Content-type"]
+ @ap.status = status.to_i
+ @ap.send_http_header
@ap.print body
end
@@ -578,9 +578,9 @@
= XMLRPC::Server
== Synopsis
require "xmlrpc/server"
-
- s = XMLRPC::Server.new(8080)
+ s = XMLRPC::Server.new(8080)
+
s.add_handler("michael.add") do |a,b|
a + b
end
@@ -589,15 +589,15 @@
if b == 0
raise XMLRPC::FaultException.new(1, "division by zero")
else
- a / b
+ a / b
end
- end
+ end
s.set_default_handler do |name, *args|
raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
" or wrong number of parameters!")
end
-
+
s.serve
== Description
@@ -610,13 +610,13 @@
== Class Methods
--- XMLRPC::Server.new( port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a )
Creates a new (({XMLRPC::Server})) instance, which is a XML-RPC server listening on
- port ((|port|)) and accepts requests for the host ((|host|)), which is by default only the localhost.
+ port ((|port|)) and accepts requests for the host ((|host|)), which is by default only the localhost.
The server is not started, to start it you have to call ((<serve|XMLRPC::Server#serve>)).
Parameters ((|audit|)) and ((|debug|)) are obsolete!
- All additionally given parameters in ((|*a|)) are by-passed to ((<XMLRPC::BasicServer.new>)).
-
+ All additionally given parameters in ((|*a|)) are by-passed to ((<XMLRPC::BasicServer.new>)).
+
== Instance Methods
--- XMLRPC::Server#serve
Call this after you have added all you handlers to the server.
@@ -624,7 +624,7 @@
--- XMLRPC::Server#shutdown
Stops and shuts the server down.
-
+
=end
class WEBrickServlet < BasicServer; end # forward declaration
@@ -634,26 +634,22 @@
def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a)
super(*a)
require 'webrick'
- @server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections,
+ @server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections,
:Logger => WEBrick::Log.new(stdlog))
@server.mount("/", self)
end
-
+
def serve
- if RUBY_PLATFORM =~ /mingw|mswin32/
- signals = [1]
- else
- signals = %w[INT TERM HUP]
- end
+ signals = %w[INT TERM HUP] & Signal.list.keys
signals.each { |signal| trap(signal) { @server.shutdown } }
@server.start
end
-
+
def shutdown
@server.shutdown
end
-
+
end
=begin
@@ -672,16 +668,16 @@
if b == 0
raise XMLRPC::FaultException.new(1, "division by zero")
else
- a / b
+ a / b
end
- end
+ end
s.set_default_handler do |name, *args|
raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
" or wrong number of parameters!")
end
- httpserver = WEBrick::HTTPServer.new(:Port => 8080)
+ httpserver = WEBrick::HTTPServer.new(:Port => 8080)
httpserver.mount("/RPC2", s)
trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows
httpserver.start
@@ -695,7 +691,7 @@
--- XMLRPC::WEBrickServlet#get_valid_ip
Return the via method ((<set_valid_ip|XMLRPC::Server#set_valid_ip>)) specified
valid IP addresses.
-
+
== Description
Implements a servlet for use with WEBrick, a pure Ruby (HTTP-) server framework.
@@ -711,10 +707,10 @@
@valid_ip = nil
end
- # deprecated from WEBrick/1.2.2.
+ # deprecated from WEBrick/1.2.2.
# but does not break anything.
def require_path_info?
- false
+ false
end
def get_instance(config, *options)
@@ -736,7 +732,7 @@
def service(request, response)
- if @valid_ip
+ if @valid_ip
raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip }
end
@@ -745,9 +741,9 @@
"unsupported method `#{request.request_method}'."
end
- if parse_content_type(request['Content-type']).first != "text/xml"
+ if parse_content_type(request['Content-type']).first != "text/xml"
raise WEBrick::HTTPStatus::BadRequest
- end
+ end
length = (request['Content-length'] || 0).to_i
@@ -760,14 +756,14 @@
end
resp = process(data)
- if resp.nil? or resp.size <= 0
+ if resp.nil? or resp.size <= 0
raise WEBrick::HTTPStatus::InternalServerError
end
response.status = 200
response['Content-Length'] = resp.size
response['Content-Type'] = "text/xml; charset=utf-8"
- response.body = resp
+ response.body = resp
end
end
@@ -777,6 +773,6 @@
=begin
= History
- $Id: server.rb 20879 2008-12-19 11:37:33Z yugui $
+ $Id: server.rb 26986 2010-03-20 03:30:59Z nobu $
=end
Modified: MacRuby/trunk/lib/xmlrpc/utils.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/utils.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/lib/xmlrpc/utils.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,12 +1,12 @@
#
# Defines ParserWriterChooseMixin, which makes it possible to choose a
# different XML writer and/or XML parser then the default one.
-# The Mixin is used in client.rb (class Client) and server.rb (class
+# The Mixin is used in client.rb (class Client) and server.rb (class
# BasicServer)
-#
+#
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann at ntecs.de)
#
-# $Id: utils.rb 19657 2008-10-01 13:46:53Z mame $
+# $Id: utils.rb 27537 2010-04-28 18:51:35Z jeg2 $
#
module XMLRPC
@@ -15,7 +15,7 @@
# This module enables a user-class to be marshalled
# by XML-RPC for Ruby into a Hash, with one additional
# key/value pair "___class___" => ClassName
- #
+ #
module Marshallable
end
@@ -72,9 +72,9 @@
mname = nil
sig = [sig] if sig.kind_of? String
- sig = sig.collect do |s|
+ sig = sig.collect do |s|
name, si = parse_sig(s)
- raise "Wrong signatures!" if mname != nil and name != mname
+ raise "Wrong signatures!" if mname != nil and name != mname
mname = name
si
end
@@ -83,12 +83,12 @@
end
private # ---------------------------------
-
+
def parse_sig(sig)
# sig is a String
if sig =~ /^\s*(\w+)\s+([^(]+)(\(([^)]*)\))?\s*$/
params = [$1]
- name = $2.strip
+ name = $2.strip
$4.split(",").each {|i| params << i.strip} if $4 != nil
return name, params
else
@@ -109,10 +109,10 @@
instance_eval(&p)
end
- def get_methods(obj, delim=".")
+ def get_methods(obj, delim=".")
prefix = @prefix + delim
- @methods.collect { |name, meth, sig, help|
- [prefix + name, obj.method(meth).to_proc, sig, help]
+ @methods.collect { |name, meth, sig, help|
+ [prefix + name.to_s, obj.method(meth).to_proc, sig, help]
}
end
@@ -132,7 +132,7 @@
def get_methods(obj, delim=".")
prefix = @prefix + delim
obj.class.public_instance_methods(false).collect { |name|
- [prefix + name, obj.method(name).to_proc, nil, nil]
+ [prefix + name.to_s, obj.method(name).to_proc, nil, nil]
}
end
end
@@ -141,16 +141,16 @@
end # module Service
- #
+ #
# short-form to create a Service::Interface
#
def self.interface(prefix, &p)
- Service::Interface.new(prefix, &p)
+ Service::Interface.new(prefix, &p)
end
# short-cut for creating a PublicInstanceMethodsInterface
def self.iPIMethods(prefix)
- Service::PublicInstanceMethodsInterface.new(prefix)
+ Service::PublicInstanceMethodsInterface.new(prefix)
end
Modified: MacRuby/trunk/numeric.c
===================================================================
--- MacRuby/trunk/numeric.c 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/numeric.c 2010-05-18 01:40:51 UTC (rev 4114)
@@ -265,6 +265,20 @@
/*
* call-seq:
+ * num.i -> Complex(0,num)
+ *
+ * Returns the corresponding imaginary number.
+ * Not available for complex numbers.
+ */
+
+static VALUE
+num_imaginary(VALUE num, SEL sel)
+{
+ return rb_complex_new(INT2FIX(0), num);
+}
+
+/*
+ * call-seq:
* -num => numeric
*
* Unary Minus---Returns the receiver's value, negated.
@@ -3380,6 +3394,7 @@
rb_objc_define_method(rb_cNumeric, "initialize_copy", num_init_copy, 1);
rb_objc_define_method(rb_cNumeric, "coerce", num_coerce, 1);
+ rb_objc_define_method(rb_cNumeric, "i", num_imaginary, 0);
rb_objc_define_method(rb_cNumeric, "+@", num_uplus, 0);
rb_objc_define_method(rb_cNumeric, "-@", num_uminus, 0);
rb_objc_define_method(rb_cNumeric, "<=>", num_cmp, 1);
Modified: MacRuby/trunk/rakelib/builder/builder.rb
===================================================================
--- MacRuby/trunk/rakelib/builder/builder.rb 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/rakelib/builder/builder.rb 2010-05-18 01:40:51 UTC (rev 4114)
@@ -11,7 +11,6 @@
EXTENSIONS = %w{
ripper digest etc readline libyaml fcntl socket zlib bigdecimal openssl json
- nkf
}.sort
class Builder
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/cookie/value_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/cookie/value_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/cookie/value_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +0,0 @@
-fails:CGI::Cookie#value is in synch with self
-fails:CGI::Cookie#value= automatically converts the passed Object to an Array using #Array
-fails:CGI::Cookie#value= does keep self and the values in sync
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/initialize_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/initialize_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,2 +0,0 @@
-fails:CGI#initialize when passed no arguments does not extend self with CGI::HtmlExtension
-fails:CGI#initialize when passed no arguments does not extend self with any of the other HTML modules
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/unescape_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/unescape_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/cgi/unescape_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -0,0 +1 @@
+fails:CGI.unescape url-decodes the passed argument
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/csv/parse_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/csv/parse_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/csv/parse_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,7 +0,0 @@
-fails:CSV.parse parses 'foo,bar,baz' into [['foo','bar','baz']]
-fails:CSV.parse parses 'foo,baz' into [[foo,nil,baz]]
-fails:"CSV.parse parses 'foo,bar\nbaz,quz' into [['foo','bar'],['baz','quz']]"
-fails:"CSV.parse parses 'foo,bar'\nbaz' into [['foo','bar'],['baz']]"
-fails:"CSV.parse parses 'foo\nbar,baz' into [['foo'],['bar','baz']]"
-fails:CSV.parse parses 'foo;bar' into [['foo','bar']] with a separator of ;
-fails:"CSV.parse parses 'foo;bar\nbaz;quz' into [['foo','bar'],['baz','quz']] with a separator of ;"
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/date/strptime_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/date/strptime_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/date/strptime_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Date#strptime parses a week number for a week starting on Monday
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/getoptlong/set_options_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/getoptlong/set_options_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/getoptlong/set_options_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:GetoptLong#set_options raises an ArgumentError if one of the given arguments is not an Array
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/logger/device/close_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/logger/device/close_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/logger/device/close_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Logger::LogDevice#close closes the LogDevice's stream
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/logger/device/write_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/logger/device/write_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/logger/device/write_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Logger::LogDevice#write fails if the device is already closed
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/logger/logger/close_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/logger/logger/close_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/logger/logger/close_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Logger#close closes the logging device
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/build_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/build_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/build_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,9 +0,0 @@
-fails:Matrix.build returns a Matrix object of the given size
-fails:Matrix.build builds the Matrix using the given block
-fails:Matrix.build iterates through the first row, then the second, ...
-fails:Matrix.build returns an Enumerator is no block is given
-fails:Matrix.build requires integers as parameters
-fails:Matrix.build requires non-negative integers
-fails:Matrix.build returns empty Matrix if one argument is zero
-fails:Matrix.build tries to calls :to_int on arguments
-fails:Matrix.build builds an nxn Matrix when given only one argument
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/collect_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/collect_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/collect_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#collect returns an enumerator if no block is given
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_size_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_size_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_size_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#column_size returns 0 for empty matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +0,0 @@
-fails:Matrix#column returns self when called with a block
-fails:Matrix#column returns nil when out of bounds
-fails:Matrix#column never yields when out of bounds
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_vector_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_vector_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/column_vector_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix.column_vector returns an empty Matrix when called with an empty Array
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/columns_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/columns_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/columns_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix.columns handles empty matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/conj_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/conj_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/conj_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,2 +0,0 @@
-fails:Matrix#conj returns a matrix with all entries 'conjugated'
-fails:Matrix#conj returns empty matrices on the same size if empty
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/conjugate_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/conjugate_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/conjugate_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,2 +0,0 @@
-fails:Matrix#conjugate returns a matrix with all entries 'conjugated'
-fails:Matrix#conjugate returns empty matrices on the same size if empty
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/constructor_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/constructor_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/constructor_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +0,0 @@
-fails:Matrix.[] requires arrays as parameters
-fails:Matrix.[] creates an empty Matrix with no arguments
-fails:Matrix.[] raises for non-rectangular matrices
-fails:Matrix.[] accepts vector arguments
-fails:Matrix.[] tries to calls :to_ary on arguments
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/det_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/det_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/det_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +0,0 @@
-fails:Matrix#det returns 1 for an empty Matrix
-fails:Matrix#det returns the determinant even for Matrices containing 0 as first entry
-fails:Matrix#det raises an error for rectangular matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/determinant_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/determinant_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/determinant_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +0,0 @@
-fails:Matrix#determinant returns 1 for an empty Matrix
-fails:Matrix#determinant returns the determinant even for Matrices containing 0 as first entry
-fails:Matrix#determinant raises an error for rectangular matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/divide_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/divide_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/divide_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#/ raises a TypeError if other is of wrong type
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/each_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/each_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/each_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +0,0 @@
-fails:Matrix#each returns an Enumerator when called without a block
-fails:Matrix#each returns self
-fails:Matrix#each yields the elements starting with the those of the first row
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/each_with_index_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/each_with_index_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/each_with_index_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +0,0 @@
-fails:Matrix#each_with_index returns an Enumerator when called without a block
-fails:Matrix#each_with_index returns self
-fails:Matrix#each_with_index yields the elements starting with the those of the first row
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/element_reference_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/element_reference_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/element_reference_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#[] returns nil for an invalid index pair
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/empty_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/empty_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/empty_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,8 +0,0 @@
-fails:Matrix#empty? returns true when the Matrix is empty
-fails:Matrix#empty? returns false when the Matrix has elements
-fails:Matrix#empty? doesn't accept any parameter
-fails:Matrix.empty returns an empty matrix of the requested size
-fails:Matrix.empty has arguments defaulting to 0
-fails:Matrix.empty does not accept more than two parameters
-fails:Matrix.empty raises an error if both dimensions are > 0
-fails:Matrix.empty raises an error if any dimension is < 0
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/exponent_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/exponent_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/exponent_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#** raises a ErrOperationNotImplemented exception for powers that aren't Integers
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/imag_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/imag_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/imag_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,2 +0,0 @@
-fails:Matrix#imag returns a matrix with the imaginary part of the elements of the receiver
-fails:Matrix#imag returns empty matrices on the same size if empty
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/imaginary_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/imaginary_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/imaginary_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,2 +0,0 @@
-fails:Matrix#imaginary returns a matrix with the imaginary part of the elements of the receiver
-fails:Matrix#imaginary returns empty matrices on the same size if empty
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/inspect_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/inspect_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/inspect_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#inspect returns 'Matrix.empty(...)' for empty matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/map_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/map_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/map_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#map returns an enumerator if no block is given
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/minor_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/minor_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/minor_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,4 +0,0 @@
-fails:Matrix#minor with start_row, nrows, start_col, ncols returns an empty Matrix unless nrows and ncols are greater than 0
-fails:Matrix#minor with start_row, nrows, start_col, ncols returns nil for out-of-bounds start_row/col
-fails:Matrix#minor with start_row, nrows, start_col, ncols returns nil for negative nrows or ncols
-fails:Matrix#minor with col_range, row_range returns nil if col_range or row_range is out of range
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/minus_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/minus_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/minus_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#- raises a TypeError if other is of wrong type
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/multiply_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/multiply_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/multiply_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,4 +0,0 @@
-fails:Matrix#* returns a zero matrix if (nx0) * (0xn)
-fails:Matrix#* returns an empty matrix if (0xn) * (nx0)
-fails:Matrix#* returns a 0xm matrix if (0xm) * (mxn)
-fails:Matrix#* raises a TypeError if other is of wrong type
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/plus_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/plus_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/plus_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#+ raises a TypeError if other is of wrong type
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rank_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rank_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rank_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,2 +1 @@
critical:Matrix#rank doesn't loop forever
-fails:Matrix#rank works for some easy rectangular matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/real_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/real_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/real_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,5 +0,0 @@
-fails:Matrix#real? returns true for matrices with all real entries
-fails:Matrix#real? returns true for empty matrices
-fails:Matrix#real? returns false if one element is a Complex
-fails:Matrix#real returns a matrix with the real part of the elements of the receiver
-fails:Matrix#real returns empty matrices on the same size if empty
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rect_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rect_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rect_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#rect returns [receiver.real, receiver.imag]
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rectangular_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rectangular_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/rectangular_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#rectangular returns [receiver.real, receiver.imag]
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/regular_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/regular_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/regular_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,4 +1,2 @@
critical:Matrix#regular? returns false unless rank(A) != n
critical:Matrix#regular? returns false for singular matrices
-fails:Matrix#regular? returns true for an empty 0x0 matrix
-fails:Matrix#regular? raises an error for rectangular matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/row_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/row_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/row_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +0,0 @@
-fails:Matrix#row returns self when called with a block
-fails:Matrix#row returns nil when out of bounds
-fails:Matrix#row never yields when out of bounds
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/singular_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/singular_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/singular_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,3 +1 @@
critical:Matrix#singular? returns true for singular matrices
-fails:Matrix#singular? returns false for an empty 0x0 matrix
-fails:Matrix#singular? raises an error for rectangular matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/square_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/square_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/square_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#square? returns handles empty matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/t_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/t_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/t_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#transpose can transpose empty matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/tr_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/tr_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/tr_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#tr returns the sum of diagonal elements in a rectangular Matrix
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/trace_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/trace_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/trace_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#trace returns the sum of diagonal elements in a rectangular Matrix
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/transpose_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/transpose_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/transpose_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:Matrix#transpose can transpose empty matrices
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/vector/each2_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/vector/each2_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/vector/each2_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1,2 +0,0 @@
-fails:Vector.each2 given one argument returns self when given a block
-fails:Vector.each2 given one argument returns an enumerator if no block given
Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/uri/eql_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/uri/eql_tags.txt 2010-05-17 21:25:19 UTC (rev 4113)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/uri/eql_tags.txt 2010-05-18 01:40:51 UTC (rev 4114)
@@ -1 +0,0 @@
-fails:URI#eql? returns false for when compared to non-uri objects
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100517/4d0061e8/attachment-0001.html>
More information about the macruby-changes
mailing list