ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  ¥2" ÿÄ     ÿÄ J    ! 1AQ"aq2‘#BR‚¡ÁÑ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3±ð#b¡ÿÚ   ? ¼QxJQaÍuò¸Zö Úü8,ÐÚú "SSn<rçù–´âE—^ªBÖ9À\†¸ÔÁT­ÃÛ5 ëd´³Í#Ý;Þ38œî ¶H£M:wÎ3…³…âpÔF&‚FK¸9„â4àGEõªfÿ ‘ñ(ßw­pŽF|È¥ù®häðÍѶ¹‘[ÒinÙW¶ùñY˜Q{›K"išÒ[Ú8žë\F¹@-?v"ÔU”,ìöžkÿ {I‡£šÍ?e ríV ?> ......................................... ............................................................................. ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  ¥2" ÿÄ     ÿÄ J    ! 1AQ"aq2‘#BR‚¡ÁÑ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3±ð#b¡ÿÚ   ? ¼QxJQaÍuò¸Zö Úü8,ÐÚú "SSn<rçù–´âE—^ªBÖ9À\†¸ÔÁT­ÃÛ5 ëd´³Í#Ý;Þ38œî ¶H£M:wÎ3…³…âpÔF&‚FK¸9„â4àGEõªfÿ ‘ñ(ßw­pŽF|È¥ù®häðÍѶ¹‘[ÒinÙW¶ùñY˜Q{›K"išÒ[Ú8žë\F¹@-?v"ÔU”,ìöžkÿ {I‡£šÍ?e ríV ?> ......................................... ............................................................................. ???????????????????????????????????? ???????????????????????????????????? ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  ¥2" ÿÄ     ÿÄ J    ! 1AQ"aq2‘#BR‚¡ÁÑ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3±ð#b¡ÿÚ   ? ¼QxJQaÍuò¸Zö Úü8,ÐÚú "SSn<rçù–´âE—^ªBÖ9À\†¸ÔÁT­ÃÛ5 ëd´³Í#Ý;Þ38œî ¶H£M:wÎ3…³…âpÔF&‚FK¸9„â4àGEõªfÿ ‘ñ(ßw­pŽF|È¥ù®häðÍѶ¹‘[ÒinÙW¶ùñY˜Q{›K"išÒ[Ú8žë\F¹@-?v"ÔU”,ìöžkÿ {I‡£šÍ?e ríV ?> ......................................... ............................................................................. ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  ¥2" ÿÄ     ÿÄ J    ! 1AQ"aq2‘#BR‚¡ÁÑ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3±ð#b¡ÿÚ   ? ¼QxJQaÍuò¸Zö Úü8,ÐÚú "SSn<rçù–´âE—^ªBÖ9À\†¸ÔÁT­ÃÛ5 ëd´³Í#Ý;Þ38œî ¶H£M:wÎ3…³…âpÔF&‚FK¸9„â4àGEõªfÿ ‘ñ(ßw­pŽF|È¥ù®häðÍѶ¹‘[ÒinÙW¶ùñY˜Q{›K"išÒ[Ú8žë\F¹@-?v"ÔU”,ìöžkÿ {I‡£šÍ?e ríV ?> ......................................... ............................................................................. ???????????????????????????????????? ???????????????????????????????????? U:RDoc::NormalClass[iI" PStore:ET@I" Object;To:RDoc::Markup::Document: @parts[o;;[ho:RDoc::Markup::Paragraph;[ I"L\PStore implements a file based persistence mechanism based on a Hash. ;TI">User code can store hierarchies of Ruby objects (values) ;TI")into the data store by name (keys). ;TI"6An object hierarchy may be just a single object. ;TI">User code may later read values back from the data store ;TI"$or even update data, as needed.;To:RDoc::Markup::BlankLineo; ;[I"SThe transactional behavior ensures that any changes succeed or fail together. ;TI"WThis can be used to ensure that the data store is not left in a transitory state, ;TI"8where some values were updated but others were not.;T@o; ;[I"UBehind the scenes, Ruby objects are stored to the data store file with Marshal. ;TI"LThat carries the usual limitations. Proc objects cannot be marshalled, ;TI"for example.;T@o; ;[I"DThere are three important concepts here (details at the links):;T@o:RDoc::Markup::List: @type: BULLET: @items[o:RDoc::Markup::ListItem: @label0;[o; ;[I"K{Store}[rdoc-ref:PStore@The+Store]: a store is an instance of \PStore.;To;;0;[o; ;[I"A{Entries}[rdoc-ref:PStore@Entries]: the store is hash-like; ;TI"/each entry is the key for a stored object.;To;;0;[o; ;[ I"T{Transactions}[rdoc-ref:PStore@Transactions]: each transaction is a collection ;TI"*of prospective changes to the store; ;TI"=a transaction is defined in the block given with a call ;TI"to PStore#transaction.;T@S:RDoc::Markup::Heading: leveli: textI"About the Examples;T@o; ;[I"CExamples on this page need a store that has known properties. ;TI">They can get a new (and populated) store by calling thus:;T@o:RDoc::Markup::Verbatim;[I"example_store do |store| ;TI"- # Example code using store goes here. ;TI" end ;T: @format0o; ;[I"6All we really need to know about +example_store+ ;TI"Iis that it yields a fresh store with a known population of entries; ;TI"its implementation:;T@o;;[I"require 'pstore' ;TI"require 'tempfile' ;TI"3# Yield a pristine store for use in examples. ;TI"def example_store ;TI"/ # Create the store in a temporary file. ;TI"! Tempfile.create do |file| ;TI"" store = PStore.new(file) ;TI" # Populate the store. ;TI" store.transaction do ;TI" store[:foo] = 0 ;TI" store[:bar] = 1 ;TI" store[:baz] = 2 ;TI" end ;TI" yield store ;TI" end ;TI" end ;T;0S;;i;I"The Store;T@o; ;[ I"PThe contents of the store are maintained in a file whose path is specified ;TI"1when the store is created (see PStore.new). ;TI"0The objects are stored and retrieved using ;TI"Tmodule Marshal, which means that certain objects cannot be added to the store; ;TI"0see {Marshal::dump}[rdoc-ref:Marshal.dump].;T@S;;i;I" Entries;T@o; ;[I"-A store may have any number of entries. ;TI"9Each entry has a key and a value, just as in a hash:;T@o; ; ; ;[o;;0;[o; ;[ I" [:foo, :bar, :baz] ;TI" store[:bat] = 3 ;TI"2 store.keys # => [:foo, :bar, :baz, :bat] ;TI" end ;TI" end ;T;0o; ;[ I"EExecution of the transaction is deferred until the block exits, ;TI"4and is executed _atomically_ (all-or-nothing): ;TI"=either all transaction calls are executed, or none are. ;TI"/This maintains the integrity of the store.;T@o; ;[I"LOther code in the block (including even calls to #path and PStore.new) ;TI"+is executed immediately, not deferred.;T@o; ;[I"The transaction block:;T@o; ; ; ;[o;;0;[o; ;[I"3May not contain a nested call to #transaction.;To;;0;[o; ;[I"BIs the only context where methods that read from or write to ;TI"the store are allowed.;T@o; ;[I"DAs seen above, changes in a transaction are made automatically ;TI"when the block exits. ;TI"GThe block may be exited early by calling method #commit or #abort.;T@o; ; ; ;[o;;0;[o; ;[I"IMethod #commit triggers the update to the store and exits the block:;T@o;;[I"example_store do |store| ;TI" store.transaction do ;TI", store.keys # => [:foo, :bar, :baz] ;TI" store[:bat] = 3 ;TI" store.commit ;TI" fail 'Cannot get here' ;TI" end ;TI" store.transaction do ;TI"! # Update was completed. ;TI"2 store.keys # => [:foo, :bar, :baz, :bat] ;TI" end ;TI" end ;T;0o;;0;[o; ;[I"HMethod #abort discards the update to the store and exits the block:;T@o;;[I"example_store do |store| ;TI" store.transaction do ;TI", store.keys # => [:foo, :bar, :baz] ;TI" store[:bat] = 3 ;TI" store.abort ;TI" fail 'Cannot get here' ;TI" end ;TI" store.transaction do ;TI"% # Update was not completed. ;TI", store.keys # => [:foo, :bar, :baz] ;TI" end ;TI" end ;T;0S;;i;I"Read-Only Transactions;T@o; ;[I"GBy default, a transaction allows both reading from and writing to ;TI"the store:;T@o;;[ I"store.transaction do ;TI"! # Read-write transaction. ;TI"A # Any code except a call to #transaction is allowed here. ;TI" end ;T;0o; ;[I"2If argument +read_only+ is passed as +true+, ;TI"only reading is allowed:;T@o;;[ I" store.transaction(true) do ;TI" # Read-only transaction: ;TI"H # Calls to #transaction, #[]=, and #delete are not allowed here. ;TI" end ;T;0S;;i;I"Hierarchical Values;T@o; ;[I"DThe value for an entry may be a simple object (as seen above). ;TI"?It may also be a hierarchy of objects nested to any depth:;T@o;;[I"+deep_store = PStore.new('deep.store') ;TI"deep_store.transaction do ;TI"& array_of_hashes = [{}, {}, {}] ;TI"6 deep_store[:array_of_hashes] = array_of_hashes ;TI"6 deep_store[:array_of_hashes] # => [{}, {}, {}] ;TI"4 hash_of_arrays = {foo: [], bar: [], baz: []} ;TI"4 deep_store[:hash_of_arrays] = hash_of_arrays ;TI"H deep_store[:hash_of_arrays] # => {:foo=>[], :bar=>[], :baz=>[]} ;TI"4 deep_store[:hash_of_arrays][:foo].push(:bat) ;TI"L deep_store[:hash_of_arrays] # => {:foo=>[:bat], :bar=>[], :baz=>[]} ;TI" end ;T;0o; ;[I"!And recall that you can use ;TI".{dig methods}[rdoc-ref:dig_methods.rdoc] ;TI"(in a returned hierarchy of objects.;T@S;;i;I"Working with the Store;T@S;;i;I"Creating a Store;T@o; ;[I".Use method PStore.new to create a store. ;TI"8The new store creates or opens its containing file:;T@o;;[I"#store = PStore.new('t.store') ;T;0S;;i;I"Modifying the Store;T@o; ;[I"2Use method #[]= to update or create an entry:;T@o;;[ I"example_store do |store| ;TI" store.transaction do ;TI"# store[:foo] = 1 # Update. ;TI"# store[:bam] = 1 # Create. ;TI" end ;TI" end ;T;0o; ;[I"+Use method #delete to remove an entry:;T@o;;[ I"example_store do |store| ;TI" store.transaction do ;TI" store.delete(:foo) ;TI" store[:foo] # => nil ;TI" end ;TI" end ;T;0S;;i;I"Retrieving Values;T@o; ;[I"CUse method #fetch (allows default) or #[] (defaults to +nil+) ;TI"to retrieve an entry:;T@o;;[I"example_store do |store| ;TI" store.transaction do ;TI"( store[:foo] # => 0 ;TI"* store[:nope] # => nil ;TI"( store.fetch(:baz) # => 2 ;TI"* store.fetch(:nope, nil) # => nil ;TI"5 store.fetch(:nope) # Raises exception. ;TI" end ;TI" end ;T;0S;;i;I"Querying the Store;T@o; ;[I">Use method #key? to determine whether a given key exists:;T@o;;[ I"example_store do |store| ;TI" store.transaction do ;TI"$ store.key?(:foo) # => true ;TI" end ;TI" end ;T;0o; ;[I"'Use method #keys to retrieve keys:;T@o;;[ I"example_store do |store| ;TI" store.transaction do ;TI", store.keys # => [:foo, :bar, :baz] ;TI" end ;TI" end ;T;0o; ;[I"KUse method #path to retrieve the path to the store's underlying file; ;TI"@this method may be called from outside a transaction block:;T@o;;[I"#store = PStore.new('t.store') ;TI"store.path # => "t.store" ;T;0S;;i;I"Transaction Safety;T@o; ;[I"!For transaction safety, see:;T@o; ; ; ;[o;;0;[o; ;[I":Optional argument +thread_safe+ at method PStore.new.;To;;0;[o; ;[I"Attribute #ultra_safe.;T@o; ;[I"TNeedless to say, if you're storing valuable data with \PStore, then you should ;TI"/backup the \PStore file from time to time.;T@S;;i;I"An Example Store;T@o;;[4I"require "pstore" ;TI" ;TI"# A mock wiki object. ;TI"class WikiPage ;TI" ;TI" attr_reader :page_name ;TI" ;TI"3 def initialize(page_name, author, contents) ;TI" @page_name = page_name ;TI" @revisions = Array.new ;TI"( add_revision(author, contents) ;TI" end ;TI" ;TI"* def add_revision(author, contents) ;TI"+ @revisions << {created: Time.now, ;TI"( author: author, ;TI", contents: contents} ;TI" end ;TI" ;TI" def wiki_page_references ;TI"R [@page_name] + @revisions.last[:contents].scan(/\b(?:[A-Z]+[a-z]+){2,}/) ;TI" end ;TI" ;TI" end ;TI" ;TI"# Create a new wiki page. ;TI"Bhome_page = WikiPage.new("HomePage", "James Edward Gray II", ;TI"J "A page about the JoysOfDocumentation..." ) ;TI" ;TI",wiki = PStore.new("wiki_pages.pstore") ;TI"?# Update page data and the index together, or not at all. ;TI"wiki.transaction do ;TI" # Store page. ;TI"- wiki[home_page.page_name] = home_page ;TI" # Create page index. ;TI"' wiki[:wiki_index] ||= Array.new ;TI" # Update wiki index. ;TI"? wiki[:wiki_index].push(*home_page.wiki_page_references) ;TI" end ;TI" ;TI";# Read wiki data, setting argument read_only to true. ;TI"wiki.transaction(true) do ;TI" wiki.keys.each do |key| ;TI" puts key ;TI" puts wiki[key] ;TI" end ;TI"end;T;0: @fileI"lib/pstore.rb;T:0@omit_headings_from_table_of_contents_below0;0;0[[ I"ultra_safe;TI"RW;T: publicFI"lib/pstore.rb;T[ U:RDoc::Constant[iI" VERSION;TI"PStore::VERSION;T;0o;;[;@;0@@cRDoc::NormalClass0U;[iI"RDWR_ACCESS;TI"PStore::RDWR_ACCESS;T;0o;;[;@;0@@@0U;[iI"RD_ACCESS;TI"PStore::RD_ACCESS;T;0o;;[;@;0@@@0U;[iI"WR_ACCESS;TI"PStore::WR_ACCESS;T;0o;;[;@;0@@@0U;[iI"CHECKSUM_ALGO;TI"PStore::CHECKSUM_ALGO;T;0o;;[o; ;[I"5Constant for relieving Ruby's garbage collector.;T;@;0@@@0U;[iI"EMPTY_STRING;TI"PStore::EMPTY_STRING;T;0o;;[;@;0@@@0U;[iI"EMPTY_MARSHAL_DATA;TI"PStore::EMPTY_MARSHAL_DATA;T;0o;;[;@;0@@@0U;[iI"EMPTY_MARSHAL_CHECKSUM;TI"#PStore::EMPTY_MARSHAL_CHECKSUM;T;0o;;[;@;0@@@0[[[I" class;T[[;[[I"new;T@[:protected[[: private[[I" instance;T[[;[[I"[];T@[I"[]=;T@[I" abort;T@[I" commit;T@[I" delete;T@[I" fetch;T@[I" key?;T@[I" keys;T@[I" path;T@[I" root?;T@[I" roots;T@[I"transaction;T@[;[[;[[I"empty_marshal_checksum;T@[I"empty_marshal_data;T@[I"in_transaction;T@[I"in_transaction_wr;T@[I"load_data;T@[I"on_windows?;T@[I"open_and_lock_file;T@[I"save_data;T@[I"/save_data_with_atomic_file_rename_strategy;T@[I"!save_data_with_fast_strategy;T@[[U:RDoc::Context::Section[i0o;;[;0;0[@@cRDoc::TopLevel