Wrapper for arrays within a struct
Represents the use of the forwarding parameter in a method, block, or lambda declaration.
def foo(...) ^^^ end
Raised when an invalid operation is attempted on a Fiber
, in particular when attempting to call/resume a dead fiber, attempting to yield from the root fiber, or calling a fiber across threads.
fiber = Fiber.new{} fiber.resume #=> nil fiber.resume #=> FiberError: dead fiber called
A class which allows both internal and external iteration.
An Enumerator
can be created by the following methods.
Most methods have two forms: a block form where the contents are evaluated for each item in the enumeration, and a non-block form which returns a new Enumerator
wrapping the iteration.
enumerator = %w(one two three).each puts enumerator.class # => Enumerator enumerator.each_with_object("foo") do |item, obj| puts "#{obj}: #{item}" end # foo: one # foo: two # foo: three enum_with_obj = enumerator.each_with_object("foo") puts enum_with_obj.class # => Enumerator enum_with_obj.each do |item, obj| puts "#{obj}: #{item}" end # foo: one # foo: two # foo: three
This allows you to chain Enumerators together. For example, you can map a list’s elements to strings containing the index and the element as a string via:
puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" } # => ["0:foo", "1:bar", "2:baz"]
An Enumerator
can also be used as an external iterator. For example, Enumerator#next
returns the next value of the iterator or raises StopIteration
if the Enumerator
is at the end.
e = [1,2,3].each # returns an enumerator object. puts e.next # => 1 puts e.next # => 2 puts e.next # => 3 puts e.next # raises StopIteration
next
, next_values
, peek
, and peek_values
are the only methods which use external iteration (and Array#zip(Enumerable-not-Array)
which uses next
internally).
These methods do not affect other internal enumeration methods, unless the underlying iteration method itself has side-effect, e.g. IO#each_line
.
FrozenError
will be raised if these methods are called against a frozen enumerator. Since rewind
and feed
also change state for external iteration, these methods may raise FrozenError
too.
External iteration differs significantly from internal iteration due to using a Fiber:
The Fiber
adds some overhead compared to internal enumeration.
The stacktrace will only include the stack from the Enumerator
, not above.
Fiber-local variables are not inherited inside the Enumerator
Fiber
, which instead starts with no Fiber-local variables.
Fiber
storage variables are inherited and are designed to handle Enumerator
Fibers. Assigning to a Fiber
storage variable only affects the current Fiber
, so if you want to change state in the caller Fiber
of the Enumerator
Fiber
, you need to use an extra indirection (e.g., use some object in the Fiber
storage variable and mutate some ivar of it).
Concretely:
Thread.current[:fiber_local] = 1 Fiber[:storage_var] = 1 e = Enumerator.new do |y| p Thread.current[:fiber_local] # for external iteration: nil, for internal iteration: 1 p Fiber[:storage_var] # => 1, inherited Fiber[:storage_var] += 1 y << 42 end p e.next # => 42 p Fiber[:storage_var] # => 1 (it ran in a different Fiber) e.each { p _1 } p Fiber[:storage_var] # => 2 (it ran in the same Fiber/"stack" as the current Fiber)
You can use an external iterator to implement an internal iterator as follows:
def ext_each(e) while true begin vs = e.next_values rescue StopIteration return $!.result end y = yield(*vs) e.feed y end end o = Object.new def o.each puts yield puts yield(1) puts yield(1, 2) 3 end # use o.each as an internal iterator directly. puts o.each {|*x| puts x; [:b, *x] } # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3 # convert o.each to an external iterator for # implementing an internal iterator. puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] } # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
Raised to stop the iteration, in particular by Enumerator#next
. It is rescued by Kernel#loop
.
loop do puts "Hello" raise StopIteration puts "World" end puts "Done!"
produces:
Hello Done!
Raised when the interrupt signal is received, typically because the user has pressed Control-C (on most posix platforms). As such, it is a subclass of SignalException
.
begin puts "Press ctrl-C when you get bored" loop {} rescue Interrupt => e puts "Note: You will typically use Signal.trap instead." end
produces:
Press ctrl-C when you get bored
then waits until it is interrupted with Control-C and then prints:
Note: You will typically use Signal.trap instead.
Raised when encountering an object that is not of the expected type.
[1, 2, 3].first("two")
raises the exception:
TypeError: no implicit conversion of String into Integer
Raised when the given index is invalid.
a = [:foo, :bar] a.fetch(0) #=> :foo a[4] #=> nil a.fetch(4) #=> IndexError: index 4 outside of array bounds: -2...2
Raised when the specified key is not found. It is a subclass of IndexError
.
h = {"foo" => :bar} h.fetch("foo") #=> :bar h.fetch("baz") #=> KeyError: key not found: "baz"
ScriptError
is the superclass for errors raised when a script can not be executed because of a LoadError
, NotImplementedError
or a SyntaxError
. Note these type of ScriptErrors
are not StandardError
and will not be rescued unless it is specified explicitly (or its ancestor Exception
).
Raised when encountering Ruby code with an invalid syntax.
eval("1+1=2")
raises the exception:
SyntaxError: (eval):1: syntax error, unexpected '=', expecting $end
Raised when a file required (a Ruby script, extension library, …) fails to load.
require 'this/file/does/not/exist'
raises the exception:
LoadError: no such file to load -- this/file/does/not/exist
for RubyGems without Bundler
environment. If loading library is not part of the default gems and the bundled gems, warn it.
Raised when a feature is not implemented on the current platform. For example, methods depending on the fsync
or fork
system calls may raise this exception if the underlying operating system or Ruby runtime does not support them.
Note that if fork
raises a NotImplementedError
, then respond_to?(:fork)
returns false
.
Raised when a given name is invalid or undefined.
puts foo
raises the exception:
NameError: undefined local variable or method `foo' for main:Object
Since constant names must start with a capital:
Integer.const_set :answer, 42
raises the exception:
NameError: wrong constant name answer
Raised when a method is called on a receiver which doesn’t have it defined and also fails to respond with method_missing
.
"hello".to_ary
raises the exception:
NoMethodError: undefined method `to_ary' for an instance of String
A generic error class raised when an invalid operation is attempted. Kernel#raise
will raise a RuntimeError
if no Exception
class is specified.
raise "ouch"
raises the exception:
RuntimeError: ouch
Raised when there is an attempt to modify a frozen object.
[1, 2, 3].freeze << 4
raises the exception:
FrozenError: can't modify frozen Array
No longer used by internal code.
Raised when memory allocation fails.
EncodingError
is the base class for encoding errors.
SystemCallError
is the base class for all low-level platform-dependent errors.
The errors available on the current platform are subclasses of SystemCallError
and are defined in the Errno
module.
File.open("does/not/exist")
raises the exception:
Errno::ENOENT: No such file or directory - does/not/exist