Results for: "pstore"

Open the specified filename (either in read-only mode or in read-write mode) and lock it for reading or writing.

The opened File object will be returned. If read_only is true, and the file does not exist, then nil will be returned.

All exceptions are propagated.

Create a new CGI::Session::PStore instance

This constructor is used internally by CGI::Session. The user does not generally need to call it directly.

session is the session for which this instance is being created. The session id must only contain alphanumeric characters; automatically generated session ids observe this requirement.

option is a hash of options for the initializer. The following options are recognised:

tmpdir

the directory to use for storing the PStore file. Defaults to Dir::tmpdir (generally “/tmp” on Unix systems).

prefix

the prefix to add to the session id when generating the filename for this session’s PStore file. Defaults to the empty string.

This session’s PStore file will be created if it does not exist, or opened if it does.

Save session state to the session’s PStore file.

Update and close the session’s PStore file.

Close and delete the session’s PStore file.

No documentation available

Raised in case of a stack overflow.

def me_myself_and_i
  me_myself_and_i
end
me_myself_and_i

raises the exception:

SystemStackError: stack level too deep

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"]

== External Iteration

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

These methods do not affect other internal enumeration methods, unless the underlying iteration method itself has side-effect, e.g. IO#each_line.

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)

== Convert External Iteration to Internal Iteration

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!

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 memory allocation fails.

SystemCallError is the base class for all low-level platform-dependent errors.

The errors available on the current platform are subclasses of SystemCallError and are defined in the Errno module.

File.open("does/not/exist")

raises the exception:

Errno::ENOENT: No such file or directory - does/not/exist

Use the Monitor class when you want to have a lock object for blocks with mutual exclusion.

require 'monitor'

lock = Monitor.new
lock.synchronize do
  # exclusive access
end

This library provides three different ways to delegate method calls to an object. The easiest to use is SimpleDelegator. Pass an object to the constructor and all methods supported by the object will be delegated. This object can be changed later.

Going a step further, the top level DelegateClass method allows you to easily setup delegation through class inheritance. This is considerably more flexible and thus probably the most common use for this library.

Finally, if you need full control over the delegation scheme, you can inherit from the abstract class Delegator and customize as needed. (If you find yourself needing this control, have a look at Forwardable which is also in the standard library. It may suit your needs better.)

SimpleDelegator’s implementation serves as a nice example of the use of Delegator:

require 'delegate'

class SimpleDelegator < Delegator
  def __getobj__
    @delegate_sd_obj # return object we are delegating to, required
  end

  def __setobj__(obj)
    @delegate_sd_obj = obj # change delegation object,
                           # a feature we're providing
  end
end

Notes

Be advised, RDoc will not detect delegated methods.

A concrete implementation of Delegator, this class provides the means to delegate all supported method calls to the object passed into the constructor and even to change the object being delegated to at a later time with __setobj__.

class User
  def born_on
    Date.new(1989, 9, 10)
  end
end

require 'delegate'

class UserDecorator < SimpleDelegator
  def birth_year
    born_on.year
  end
end

decorated_user = UserDecorator.new(User.new)
decorated_user.birth_year  #=> 1989
decorated_user.__getobj__  #=> #<User: ...>

A SimpleDelegator instance can take advantage of the fact that SimpleDelegator is a subclass of Delegator to call super to have methods called on the object being delegated to.

class SuperArray < SimpleDelegator
  def [](*args)
    super + 1
  end
end

SuperArray.new([1])[0]  #=> 2

Here’s a simple example that takes advantage of the fact that SimpleDelegator’s delegation object can be changed at any time.

class Stats
  def initialize
    @source = SimpleDelegator.new([])
  end

  def stats(records)
    @source.__setobj__(records)

    "Elements:  #{@source.size}\n" +
    " Non-Nil:  #{@source.compact.size}\n" +
    "  Unique:  #{@source.uniq.size}\n"
  end
end

s = Stats.new
puts s.stats(%w{James Edward Gray II})
puts
puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])

Prints:

Elements:  4
 Non-Nil:  4
  Unique:  4

Elements:  8
 Non-Nil:  7
  Unique:  6

Ractor is an Actor-model abstraction for Ruby that provides thread-safe parallel execution.

Ractor.new can make a new Ractor, and it will run in parallel.

# The simplest ractor
r = Ractor.new {puts "I am in Ractor!"}
r.take # wait for it to finish
# here "I am in Ractor!" would be printed

Ractors do not share usual objects, so the same kinds of thread-safety concerns such as data-race, race-conditions are not available on multi-ractor programming.

To achieve this, ractors severely limit object sharing between different ractors. For example, unlike threads, ractors can’t access each other’s objects, nor any objects through variables of the outer scope.

a = 1
r = Ractor.new {puts "I am in Ractor! a=#{a}"}
# fails immediately with
# ArgumentError (can not isolate a Proc because it accesses outer variables (a).)

On CRuby (the default implementation), Global Virtual Machine Lock (GVL) is held per ractor, so ractors are performed in parallel without locking each other.

Instead of accessing the shared state, the objects should be passed to and from ractors via sending and receiving objects as messages.

a = 1
r = Ractor.new do
  a_in_ractor = receive # receive blocks till somebody will pass message
  puts "I am in Ractor! a=#{a_in_ractor}"
end
r.send(a)  # pass it
r.take
# here "I am in Ractor! a=1" would be printed

There are two pairs of methods for sending/receiving messages:

In addition to that, an argument to Ractor.new would be passed to block and available there as if received by Ractor.receive, and the last block value would be sent outside of the ractor as if sent by Ractor.yield.

A little demonstration on a classic ping-pong:

server = Ractor.new do
  puts "Server starts: #{self.inspect}"
  puts "Server sends: ping"
  Ractor.yield 'ping'                       # The server doesn't know the receiver and sends to whoever interested
  received = Ractor.receive                 # The server doesn't know the sender and receives from whoever sent
  puts "Server received: #{received}"
end

client = Ractor.new(server) do |srv|        # The server is sent inside client, and available as srv
  puts "Client starts: #{self.inspect}"
  received = srv.take                       # The Client takes a message specifically from the server
  puts "Client received from " \
       "#{srv.inspect}: #{received}"
  puts "Client sends to " \
       "#{srv.inspect}: pong"
  srv.send 'pong'                           # The client sends a message specifically to the server
end

[client, server].each(&:take)               # Wait till they both finish

This will output:

Server starts: #<Ractor:#2 test.rb:1 running>
Server sends: ping
Client starts: #<Ractor:#3 test.rb:8 running>
Client received from #<Ractor:#2 rac.rb:1 blocking>: ping
Client sends to #<Ractor:#2 rac.rb:1 blocking>: pong
Server received: pong

It is said that Ractor receives messages via the incoming port, and sends them to the outgoing port. Either one can be disabled with Ractor#close_incoming and Ractor#close_outgoing respectively. If a ractor terminated, its ports will be closed automatically.

Shareable and unshareable objects

When the object is sent to and from the ractor, it is important to understand whether the object is shareable or unshareable. Most of objects are unshareable objects.

Shareable objects are basically those which can be used by several threads without compromising thread-safety; e.g. immutable ones. Ractor.shareable? allows to check this, and Ractor.make_shareable tries to make object shareable if it is not.

Ractor.shareable?(1)            #=> true -- numbers and other immutable basic values are
Ractor.shareable?('foo')        #=> false, unless the string is frozen due to # freeze_string_literals: true
Ractor.shareable?('foo'.freeze) #=> true

ary = ['hello', 'world']
ary.frozen?                 #=> false
ary[0].frozen?              #=> false
Ractor.make_shareable(ary)
ary.frozen?                 #=> true
ary[0].frozen?              #=> true
ary[1].frozen?              #=> true

When a shareable object is sent (via send or Ractor.yield), no additional processing happens, and it just becomes usable by both ractors. When an unshareable object is sent, it can be either copied or moved. The first is the default, and it makes the object’s full copy by deep cloning of non-shareable parts of its structure.

data = ['foo', 'bar'.freeze]
r = Ractor.new do
  data2 = Ractor.receive
  puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}"
end
r.send(data)
r.take
puts "Outside  : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"

This will output:

In ractor: 340, 360, 320
Outside  : 380, 400, 320

(Note that object id of both array and non-frozen string inside array have changed inside the ractor, showing it is different objects. But the second array’s element, which is a shareable frozen string, has the same object_id.)

Deep cloning of the objects may be slow, and sometimes impossible. Alternatively, move: true may be used on sending. This will move the object to the receiving ractor, making it inaccessible for a sending ractor.

data = ['foo', 'bar']
r = Ractor.new do
  data_in_ractor = Ractor.receive
  puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}"
end
r.send(data, move: true)
r.take
puts "Outside: moved? #{Ractor::MovedObject === data}"
puts "Outside: #{data.inspect}"

This will output:

In ractor: 100, 120
Outside: moved? true
test.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError)

Notice that even inspect (and more basic methods like __id__) is inaccessible on a moved object.

Besides frozen objects, there are shareable objects. Class and Module objects are shareable so the Class/Module definitions are shared between ractors. Ractor objects are also shareable objects. All operations for the shareable mutable objects are thread-safe, so the thread-safety property will be kept. We can not define mutable shareable objects in Ruby, but C extensions can introduce them.

It is prohibited to access instance variables of mutable shareable objects (especially Modules and classes) from ractors other than main:

class C
  class << self
    attr_accessor :tricky
  end
end

C.tricky = 'test'

r = Ractor.new(C) do |cls|
  puts "I see #{cls}"
  puts "I can't see #{cls.tricky}"
end
r.take
# I see C
# can not access instance variables of classes/modules from non-main Ractors (RuntimeError)

Ractors can access constants if they are shareable. The main Ractor is the only one that can access non-shareable constants.

GOOD = 'good'.freeze
BAD = 'bad'

r = Ractor.new do
  puts "GOOD=#{GOOD}"
  puts "BAD=#{BAD}"
end
r.take
# GOOD=good
# can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError)

# Consider the same C class from above

r = Ractor.new do
  puts "I see #{C}"
  puts "I can't see #{C.tricky}"
end
r.take
# I see C
# can not access instance variables of classes/modules from non-main Ractors (RuntimeError)

See also the description of # shareable_constant_value pragma in Comments syntax explanation.

Ractors vs threads

Each ractor creates its own thread. New threads can be created from inside ractor (and, on CRuby, sharing GVL with other threads of this ractor).

r = Ractor.new do
  a = 1
  Thread.new {puts "Thread in ractor: a=#{a}"}.join
end
r.take
# Here "Thread in ractor: a=1" will be printed

Note on code examples

In examples below, sometimes we use the following method to wait till ractors that are not currently blocked will finish (or process till next blocking) method.

def wait
  sleep(0.1)
end

It is **only for demonstration purposes** and shouldn’t be used in a real code. Most of the times, just take is used to wait till ractor will finish.

Reference

See Ractor design doc for more details.

Raised when given an invalid regexp expression.

Regexp.new("?")

raises the exception:

RegexpError: target of repeat operator is not specified: /?/

Raised when an invalid operation is attempted on a thread.

For example, when no other thread has been started:

Thread.stop

This will raises the following exception:

ThreadError: stopping only thread
note: use sleep to stop forever
No documentation available
No documentation available

Cleared reference exception

This exception is raised if a generator or unparser error occurs.

Response class for Request Header Fields Too Large responses (status code 431).

An individual header field is too large, or all the header fields collectively, are too large. See 431 Request Header Fields Too Large.

No documentation available
Search took: 2ms  ·  Total Results: 3094