Results for: "module_function"

A pointer to a C structure

Raised when OLE processing failed.

EX:

obj = WIN32OLE.new("NonExistProgID")

raises the exception:

WIN32OLE::RuntimeError: unknown OLE server: `NonExistProgID'
    HRESULT error code:0x800401f3
      Invalid class string

Subclass of Zlib::Error

When zlib returns a Z_VERSION_ERROR, usually if the zlib library version is incompatible with the version assumed by the caller.

Overview

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.

Lifecycle

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.

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 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.

Storing session state

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!

Maintaining the session id.

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.

Examples of use

Setting the user’s name

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

Creating a new session safely

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
No documentation available

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

No documentation available
No documentation available

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. 1.0

  2. 1.0.b1

  3. 1.0.a.2

  4. 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'

How Software Changes

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!).

  1. The change may be an implementation detail only and have no effect on the client software.

  2. The change may add new features, but do so in a way that client software written to an earlier version is still compatible.

  3. 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.

Examples of Category 1 changes:

Examples of Category 2 changes might be:

Examples of Category 3 changes might be:

RubyGems Rational Versioning

Examples

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!).

Preventing 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   ... &infin;
"~> 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.

No documentation available

Raised by transcoding methods when a named encoding does not correspond with a known converter.

Mixin module that provides the following:

  1. 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.

  2. Access to cookies, including the cookies attribute.

  3. Access to parameters, including the params attribute, and overloading [] to perform parameter value lookup by key.

  4. 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]

Object is the default root of all Ruby objects. Object inherits from BasicObject which allows creating alternate object hierarchies. Methods on Object are available to all classes unless explicitly overridden.

Object mixes in the Kernel module, making the built-in kernel functions globally accessible. Although the instance methods of Object are defined by the Kernel module, we have chosen to document them here for clarity.

When referencing constants in classes inheriting from Object you do not need to use the full namespace. For example, referencing File inside YourClass will find the top-level File class.

In the descriptions of Object’s methods, the parameter symbol refers to a symbol, which is either a quoted string or a Symbol (such as :name).

What’s Here

First, what’s elsewhere. Class Object:

Here, class Object provides methods for:

Querying

Instance Variables

Other

DateTime

A subclass of Date that easily handles date, hour, minute, second, and offset.

DateTime class is considered deprecated. Use Time class.

DateTime does not consider any leap seconds, does not track any summer time rules.

A DateTime object is created with DateTime::new, DateTime::jd, DateTime::ordinal, DateTime::commercial, DateTime::parse, DateTime::strptime, DateTime::now, Time#to_datetime, etc.

require 'date'

DateTime.new(2001,2,3,4,5,6)
                    #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...>

The last element of day, hour, minute, or second can be a fractional number. The fractional number’s precision is assumed at most nanosecond.

DateTime.new(2001,2,3.5)
                    #=> #<DateTime: 2001-02-03T12:00:00+00:00 ...>

An optional argument, the offset, indicates the difference between the local time and UTC. For example, Rational(3,24) represents ahead of 3 hours of UTC, Rational(-5,24) represents behind of 5 hours of UTC. The offset should be -1 to +1, and its precision is assumed at most second. The default value is zero (equals to UTC).

DateTime.new(2001,2,3,4,5,6,Rational(3,24))
                    #=> #<DateTime: 2001-02-03T04:05:06+03:00 ...>

The offset also accepts string form:

DateTime.new(2001,2,3,4,5,6,'+03:00')
                    #=> #<DateTime: 2001-02-03T04:05:06+03:00 ...>

An optional argument, the day of calendar reform (start), denotes a Julian day number, which should be 2298874 to 2426355 or negative/positive infinity. The default value is Date::ITALY (2299161=1582-10-15).

A DateTime object has various methods. See each reference.

d = DateTime.parse('3rd Feb 2001 04:05:06+03:30')
                    #=> #<DateTime: 2001-02-03T04:05:06+03:30 ...>
d.hour              #=> 4
d.min               #=> 5
d.sec               #=> 6
d.offset            #=> (7/48)
d.zone              #=> "+03:30"
d += Rational('1.5')
                    #=> #<DateTime: 2001-02-04%16:05:06+03:30 ...>
d = d.new_offset('+09:00')
                    #=> #<DateTime: 2001-02-04%21:35:06+09:00 ...>
d.strftime('%I:%M:%S %p')
                    #=> "09:35:06 PM"
d > DateTime.new(1999)
                    #=> true

When should you use DateTime and when should you use Time?

It’s a common misconception that William Shakespeare and Miguel de Cervantes died on the same day in history - so much so that UNESCO named April 23 as World Book Day because of this fact. However, because England hadn’t yet adopted the Gregorian Calendar Reform (and wouldn’t until 1752) their deaths are actually 10 days apart. Since Ruby’s Time class implements a proleptic Gregorian calendar and has no concept of calendar reform there’s no way to express this with Time objects. This is where DateTime steps in:

shakespeare = DateTime.iso8601('1616-04-23', Date::ENGLAND)
 #=> Tue, 23 Apr 1616 00:00:00 +0000
cervantes = DateTime.iso8601('1616-04-23', Date::ITALY)
 #=> Sat, 23 Apr 1616 00:00:00 +0000

Already you can see something is weird - the days of the week are different. Taking this further:

cervantes == shakespeare
 #=> false
(shakespeare - cervantes).to_i
 #=> 10

This shows that in fact they died 10 days apart (in reality 11 days since Cervantes died a day earlier but was buried on the 23rd). We can see the actual date of Shakespeare’s death by using the gregorian method to convert it:

shakespeare.gregorian
 #=> Tue, 03 May 1616 00:00:00 +0000

So there’s an argument that all the celebrations that take place on the 23rd April in Stratford-upon-Avon are actually the wrong date since England is now using the Gregorian calendar. You can see why when we transition across the reform date boundary:

# start off with the anniversary of Shakespeare's birth in 1751
shakespeare = DateTime.iso8601('1751-04-23', Date::ENGLAND)
 #=> Tue, 23 Apr 1751 00:00:00 +0000

# add 366 days since 1752 is a leap year and April 23 is after February 29
shakespeare + 366
 #=> Thu, 23 Apr 1752 00:00:00 +0000

# add another 365 days to take us to the anniversary in 1753
shakespeare + 366 + 365
 #=> Fri, 04 May 1753 00:00:00 +0000

As you can see, if we’re accurately tracking the number of solar years since Shakespeare’s birthday then the correct anniversary date would be the 4th May and not the 23rd April.

So when should you use DateTime in Ruby and when should you use Time? Almost certainly you’ll want to use Time since your app is probably dealing with current dates and times. However, if you need to deal with dates and times in a historical context you’ll want to use DateTime to avoid making the same mistakes as UNESCO. If you also have to deal with timezones then best of luck - just bear in mind that you’ll probably be dealing with local solar times, since it wasn’t until the 19th century that the introduction of the railways necessitated the need for Standard Time and eventually timezones.

A Time object represents a date and time:

Time.new(2000, 1, 1, 0, 0, 0) # => 2000-01-01 00:00:00 -0600

Although its value can be expressed as a single numeric (see Epoch Seconds below), it can be convenient to deal with the value by parts:

t = Time.new(-2000, 1, 1, 0, 0, 0.0)
# => -2000-01-01 00:00:00 -0600
t.year # => -2000
t.month # => 1
t.mday # => 1
t.hour # => 0
t.min # => 0
t.sec # => 0
t.subsec # => 0

t = Time.new(2000, 12, 31, 23, 59, 59.5)
# => 2000-12-31 23:59:59.5 -0600
t.year # => 2000
t.month # => 12
t.mday # => 31
t.hour # => 23
t.min # => 59
t.sec # => 59
t.subsec # => (1/2)

Epoch Seconds

Epoch seconds is the exact number of seconds (including fractional subseconds) since the Unix Epoch, January 1, 1970.

You can retrieve that value exactly using method Time.to_r:

Time.at(0).to_r        # => (0/1)
Time.at(0.999999).to_r # => (9007190247541737/9007199254740992)

Other retrieval methods such as Time#to_i and Time#to_f may return a value that rounds or truncates subseconds.

Time Resolution

A Time object derived from the system clock (for example, by method Time.now) has the resolution supported by the system.

Time Internal Representation

Time implementation uses a signed 63 bit integer, Integer(T_BIGNUM), or Rational. It is a number of nanoseconds since the Epoch. The signed 63 bit integer can represent 1823-11-12 to 2116-02-20. When Integer or Rational is used (before 1823, after 2116, under nanosecond), Time works slower than when the signed 63 bit integer is used.

Ruby uses the C function “localtime” and “gmtime” to map between the number and 6-tuple (year,month,day,hour,minute,second). “localtime” is used for local time and “gmtime” is used for UTC.

Integer(T_BIGNUM) and Rational has no range limit, but the localtime and gmtime has range limits due to the C types “time_t” and “struct tm”. If that limit is exceeded, Ruby extrapolates the localtime function.

The Time class always uses the Gregorian calendar. I.e. the proleptic Gregorian calendar is used. Other calendars, such as Julian calendar, are not supported.

“time_t” can represent 1901-12-14 to 2038-01-19 if it is 32 bit signed integer, -292277022657-01-27 to 292277026596-12-05 if it is 64 bit signed integer. However “localtime” on some platforms doesn’t supports negative time_t (before 1970).

“struct tm” has tm_year member to represent years. (tm_year = 0 means the year 1900.) It is defined as int in the C standard. tm_year can represent between -2147481748 to 2147485547 if int is 32 bit.

Ruby supports leap seconds as far as if the C function “localtime” and “gmtime” supports it. They use the tz database in most Unix systems. The tz database has timezones which supports leap seconds. For example, “Asia/Tokyo” doesn’t support leap seconds but “right/Asia/Tokyo” supports leap seconds. So, Ruby supports leap seconds if the TZ environment variable is set to “right/Asia/Tokyo” in most Unix systems.

Examples

All of these examples were done using the EST timezone which is GMT-5.

Creating a New Time Instance

You can create a new instance of Time with Time.new. This will use the current system time. Time.now is an alias for this. You can also pass parts of the time to Time.new such as year, month, minute, etc. When you want to construct a time this way you must pass at least a year. If you pass the year with nothing else time will default to January 1 of that year at 00:00:00 with the current system timezone. Here are some examples:

Time.new(2002)         #=> 2002-01-01 00:00:00 -0500
Time.new(2002, 10)     #=> 2002-10-01 00:00:00 -0500
Time.new(2002, 10, 31) #=> 2002-10-31 00:00:00 -0500

You can pass a UTC offset:

Time.new(2002, 10, 31, 2, 2, 2, "+02:00") #=> 2002-10-31 02:02:02 +0200

Or a timezone object:

zone = timezone("Europe/Athens")      # Eastern European Time, UTC+2
Time.new(2002, 10, 31, 2, 2, 2, zone) #=> 2002-10-31 02:02:02 +0200

You can also use Time.local and Time.utc to infer local and UTC timezones instead of using the current system setting.

You can also create a new time using Time.at which takes the number of seconds (with subsecond) since the Unix Epoch.

Time.at(628232400) #=> 1989-11-28 00:00:00 -0500

Working with an Instance of Time

Once you have an instance of Time there is a multitude of things you can do with it. Below are some examples. For all of the following examples, we will work on the assumption that you have done the following:

t = Time.new(1993, 02, 24, 12, 0, 0, "+09:00")

Was that a monday?

t.monday? #=> false

What year was that again?

t.year #=> 1993

Was it daylight savings at the time?

t.dst? #=> false

What’s the day a year later?

t + (60*60*24*365) #=> 1994-02-24 12:00:00 +0900

How many seconds was that since the Unix Epoch?

t.to_i #=> 730522800

You can also do standard functions like compare two times.

t1 = Time.new(2010)
t2 = Time.new(2011)

t1 == t2 #=> false
t1 == t1 #=> true
t1 <  t2 #=> true
t1 >  t2 #=> false

Time.new(2010,10,31).between?(t1, t2) #=> true

What’s Here

First, what’s elsewhere. Class Time:

Here, class Time provides methods that are useful for:

Methods for Creating

Methods for Fetching

Methods for Querying

Methods for Comparing

Methods for Converting

Methods for Rounding

For the forms of argument zone, see Timezone Specifiers.

Timezone Specifiers

Certain Time methods accept arguments that specify timezones:

The value given with any of these must be one of the following (each detailed below):

Hours/Minutes Offsets

The zone value may be a string offset from UTC in the form '+HH:MM' or '-HH:MM', where:

Examples:

t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
Time.at(t, in: '-23:59')            # => 1999-12-31 20:16:01 -2359
Time.at(t, in: '+23:59')            # => 2000-01-02 20:14:01 +2359

Single-Letter Offsets

The zone value may be a letter in the range 'A'..'I' or 'K'..'Z'; see List of military time zones:

t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
Time.at(t, in: 'A')                 # => 2000-01-01 21:15:01 +0100
Time.at(t, in: 'I')                 # => 2000-01-02 05:15:01 +0900
Time.at(t, in: 'K')                 # => 2000-01-02 06:15:01 +1000
Time.at(t, in: 'Y')                 # => 2000-01-01 08:15:01 -1200
Time.at(t, in: 'Z')                 # => 2000-01-01 20:15:01 UTC

Integer Offsets

The zone value may be an integer number of seconds in the range -86399..86399:

t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
Time.at(t, in: -86399)              # => 1999-12-31 20:15:02 -235959
Time.at(t, in: 86399)               # => 2000-01-02 20:15:00 +235959

Timezone Objects

The zone value may be an object responding to certain timezone methods, an instance of Timezone and TZInfo for example.

The timezone methods are:

A custom timezone class may have these instance methods, which will be called if defined:

Time-Like Objects

A Time-like object is a container object capable of interfacing with timezone libraries for timezone conversion.

The argument to the timezone conversion methods above will have attributes similar to Time, except that timezone related attributes are meaningless.

The objects returned by local_to_utc and utc_to_local methods of the timezone object may be of the same class as their arguments, of arbitrary object classes, or of class Integer.

For a returned class other than Integer, the class must have the following methods:

For a returned Integer, its components, decomposed in UTC, are interpreted as times in the specified timezone.

Timezone Names

If the class (the receiver of class methods, or the class of the receiver of instance methods) has find_timezone singleton method, this method is called to achieve the corresponding timezone object from a timezone name.

For example, using Timezone:

class TimeWithTimezone < Time
  require 'timezone'
  def self.find_timezone(z) = Timezone[z]
end

TimeWithTimezone.now(in: "America/New_York")        #=> 2023-12-25 00:00:00 -0500
TimeWithTimezone.new("2023-12-25 America/New_York") #=> 2023-12-25 00:00:00 -0500

Or, using TZInfo:

class TimeWithTZInfo < Time
  require 'tzinfo'
  def self.find_timezone(z) = TZInfo::Timezone.get(z)
end

TimeWithTZInfo.now(in: "America/New_York")          #=> 2023-12-25 00:00:00 -0500
TimeWithTZInfo.new("2023-12-25 America/New_York")   #=> 2023-12-25 00:00:00 -0500

You can define this method per subclasses, or on the toplevel Time class.

IO

An instance of class IO (commonly called a stream) represents an input/output stream in the underlying operating system. Class IO is the basis for input and output in Ruby.

Class File is the only class in the Ruby core that is a subclass of IO. Some classes in the Ruby standard library are also subclasses of IO; these include TCPSocket and UDPSocket.

The global constant ARGF (also accessible as $<) provides an IO-like stream that allows access to all file paths found in ARGV (or found in STDIN if ARGV is empty). ARGF is not itself a subclass of IO.

Class StringIO provides an IO-like stream that handles a String. StringIO is not itself a subclass of IO.

Important objects based on IO include:

An instance of IO may be created using:

Like a File stream, an IO stream has:

And like other IO streams, it has:

Extension io/console

Extension io/console provides numerous methods for interacting with the console; requiring it adds numerous methods to class IO.

Example Files

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

Open Options

A number of IO methods accept optional keyword arguments that determine how a new stream is to be opened:

Also available are the options offered in String#encode, which may control conversion between external and internal encoding.

Basic IO

You can perform basic stream IO with these methods, which typically operate on multi-byte strings:

Position

An IO stream has a nonnegative integer position, which is the byte offset at which the next read or write is to occur. A new stream has position zero (and line number zero); method rewind resets the position (and line number) to zero.

The relevant methods:

Open and Closed Streams

A new IO stream may be open for reading, open for writing, or both.

A stream is automatically closed when claimed by the garbage collector.

Attempted reading or writing on a closed stream raises an exception.

The relevant methods:

End-of-Stream

You can query whether a stream is positioned at its end:

You can reposition to end-of-stream by using method IO#seek:

f = File.new('t.txt')
f.eof? # => false
f.seek(0, :END)
f.eof? # => true
f.close

Or by reading all stream content (which is slower than using IO#seek):

f.rewind
f.eof? # => false
f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
f.eof? # => true

Line IO

Class IO supports line-oriented input and output

Line Input

Class IO supports line-oriented input for files and IO streams

File Line Input

You can read lines from a file using these methods:

For each of these methods:

Stream Line Input

You can read lines from an IO stream using these methods:

For each of these methods:

Line Separator

Each of the line input methods uses a line separator: the string that determines what is considered a line; it is sometimes called the input record separator.

The default line separator is taken from global variable $/, whose initial value is "\n".

Generally, the line to be read next is all data from the current position to the next line separator (but see Special Line Separator Values):

f = File.new('t.txt')
# Method gets with no sep argument returns the next line, according to $/.
f.gets # => "First line\n"
f.gets # => "Second line\n"
f.gets # => "\n"
f.gets # => "Fourth line\n"
f.gets # => "Fifth line\n"
f.close

You can use a different line separator by passing argument sep:

f = File.new('t.txt')
f.gets('l')   # => "First l"
f.gets('li')  # => "ine\nSecond li"
f.gets('lin') # => "ne\n\nFourth lin"
f.gets        # => "e\n"
f.close

Or by setting global variable $/:

f = File.new('t.txt')
$/ = 'l'
f.gets # => "First l"
f.gets # => "ine\nSecond l"
f.gets # => "ine\n\nFourth l"
f.close
Special Line Separator Values

Each of the line input methods accepts two special values for parameter sep:

Line Limit

Each of the line input methods uses an integer line limit, which restricts the number of bytes that may be returned. (A multi-byte character will not be split, and so a returned line may be slightly longer than the limit).

The default limit value is -1; any negative limit value means that there is no limit.

If there is no limit, the line is determined only by sep.

# Text with 1-byte characters.
File.open('t.txt') {|f| f.gets(1) }  # => "F"
File.open('t.txt') {|f| f.gets(2) }  # => "Fi"
File.open('t.txt') {|f| f.gets(3) }  # => "Fir"
File.open('t.txt') {|f| f.gets(4) }  # => "Firs"
# No more than one line.
File.open('t.txt') {|f| f.gets(10) } # => "First line"
File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
File.open('t.txt') {|f| f.gets(12) } # => "First line\n"

# Text with 2-byte characters, which will not be split.
File.open('t.rus') {|f| f.gets(1).size } # => 1
File.open('t.rus') {|f| f.gets(2).size } # => 1
File.open('t.rus') {|f| f.gets(3).size } # => 2
File.open('t.rus') {|f| f.gets(4).size } # => 2
Line Separator and Line Limit

With arguments sep and limit given, combines the two behaviors:

Example:

File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
File.open('t.txt') {|f| f.gets('li', 2) }  # => "Fi"
Line Number

A readable IO stream has a non-negative integer line number:

Unless modified by a call to method IO#lineno=, the line number is the number of lines read by certain line-oriented methods, according to the effective line separator:

A new stream is initially has line number zero (and position zero); method rewind resets the line number (and position) to zero:

f = File.new('t.txt')
f.lineno # => 0
f.gets   # => "First line\n"
f.lineno # => 1
f.rewind
f.lineno # => 0
f.close

Reading lines from a stream usually changes its line number:

f = File.new('t.txt', 'r')
f.lineno   # => 0
f.readline # => "This is line one.\n"
f.lineno   # => 1
f.readline # => "This is the second line.\n"
f.lineno   # => 2
f.readline # => "Here's the third line.\n"
f.lineno   # => 3
f.eof?     # => true
f.close

Iterating over lines in a stream usually changes its line number:

File.open('t.txt') do |f|
  f.each_line do |line|
    p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
  end
end

Output:

"position=11 eof?=false lineno=1"
"position=23 eof?=false lineno=2"
"position=24 eof?=false lineno=3"
"position=36 eof?=false lineno=4"
"position=47 eof?=true lineno=5"

Unlike the stream’s position, the line number does not affect where the next read or write will occur:

f = File.new('t.txt')
f.lineno = 1000
f.lineno # => 1000
f.gets   # => "First line\n"
f.lineno # => 1001
f.close

Associated with the line number is the global variable $.:

Line Output

You can write to an IO stream line-by-line using this method:

Character IO

You can process an IO stream character-by-character using these methods:

Byte IO

You can process an IO stream byte-by-byte using these methods:

Codepoint IO

You can process an IO stream codepoint-by-codepoint:

What’s Here

First, what’s elsewhere. Class IO:

Here, class IO provides methods that are useful for:

Creating

Reading

Writing

Positioning

Iterating

Settings

Querying

Buffering

Low-Level Access

Other

An OpenStruct is a data structure, similar to a Hash, that allows the definition of arbitrary attributes with their accompanying values. This is accomplished by using Ruby’s metaprogramming to define methods on the class itself.

Examples

require "ostruct"

person = OpenStruct.new
person.name = "John Smith"
person.age  = 70

person.name      # => "John Smith"
person.age       # => 70
person.address   # => nil

An OpenStruct employs a Hash internally to store the attributes and values and can even be initialized with one:

australia = OpenStruct.new(:country => "Australia", :capital => "Canberra")
  # => #<OpenStruct country="Australia", capital="Canberra">

Hash keys with spaces or characters that could normally not be used for method calls (e.g. ()[]*) will not be immediately available on the OpenStruct object as a method for retrieval or assignment, but can still be reached through the Object#send method or using [].

measurements = OpenStruct.new("length (in inches)" => 24)
measurements[:"length (in inches)"]       # => 24
measurements.send("length (in inches)")   # => 24

message = OpenStruct.new(:queued? => true)
message.queued?                           # => true
message.send("queued?=", false)
message.queued?                           # => false

Removing the presence of an attribute requires the execution of the delete_field method as setting the property value to nil will not remove the attribute.

first_pet  = OpenStruct.new(:name => "Rowdy", :owner => "John Smith")
second_pet = OpenStruct.new(:name => "Rowdy")

first_pet.owner = nil
first_pet                 # => #<OpenStruct name="Rowdy", owner=nil>
first_pet == second_pet   # => false

first_pet.delete_field(:owner)
first_pet                 # => #<OpenStruct name="Rowdy">
first_pet == second_pet   # => true

Ractor compatibility: A frozen OpenStruct with shareable values is itself shareable.

Caveats

An OpenStruct utilizes Ruby’s method lookup structure to find and define the necessary methods for properties. This is accomplished through the methods method_missing and define_singleton_method.

This should be a consideration if there is a concern about the performance of the objects that are created, as there is much more overhead in the setting of these properties compared to using a Hash or a Struct. Creating an open struct from a small Hash and accessing a few of the entries can be 200 times slower than accessing the hash directly.

This is a potential security issue; building OpenStruct from untrusted user data (e.g. JSON web request) may be susceptible to a “symbol denial of service” attack since the keys create methods and names of methods are never garbage collected.

This may also be the source of incompatibilities between Ruby versions:

o = OpenStruct.new
o.then # => nil in Ruby < 2.6, enumerator for Ruby >= 2.6

Builtin methods may be overwritten this way, which may be a source of bugs or security issues:

o = OpenStruct.new
o.methods # => [:to_h, :marshal_load, :marshal_dump, :each_pair, ...
o.methods = [:foo, :bar]
o.methods # => [:foo, :bar]

To help remedy clashes, OpenStruct uses only protected/private methods ending with ! and defines aliases for builtin public methods by adding a !:

o = OpenStruct.new(make: 'Bentley', class: :luxury)
o.class # => :luxury
o.class! # => OpenStruct

It is recommended (but not enforced) to not use fields ending in !; Note that a subclass’ methods may not be overwritten, nor can OpenStruct’s own methods ending with !.

For all these reasons, consider not using OpenStruct at all.

Search took: 18ms  ·  Total Results: 3609