Results for: "to_proc"

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 given an invalid regexp expression.

Regexp.new("?")

raises the exception:

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

ThreadGroup provides a means of keeping track of a number of threads as a group.

A given Thread object can only belong to one ThreadGroup at a time; adding a thread to a new group will remove it from any previous group.

Newly created threads belong to the same group as the thread from which they were created.

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

The exception class which will be raised when pushing into a closed Queue. See Thread::Queue#close and Thread::SizedQueue#close.

No documentation available

The Prism Ruby parser.

“Parsing Ruby is suddenly manageable!”

- You, hopefully

This file is generated by the templates/template.rb script and should not be modified manually. See templates/lib/prism/compiler.rb.erb if you are looking to modify the template

This file is generated by the templates/template.rb script and should not be modified manually. See templates/lib/prism/dispatcher.rb.erb if you are looking to modify the template

This file is generated by the templates/template.rb script and should not be modified manually. See templates/lib/prism/dsl.rb.erb if you are looking to modify the template

This file is generated by the templates/template.rb script and should not be modified manually. See templates/lib/prism/mutation_compiler.rb.erb if you are looking to modify the template

This file is generated by the templates/template.rb script and should not be modified manually. See templates/lib/prism/node.rb.erb if you are looking to modify the template

Here we are reopening the prism module to provide methods on nodes that aren’t templated and are meant as convenience methods.

This file is generated by the templates/template.rb script and should not be modified manually. See templates/lib/prism/visitor.rb.erb if you are looking to modify the template

No documentation available
No documentation available

Represents assigning to a constant using an operator that isn’t ‘=`.

Target += value
^^^^^^^^^^^^^^^

OCSP error class.

Raised when an operation would resize or re-allocate a locked buffer.

Raised when the buffer cannot be allocated for some reason, or you try to use a buffer that’s not allocated.

Class for representing WebDAV method PROPFIND:

require 'net/http'
uri = URI('http://example.com')
hostname = uri.hostname # => "example.com"
req = Net::HTTP::Propfind.new(uri) # => #<Net::HTTP::Propfind PROPFIND>
res = Net::HTTP.start(hostname) do |http|
  http.request(req)
end

See Request Headers.

Related:

Class for representing WebDAV method PROPPATCH:

require 'net/http'
uri = URI('http://example.com')
hostname = uri.hostname # => "example.com"
req = Net::HTTP::Proppatch.new(uri) # => #<Net::HTTP::Proppatch PROPPATCH>
res = Net::HTTP.start(hostname) do |http|
  http.request(req)
end

See Request Headers.

Related:

An absolutely silent progress reporter.

A basic dotted progress reporter.

A progress reporter that prints out messages about the current progress.

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

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!

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

Class GetoptLong provides parsing both for options and for regular arguments.

Using GetoptLong, you can define options for your program. The program can then capture and respond to whatever options are included in the command that executes the program.

A simple example: file simple.rb:

require 'getoptlong'

options = GetoptLong.new(
  ['--number', '-n', GetoptLong::REQUIRED_ARGUMENT],
  ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
  ['--help', '-h', GetoptLong::NO_ARGUMENT]
)

If you are somewhat familiar with options, you may want to skip to this full example.

Options

A GetoptLong option has:

Options may be defined by calling singleton method GetoptLong.new, which returns a new GetoptLong object. Options may then be processed by calling other methods such as GetoptLong#each.

Option Name and Aliases

In the array that defines an option, the first element is the string option name. Often the name takes the ‘long’ form, beginning with two hyphens.

The option name may have any number of aliases, which are defined by additional string elements.

The name and each alias must be of one of two forms:

File aliases.rb:

require 'getoptlong'

options = GetoptLong.new(
  ['--xxx', '-x', '--aaa', '-a', '-p', GetoptLong::NO_ARGUMENT]
)
options.each do |option, argument|
  p [option, argument]
end

An option may be cited by its name, or by any of its aliases; the parsed option always reports the name, not an alias:

$ ruby aliases.rb -a -p --xxx --aaa -x

Output:

["--xxx", ""]
["--xxx", ""]
["--xxx", ""]
["--xxx", ""]
["--xxx", ""]

An option may also be cited by an abbreviation of its name or any alias, as long as that abbreviation is unique among the options.

File abbrev.rb:

require 'getoptlong'

options = GetoptLong.new(
  ['--xxx', GetoptLong::NO_ARGUMENT],
  ['--xyz', GetoptLong::NO_ARGUMENT]
)
options.each do |option, argument|
  p [option, argument]
end

Command line:

$ ruby abbrev.rb --xxx --xx --xyz --xy

Output:

["--xxx", ""]
["--xxx", ""]
["--xyz", ""]
["--xyz", ""]

This command line raises GetoptLong::AmbiguousOption:

$ ruby abbrev.rb --x

Repetition

An option may be cited more than once:

$ ruby abbrev.rb --xxx --xyz --xxx --xyz

Output:

["--xxx", ""]
["--xyz", ""]
["--xxx", ""]
["--xyz", ""]

Treating Remaining Options as Arguments

A option-like token that appears anywhere after the token -- is treated as an ordinary argument, and is not processed as an option:

$ ruby abbrev.rb --xxx --xyz -- --xxx --xyz

Output:

["--xxx", ""]
["--xyz", ""]

Option Types

Each option definition includes an option type, which controls whether the option takes an argument.

File types.rb:

require 'getoptlong'

options = GetoptLong.new(
  ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
  ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
  ['--zzz', GetoptLong::NO_ARGUMENT]
)
options.each do |option, argument|
  p [option, argument]
end

Note that an option type has to do with the option argument (whether it is required, optional, or forbidden), not with whether the option itself is required.

Option with Required Argument

An option of type GetoptLong::REQUIRED_ARGUMENT must be followed by an argument, which is associated with that option:

$ ruby types.rb --xxx foo

Output:

["--xxx", "foo"]

If the option is not last, its argument is whatever follows it (even if the argument looks like another option):

$ ruby types.rb --xxx --yyy

Output:

["--xxx", "--yyy"]

If the option is last, an exception is raised:

$ ruby types.rb
# Raises GetoptLong::MissingArgument

Option with Optional Argument

An option of type GetoptLong::OPTIONAL_ARGUMENT may be followed by an argument, which if given is associated with that option.

If the option is last, it does not have an argument:

$ ruby types.rb --yyy

Output:

["--yyy", ""]

If the option is followed by another option, it does not have an argument:

$ ruby types.rb --yyy --zzz

Output:

["--yyy", ""]
["--zzz", ""]

Otherwise the option is followed by its argument, which is associated with that option:

$ ruby types.rb --yyy foo

Output:

["--yyy", "foo"]

Option with No Argument

An option of type GetoptLong::NO_ARGUMENT takes no argument:

ruby types.rb --zzz foo

Output:

["--zzz", ""]

ARGV

You can process options either with method each and a block, or with method get.

During processing, each found option is removed, along with its argument if there is one. After processing, each remaining element was neither an option nor the argument for an option.

File argv.rb:

require 'getoptlong'

options = GetoptLong.new(
  ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
  ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
  ['--zzz', GetoptLong::NO_ARGUMENT]
)
puts "Original ARGV: #{ARGV}"
options.each do |option, argument|
  p [option, argument]
end
puts "Remaining ARGV: #{ARGV}"

Command line:

$ ruby argv.rb --xxx Foo --yyy Bar Baz --zzz Bat Bam

Output:

Original ARGV: ["--xxx", "Foo", "--yyy", "Bar", "Baz", "--zzz", "Bat", "Bam"]
["--xxx", "Foo"]
["--yyy", "Bar"]
["--zzz", ""]
Remaining ARGV: ["Baz", "Bat", "Bam"]

Ordering

There are three settings that control the way the options are interpreted:

The initial setting for a new GetoptLong object is REQUIRE_ORDER if environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise.

PERMUTE Ordering

In the PERMUTE ordering, options and other, non-option, arguments may appear in any order and any mixture.

File permute.rb:

require 'getoptlong'

options = GetoptLong.new(
  ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
  ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
  ['--zzz', GetoptLong::NO_ARGUMENT]
)
puts "Original ARGV: #{ARGV}"
options.each do |option, argument|
  p [option, argument]
end
puts "Remaining ARGV: #{ARGV}"

Command line:

$ ruby permute.rb Foo --zzz Bar --xxx Baz --yyy Bat Bam --xxx Bag Bah

Output:

Original ARGV: ["Foo", "--zzz", "Bar", "--xxx", "Baz", "--yyy", "Bat", "Bam", "--xxx", "Bag", "Bah"]
["--zzz", ""]
["--xxx", "Baz"]
["--yyy", "Bat"]
["--xxx", "Bag"]
Remaining ARGV: ["Foo", "Bar", "Bam", "Bah"]

REQUIRE_ORDER Ordering

In the REQUIRE_ORDER ordering, all options precede all non-options; that is, each word after the first non-option word is treated as a non-option word (even if it begins with a hyphen).

File require_order.rb:

require 'getoptlong'

options = GetoptLong.new(
  ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
  ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
  ['--zzz', GetoptLong::NO_ARGUMENT]
)
options.ordering = GetoptLong::REQUIRE_ORDER
puts "Original ARGV: #{ARGV}"
options.each do |option, argument|
  p [option, argument]
end
puts "Remaining ARGV: #{ARGV}"

Command line:

$ ruby require_order.rb --xxx Foo Bar --xxx Baz --yyy Bat -zzz

Output:

Original ARGV: ["--xxx", "Foo", "Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"]
["--xxx", "Foo"]
Remaining ARGV: ["Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"]

RETURN_IN_ORDER Ordering

In the RETURN_IN_ORDER ordering, every word is treated as an option. A word that begins with a hyphen (or two) is treated in the usual way; a word word that does not so begin is treated as an option whose name is an empty string, and whose value is word.

File return_in_order.rb:

require 'getoptlong'

options = GetoptLong.new(
  ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
  ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
  ['--zzz', GetoptLong::NO_ARGUMENT]
)
options.ordering = GetoptLong::RETURN_IN_ORDER
puts "Original ARGV: #{ARGV}"
options.each do |option, argument|
  p [option, argument]
end
puts "Remaining ARGV: #{ARGV}"

Command line:

$ ruby return_in_order.rb Foo --xxx Bar Baz --zzz Bat Bam

Output:

Original ARGV: ["Foo", "--xxx", "Bar", "Baz", "--zzz", "Bat", "Bam"]
["", "Foo"]
["--xxx", "Bar"]
["", "Baz"]
["--zzz", ""]
["", "Bat"]
["", "Bam"]
Remaining ARGV: []

Full Example

File fibonacci.rb:

require 'getoptlong'

options = GetoptLong.new(
  ['--number', '-n', GetoptLong::REQUIRED_ARGUMENT],
  ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
  ['--help', '-h', GetoptLong::NO_ARGUMENT]
)

def help(status = 0)
  puts <<~HELP
    Usage:

      -n n, --number n:
        Compute Fibonacci number for n.
      -v [boolean], --verbose [boolean]:
        Show intermediate results; default is 'false'.
      -h, --help:
        Show this help.
  HELP
  exit(status)
end

def print_fibonacci (number)
  return 0 if number == 0
  return 1 if number == 1 or number == 2
  i = 0
  j = 1
  (2..number).each do
    k = i + j
    i = j
    j = k
    puts j if @verbose
  end
  puts j unless @verbose
end

options.each do |option, argument|
  case option
  when '--number'
    @number = argument.to_i
  when '--verbose'
    @verbose = if argument.empty?
      true
    elsif argument.match(/true/i)
      true
    elsif argument.match(/false/i)
      false
    else
      puts '--verbose argument must be true or false'
      help(255)
    end
  when '--help'
    help
  end
end

unless @number
  puts 'Option --number is required.'
  help(255)
end

print_fibonacci(@number)

Command line:

$ ruby fibonacci.rb

Output:

Option --number is required.
Usage:

  -n n, --number n:
    Compute Fibonacci number for n.
  -v [boolean], --verbose [boolean]:
    Show intermediate results; default is 'false'.
  -h, --help:
    Show this help.

Command line:

$ ruby fibonacci.rb --number

Raises GetoptLong::MissingArgument:

fibonacci.rb: option `--number' requires an argument

Command line:

$ ruby fibonacci.rb --number 6

Output:

8

Command line:

$ ruby fibonacci.rb --number 6 --verbose

Output:

1
2
3
5
8

Command line:

$ ruby fibonacci.rb --number 6 --verbose yes

Output:

--verbose argument must be true or false
Usage:

  -n n, --number n:
    Compute Fibonacci number for n.
  -v [boolean], --verbose [boolean]:
    Show intermediate results; default is 'false'.
  -h, --help:
    Show this help.

PStore implements a file based persistence mechanism based on a Hash. User code can store hierarchies of Ruby objects (values) into the data store by name (keys). An object hierarchy may be just a single object. User code may later read values back from the data store or even update data, as needed.

The transactional behavior ensures that any changes succeed or fail together. This can be used to ensure that the data store is not left in a transitory state, where some values were updated but others were not.

Behind the scenes, Ruby objects are stored to the data store file with Marshal. That carries the usual limitations. Proc objects cannot be marshalled, for example.

There are three important concepts here (details at the links):

About the Examples

Examples on this page need a store that has known properties. They can get a new (and populated) store by calling thus:

example_store do |store|
  # Example code using store goes here.
end

All we really need to know about example_store is that it yields a fresh store with a known population of entries; its implementation:

require 'pstore'
require 'tempfile'
# Yield a pristine store for use in examples.
def example_store
  # Create the store in a temporary file.
  Tempfile.create do |file|
    store = PStore.new(file)
    # Populate the store.
    store.transaction do
      store[:foo] = 0
      store[:bar] = 1
      store[:baz] = 2
    end
    yield store
  end
end

The Store

The contents of the store are maintained in a file whose path is specified when the store is created (see PStore.new). The objects are stored and retrieved using module Marshal, which means that certain objects cannot be added to the store; see Marshal::dump.

Entries

A store may have any number of entries. Each entry has a key and a value, just as in a hash:

Transactions

The Transaction Block

The block given with a call to method transaction# contains a transaction, which consists of calls to PStore methods that read from or write to the store (that is, all PStore methods except transaction itself, path, and Pstore.new):

example_store do |store|
  store.transaction do
    store.keys # => [:foo, :bar, :baz]
    store[:bat] = 3
    store.keys # => [:foo, :bar, :baz, :bat]
  end
end

Execution of the transaction is deferred until the block exits, and is executed atomically (all-or-nothing): either all transaction calls are executed, or none are. This maintains the integrity of the store.

Other code in the block (including even calls to path and PStore.new) is executed immediately, not deferred.

The transaction block:

As seen above, changes in a transaction are made automatically when the block exits. The block may be exited early by calling method commit or abort.

Read-Only Transactions

By default, a transaction allows both reading from and writing to the store:

store.transaction do
  # Read-write transaction.
  # Any code except a call to #transaction is allowed here.
end

If argument read_only is passed as true, only reading is allowed:

store.transaction(true) do
  # Read-only transaction:
  # Calls to #transaction, #[]=, and #delete are not allowed here.
end

Hierarchical Values

The value for an entry may be a simple object (as seen above). It may also be a hierarchy of objects nested to any depth:

deep_store = PStore.new('deep.store')
deep_store.transaction do
  array_of_hashes = [{}, {}, {}]
  deep_store[:array_of_hashes] = array_of_hashes
  deep_store[:array_of_hashes] # => [{}, {}, {}]
  hash_of_arrays = {foo: [], bar: [], baz: []}
  deep_store[:hash_of_arrays] = hash_of_arrays
  deep_store[:hash_of_arrays]  # => {:foo=>[], :bar=>[], :baz=>[]}
  deep_store[:hash_of_arrays][:foo].push(:bat)
  deep_store[:hash_of_arrays]  # => {:foo=>[:bat], :bar=>[], :baz=>[]}
end

And recall that you can use dig methods in a returned hierarchy of objects.

Working with the Store

Creating a Store

Use method PStore.new to create a store. The new store creates or opens its containing file:

store = PStore.new('t.store')

Modifying the Store

Use method []= to update or create an entry:

example_store do |store|
  store.transaction do
    store[:foo] = 1 # Update.
    store[:bam] = 1 # Create.
  end
end

Use method delete to remove an entry:

example_store do |store|
  store.transaction do
    store.delete(:foo)
    store[:foo] # => nil
  end
end

Retrieving Values

Use method fetch (allows default) or [] (defaults to nil) to retrieve an entry:

example_store do |store|
  store.transaction do
    store[:foo]             # => 0
    store[:nope]            # => nil
    store.fetch(:baz)       # => 2
    store.fetch(:nope, nil) # => nil
    store.fetch(:nope)      # Raises exception.
  end
end

Querying the Store

Use method key? to determine whether a given key exists:

example_store do |store|
  store.transaction do
    store.key?(:foo) # => true
  end
end

Use method keys to retrieve keys:

example_store do |store|
  store.transaction do
    store.keys # => [:foo, :bar, :baz]
  end
end

Use method path to retrieve the path to the store’s underlying file; this method may be called from outside a transaction block:

store = PStore.new('t.store')
store.path # => "t.store"

Transaction Safety

For transaction safety, see:

Needless to say, if you’re storing valuable data with PStore, then you should backup the PStore file from time to time.

An Example Store

require "pstore"

# A mock wiki object.
class WikiPage

  attr_reader :page_name

  def initialize(page_name, author, contents)
    @page_name = page_name
    @revisions = Array.new
    add_revision(author, contents)
  end

  def add_revision(author, contents)
    @revisions << {created: Time.now,
                   author: author,
                   contents: contents}
  end

  def wiki_page_references
    [@page_name] + @revisions.last[:contents].scan(/\b(?:[A-Z]+[a-z]+){2,}/)
  end

end

# Create a new wiki page.
home_page = WikiPage.new("HomePage", "James Edward Gray II",
                         "A page about the JoysOfDocumentation..." )

wiki = PStore.new("wiki_pages.pstore")
# Update page data and the index together, or not at all.
wiki.transaction do
  # Store page.
  wiki[home_page.page_name] = home_page
  # Create page index.
  wiki[:wiki_index] ||= Array.new
  # Update wiki index.
  wiki[:wiki_index].push(*home_page.wiki_page_references)
end

# Read wiki data, setting argument read_only to true.
wiki.transaction(true) do
  wiki.keys.each do |key|
    puts key
    puts wiki[key]
  end
end
Search took: 6ms  ·  Total Results: 1894