stdlib/pstore/0/pstore.rbs in rbs-3.0.0.dev.2 vs stdlib/pstore/0/pstore.rbs in rbs-3.0.0.dev.3
- old
+ new
@@ -1,277 +1,492 @@
# <!-- rdoc-file=lib/pstore.rb -->
-# PStore implements a file based persistence mechanism based on a Hash. User
-# code can store hierarchies of Ruby objects (values) into the data store file
-# 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.
+# 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
+# Marshal. That carries the usual limitations. Proc objects cannot be
# marshalled, for example.
#
-# ## Usage example:
+# There are three important concepts here (details at the links):
#
+# * [Store](rdoc-ref:PStore@The+Store): a store is an instance of PStore.
+# * [Entries](rdoc-ref:PStore@Entries): the store is hash-like; each entry is
+# the key for a stored object.
+# * [Transactions](rdoc-ref:PStore@Transactions): each transaction is a
+# collection of prospective changes to the store; a transaction is defined
+# in the block given with a call to PStore#transaction.
+#
+#
+# ## 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](rdoc-ref:Marshal.dump).
+#
+# ## Entries
+#
+# A store may have any number of entries. Each entry has a key and a value, just
+# as in a hash:
+#
+# * Key: as in a hash, the key can be (almost) any object; see [Hash
+# Keys](rdoc-ref:Hash@Hash+Keys). You may find it convenient to keep it
+# simple by using only symbols or strings as keys.
+# * Value: the value may be any object that can be marshalled by Marshal (see
+# [Marshal::dump](rdoc-ref:Marshal.dump)) and in fact may be a collection
+# (e.g., an array, a hash, a set, a range, etc). That collection may in turn
+# contain nested objects, including collections, to any depth; those objects
+# must also be Marshal-able. See [Hierarchical
+# Values](rdoc-ref:PStore@Hierarchical+Values).
+#
+#
+# ## 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:
+#
+# * May not contain a nested call to #transaction.
+# * Is the only context where methods that read from or write to the store are
+# allowed.
+#
+#
+# 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.
+#
+# * Method #commit triggers the update to the store and exits the block:
+#
+# example_store do |store|
+# store.transaction do
+# store.keys # => [:foo, :bar, :baz]
+# store[:bat] = 3
+# store.commit
+# fail 'Cannot get here'
+# end
+# store.transaction do
+# # Update was completed.
+# store.keys # => [:foo, :bar, :baz, :bat]
+# end
+# end
+#
+# * Method #abort discards the update to the store and exits the block:
+#
+# example_store do |store|
+# store.transaction do
+# store.keys # => [:foo, :bar, :baz]
+# store[:bat] = 3
+# store.abort
+# fail 'Cannot get here'
+# end
+# store.transaction do
+# # Update was not completed.
+# store.keys # => [:foo, :bar, :baz]
+# end
+# end
+#
+#
+# ### 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](rdoc-ref:dig_methods.rdoc) 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:
+#
+# * Optional argument `thread_safe` at method PStore.new.
+# * Attribute #ultra_safe.
+#
+#
+# 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...
+# # A mock wiki object.
# class WikiPage
-# def initialize( page_name, author, contents )
+#
+# attr_reader :page_name
+#
+# def initialize(page_name, author, contents)
# @page_name = page_name
# @revisions = Array.new
-#
# add_revision(author, contents)
# end
#
-# attr_reader :page_name
-#
-# def add_revision( author, contents )
-# @revisions << { :created => Time.now,
-# :author => author,
-# :contents => contents }
+# 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 page...
-# home_page = WikiPage.new( "HomePage", "James Edward Gray II",
-# "A page about the JoysOfDocumentation..." )
+# # Create a new wiki page.
+# home_page = WikiPage.new("HomePage", "James Edward Gray II",
+# "A page about the JoysOfDocumentation..." )
#
-# # then we want to update page data and the index together, or not at all...
# wiki = PStore.new("wiki_pages.pstore")
-# wiki.transaction do # begin transaction; do all of this or none of it
-# # store page...
+# # Update page data and the index together, or not at all.
+# wiki.transaction do
+# # Store page.
# wiki[home_page.page_name] = home_page
-# # ensure that an index has been created...
+# # Create page index.
# wiki[:wiki_index] ||= Array.new
-# # update wiki index...
+# # Update wiki index.
# wiki[:wiki_index].push(*home_page.wiki_page_references)
-# end # commit changes to wiki data store file
+# end
#
-# ### Some time later... ###
-#
-# # read wiki data...
-# wiki.transaction(true) do # begin read-only transaction, no changes allowed
-# wiki.roots.each do |data_root_name|
-# p data_root_name
-# p wiki[data_root_name]
+# # 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
#
-# ## Transaction modes
-#
-# By default, file integrity is only ensured as long as the operating system
-# (and the underlying hardware) doesn't raise any unexpected I/O errors. If an
-# I/O error occurs while PStore is writing to its file, then the file will
-# become corrupted.
-#
-# You can prevent this by setting *pstore.ultra_safe = true*. However, this
-# results in a minor performance loss, and only works on platforms that support
-# atomic file renames. Please consult the documentation for `ultra_safe` for
-# details.
-#
-# Needless to say, if you're storing valuable data with PStore, then you should
-# backup the PStore files from time to time.
-#
class PStore
public
# <!--
# rdoc-file=lib/pstore.rb
- # - [](name)
+ # - [](key)
# -->
- # Retrieves a value from the PStore file data, by *name*. The hierarchy of Ruby
- # objects stored under that root *name* will be returned.
+ # Returns the value for the given `key` if the key exists. `nil` otherwise; if
+ # not `nil`, the returned value is an object or a hierarchy of objects:
#
- # **WARNING**: This method is only valid in a PStore#transaction. It will
- # raise PStore::Error if called at any other time.
+ # example_store do |store|
+ # store.transaction do
+ # store[:foo] # => 0
+ # store[:nope] # => nil
+ # end
+ # end
#
+ # Returns `nil` if there is no such key.
+ #
+ # See also [Hierarchical Values](rdoc-ref:PStore@Hierarchical+Values).
+ #
+ # Raises an exception if called outside a transaction block.
+ #
def []: (untyped name) -> untyped
# <!--
# rdoc-file=lib/pstore.rb
- # - []=(name, value)
+ # - []=(key, value)
# -->
- # Stores an individual Ruby object or a hierarchy of Ruby objects in the data
- # store file under the root *name*. Assigning to a *name* already in the data
- # store clobbers the old data.
+ # Creates or replaces the value for the given `key`:
#
- # ## Example:
+ # example_store do |store|
+ # temp.transaction do
+ # temp[:bat] = 3
+ # end
+ # end
#
- # require "pstore"
+ # See also [Hierarchical Values](rdoc-ref:PStore@Hierarchical+Values).
#
- # store = PStore.new("data_file.pstore")
- # store.transaction do # begin transaction
- # # load some data into the store...
- # store[:single_object] = "My data..."
- # store[:obj_hierarchy] = { "Kev Jackson" => ["rational.rb", "pstore.rb"],
- # "James Gray" => ["erb.rb", "pstore.rb"] }
- # end # commit changes to data store file
+ # Raises an exception if called outside a transaction block.
#
- # **WARNING**: This method is only valid in a PStore#transaction and it cannot
- # be read-only. It will raise PStore::Error if called at any other time.
- #
def []=: (untyped name, untyped value) -> untyped
# <!--
# rdoc-file=lib/pstore.rb
# - abort()
# -->
- # Ends the current PStore#transaction, discarding any changes to the data store.
+ # Exits the current transaction block, discarding any changes specified in the
+ # transaction block. See [Committing or
+ # Aborting](rdoc-ref:PStore@Committing+or+Aborting).
#
- # ## Example:
+ # Raises an exception if called outside a transaction block.
#
- # require "pstore"
- #
- # store = PStore.new("data_file.pstore")
- # store.transaction do # begin transaction
- # store[:one] = 1 # this change is not applied, see below...
- # store[:two] = 2 # this change is not applied, see below...
- #
- # store.abort # end transaction here, discard all changes
- #
- # store[:three] = 3 # this change is never reached
- # end
- #
- # **WARNING**: This method is only valid in a PStore#transaction. It will
- # raise PStore::Error if called at any other time.
- #
def abort: () -> untyped
# <!--
# rdoc-file=lib/pstore.rb
# - commit()
# -->
- # Ends the current PStore#transaction, committing any changes to the data store
- # immediately.
+ # Exits the current transaction block, committing any changes specified in the
+ # transaction block. See [Committing or
+ # Aborting](rdoc-ref:PStore@Committing+or+Aborting).
#
- # ## Example:
+ # Raises an exception if called outside a transaction block.
#
- # require "pstore"
- #
- # store = PStore.new("data_file.pstore")
- # store.transaction do # begin transaction
- # # load some data into the store...
- # store[:one] = 1
- # store[:two] = 2
- #
- # store.commit # end transaction here, committing changes
- #
- # store[:three] = 3 # this change is never reached
- # end
- #
- # **WARNING**: This method is only valid in a PStore#transaction. It will
- # raise PStore::Error if called at any other time.
- #
def commit: () -> nil
# <!--
# rdoc-file=lib/pstore.rb
- # - delete(name)
+ # - delete(key)
# -->
- # Removes an object hierarchy from the data store, by *name*.
+ # Removes and returns the value at `key` if it exists:
#
- # **WARNING**: This method is only valid in a PStore#transaction and it cannot
- # be read-only. It will raise PStore::Error if called at any other time.
+ # example_store do |store|
+ # store.transaction do
+ # store[:bat] = 3
+ # store.delete(:bat)
+ # end
+ # end
#
+ # Returns `nil` if there is no such key.
+ #
+ # Raises an exception if called outside a transaction block.
+ #
def delete: (untyped name) -> untyped
# <!--
# rdoc-file=lib/pstore.rb
- # - fetch(name, default=PStore::Error)
+ # - fetch(key, default=PStore::Error)
# -->
- # This method is just like PStore#[], save that you may also provide a *default*
- # value for the object. In the event the specified *name* is not found in the
- # data store, your *default* will be returned instead. If you do not specify a
- # default, PStore::Error will be raised if the object is not found.
+ # Like #[], except that it accepts a default value for the store. If the `key`
+ # does not exist:
#
- # **WARNING**: This method is only valid in a PStore#transaction. It will
- # raise PStore::Error if called at any other time.
+ # * Raises an exception if `default` is `PStore::Error`.
+ # * Returns the value of `default` otherwise:
#
+ # example_store do |store|
+ # store.transaction do
+ # store.fetch(:nope, nil) # => nil
+ # store.fetch(:nope) # Raises an exception.
+ # end
+ # end
+ #
+ #
+ # Raises an exception if called outside a transaction block.
+ #
def fetch: (untyped name, ?untyped default) -> untyped
# <!--
# rdoc-file=lib/pstore.rb
# - path()
# -->
- # Returns the path to the data store file.
+ # Returns the string file path used to create the store:
#
+ # store.path # => "flat.store"
+ #
def path: () -> untyped
# <!--
# rdoc-file=lib/pstore.rb
- # - root?(name)
+ # - root?(key)
# -->
- # Returns true if the supplied *name* is currently in the data store.
#
- # **WARNING**: This method is only valid in a PStore#transaction. It will
- # raise PStore::Error if called at any other time.
- #
def root?: (untyped name) -> bool
# <!--
# rdoc-file=lib/pstore.rb
# - roots()
# -->
- # Returns the names of all object hierarchies currently in the store.
#
- # **WARNING**: This method is only valid in a PStore#transaction. It will
- # raise PStore::Error if called at any other time.
- #
def roots: () -> Array[untyped]
# <!--
# rdoc-file=lib/pstore.rb
# - transaction(read_only = false) { |pstore| ... }
# -->
- # Opens a new transaction for the data store. Code executed inside a block
- # passed to this method may read and write data to and from the data store file.
+ # Opens a transaction block for the store. See
+ # [Transactions](rdoc-ref:PStore@Transactions).
#
- # At the end of the block, changes are committed to the data store
- # automatically. You may exit the transaction early with a call to either
- # PStore#commit or PStore#abort. See those methods for details about how
- # changes are handled. Raising an uncaught Exception in the block is equivalent
- # to calling PStore#abort.
+ # With argument `read_only` as `false`, the block may both read from and write
+ # to the store.
#
- # If *read_only* is set to `true`, you will only be allowed to read from the
- # data store during the transaction and any attempts to change the data will
- # raise a PStore::Error.
+ # With argument `read_only` as `true`, the block may not include calls to
+ # #transaction, #[]=, or #delete.
#
- # Note that PStore does not support nested transactions.
+ # Raises an exception if called within a transaction block.
#
def transaction: (?untyped read_only) -> untyped
# <!-- rdoc-file=lib/pstore.rb -->
- # Whether PStore should do its best to prevent file corruptions, even when under
- # unlikely-to-occur error conditions such as out-of-space conditions and other
- # unusual OS filesystem errors. Setting this flag comes at the price in the form
- # of a performance loss.
+ # Whether PStore should do its best to prevent file corruptions, even when an
+ # unlikely error (such as memory-error or filesystem error) occurs:
#
- # This flag only has effect on platforms on which file renames are atomic (e.g.
- # all POSIX platforms: Linux, MacOS X, FreeBSD, etc). The default value is
- # false.
+ # * `true`: changes are posted by creating a temporary file, writing the
+ # updated data to it, then renaming the file to the given #path. File
+ # integrity is maintained. Note: has effect only if the filesystem has
+ # atomic file rename (as do POSIX platforms Linux, MacOS, FreeBSD and
+ # others).
#
+ # * `false` (the default): changes are posted by rewinding the open file and
+ # writing the updated data. File integrity is maintained if the filesystem
+ # raises no unexpected I/O error; if such an error occurs during a write to
+ # the store, the file may become corrupted.
+ #
def ultra_safe: () -> untyped
# <!-- rdoc-file=lib/pstore.rb -->
- # Whether PStore should do its best to prevent file corruptions, even when under
- # unlikely-to-occur error conditions such as out-of-space conditions and other
- # unusual OS filesystem errors. Setting this flag comes at the price in the form
- # of a performance loss.
+ # Whether PStore should do its best to prevent file corruptions, even when an
+ # unlikely error (such as memory-error or filesystem error) occurs:
#
- # This flag only has effect on platforms on which file renames are atomic (e.g.
- # all POSIX platforms: Linux, MacOS X, FreeBSD, etc). The default value is
- # false.
+ # * `true`: changes are posted by creating a temporary file, writing the
+ # updated data to it, then renaming the file to the given #path. File
+ # integrity is maintained. Note: has effect only if the filesystem has
+ # atomic file rename (as do POSIX platforms Linux, MacOS, FreeBSD and
+ # others).
#
+ # * `false` (the default): changes are posted by rewinding the open file and
+ # writing the updated data. File integrity is maintained if the filesystem
+ # raises no unexpected I/O error; if such an error occurs during a write to
+ # the store, the file may become corrupted.
+ #
def ultra_safe=: (untyped) -> untyped
private
def dump: (untyped table) -> untyped
@@ -309,14 +524,23 @@
# <!--
# rdoc-file=lib/pstore.rb
# - new(file, thread_safe = false)
# -->
- # To construct a PStore object, pass in the *file* path where you would like the
- # data to be stored.
+ # Returns a new PStore object.
#
- # PStore objects are always reentrant. But if *thread_safe* is set to true, then
- # it will become thread-safe at the cost of a minor performance hit.
+ # Argument `file` is the path to the file in which objects are to be stored; if
+ # the file exists, it should be one that was written by PStore.
+ #
+ # path = 't.store'
+ # store = PStore.new(path)
+ #
+ # A PStore object is
+ # [reentrant](https://en.wikipedia.org/wiki/Reentrancy_(computing)). If argument
+ # `thread_safe` is given as `true`, the object is also thread-safe (at the cost
+ # of a small performance penalty):
+ #
+ # store = PStore.new(path, true)
#
def initialize: (untyped file, ?boolish thread_safe) -> untyped
def load: (untyped content) -> untyped