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. 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 to the user. This adds state information to the otherwise stateless HTTP request/response protocol.
A CGI::Session
instance is created from a CGI
object. By default, this CGI::Session
instance will start a new session if none currently exists, or continue the current session for this client if one does exist. The new_session
option can be used to either always or never create a new session. See new() for more details.
delete()
deletes a session from session storage. It does not however remove the session id from the client. If the client makes another request with the same id, the effect will be to start a new session with the old session’s id.
The Session
class associates data with a session as key-value pairs. 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).
When session processing has been completed for a request, the session should be closed using the close() method. This will store the session’s state to persistent storage. If you want to store the session’s state to persistent storage without finishing session processing for this request, call the update() method.
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 storage type.
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, and provides file-locking and transaction support.
Custom storage types can also be created by defining a class with the following methods:
new(session, options) restore # returns hash of session data. update close delete
Changing storage type mid-session does not work. Note in particular that by default the FileStore
and PStore
session data files have the same name. If your application switches from one to the other without making sure that filenames will be different and clients still have old sessions lying around in cookies, then things will break nastily!
Most session state is maintained on the server. However, a session id must be passed backwards and forwards between client and server to maintain a reference to this session state.
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
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.
require 'cgi' require 'cgi/session' require 'cgi/session/pstore' # provides CGI::Session::PStore cgi = CGI.new("html4") 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 'prefix' => 'pstore_sid_') # PStore option if cgi.has_key?('user_name') and cgi['user_name'] != '' # coerce to String: cgi[] returns the # string-like CGI::QueryExtension::Value session['user_name'] = cgi['user_name'].to_s elsif !session['user_name'] session['user_name'] = "guest" end session.close
require 'cgi' require 'cgi/session' 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 # from being maliciously hijacked later on. begin 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) session.close
Timer id conversion keeps objects alive for a certain amount of time after their last access. The default time period is 600 seconds and can be changed upon initialization.
To use TimerIdConv:
DRb.install_id_conv TimerIdConv.new 60 # one minute
Response class for Continue
responses (status code 100).
A Continue
response indicates that the server has received the request headers.
References:
Response class for Partial Content
responses (status code 206).
The Partial Content
response indicates that the server is delivering only part of the resource (byte serving) due to a Range
header in the request.
References:
Response class for Conflict
responses (status code 409).
The request could not be processed because of conflict in the current state of the resource.
References:
Response class for HTTP Version Not Supported
responses (status code 505).
The server does not support the HTTP
version used in the request.
References:
Response class for Variant Also Negotiates
responses (status code 506).
Transparent content negotiation for the request results in a circular reference.
References:
Raised when trying to activate a gem, and the gem exists on the system, but not the requested version. Instead of rescuing from this class, make sure to rescue from the superclass Gem::LoadError
to catch all types of load errors.
Raised when there are conflicting gem specs loaded
Raised when a gem dependencies file specifies a ruby version that does not match the current version.
The Version
class processes string versions into comparable values. A version string should normally be a series of numbers separated by periods. Each part (digits separated by periods) is considered its own number, and these are used for sorting. So for instance, 3.10 sorts higher than 3.2 because ten is greater than two.
If any part contains letters (currently only a-z are supported) then that version is considered prerelease. Versions with a prerelease part in the Nth part sort less than versions with N-1 parts. Prerelease parts are sorted alphabetically using the normal Ruby string sorting rules. If a prerelease part contains both letters and numbers, it will be broken into multiple parts to provide expected sort behavior (1.0.a10 becomes 1.0.a.10, and is greater than 1.0.a9).
Prereleases sort between real releases (newest to oldest):
1.0
1.0.b1
1.0.a.2
0.9
If you want to specify a version restriction that includes both prereleases and regular releases of the 1.x series this is the best way:
s.add_dependency 'example', '>= 1.0.0.a', '< 2.0.0'
Users expect to be able to specify a version constraint that gives them some reasonable expectation that new versions of a library will work with their software if the version constraint is true, and not work with their software if the version constraint is false. In other words, the perfect system will accept all compatible versions of the library and reject all incompatible versions.
Libraries change in 3 ways (well, more than 3, but stay focused here!).
The change may be an implementation detail only and have no effect on the client software.
The change may add new features, but do so in a way that client software written to an earlier version is still compatible.
The change may change the public interface of the library in such a way that old software is no longer compatible.
Some examples are appropriate at this point. Suppose I have a Stack class that supports a push
and a pop
method.
Switch from an array based implementation to a linked-list based implementation.
Provide an automatic (and transparent) backing store for large stacks.
Add a depth
method to return the current depth of the stack.
Add a top
method that returns the current top of stack (without changing the stack).
Change push
so that it returns the item pushed (previously it had no usable return value).
Changes pop
so that it no longer returns a value (you must use top
to get the top of the stack).
Rename the methods to push_item
and pop_item
.
Rational
Versioning Versions shall be represented by three non-negative integers, separated by periods (e.g. 3.1.4). The first integers is the “major” version number, the second integer is the “minor” version number, and the third integer is the “build” number.
A category 1 change (implementation detail) will increment the build number.
A category 2 change (backwards compatible) will increment the minor version number and reset the build number.
A category 3 change (incompatible) will increment the major build number and reset the minor and build numbers.
Any “public” release of a gem should have a different version. Normally that means incrementing the build number. This means a developer can generate builds all day long, but as soon as they make a public release, the version must be updated.
Let’s work through a project lifecycle using our Stack example from above.
Version
0.0.1
The initial Stack class is release.
Version
0.0.2
Switched to a linked=list implementation because it is cooler.
Version
0.1.0
Added a depth
method.
Version
1.0.0
Added top
and made pop
return nil (pop
used to return the old top item).
Version
1.1.0
push
now returns the value pushed (it used it return nil).
Version
1.1.1
Fixed a bug in the linked list implementation.
Version
1.1.2
Fixed a bug introduced in the last fix.
Client A needs a stack with basic push/pop capability. They write to the original interface (no top
), so their version constraint looks like:
gem 'stack', '>= 0.0'
Essentially, any version is OK with Client A. An incompatible change to the library will cause them grief, but they are willing to take the chance (we call Client A optimistic).
Client B is just like Client A except for two things: (1) They use the depth
method and (2) they are worried about future incompatibilities, so they write their version constraint like this:
gem 'stack', '~> 0.1'
The depth
method was introduced in version 0.1.0, so that version or anything later is fine, as long as the version stays below version 1.0 where incompatibilities are introduced. We call Client B pessimistic because they are worried about incompatible future changes (it is OK to be pessimistic!).
Version
Catastrophe: From: www.zenspider.com/ruby/2008/10/rubygems-how-to-preventing-catastrophe.html
Let’s say you’re depending on the fnord gem version 2.y.z. If you specify your dependency as “>= 2.0.0” then, you’re good, right? What happens if fnord 3.0 comes out and it isn’t backwards compatible with 2.y.z? Your stuff will break as a result of using “>=”. The better route is to specify your dependency with an “approximate” version specifier (“~>”). They’re a tad confusing, so here is how the dependency specifiers work:
Specification From ... To (exclusive) ">= 3.0" 3.0 ... ∞ "~> 3.0" 3.0 ... 4.0 "~> 3.0.0" 3.0.0 ... 3.1 "~> 3.5" 3.5 ... 4.0 "~> 3.5.0" 3.5.0 ... 3.6 "~> 3" 3.0 ... 4.0
For the last example, single-digit versions are automatically extended with a zero to give a sensible result.
Raised by transcoding methods when a named encoding does not correspond with a known converter.
Mixin module that provides the following:
Access to the CGI
environment variables as methods. See documentation to the CGI
class for a list of these variables. The methods are exposed by removing the leading HTTP_
(if it exists) and downcasing the name. For example, auth_type
will return the environment variable AUTH_TYPE
, and accept
will return the value for HTTP_ACCEPT
.
Access to cookies, including the cookies attribute.
Access to parameters, including the params attribute, and overloading []
to perform parameter value lookup by key.
The initialize_query
method, for initializing the above mechanisms, handling multipart forms, and allowing the class to be used in “offline” mode.
Utility methods for using the RubyGems API.
The WebauthnListener
class retrieves an OTP after a user successfully WebAuthns with the Gem host. An instance opens a socket using the TCPServer
instance given and listens for a request from the Gem host. The request should be a GET request to the root path and contains the OTP code in the form of a query parameter ‘code`. The listener will return the code which will be used as the OTP for API requests.
Types of responses sent by the listener after receiving a request:
- 200 OK: OTP code was successfully retrieved - 204 No Content: If the request was an OPTIONS request - 400 Bad Request: If the request did not contain a query parameter `code` - 404 Not Found: The request was not to the root path - 405 Method Not Allowed: OTP code was not retrieved because the request was not a GET/OPTIONS request
Example usage:
thread = Gem::WebauthnListener.listener_thread("https://rubygems.example", server) thread.join otp = thread[:otp] error = thread[:error]
The WebauthnListener
Response class is used by the WebauthnListener
to create responses to be sent to the Gem host. It creates a Gem::Net::HTTPResponse instance when initialized and can be converted to the appropriate format to be sent by a socket using ‘to_s`. Gem::Net::HTTPResponse instances cannot be directly sent over a socket.
Types of response classes:
- OkResponse - NoContentResponse - BadRequestResponse - NotFoundResponse - MethodNotAllowedResponse
Example usage:
server = TCPServer.new(0) socket = server.accept response = OkResponse.for("https://rubygems.example") socket.print response.to_s socket.close
The WebauthnPoller
class retrieves an OTP after a user successfully WebAuthns. An instance polls the Gem host for the OTP code. The polling request (api/v1/webauthn_verification/<webauthn_token>/status.json) is sent to the Gem host every 5 seconds and will timeout after 5 minutes. If the status field in the json response is “success”, the code field will contain the OTP code.
Example usage:
thread = Gem::WebauthnPoller.poll_thread( {}, "RubyGems.org", "https://rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY", { email: "email@example.com", password: "password" } ) thread.join otp = thread[:otp] error = thread[:error]
A Complex object houses a pair of values, given when the object is created as either rectangular coordinates or polar coordinates.
The rectangular coordinates of a complex number are called the real and imaginary parts; see Complex number definition.
You can create a Complex object from rectangular coordinates with:
A complex literal.
Method Complex.rect
.
Method Kernel#Complex
, either with numeric arguments or with certain string arguments.
Method String#to_c
, for certain strings.
Note that each of the stored parts may be a an instance one of the classes Complex
, Float
, Integer
, or Rational
; they may be retrieved:
Separately, with methods Complex#real
and Complex#imaginary
.
Together, with method Complex#rect
.
The corresponding (computed) polar values may be retrieved:
Separately, with methods Complex#abs
and Complex#arg
.
Together, with method Complex#polar
.
The polar coordinates of a complex number are called the absolute and argument parts; see Complex polar plane.
In this class, the argument part in expressed radians (not degrees).
You can create a Complex object from polar coordinates with:
Method Complex.polar
.
Method Kernel#Complex
, with certain string arguments.
Method String#to_c
, for certain strings.
Note that each of the stored parts may be a an instance one of the classes Complex
, Float
, Integer
, or Rational
; they may be retrieved:
Separately, with methods Complex#abs
and Complex#arg
.
Together, with method Complex#polar
.
The corresponding (computed) rectangular values may be retrieved:
Separately, with methods Complex#real
and Complex#imag
.
Together, with method Complex#rect
.
A File object is a representation of a file in the underlying platform.
Class File extends module FileTest
, supporting such singleton methods as File.exist?
.
Many examples here use these variables:
# English text with newlines. text = <<~EOT First line Second line Fourth line Fifth line EOT # Russian text. russian = "\u{442 435 441 442}" # => "тест" # Binary data. data = "\u9990\u9991\u9992\u9993\u9994" # Text file. File.write('t.txt', text) # File with Russian text. File.write('t.rus', russian) # File with binary data. f = File.new('t.dat', 'wb:UTF-16') f.write(data) f.close
Methods File.new
and File.open
each create a File object for a given file path.
Methods File.new
and File.open
each may take string argument mode
, which:
Begins with a 1- or 2-character read/write mode.
May also contain a 1-character data mode.
May also contain a 1-character file-create mode.
The read/write mode
determines:
Whether the file is to be initially truncated.
Whether reading is allowed, and if so:
The initial read position in the file.
Where in the file reading can occur.
Whether writing is allowed, and if so:
The initial write position in the file.
Where in the file writing can occur.
These tables summarize:
Read/Write Modes for Existing File |------|-----------|----------|----------|----------|-----------| | R/W | Initial | | Initial | | Initial | | Mode | Truncate? | Read | Read Pos | Write | Write Pos | |------|-----------|----------|----------|----------|-----------| | 'r' | No | Anywhere | 0 | Error | - | | 'w' | Yes | Error | - | Anywhere | 0 | | 'a' | No | Error | - | End only | End | | 'r+' | No | Anywhere | 0 | Anywhere | 0 | | 'w+' | Yes | Anywhere | 0 | Anywhere | 0 | | 'a+' | No | Anywhere | End | End only | End | |------|-----------|----------|----------|----------|-----------| Read/Write Modes for \File To Be Created |------|----------|----------|----------|-----------| | R/W | | Initial | | Initial | | Mode | Read | Read Pos | Write | Write Pos | |------|----------|----------|----------|-----------| | 'w' | Error | - | Anywhere | 0 | | 'a' | Error | - | End only | 0 | | 'w+' | Anywhere | 0 | Anywhere | 0 | | 'a+' | Anywhere | 0 | End only | End | |------|----------|----------|----------|-----------|
Note that modes 'r'
and 'r+'
are not allowed for a non-existent file (exception raised).
In the tables:
Anywhere
means that methods IO#rewind
, IO#pos=
, and IO#seek
may be used to change the file’s position, so that allowed reading or writing may occur anywhere in the file.
End only
means that writing can occur only at end-of-file, and that methods IO#rewind
, IO#pos=
, and IO#seek
do not affect writing.
Error
means that an exception is raised if disallowed reading or writing is attempted.
'r'
:
File
is not initially truncated:
f = File.new('t.txt') # => #<File:t.txt> f.size == 0 # => false
File’s initial read position is 0:
f.pos # => 0
File
may be read anywhere; see IO#rewind
, IO#pos=
, IO#seek
:
f.readline # => "First line\n" f.readline # => "Second line\n" f.rewind f.readline # => "First line\n" f.pos = 1 f.readline # => "irst line\n" f.seek(1, :CUR) f.readline # => "econd line\n"
Writing is not allowed:
f.write('foo') # Raises IOError.
'w'
:
File
is initially truncated:
path = 't.tmp' File.write(path, text) f = File.new(path, 'w') f.size == 0 # => true
File’s initial write position is 0:
f.pos # => 0
File
may be written anywhere (even past end-of-file); see IO#rewind
, IO#pos=
, IO#seek
:
f.write('foo') f.flush File.read(path) # => "foo" f.pos # => 3 f.write('bar') f.flush File.read(path) # => "foobar" f.pos # => 6 f.rewind f.write('baz') f.flush File.read(path) # => "bazbar" f.pos # => 3 f.pos = 3 f.write('foo') f.flush File.read(path) # => "bazfoo" f.pos # => 6 f.seek(-3, :END) f.write('bam') f.flush File.read(path) # => "bazbam" f.pos # => 6 f.pos = 8 f.write('bah') # Zero padding as needed. f.flush File.read(path) # => "bazbam\u0000\u0000bah" f.pos # => 11
Reading is not allowed:
f.read # Raises IOError.
'a'
:
File
is not initially truncated:
path = 't.tmp' File.write(path, 'foo') f = File.new(path, 'a') f.size == 0 # => false
File’s initial position is 0 (but is ignored):
f.pos # => 0
File
may be written only at end-of-file; IO#rewind
, IO#pos=
, IO#seek
do not affect writing:
f.write('bar') f.flush File.read(path) # => "foobar" f.write('baz') f.flush File.read(path) # => "foobarbaz" f.rewind f.write('bat') f.flush File.read(path) # => "foobarbazbat"
Reading is not allowed:
f.read # Raises IOError.
'r+'
:
File
is not initially truncated:
path = 't.tmp' File.write(path, text) f = File.new(path, 'r+') f.size == 0 # => false
File’s initial read position is 0:
f.pos # => 0
File
may be read or written anywhere (even past end-of-file); see IO#rewind
, IO#pos=
, IO#seek
:
f.readline # => "First line\n" f.readline # => "Second line\n" f.rewind f.readline # => "First line\n" f.pos = 1 f.readline # => "irst line\n" f.seek(1, :CUR) f.readline # => "econd line\n" f.rewind f.write('WWW') f.flush File.read(path) # => "WWWst line\nSecond line\nFourth line\nFifth line\n" f.pos = 10 f.write('XXX') f.flush File.read(path) # => "WWWst lineXXXecond line\nFourth line\nFifth line\n" f.seek(-6, :END) # => 0 f.write('YYY') # => 3 f.flush # => #<File:t.tmp> File.read(path) # => "WWWst lineXXXecond line\nFourth line\nFifth YYYe\n" f.seek(2, :END) f.write('ZZZ') # Zero padding as needed. f.flush File.read(path) # => "WWWst lineXXXecond line\nFourth line\nFifth YYYe\n\u0000\u0000ZZZ"
'a+'
:
File
is not initially truncated:
path = 't.tmp' File.write(path, 'foo') f = File.new(path, 'a+') f.size == 0 # => false
File’s initial read position is 0:
f.pos # => 0
File
may be written only at end-of-file; IO#rewind
, IO#pos=
, IO#seek
do not affect writing:
f.write('bar') f.flush File.read(path) # => "foobar" f.write('baz') f.flush File.read(path) # => "foobarbaz" f.rewind f.write('bat') f.flush File.read(path) # => "foobarbazbat"
File
may be read anywhere; see IO#rewind
, IO#pos=
, IO#seek
:
f.rewind f.read # => "foobarbazbat" f.pos = 3 f.read # => "barbazbat" f.seek(-3, :END) f.read # => "bat"
Note that modes 'r'
and 'r+'
are not allowed for a non-existent file (exception raised).
'w'
:
File’s initial write position is 0:
path = 't.tmp' FileUtils.rm_f(path) f = File.new(path, 'w') f.pos # => 0
File
may be written anywhere (even past end-of-file); see IO#rewind
, IO#pos=
, IO#seek
:
f.write('foo') f.flush File.read(path) # => "foo" f.pos # => 3 f.write('bar') f.flush File.read(path) # => "foobar" f.pos # => 6 f.rewind f.write('baz') f.flush File.read(path) # => "bazbar" f.pos # => 3 f.pos = 3 f.write('foo') f.flush File.read(path) # => "bazfoo" f.pos # => 6 f.seek(-3, :END) f.write('bam') f.flush File.read(path) # => "bazbam" f.pos # => 6 f.pos = 8 f.write('bah') # Zero padding as needed. f.flush File.read(path) # => "bazbam\u0000\u0000bah" f.pos # => 11
Reading is not allowed:
f.read # Raises IOError.
'a'
:
File’s initial write position is 0:
path = 't.tmp' FileUtils.rm_f(path) f = File.new(path, 'a') f.pos # => 0
Writing occurs only at end-of-file:
f.write('foo') f.pos # => 3 f.write('bar') f.pos # => 6 f.flush File.read(path) # => "foobar" f.rewind f.write('baz') f.flush File.read(path) # => "foobarbaz"
Reading is not allowed:
f.read # Raises IOError.
'w+'
:
File’s initial position is 0:
path = 't.tmp' FileUtils.rm_f(path) f = File.new(path, 'w+') f.pos # => 0
File
may be written anywhere (even past end-of-file); see IO#rewind
, IO#pos=
, IO#seek
:
f.write('foo') f.flush File.read(path) # => "foo" f.pos # => 3 f.write('bar') f.flush File.read(path) # => "foobar" f.pos # => 6 f.rewind f.write('baz') f.flush File.read(path) # => "bazbar" f.pos # => 3 f.pos = 3 f.write('foo') f.flush File.read(path) # => "bazfoo" f.pos # => 6 f.seek(-3, :END) f.write('bam') f.flush File.read(path) # => "bazbam" f.pos # => 6 f.pos = 8 f.write('bah') # Zero padding as needed. f.flush File.read(path) # => "bazbam\u0000\u0000bah" f.pos # => 11
File
may be read anywhere (even past end-of-file); see IO#rewind
, IO#pos=
, IO#seek
:
f.rewind # => 0 f.read # => "bazbam\u0000\u0000bah" f.pos = 3 # => 3 f.read # => "bam\u0000\u0000bah" f.seek(-3, :END) # => 0 f.read # => "bah"
'a+'
:
File’s initial write position is 0:
path = 't.tmp' FileUtils.rm_f(path) f = File.new(path, 'a+') f.pos # => 0
Writing occurs only at end-of-file:
f.write('foo') f.pos # => 3 f.write('bar') f.pos # => 6 f.flush File.read(path) # => "foobar" f.rewind f.write('baz') f.flush File.read(path) # => "foobarbaz"
File
may be read anywhere (even past end-of-file); see IO#rewind
, IO#pos=
, IO#seek
:
f.rewind f.read # => "foobarbaz" f.pos = 3 f.read # => "barbaz" f.seek(-3, :END) f.read # => "baz" f.pos = 800 f.read # => ""
To specify whether data is to be treated as text or as binary data, either of the following may be suffixed to any of the string read/write modes above:
't'
: Text data; sets the default external encoding to Encoding::UTF_8
; on Windows, enables conversion between EOL and CRLF and enables interpreting 0x1A
as an end-of-file marker.
'b'
: Binary data; sets the default external encoding to Encoding::ASCII_8BIT
; on Windows, suppresses conversion between EOL and CRLF and disables interpreting 0x1A
as an end-of-file marker.
If neither is given, the stream defaults to text data.
Examples:
File.new('t.txt', 'rt') File.new('t.dat', 'rb')
When the data mode is specified, the read/write mode may not be omitted, and the data mode must precede the file-create mode, if given:
File.new('t.dat', 'b') # Raises an exception. File.new('t.dat', 'rxb') # Raises an exception.
The following may be suffixed to any writable string mode above:
'x'
: Creates the file if it does not exist; raises an exception if the file exists.
Example:
File.new('t.tmp', 'wx')
When the file-create mode is specified, the read/write mode may not be omitted, and the file-create mode must follow the data mode:
File.new('t.dat', 'x') # Raises an exception. File.new('t.dat', 'rxb') # Raises an exception.
When mode is an integer it must be one or more of the following constants, which may be combined by the bitwise OR operator |
:
File::RDONLY
: Open for reading only.
File::WRONLY
: Open for writing only.
File::RDWR
: Open for reading and writing.
File::APPEND
: Open for appending only.
Examples:
File.new('t.txt', File::RDONLY) File.new('t.tmp', File::RDWR | File::CREAT | File::EXCL)
Note: Method
IO#set_encoding
does not allow the mode to be specified as an integer.
These constants may also be ORed into the integer mode:
File::CREAT
: Create file if it does not exist.
File::EXCL
: Raise an exception if File::CREAT
is given and the file exists.
Data mode cannot be specified as an integer. When the stream access mode is given as an integer, the data mode is always text, never binary.
Note that although there is a constant File::BINARY
, setting its value in an integer stream mode has no effect; this is because, as documented in File::Constants
, the File::BINARY
value disables line code conversion, but does not change the external encoding.
Any of the string modes above may specify encodings - either external encoding only or both external and internal encodings - by appending one or both encoding names, separated by colons:
f = File.new('t.dat', 'rb') f.external_encoding # => #<Encoding:ASCII-8BIT> f.internal_encoding # => nil f = File.new('t.dat', 'rb:UTF-16') f.external_encoding # => #<Encoding:UTF-16 (dummy)> f.internal_encoding # => nil f = File.new('t.dat', 'rb:UTF-16:UTF-16') f.external_encoding # => #<Encoding:UTF-16 (dummy)> f.internal_encoding # => #<Encoding:UTF-16> f.close
The numerous encoding names are available in array Encoding.name_list
:
Encoding.name_list.take(3) # => ["ASCII-8BIT", "UTF-8", "US-ASCII"]
When the external encoding is set, strings read are tagged by that encoding when reading, and strings written are converted to that encoding when writing.
When both external and internal encodings are set, strings read are converted from external to internal encoding, and strings written are converted from internal to external encoding. For further details about transcoding input and output, see Encodings.
If the external encoding is 'BOM|UTF-8'
, 'BOM|UTF-16LE'
or 'BOM|UTF16-BE'
, Ruby checks for a Unicode BOM in the input document to help determine the encoding. For UTF-16 encodings the file open mode must be binary. If the BOM is found, it is stripped and the external encoding from the BOM is used.
Note that the BOM-style encoding option is case insensitive, so 'bom|utf-8'
is also valid.
A File object has permissions, an octal integer representing the permissions of an actual file in the underlying platform.
Note that file permissions are quite different from the mode of a file stream (File object).
In a File object, the permissions are available thus, where method mode
, despite its name, returns permissions:
f = File.new('t.txt') f.lstat.mode.to_s(8) # => "100644"
On a Unix-based operating system, the three low-order octal digits represent the permissions for owner (6), group (4), and world (4). The triplet of bits in each octal digit represent, respectively, read, write, and execute permissions.
Permissions 0644
thus represent read-write access for owner and read-only access for group and world. See man pages open(2) and chmod(2).
For a directory, the meaning of the execute bit changes: when set, the directory can be searched.
Higher-order bits in permissions may indicate the type of file (plain, directory, pipe, socket, etc.) and various other special features.
On non-Posix operating systems, permissions may include only read-only or read-write, in which case, the remaining permission will resemble typical values. On Windows, for instance, the default permissions are 0644
; The only change that can be made is to make the file read-only, which is reported as 0444
.
For a method that actually creates a file in the underlying platform (as opposed to merely creating a File object), permissions may be specified:
File.new('t.tmp', File::CREAT, 0644) File.new('t.tmp', File::CREAT, 0444)
Permissions may also be changed:
f = File.new('t.tmp', File::CREAT, 0444) f.chmod(0644) f.chmod(0444)
Various constants for use in File and IO
methods may be found in module File::Constants
; an array of their names is returned by File::Constants.constants
.
First, what’s elsewhere. Class File:
Inherits from class IO, in particular, methods for creating, reading, and writing files
Includes module FileTest
, which provides dozens of additional methods.
Here, class File provides methods that are useful for:
::new
: Opens the file at the given path; returns the file.
::open
: Same as ::new
, but when given a block will yield the file to the block, and close the file upon exiting the block.
::link
: Creates a new name for an existing file using a hard link.
::mkfifo
: Returns the FIFO file created at the given path.
::symlink
: Creates a symbolic link for the given file path.
Paths
::absolute_path
: Returns the absolute file path for the given path.
::absolute_path?
: Returns whether the given path is the absolute file path.
::basename
: Returns the last component of the given file path.
::dirname
: Returns all but the last component of the given file path.
::expand_path
: Returns the absolute file path for the given path, expanding ~
for a home directory.
::extname
: Returns the file extension for the given file path.
::fnmatch?
(aliased as ::fnmatch
): Returns whether the given file path matches the given pattern.
::join
: Joins path components into a single path string.
::path
: Returns the string representation of the given path.
::readlink
: Returns the path to the file at the given symbolic link.
::realdirpath
: Returns the real path for the given file path, where the last component need not exist.
::realpath
: Returns the real path for the given file path, where all components must exist.
::split
: Returns an array of two strings: the directory name and basename of the file at the given path.
path
(aliased as to_path
): Returns the string representation of the given path.
Times
::atime
: Returns a Time
for the most recent access to the given file.
::birthtime
: Returns a Time
for the creation of the given file.
::ctime
: Returns a Time
for the metadata change of the given file.
::mtime
: Returns a Time
for the most recent data modification to the content of the given file.
mtime
: Returns a Time
for the most recent data modification to the content of self
.
Types
::blockdev?
: Returns whether the file at the given path is a block device.
::chardev?
: Returns whether the file at the given path is a character device.
::directory?
: Returns whether the file at the given path is a directory.
::executable?
: Returns whether the file at the given path is executable by the effective user and group of the current process.
::executable_real?
: Returns whether the file at the given path is executable by the real user and group of the current process.
::exist?
: Returns whether the file at the given path exists.
::file?
: Returns whether the file at the given path is a regular file.
::ftype
: Returns a string giving the type of the file at the given path.
::grpowned?
: Returns whether the effective group of the current process owns the file at the given path.
::identical?
: Returns whether the files at two given paths are identical.
::lstat
: Returns the File::Stat
object for the last symbolic link in the given path.
::owned?
: Returns whether the effective user of the current process owns the file at the given path.
::pipe?
: Returns whether the file at the given path is a pipe.
::readable?
: Returns whether the file at the given path is readable by the effective user and group of the current process.
::readable_real?
: Returns whether the file at the given path is readable by the real user and group of the current process.
::setgid?
: Returns whether the setgid bit is set for the file at the given path.
::setuid?
: Returns whether the setuid bit is set for the file at the given path.
::socket?
: Returns whether the file at the given path is a socket.
::stat
: Returns the File::Stat
object for the file at the given path.
::sticky?
: Returns whether the file at the given path has its sticky bit set.
::symlink?
: Returns whether the file at the given path is a symbolic link.
::umask
: Returns the umask value for the current process.
::world_readable?
: Returns whether the file at the given path is readable by others.
::world_writable?
: Returns whether the file at the given path is writable by others.
::writable?
: Returns whether the file at the given path is writable by the effective user and group of the current process.
::writable_real?
: Returns whether the file at the given path is writable by the real user and group of the current process.
lstat
: Returns the File::Stat
object for the last symbolic link in the path for self
.
Contents
::empty?
(aliased as ::zero?
): Returns whether the file at the given path exists and is empty.
::size
: Returns the size (bytes) of the file at the given path.
::size?
: Returns nil
if there is no file at the given path, or if that file is empty; otherwise returns the file size (bytes).
size
: Returns the size (bytes) of self
.
::chmod
: Changes permissions of the file at the given path.
::chown
: Change ownership of the file at the given path.
::lchmod
: Changes permissions of the last symbolic link in the given path.
::lchown
: Change ownership of the last symbolic in the given path.
::lutime
: For each given file path, sets the access time and modification time of the last symbolic link in the path.
::rename
: Moves the file at one given path to another given path.
::utime
: Sets the access time and modification time of each file at the given paths.
flock
: Locks or unlocks self
.
::truncate
: Truncates the file at the given file path to the given size.
::unlink
(aliased as ::delete
): Deletes the file for each given file path.
truncate
: Truncates self
to the given size.
Raised when a method is called on a receiver which doesn’t have it defined and also fails to respond with method_missing
.
"hello".to_ary
raises the exception:
NoMethodError: undefined method `to_ary' for an instance of String
Raised when memory allocation fails.
SystemCallError
is the base class for all low-level platform-dependent errors.
The errors available on the current platform are subclasses of SystemCallError
and are defined in the Errno
module.
File.open("does/not/exist")
raises the exception:
Errno::ENOENT: No such file or directory - does/not/exist
WIN32OLE
objects represent OLE Automation object in Ruby.
By using WIN32OLE
, you can access OLE server like VBScript.
Here is sample script.
require 'win32ole' excel = WIN32OLE.new('Excel.Application') excel.visible = true workbook = excel.Workbooks.Add(); worksheet = workbook.Worksheets(1); worksheet.Range("A1:D1").value = ["North","South","East","West"]; worksheet.Range("A2:B2").value = [5.2, 10]; worksheet.Range("C2").value = 8; worksheet.Range("D2").value = 20; range = worksheet.Range("A1:D2"); range.select chart = workbook.Charts.Add; workbook.saved = true; excel.ActiveWorkbook.Close(0); excel.Quit();
Unfortunately, Win32OLE doesn’t support the argument passed by reference directly. Instead, Win32OLE provides WIN32OLE::ARGV
or WIN32OLE_VARIANT object. If you want to get the result value of argument passed by reference, you can use WIN32OLE::ARGV
or WIN32OLE_VARIANT.
oleobj.method(arg1, arg2, refargv3) puts WIN32OLE::ARGV[2] # the value of refargv3 after called oleobj.method
or
refargv3 = WIN32OLE_VARIANT.new(XXX, WIN32OLE::VARIANT::VT_BYREF|WIN32OLE::VARIANT::VT_XXX) oleobj.method(arg1, arg2, refargv3) p refargv3.value # the value of refargv3 after called oleobj.method.
OLEProperty
helper class of Property with arguments.