Helper methods for both Gem::Installer
and Gem::Uninstaller
This module contains various utility methods as module methods.
An Array is an ordered, integer-indexed collection of objects, called elements. Any object may be an Array element.
Array indexing starts at 0, as in C or Java.
A positive index is an offset from the first element:
Index 0 indicates the first element.
Index 1 indicates the second element.
…
A negative index is an offset, backwards, from the end of the array:
Index -1 indicates the last element.
Index -2 indicates the next-to-last element.
…
A non-negative index is in range if it is smaller than the size of the array. For a 3-element array:
Indexes 0 through 2 are in range.
Index 3 is out of range.
A negative index is in range if its absolute value is not larger than the size of the array. For a 3-element array:
Indexes -1 through -3 are in range.
Index -4 is out of range.
You can create an Array object explicitly with:
An array literal.
You can convert certain objects to Arrays with:
Method Array.
An Array can contain different types of objects. For example, the array below contains an Integer
, a String
and a Float:
ary = [1, "two", 3.0] #=> [1, "two", 3.0]
An array can also be created by calling Array.new
with zero, one (the initial size of the Array
) or two arguments (the initial size and a default object).
ary = Array.new #=> [] Array.new(3) #=> [nil, nil, nil] Array.new(3, true) #=> [true, true, true]
Note that the second argument populates the array with references to the same object. Therefore, it is only recommended in cases when you need to instantiate arrays with natively immutable objects such as Symbols, numbers, true or false.
To create an array with separate objects a block can be passed instead. This method is safe to use with mutable objects such as hashes, strings or other arrays:
Array.new(4) {Hash.new} #=> [{}, {}, {}, {}] Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"]
This is also a quick way to build up multi-dimensional arrays:
empty_table = Array.new(3) {Array.new(3)} #=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
An array can also be created by using the Array() method, provided by Kernel
, which tries to call to_ary
, then to_a
on its argument.
Array({:a => "a", :b => "b"}) #=> [[:a, "a"], [:b, "b"]]
In addition to the methods it mixes in through the Enumerable
module, the Array
class has proprietary methods for accessing, searching and otherwise manipulating arrays.
Some of the more common ones are illustrated below.
Elements in an array can be retrieved using the Array#[]
method. It can take a single integer argument (a numeric index), a pair of arguments (start and length) or a range. Negative indices start counting from the end, with -1 being the last element.
arr = [1, 2, 3, 4, 5, 6] arr[2] #=> 3 arr[100] #=> nil arr[-3] #=> 4 arr[2, 3] #=> [3, 4, 5] arr[1..4] #=> [2, 3, 4, 5] arr[1..-3] #=> [2, 3, 4]
Another way to access a particular array element is by using the at
method
arr.at(0) #=> 1
The slice
method works in an identical manner to Array#[]
.
To raise an error for indices outside of the array bounds or else to provide a default value when that happens, you can use fetch
.
arr = ['a', 'b', 'c', 'd', 'e', 'f'] arr.fetch(100) #=> IndexError: index 100 outside of array bounds: -6...6 arr.fetch(100, "oops") #=> "oops"
The special methods first
and last
will return the first and last elements of an array, respectively.
arr.first #=> 1 arr.last #=> 6
To return the first n
elements of an array, use take
arr.take(3) #=> [1, 2, 3]
drop
does the opposite of take
, by returning the elements after n
elements have been dropped:
arr.drop(3) #=> [4, 5, 6]
Array
Arrays keep track of their own length at all times. To query an array about the number of elements it contains, use length
, count
or size
.
browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE'] browsers.length #=> 5 browsers.count #=> 5
To check whether an array contains any elements at all
browsers.empty? #=> false
To check whether a particular item is included in the array
browsers.include?('Konqueror') #=> false
Items can be added to the end of an array by using either push
or <<
arr = [1, 2, 3, 4] arr.push(5) #=> [1, 2, 3, 4, 5] arr << 6 #=> [1, 2, 3, 4, 5, 6]
unshift
will add a new item to the beginning of an array.
arr.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6]
With insert
you can add a new element to an array at any position.
arr.insert(3, 'apple') #=> [0, 1, 2, 'apple', 3, 4, 5, 6]
Using the insert
method, you can also insert multiple values at once:
arr.insert(3, 'orange', 'pear', 'grapefruit') #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6]
Array
The method pop
removes the last element in an array and returns it:
arr = [1, 2, 3, 4, 5, 6] arr.pop #=> 6 arr #=> [1, 2, 3, 4, 5]
To retrieve and at the same time remove the first item, use shift
:
arr.shift #=> 1 arr #=> [2, 3, 4, 5]
To delete an element at a particular index:
arr.delete_at(2) #=> 4 arr #=> [2, 3, 5]
To delete a particular element anywhere in an array, use delete
:
arr = [1, 2, 2, 3] arr.delete(2) #=> 2 arr #=> [1,3]
A useful method if you need to remove nil
values from an array is compact
:
arr = ['foo', 0, nil, 'bar', 7, 'baz', nil] arr.compact #=> ['foo', 0, 'bar', 7, 'baz'] arr #=> ['foo', 0, nil, 'bar', 7, 'baz', nil] arr.compact! #=> ['foo', 0, 'bar', 7, 'baz'] arr #=> ['foo', 0, 'bar', 7, 'baz']
Another common need is to remove duplicate elements from an array.
It has the non-destructive uniq
, and destructive method uniq!
arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556] arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123]
Like all classes that include the Enumerable
module, Array
has an each method, which defines what elements should be iterated over and how. In case of Array’s each
, all elements in the Array
instance are yielded to the supplied block in sequence.
Note that this operation leaves the array unchanged.
arr = [1, 2, 3, 4, 5] arr.each {|a| print a -= 10, " "} # prints: -9 -8 -7 -6 -5 #=> [1, 2, 3, 4, 5]
Another sometimes useful iterator is reverse_each
which will iterate over the elements in the array in reverse order.
words = %w[first second third fourth fifth sixth] str = "" words.reverse_each {|word| str += "#{word} "} p str #=> "sixth fifth fourth third second first "
The map
method can be used to create a new array based on the original array, but with the values modified by the supplied block:
arr.map {|a| 2*a} #=> [2, 4, 6, 8, 10] arr #=> [1, 2, 3, 4, 5] arr.map! {|a| a**2} #=> [1, 4, 9, 16, 25] arr #=> [1, 4, 9, 16, 25]
Array
Elements can be selected from an array according to criteria defined in a block. The selection can happen in a destructive or a non-destructive manner. While the destructive operations will modify the array they were called on, the non-destructive methods usually return a new array with the selected elements, but leave the original array unchanged.
arr = [1, 2, 3, 4, 5, 6] arr.select {|a| a > 3} #=> [4, 5, 6] arr.reject {|a| a < 3} #=> [3, 4, 5, 6] arr.drop_while {|a| a < 4} #=> [4, 5, 6] arr #=> [1, 2, 3, 4, 5, 6]
select!
and reject!
are the corresponding destructive methods to select
and reject
Similar to select
vs. reject
, delete_if
and keep_if
have the exact opposite result when supplied with the same block:
arr.delete_if {|a| a < 4} #=> [4, 5, 6] arr #=> [4, 5, 6] arr = [1, 2, 3, 4, 5, 6] arr.keep_if {|a| a < 4} #=> [1, 2, 3] arr #=> [1, 2, 3]
First, what’s elsewhere. Class Array:
Inherits from class Object.
Includes module Enumerable, which provides dozens of additional methods.
Here, class Array provides methods that are useful for:
Array
::[]
Returns a new array populated with given objects.
::new
Returns a new array.
::try_convert
Returns a new array created from a given object.
length
, size
Returns the count of elements.
include?
Returns whether any element ==
a given object.
empty?
Returns whether there are no elements.
all?
Returns whether all elements meet a given criterion.
any?
Returns whether any element meets a given criterion.
none?
Returns whether no element ==
a given object.
one?
Returns whether exactly one element ==
a given object.
count
Returns the count of elements that meet a given criterion.
find_index
, index
Returns the index of the first element that meets a given criterion.
rindex
Returns the index of the last element that meets a given criterion.
hash
Returns the integer hash code.
Returns -1, 0, or 1 as self
is less than, equal to, or greater than a given object.
Returns whether each element in self
is ==
to the corresponding element in a given object.
eql?
Returns whether each element in self
is eql?
to the corresponding element in a given object.
These methods do not modify self
.
[]
Returns one or more elements.
fetch
Returns the element at a given offset.
first
Returns one or more leading elements.
last
Returns one or more trailing elements.
max
Returns one or more maximum-valued elements, as determined by <=>
or a given block.
max
Returns one or more minimum-valued elements, as determined by <=>
or a given block.
minmax
Returns the minimum-valued and maximum-valued elements, as determined by <=>
or a given block.
assoc
Returns the first element that is an array whose first element ==
a given object.
rassoc
Returns the first element that is an array whose second element ==
a given object.
at
Returns the element at a given offset.
values_at
Returns the elements at given offsets.
dig
Returns the object in nested objects that is specified by a given index and additional arguments.
drop
Returns trailing elements as determined by a given index.
take
Returns leading elements as determined by a given index.
drop_while
Returns trailing elements as determined by a given block.
take_while
Returns leading elements as determined by a given block.
slice
Returns consecutive elements as determined by a given argument.
sort
Returns all elements in an order determined by <=>
or a given block.
reverse
Returns all elements in reverse order.
compact
Returns an array containing all non-nil
elements.
select
, filter
Returns an array containing elements selected by a given block.
uniq
Returns an array containing non-duplicate elements.
rotate
Returns all elements with some rotated from one end to the other.
bsearch
Returns an element selected via a binary search as determined by a given block.
bsearch_index
Returns the index of an element selected via a binary search as determined by a given block.
sample
Returns one or more random elements.
shuffle
Returns elements in a random order.
These methods add, replace, or reorder elements in self
.
[]=
Assigns specified elements with a given object.
push
, append
, <<
Appends trailing elements.
unshift
, prepend
Prepends leading elements.
insert
Inserts given objects at a given offset; does not replace elements.
concat
Appends all elements from given arrays.
fill
Replaces specified elements with specified objects.
replace
Replaces the content of self
with the content of a given array.
reverse!
Replaces self
with its elements reversed.
rotate!
Replaces self
with its elements rotated.
shuffle!
Replaces self
with its elements in random order.
sort!
Replaces self
with its elements sorted, as determined by <=>
or a given block.
sort_by!
Replaces self
with its elements sorted, as determined by a given block.
Each of these methods removes elements from self
:
pop
Removes and returns the last element.
shift
Removes and returns the first element.
compact!
Removes all non-nil
elements.
delete
Removes elements equal to a given object.
delete_at
Removes the element at a given offset.
delete_if
Removes elements specified by a given block.
keep_if
Removes elements not specified by a given block.
reject!
Removes elements specified by a given block.
select!
, filter!
Removes elements not specified by a given block.
slice!
Removes and returns a sequence of elements.
uniq!
Removes duplicates.
Returns an array containing elements found both in self
and a given array.
intersection
Returns an array containing elements found both in self
and in each given array.
+
Returns an array containing all elements of self
followed by all elements of a given array.
-
Returns an array containiing all elements of self
that are not found in a given array.
Returns an array containing all elements of self
and all elements of a given array, duplicates removed.
union
Returns an array containing all elements of self
and all elements of given arrays, duplicates removed.
difference
Returns an array containing all elements of self
that are not found in any of the given arrays..
product
Returns or yields all combinations of elements from self
and given arrays.
each
Passes each element to a given block.
reverse_each
Passes each element, in reverse order, to a given block.
each_index
Passes each element index to a given block.
cycle
Calls a given block with each element, then does so again, for a specified number of times, or forever.
combination
Calls a given block with combinations of elements of self
; a combination does not use the same element more than once.
permutation
Calls a given block with permutations of elements of self
; a permutation does not use the same element more than once.
repeated_combination
Calls a given block with combinations of elements of self
; a combination may use the same element more than once.
repeated_permutation
Calls a given block with permutations of elements of self
; a permutation may use the same element more than once.
map
, collect
Returns an array containing the block return-value for each element.
map!
, collect!
Replaces each element with a block return-value.
flatten
Returns an array that is a recursive flattening of self
.
flatten!
Replaces each nested array in self
with the elements from that array.
inspect
, to_s
Returns a new String
containing the elements.
join
Returns a newsString containing the elements joined by the field separator.
to_a
Returns self
or a new array containing all elements.
to_ary
Returns self
.
to_h
Returns a new hash formed from the elements.
transpose
Transposes self
, which must be an array of arrays.
zip
Returns a new array of arrays containing self
and given arrays; follow the link for details.
*
Returns one of the following:
With integer argument n
, a new array that is the concatenation of n
copies of self
.
With string argument field_separator
, a new string that is equivalent to join(field_separator)
.
abbrev
Returns a hash of unambiguous abbreviations for elements.
pack
Packs the elements into a binary sequence.
sum
Returns a sum of elements according to either +
or a given block.
for pack.c
Raised by exit
to initiate the termination of the script.
The most standard error types are subclasses of StandardError
. A rescue clause without an explicit Exception
class will rescue all StandardErrors (and only those).
def foo raise "Oups" end foo rescue "Hello" #=> "Hello"
On the other hand:
require 'does/not/exist' rescue "Hi"
raises the exception:
LoadError: no such file to load -- does/not/exist
Raised when the arguments are wrong and there isn’t a more specific Exception
class.
Ex: passing the wrong number of arguments
[1, 2, 3].first(4, 5)
raises the exception:
ArgumentError: wrong number of arguments (given 2, expected 1)
Ex: passing an argument that is not acceptable:
[1, 2, 3].first(-4)
raises the exception:
ArgumentError: negative array size
No longer used by internal code.
Expect library adds the IO
instance method expect
, which does similar act to tcl’s expect extension.
In order to use this method, you must require expect:
require 'expect'
Please see expect
for usage.
The IO
class is the basis for all input and output in Ruby. An I/O stream may be duplexed (that is, bidirectional), and so may use more than one native operating system stream.
Many of the examples in this section use the File
class, the only standard subclass of IO
. The two classes are closely associated. Like the File
class, the Socket
library subclasses from IO
(such as TCPSocket
or UDPSocket
).
The Kernel#open
method can create an IO
(or File
) object for these types of arguments:
A plain string represents a filename suitable for the underlying operating system.
A string starting with "|"
indicates a subprocess. The remainder of the string following the "|"
is invoked as a process with appropriate input/output channels connected to it.
A string equal to "|-"
will create another Ruby instance as a subprocess.
The IO
may be opened with different file modes (read-only, write-only) and encodings for proper conversion. See IO.new
for these options. See Kernel#open
for details of the various command formats described above.
IO.popen
, the Open3
library, or Process#spawn may also be used to communicate with subprocesses through an IO
.
Ruby will convert pathnames between different operating system conventions if possible. For instance, on a Windows system the filename "/gumby/ruby/test.rb"
will be opened as "\gumby\ruby\test.rb"
. When specifying a Windows-style filename in a Ruby string, remember to escape the backslashes:
"C:\\gumby\\ruby\\test.rb"
Our examples here will use the Unix-style forward slashes; File::ALT_SEPARATOR can be used to get the platform-specific separator character.
The global constant ARGF
(also accessible as $<
) provides an IO-like stream which allows access to all files mentioned on the command line (or STDIN if no files are mentioned). ARGF#path
and its alias ARGF#filename
are provided to access the name of the file currently being read.
The io/console extension provides methods for interacting with the console. The console can be accessed from IO.console
or the standard input/output/error IO
objects.
Requiring io/console adds the following methods:
Example:
require 'io/console' rows, columns = $stdout.winsize puts "Your screen is #{columns} wide and #{rows} tall"
Many examples here use these filenames and their corresponding files:
t.txt
: A text-only file that is assumed to exist via:
text = <<~EOT This is line one. This is the second line. This is the third line. EOT File.write('t.txt', text)
t.dat
: A data file that is assumed to exist via:
data = "\u9990\u9991\u9992\u9993\u9994" f = File.open('t.dat', 'wb:UTF-16') f.write(data) f.close
t.rus
: A Russian-language text file that is assumed to exist via:
File.write('t.rus', "\u{442 435 441 442}")
t.tmp
: A file that is assumed not to exist.
A number of IO method calls must or may specify a mode for the stream; the mode determines how stream is to be accessible, including:
Whether the stream is to be read-only, write-only, or read-write.
Whether the stream is positioned at its beginning or its end.
Whether the stream treats data as text-only or binary.
The external and internal encodings.
When mode
is an integer it must be one or more (combined by bitwise OR (|
) of the modes defined in File::Constants
:
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.
File::CREAT
: Create file if it does not exist.
File::EXCL
: Raise an exception if File::CREAT
is given and the file exists.
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.
When mode
is a string it must begin with one of the following:
'r'
: Read-only stream, positioned at the beginning; the stream cannot be changed to writable.
'w'
: Write-only stream, positioned at the beginning; the stream cannot be changed to readable.
'a'
: Write-only stream, positioned at the end; every write appends to the end; the stream cannot be changed to readable.
'r+'
: Read-write stream, positioned at the beginning.
'w+'
: Read-write stream, positioned at the end.
'a+'
: Read-write stream, positioned at the end.
For a writable file stream (that is, any except read-only), the file is truncated to zero if it exists, and is created if it does not exist.
Examples:
File.open('t.txt', 'r') File.open('t.tmp', 'w')
Either of the following may be suffixed to any of the above:
't'
: Text data; sets the default external encoding to Encoding::UTF_8
; on Windows, enables conversion between EOL and CRLF.
'b'
: Binary data; sets the default external encoding to Encoding::ASCII_8BIT
; on Windows, suppresses conversion between EOL and CRLF.
If neither is given, the stream defaults to text data.
Examples:
File.open('t.txt', 'rt') File.open('t.dat', 'rb')
The following may be suffixed to any writable mode above:
'x'
: Creates the file if it does not exist; raises an exception if the file exists.
Example:
File.open('t.tmp', 'wx')
Finally, the mode string 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>
The numerous encoding names are available in array Encoding.name_list
:
Encoding.name_list.size # => 175 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 Encoding
.
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 number of IO methods accept an optional parameter opts
, which determines how a new stream is to be opened:
:mode
: Stream mode.
:flags
: Integer file open flags; If mode
is also given, the two are bitwise-ORed.
:external_encoding
: External encoding for the stream.
:internal_encoding
: Internal encoding for the stream. '-'
is a synonym for the default internal encoding. If the value is nil
no conversion occurs.
:encoding
: Specifies external and internal encodings as 'extern:intern'
.
:textmode
: If a truthy value, specifies the mode as text-only, binary otherwise.
:binmode
: If a truthy value, specifies the mode as binary, text-only otherwise.
:autoclose
: If a truthy value, specifies that the fd
will close when the stream closes; otherwise it remains open.
Also available are the options offered in String#encode
, which may control conversion between external internal encoding.
A number of IO methods accept optional keyword arguments that determine how a stream is to be treated:
:chomp
: If true
, line separators are omitted; default is false
.
An IO stream has a position, which is the non-negative integer offset (in bytes) in the stream where the next read or write will occur.
Note that a text stream may have multi-byte characters, so a text stream whose position is n
(bytes) may not have n
characters preceding the current position – there may be fewer.
A new stream is initially positioned:
At the beginning (position 0
) if its mode is 'r'
, 'w'
, or 'r+'
.
At the end (position self.size
) if its mode is 'a'
, 'w+'
, or 'a+'
.
Methods to query the position:
IO#tell
and its alias IO#pos
return the position for an open stream.
IO#eof?
and its alias IO#eof
return whether the position is at the end of a readable stream.
Reading from a stream usually changes its position:
f = File.open('t.txt') f.tell # => 0 f.readline # => "This is line one.\n" f.tell # => 19 f.readline # => "This is the second line.\n" f.tell # => 45 f.eof? # => false f.readline # => "Here's the third line.\n" f.eof? # => true
Writing to a stream usually changes its position:
f = File.open('t.tmp', 'w') f.tell # => 0 f.write('foo') # => 3 f.tell # => 3 f.write('bar') # => 3 f.tell # => 6
Iterating over a stream usually changes its position:
f = File.open('t.txt') f.each do |line| p "position=#{f.pos} eof?=#{f.eof?} line=#{line}" end
Output:
"position=19 eof?=false line=This is line one.\n" "position=45 eof?=false line=This is the second line.\n" "position=70 eof?=true line=This is the third line.\n"
The position may also be changed by certain other methods:
IO#pos=
and IO#seek
change the position to a specified offset.
IO#rewind
changes the position to the beginning.
A readable IO stream has a line number, which is the non-negative integer line number in the stream where the next read will occur.
A new stream is initially has line number 0
.
Method IO#lineno
returns the line number.
Reading lines from a stream usually changes its line number:
f = File.open('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
Iterating over lines in a stream usually changes its line number:
f = File.open('t.txt') f.each_line do |line| p "position=#{f.pos} eof?=#{f.eof?} line=#{line}" end
Output:
"position=19 eof?=false line=This is line one.\n" "position=45 eof?=false line=This is the second line.\n" "position=70 eof?=true line=This is the third line.\n"
First, what’s elsewhere. Class IO:
Inherits from class Object.
Includes module Enumerable, which provides dozens of additional methods.
Here, class IO provides methods that are useful for:
::open
Creates a new IO object.
::pipe
Creates a connected pair of reader and writer IO objects.
::popen
Creates an IO object to interact with a subprocess.
::select
Selects which given IO instances are ready for reading,
writing, or have pending exceptions.
::binread
Returns a binary string with all or a subset of bytes from the given file.
::read
Returns a string with all or a subset of bytes from the given file.
::readlines
Returns an array of strings, which are the lines from the given file.
getbyte
Returns the next 8-bit byte read from self
as an integer.
getc
Returns the next character read from self
as a string.
gets
Returns the line read from self
.
pread
Returns all or the next n bytes read from self
, not updating the receiver’s offset.
read
Returns all remaining or the next n bytes read from self
for a given n.
read_nonblock
the next n bytes read from self
for a given n, in non-block mode.
readline
Returns the next line read from self
; same as getline, but raises an exception of end-of-file.
readlines
Returns an array of all lines read read from self
.
readpartial
Returns up to the given number of bytes from self
.
::binwrite
Writes the given string to the file at the given filepath, in binary mode.
::write
Writes the given string to self
.
Appends the given string to self
.
print
Prints last read line or given objects to self
.
printf
Writes to self
based on the given format string and objects.
putc
Writes a character to self
.
puts
Writes lines to self
, making sure line ends with a newline.
pwrite
Writes the given string at the given offset, not updating the receiver’s offset.
write
Writes one or more given strings to self
.
write_nonblock
Writes one or more given strings to self
in non-blocking mode.
lineno
Returns the current line number in self
.
lineno=
Sets the line number is self
.
pos=
Sets the byte offset in self
.
reopen
Reassociates self
with a new or existing IO stream.
rewind
Positions self
to the beginning of input.
seek
Sets the offset for self
relative to given position.
::foreach
Yields each line of given file to the block.
each_byte
Calls the given block with each successive byte in self
as an integer.
each_char
Calls the given block with each successive character in self
as a string.
each_codepoint
Calls the given block with each successive codepoint in self
as an integer.
autoclose=
Sets whether self
auto-closes.
binmode
Sets self
to binary mode.
close
Closes self
.
close_on_exec=
Sets the close-on-exec flag.
close_read
Closes self
for reading.
close_write
Closes self
for writing.
set_encoding
Sets the encoding for self
.
set_encoding_by_bom
Sets the encoding for self
, based on its Unicode byte-order-mark.
sync=
Sets the sync-mode to the given value.
autoclose?
Returns whether self
auto-closes.
binmode?
Returns whether self
is in binary mode.
close_on_exec?
Returns the close-on-exec flag for self
.
closed?
Returns whether self
is closed.
external_encoding
Returns the external encoding object for self
.
internal_encoding
Returns the internal encoding object for self
.
stat
Returns the File::Stat
object containing status information for self
.
sync
Returns whether self
is in sync-mode.
isatty
)
Returns whether self
is a terminal.
fdatasync
Immediately writes all buffered data in self
to disk.
flush
Flushes any buffered data within self
to the underlying operating system.
fsync
Immediately writes all buffered data and attributes in self
to disk.
ungetbyte
Prepends buffer for self
with given integer byte or string.
ungetc
Prepends buffer for self
with given string.
::sysopen
Opens the file given by its path, returning the integer file descriptor.
advise
Announces the intention to access data from self
in a specific way.
fcntl
Passes a low-level command to the file specified by the given file descriptor.
ioctl
Passes a low-level command to the device specified by the given file descriptor.
sysread
Returns up to the next n bytes read from self using a low-level read.
sysseek
Sets the offset for self
.
syswrite
Writes the given string to self
using a low-level write.
::copy_stream
Copies data from a source to a destination, each of which is a filepath or an IO-like object.
::try_convert
Returns a new IO object resulting from converting the given object.
inspect
Returns the string representation of self
.
Pathname
represents the name of a file or directory on the filesystem, but not the file itself.
The pathname depends on the Operating System: Unix, Windows, etc. This library works with pathnames of local OS, however non-Unix pathnames are supported experimentally.
A Pathname
can be relative or absolute. It’s not until you try to reference the file that it even matters whether the file exists or not.
Pathname
is immutable. It has no method for destructive update.
The goal of this class is to manipulate file path information in a neater way than standard Ruby provides. The examples below demonstrate the difference.
All functionality from File
, FileTest
, and some from Dir
and FileUtils
is included, in an unsurprising way. It is essentially a facade for all of these, and more.
Pathname
require 'pathname' 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| _ }
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| _ }
p1 = Pathname.new("/usr/lib") # Pathname:/usr/lib p2 = p1 + "ruby/1.8" # Pathname:/usr/lib/ruby/1.8 p3 = p1.parent # Pathname:/usr p4 = p2.relative_path_from(p3) # Pathname:lib/ruby/1.8 pwd = Pathname.pwd # Pathname:/home/gavin pwd.absolute? # true p5 = Pathname.new "." # Pathname:. p5 = p5 + "music/../articles" # Pathname:music/../articles p5.cleanpath # Pathname:articles p5.realpath # Pathname:/home/gavin/articles p5.children # [Pathname:/home/gavin/articles/linux, ...]
These methods are effectively manipulating a String
, because that’s all a path is. None of these access the file system except for mountpoint?
, children
, each_child
, realdirpath
and realpath
.
+
File
status predicate methods These methods are a facade for FileTest:
File
property and manipulation methods These methods are a facade for File:
open
(*args, &block)
These methods are a facade for Dir:
each_entry
(&block)
IO
These methods are a facade for IO:
each_line
(*args, &block)
These methods are a mixture of Find
, FileUtils
, and others:
Method
documentation As the above section shows, most of the methods in Pathname
are facades. The documentation for these methods generally just says, for instance, “See FileTest.writable?
”, as you should be familiar with the original method anyway, and its documentation (e.g. through ri
) will contain more information. In some cases, a brief description will follow.
Pseudo I/O on String
object, with interface corresponding to IO
.
Commonly used to simulate $stdio
or $stderr
require 'stringio' # Writing stream emulation io = StringIO.new io.puts "Hello World" io.string #=> "Hello World\n" # Reading stream emulation io = StringIO.new "first\nsecond\nlast\n" io.getc #=> "f" io.gets #=> "irst\n" io.read #=> "second\nlast\n"
OLEProperty
helper class of Property with arguments.
Raised when an IO
operation fails.
File.open("/etc/hosts") {|f| f << "example"} #=> IOError: not opened for writing File.open("/etc/hosts") {|f| f.close; f.read } #=> IOError: closed stream
Note that some IO
failures raise SystemCallError
s and these are not subclasses of IOError:
File.open("does/not/exist") #=> Errno::ENOENT: No such file or directory - does/not/exist
ARGF
is a stream designed for use in scripts that process files given as command-line arguments or passed in via STDIN.
The arguments passed to your script are stored in the ARGV
Array
, one argument per element. ARGF
assumes that any arguments that aren’t filenames have been removed from ARGV
. For example:
$ ruby argf.rb --verbose file1 file2 ARGV #=> ["--verbose", "file1", "file2"] option = ARGV.shift #=> "--verbose" ARGV #=> ["file1", "file2"]
You can now use ARGF
to work with a concatenation of each of these named files. For instance, ARGF.read
will return the contents of file1 followed by the contents of file2.
After a file in ARGV
has been read ARGF
removes it from the Array
. Thus, after all files have been read ARGV
will be empty.
You can manipulate ARGV
yourself to control what ARGF
operates on. If you remove a file from ARGV
, it is ignored by ARGF
; if you add files to ARGV
, they are treated as if they were named on the command line. For example:
ARGV.replace ["file1"] ARGF.readlines # Returns the contents of file1 as an Array ARGV #=> [] ARGV.replace ["file2", "file3"] ARGF.read # Returns the contents of file2 and file3
If ARGV
is empty, ARGF
acts as if it contained STDIN, i.e. the data piped to your script. For example:
$ echo "glark" | ruby -e 'p ARGF.read' "glark\n"
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 pure Ruby implementation.
GetoptLong
allows for POSIX-style options like --file
as well as single letter options like -f
The empty option --
(two minus symbols) is used to end option processing. This can be particularly important if options have optional arguments.
Here is a simple example of usage:
require 'getoptlong' opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--repeat', '-n', GetoptLong::REQUIRED_ARGUMENT ], [ '--name', GetoptLong::OPTIONAL_ARGUMENT ] ) dir = nil name = nil repetitions = 1 opts.each do |opt, arg| case opt 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' repetitions = arg.to_i when '--name' if arg == '' name = 'John' else name = arg end end end if ARGV.length != 1 puts "Missing dir argument (try --help)" exit 0 end dir = ARGV.shift Dir.chdir(dir) for i in (1..repetitions) print "Hello" if name print ", #{name}" end puts end
Example command line:
hello -n 6 --name -- /tmp
IPAddr
provides a set of methods to manipulate an IP address. Both IPv4 and IPv6 are supported.
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>
The Warning
module contains a single method named warn
, and the module extends itself, making Warning.warn
available. Warning.warn
is called for all warnings issued by Ruby. By default, warnings are printed to $stderr.
Changing the behavior of Warning.warn
is useful to customize how warnings are handled by Ruby, for instance by filtering some warnings, and/or outputting warnings somewhere other than $stderr.
If you want to change the behavior of Warning.warn
you should use +Warning.extend(MyNewModuleWithWarnMethod)+ and you can use ‘super` to get the default behavior of printing the warning to $stderr.
Example:
module MyWarningFilter def warn(message, category: nil, **kwargs) if /some warning I want to ignore/.match?(message) # ignore else super end end end Warning.extend MyWarningFilter
You should never redefine Warning#warn
(the instance method), as that will then no longer provide a way to use the default behavior.
The warning
gem provides convenient ways to customize Warning.warn
.
newton.rb
Solves the nonlinear algebraic equation system f = 0 by Newton’s method. This program is not dependent on BigDecimal
.
To call:
n = nlsolve(f,x) where n is the number of iterations required, x is the initial value vector f is an Object which is used to compute the values of the equations to be solved.
It must provide the following methods:
returns the values of all functions at x
returns 0.0
returns 1.0
returns 2.0
returns 10.0
returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal.
On exit, x is the solution vector.
JSON is a lightweight data-interchange format.
A JSON value is one of the following:
Double-quoted text: "foo"
.
Number: 1
, 1.0
, 2.0e2
.
Boolean: true
, false
.
Null: null
.
Array: an ordered list of values, enclosed by square brackets:
["foo", 1, 1.0, 2.0e2, true, false, null]
Object: a collection of name/value pairs, enclosed by curly braces; each name is double-quoted text; the values may be any JSON values:
{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}
A JSON array or object may contain nested arrays, objects, and scalars to any depth:
{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]} [{"foo": 0, "bar": 1}, ["baz", 2]]
To make module JSON available in your code, begin with:
require 'json'
All examples here assume that this has been done.
You can parse a String containing JSON data using either of two methods:
JSON.parse(source, opts)
JSON.parse!(source, opts)
where
source
is a Ruby object.
opts
is a Hash object containing options that control both input allowed and output formatting.
The difference between the two methods is that JSON.parse!
omits some checks and may not be safe for some source
data; use it only for data from trusted sources. Use the safer method JSON.parse
for less trusted sources.
When source
is a JSON array, JSON.parse
by default returns a Ruby Array:
json = '["foo", 1, 1.0, 2.0e2, true, false, null]' ruby = JSON.parse(json) ruby # => ["foo", 1, 1.0, 200.0, true, false, nil] ruby.class # => Array
The JSON array may contain nested arrays, objects, and scalars to any depth:
json = '[{"foo": 0, "bar": 1}, ["baz", 2]]' JSON.parse(json) # => [{"foo"=>0, "bar"=>1}, ["baz", 2]]
When the source is a JSON object, JSON.parse
by default returns a Ruby Hash:
json = '{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}' ruby = JSON.parse(json) ruby # => {"a"=>"foo", "b"=>1, "c"=>1.0, "d"=>200.0, "e"=>true, "f"=>false, "g"=>nil} ruby.class # => Hash
The JSON object may contain nested arrays, objects, and scalars to any depth:
json = '{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}' JSON.parse(json) # => {"foo"=>{"bar"=>1, "baz"=>2}, "bat"=>[0, 1, 2]}
When the source is a JSON scalar (not an array or object), JSON.parse
returns a Ruby scalar.
String:
ruby = JSON.parse('"foo"') ruby # => 'foo' ruby.class # => String
Integer:
ruby = JSON.parse('1') ruby # => 1 ruby.class # => Integer
Float:
ruby = JSON.parse('1.0') ruby # => 1.0 ruby.class # => Float ruby = JSON.parse('2.0e2') ruby # => 200 ruby.class # => Float
Boolean:
ruby = JSON.parse('true') ruby # => true ruby.class # => TrueClass ruby = JSON.parse('false') ruby # => false ruby.class # => FalseClass
Null:
ruby = JSON.parse('null') ruby # => nil ruby.class # => NilClass
Option max_nesting
(Integer) specifies the maximum nesting depth allowed; defaults to 100
; specify false
to disable depth checking.
With the default, false
:
source = '[0, [1, [2, [3]]]]' ruby = JSON.parse(source) ruby # => [0, [1, [2, [3]]]]
Too deep:
# Raises JSON::NestingError (nesting of 2 is too deep): JSON.parse(source, {max_nesting: 1})
Bad value:
# Raises TypeError (wrong argument type Symbol (expected Fixnum)): JSON.parse(source, {max_nesting: :foo})
Option allow_nan
(boolean) specifies whether to allow NaN
, Infinity
, and MinusInfinity
in source
; defaults to false
.
With the default, false
:
# Raises JSON::ParserError (225: unexpected token at '[NaN]'): JSON.parse('[NaN]') # Raises JSON::ParserError (232: unexpected token at '[Infinity]'): JSON.parse('[Infinity]') # Raises JSON::ParserError (248: unexpected token at '[-Infinity]'): JSON.parse('[-Infinity]')
Allow:
source = '[NaN, Infinity, -Infinity]' ruby = JSON.parse(source, {allow_nan: true}) ruby # => [NaN, Infinity, -Infinity]
Option symbolize_names
(boolean) specifies whether returned Hash keys should be Symbols; defaults to false
(use Strings).
With the default, false
:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}' ruby = JSON.parse(source) ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
Use Symbols:
ruby = JSON.parse(source, {symbolize_names: true}) ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}
Option object_class
(Class) specifies the Ruby class to be used for each JSON object; defaults to Hash.
With the default, Hash:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}' ruby = JSON.parse(source) ruby.class # => Hash
Use class OpenStruct:
ruby = JSON.parse(source, {object_class: OpenStruct}) ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>
Option array_class
(Class) specifies the Ruby class to be used for each JSON array; defaults to Array.
With the default, Array:
source = '["foo", 1.0, true, false, null]' ruby = JSON.parse(source) ruby.class # => Array
Use class Set:
ruby = JSON.parse(source, {array_class: Set}) ruby # => #<Set: {"foo", 1.0, true, false, nil}>
Option create_additions
(boolean) specifies whether to use JSON additions in parsing. See JSON Additions.
To generate a Ruby String containing JSON data, use method JSON.generate(source, opts)
, where
source
is a Ruby object.
opts
is a Hash object containing options that control both input allowed and output formatting.
When the source is a Ruby Array, JSON.generate
returns a String containing a JSON array:
ruby = [0, 's', :foo] json = JSON.generate(ruby) json # => '[0,"s","foo"]'
The Ruby Array array may contain nested arrays, hashes, and scalars to any depth:
ruby = [0, [1, 2], {foo: 3, bar: 4}] json = JSON.generate(ruby) json # => '[0,[1,2],{"foo":3,"bar":4}]'
When the source is a Ruby Hash, JSON.generate
returns a String containing a JSON object:
ruby = {foo: 0, bar: 's', baz: :bat} json = JSON.generate(ruby) json # => '{"foo":0,"bar":"s","baz":"bat"}'
The Ruby Hash array may contain nested arrays, hashes, and scalars to any depth:
ruby = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad} json = JSON.generate(ruby) json # => '{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}'
When the source is neither an Array nor a Hash, the generated JSON data depends on the class of the source.
When the source is a Ruby Integer or Float, JSON.generate
returns a String containing a JSON number:
JSON.generate(42) # => '42' JSON.generate(0.42) # => '0.42'
When the source is a Ruby String, JSON.generate
returns a String containing a JSON string (with double-quotes):
JSON.generate('A string') # => '"A string"'
When the source is true
, false
or nil
, JSON.generate
returns a String containing the corresponding JSON token:
JSON.generate(true) # => 'true' JSON.generate(false) # => 'false' JSON.generate(nil) # => 'null'
When the source is none of the above, JSON.generate
returns a String containing a JSON string representation of the source:
JSON.generate(:foo) # => '"foo"' JSON.generate(Complex(0, 0)) # => '"0+0i"' JSON.generate(Dir.new('.')) # => '"#<Dir>"'
Option allow_nan
(boolean) specifies whether NaN
, Infinity
, and -Infinity
may be generated; defaults to false
.
With the default, false
:
# Raises JSON::GeneratorError (920: NaN not allowed in JSON): JSON.generate(JSON::NaN) # Raises JSON::GeneratorError (917: Infinity not allowed in JSON): JSON.generate(JSON::Infinity) # Raises JSON::GeneratorError (917: -Infinity not allowed in JSON): JSON.generate(JSON::MinusInfinity)
Allow:
ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity] JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
Option max_nesting
(Integer) specifies the maximum nesting depth in obj
; defaults to 100
.
With the default, 100
:
obj = [[[[[[0]]]]]] JSON.generate(obj) # => '[[[[[[0]]]]]]'
Too deep:
# Raises JSON::NestingError (nesting of 2 is too deep): JSON.generate(obj, max_nesting: 2)
The default formatting options generate the most compact JSON data, all on one line and with no whitespace.
You can use these formatting options to generate JSON data in a more open format, using whitespace. See also JSON.pretty_generate
.
Option array_nl
(String) specifies a string (usually a newline) to be inserted after each JSON array; defaults to the empty String, ''
.
Option object_nl
(String) specifies a string (usually a newline) to be inserted after each JSON object; defaults to the empty String, ''
.
Option indent
(String) specifies the string (usually spaces) to be used for indentation; defaults to the empty String, ''
; defaults to the empty String, ''
; has no effect unless options array_nl
or object_nl
specify newlines.
Option space
(String) specifies a string (usually a space) to be inserted after the colon in each JSON object’s pair; defaults to the empty String, ''
.
Option space_before
(String) specifies a string (usually a space) to be inserted before the colon in each JSON object’s pair; defaults to the empty String, ''
.
In this example, obj
is used first to generate the shortest JSON data (no whitespace), then again with all formatting options specified:
obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}} json = JSON.generate(obj) puts 'Compact:', json opts = { array_nl: "\n", object_nl: "\n", indent: ' ', space_before: ' ', space: ' ' } puts 'Open:', JSON.generate(obj, opts)
Output:
Compact: {"foo":["bar","baz"],"bat":{"bam":0,"bad":1}} Open: { "foo" : [ "bar", "baz" ], "bat" : { "bam" : 0, "bad" : 1 } }
When you “round trip” a non-String object from Ruby to JSON and back, you have a new String, instead of the object you began with:
ruby0 = Range.new(0, 2) json = JSON.generate(ruby0) json # => '0..2"' ruby1 = JSON.parse(json) ruby1 # => '0..2' ruby1.class # => String
You can use JSON additions to preserve the original object. The addition is an extension of a ruby class, so that:
JSON.generate stores more information in the JSON string.
JSON.parse, called with option create_additions
, uses that information to create a proper Ruby object.
This example shows a Range being generated into JSON and parsed back into Ruby, both without and with the addition for Range:
ruby = Range.new(0, 2) # This passage does not use the addition for Range. json0 = JSON.generate(ruby) ruby0 = JSON.parse(json0) # This passage uses the addition for Range. require 'json/add/range' json1 = JSON.generate(ruby) ruby1 = JSON.parse(json1, create_additions: true) # Make a nice display. display = <<EOT Generated JSON: Without addition: #{json0} (#{json0.class}) With addition: #{json1} (#{json1.class}) Parsed JSON: Without addition: #{ruby0.inspect} (#{ruby0.class}) With addition: #{ruby1.inspect} (#{ruby1.class}) EOT puts display
This output shows the different results:
Generated JSON: Without addition: "0..2" (String) With addition: {"json_class":"Range","a":[0,2,false]} (String) Parsed JSON: Without addition: "0..2" (String) With addition: 0..2 (Range)
The JSON module includes additions for certain classes. You can also craft custom additions. See Custom JSON Additions.
The JSON module includes additions for certain classes. To use an addition, require
its source:
BigDecimal: require 'json/add/bigdecimal'
Complex: require 'json/add/complex'
Date: require 'json/add/date'
DateTime: require 'json/add/date_time'
Exception: require 'json/add/exception'
OpenStruct: require 'json/add/ostruct'
Range: require 'json/add/range'
Rational: require 'json/add/rational'
Regexp: require 'json/add/regexp'
Set: require 'json/add/set'
Struct: require 'json/add/struct'
Symbol: require 'json/add/symbol'
Time: require 'json/add/time'
To reduce punctuation clutter, the examples below show the generated JSON via puts
, rather than the usual inspect
,
BigDecimal:
require 'json/add/bigdecimal' ruby0 = BigDecimal(0) # 0.0 json = JSON.generate(ruby0) # {"json_class":"BigDecimal","b":"27:0.0"} ruby1 = JSON.parse(json, create_additions: true) # 0.0 ruby1.class # => BigDecimal
Complex:
require 'json/add/complex' ruby0 = Complex(1+0i) # 1+0i json = JSON.generate(ruby0) # {"json_class":"Complex","r":1,"i":0} ruby1 = JSON.parse(json, create_additions: true) # 1+0i ruby1.class # Complex
Date:
require 'json/add/date' ruby0 = Date.today # 2020-05-02 json = JSON.generate(ruby0) # {"json_class":"Date","y":2020,"m":5,"d":2,"sg":2299161.0} ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02 ruby1.class # Date
DateTime:
require 'json/add/date_time' ruby0 = DateTime.now # 2020-05-02T10:38:13-05:00 json = JSON.generate(ruby0) # {"json_class":"DateTime","y":2020,"m":5,"d":2,"H":10,"M":38,"S":13,"of":"-5/24","sg":2299161.0} ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02T10:38:13-05:00 ruby1.class # DateTime
Exception (and its subclasses including RuntimeError):
require 'json/add/exception' ruby0 = Exception.new('A message') # A message json = JSON.generate(ruby0) # {"json_class":"Exception","m":"A message","b":null} ruby1 = JSON.parse(json, create_additions: true) # A message ruby1.class # Exception ruby0 = RuntimeError.new('Another message') # Another message json = JSON.generate(ruby0) # {"json_class":"RuntimeError","m":"Another message","b":null} ruby1 = JSON.parse(json, create_additions: true) # Another message ruby1.class # RuntimeError
OpenStruct:
require 'json/add/ostruct' ruby0 = OpenStruct.new(name: 'Matz', language: 'Ruby') # #<OpenStruct name="Matz", language="Ruby"> json = JSON.generate(ruby0) # {"json_class":"OpenStruct","t":{"name":"Matz","language":"Ruby"}} ruby1 = JSON.parse(json, create_additions: true) # #<OpenStruct name="Matz", language="Ruby"> ruby1.class # OpenStruct
Range:
require 'json/add/range' ruby0 = Range.new(0, 2) # 0..2 json = JSON.generate(ruby0) # {"json_class":"Range","a":[0,2,false]} ruby1 = JSON.parse(json, create_additions: true) # 0..2 ruby1.class # Range
Rational:
require 'json/add/rational' ruby0 = Rational(1, 3) # 1/3 json = JSON.generate(ruby0) # {"json_class":"Rational","n":1,"d":3} ruby1 = JSON.parse(json, create_additions: true) # 1/3 ruby1.class # Rational
Regexp:
require 'json/add/regexp' ruby0 = Regexp.new('foo') # (?-mix:foo) json = JSON.generate(ruby0) # {"json_class":"Regexp","o":0,"s":"foo"} ruby1 = JSON.parse(json, create_additions: true) # (?-mix:foo) ruby1.class # Regexp
Set:
require 'json/add/set' ruby0 = Set.new([0, 1, 2]) # #<Set: {0, 1, 2}> json = JSON.generate(ruby0) # {"json_class":"Set","a":[0,1,2]} ruby1 = JSON.parse(json, create_additions: true) # #<Set: {0, 1, 2}> ruby1.class # Set
Struct:
require 'json/add/struct' Customer = Struct.new(:name, :address) # Customer ruby0 = Customer.new("Dave", "123 Main") # #<struct Customer name="Dave", address="123 Main"> json = JSON.generate(ruby0) # {"json_class":"Customer","v":["Dave","123 Main"]} ruby1 = JSON.parse(json, create_additions: true) # #<struct Customer name="Dave", address="123 Main"> ruby1.class # Customer
Symbol:
require 'json/add/symbol' ruby0 = :foo # foo json = JSON.generate(ruby0) # {"json_class":"Symbol","s":"foo"} ruby1 = JSON.parse(json, create_additions: true) # foo ruby1.class # Symbol
Time:
require 'json/add/time' ruby0 = Time.now # 2020-05-02 11:28:26 -0500 json = JSON.generate(ruby0) # {"json_class":"Time","s":1588436906,"n":840560000} ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02 11:28:26 -0500 ruby1.class # Time
In addition to the JSON additions provided, you can craft JSON additions of your own, either for Ruby built-in classes or for user-defined classes.
Here’s a user-defined class Foo
:
class Foo attr_accessor :bar, :baz def initialize(bar, baz) self.bar = bar self.baz = baz end end
Here’s the JSON addition for it:
# Extend class Foo with JSON addition. class Foo # Serialize Foo object with its class name and arguments def to_json(*args) { JSON.create_id => self.class.name, 'a' => [ bar, baz ] }.to_json(*args) end # Deserialize JSON string by constructing new Foo object with arguments. def self.json_create(object) new(*object['a']) end end
Demonstration:
require 'json' # This Foo object has no custom addition. foo0 = Foo.new(0, 1) json0 = JSON.generate(foo0) obj0 = JSON.parse(json0) # Lood the custom addition. require_relative 'foo_addition' # This foo has the custom addition. foo1 = Foo.new(0, 1) json1 = JSON.generate(foo1) obj1 = JSON.parse(json1, create_additions: true) # Make a nice display. display = <<EOT Generated JSON: Without custom addition: #{json0} (#{json0.class}) With custom addition: #{json1} (#{json1.class}) Parsed JSON: Without custom addition: #{obj0.inspect} (#{obj0.class}) With custom addition: #{obj1.inspect} (#{obj1.class}) EOT puts display
Output:
Generated JSON: Without custom addition: "#<Foo:0x0000000006534e80>" (String) With custom addition: {"json_class":"Foo","a":[0,1]} (String) Parsed JSON: Without custom addition: "#<Foo:0x0000000006534e80>" (String) With custom addition: #<Foo:0x0000000006473bb8 @bar=0, @baz=1> (Foo)
Kanji Converter for Ruby.
The objspace library extends the ObjectSpace
module and adds several methods to get internal statistic information about object/memory management.
You need to require 'objspace'
to use this extension module.
Generally, you *SHOULD NOT* use this library if you do not know about the MRI implementation. Mainly, this library is for (memory) profiler developers and MRI developers who need to know about MRI memory usage.
The ObjectSpace
module contains a number of routines that interact with the garbage collection facility and allow you to traverse all living objects with an iterator.
ObjectSpace
also provides support for object finalizers, procs that will be called when a specific object is about to be destroyed by garbage collection. See the documentation for ObjectSpace.define_finalizer
for important information on how to use this method correctly.
a = "A" b = "B" ObjectSpace.define_finalizer(a, proc {|id| puts "Finalizer one on #{id}" }) ObjectSpace.define_finalizer(b, proc {|id| puts "Finalizer two on #{id}" }) a = nil b = nil
produces:
Finalizer two on 537763470 Finalizer one on 537763480
The Benchmark
module provides methods to measure and report the time used to execute Ruby code.
Measure the time to construct the string given by the expression "a"*1_000_000_000
:
require 'benchmark' puts Benchmark.measure { "a"*1_000_000_000 }
On my machine (OSX 10.8.3 on i5 1.7 GHz) this generates:
0.350000 0.400000 0.750000 ( 0.835234)
This report shows the user CPU time, system CPU time, the sum of the user and system CPU times, and the elapsed real time. The unit of time is seconds.
Do some experiments sequentially using the bm
method:
require 'benchmark' n = 5000000 Benchmark.bm do |x| x.report { for i in 1..n; a = "1"; end } x.report { n.times do ; a = "1"; end } x.report { 1.upto(n) do ; a = "1"; end } end
The result:
user system total real 1.010000 0.000000 1.010000 ( 1.014479) 1.000000 0.000000 1.000000 ( 0.998261) 0.980000 0.000000 0.980000 ( 0.981335)
Continuing the previous example, put a label in each report:
require 'benchmark' n = 5000000 Benchmark.bm(7) do |x| x.report("for:") { for i in 1..n; a = "1"; end } x.report("times:") { n.times do ; a = "1"; end } x.report("upto:") { 1.upto(n) do ; a = "1"; end } end
The result:
user system total real for: 1.010000 0.000000 1.010000 ( 1.015688) times: 1.000000 0.000000 1.000000 ( 1.003611) upto: 1.030000 0.000000 1.030000 ( 1.028098)
The times for some benchmarks depend on the order in which items are run. These differences are due to the cost of memory allocation and garbage collection. To avoid these discrepancies, the bmbm
method is provided. For example, to compare ways to sort an array of floats:
require 'benchmark' array = (1..1000000).map { rand } Benchmark.bmbm do |x| x.report("sort!") { array.dup.sort! } x.report("sort") { array.dup.sort } end
The result:
Rehearsal ----------------------------------------- sort! 1.490000 0.010000 1.500000 ( 1.490520) sort 1.460000 0.000000 1.460000 ( 1.463025) -------------------------------- total: 2.960000sec user system total real sort! 1.460000 0.000000 1.460000 ( 1.460465) sort 1.450000 0.010000 1.460000 ( 1.448327)
Report statistics of sequential experiments with unique labels, using the benchmark
method:
require 'benchmark' include Benchmark # we need the CAPTION and FORMAT constants n = 5000000 Benchmark.benchmark(CAPTION, 7, FORMAT, ">total:", ">avg:") do |x| tf = x.report("for:") { for i in 1..n; a = "1"; end } tt = x.report("times:") { n.times do ; a = "1"; end } tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end } [tf+tt+tu, (tf+tt+tu)/3] end
The result:
user system total real for: 0.950000 0.000000 0.950000 ( 0.952039) times: 0.980000 0.000000 0.980000 ( 0.984938) upto: 0.950000 0.000000 0.950000 ( 0.946787) >total: 2.880000 0.000000 2.880000 ( 2.883764) >avg: 0.960000 0.000000 0.960000 ( 0.961255)
The Forwardable module provides delegation of specified methods to a designated object, using the methods def_delegator
and def_delegators
.
For example, say you have a class RecordCollection which contains an array @records
. You could provide the lookup method record_number(), which simply calls [] on the @records
array, like this:
require 'forwardable' class RecordCollection attr_accessor :records extend Forwardable def_delegator :@records, :[], :record_number end
We can use the lookup method like so:
r = RecordCollection.new r.records = [4,5,6] r.record_number(0) # => 4
Further, if you wish to provide the methods size, <<, and map, all of which delegate to @records, this is how you can do it:
class RecordCollection # re-open RecordCollection class def_delegators :@records, :size, :<<, :map end r = RecordCollection.new r.records = [1,2,3] r.record_number(0) # => 1 r.size # => 3 r << 4 # => [1, 2, 3, 4] r.map { |x| x * 2 } # => [2, 4, 6, 8]
You can even extend regular objects with Forwardable.
my_hash = Hash.new my_hash.extend Forwardable # prepare object for delegation my_hash.def_delegator "STDOUT", "puts" # add delegation for STDOUT.puts() my_hash.puts "Howdy!"
You could use Forwardable as an alternative to inheritance, when you don’t want to inherit all methods from the superclass. For instance, here is how you might add a range of Array
instance methods to a new class Queue
:
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 = Thread::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 puts q.first
This should output:
2 3 4 5 6 Ruby nil
Be advised, RDoc
will not detect delegated methods.
forwardable.rb
provides single-method delegation via the def_delegator
and def_delegators
methods. For full-class delegation via DelegateClass, see delegate.rb
.