pstore 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3de8bbd117d11303d2372e9fd0b9db5a15fb4d6b566905101e70689cd82fbe4d
4
- data.tar.gz: bbab746d38d3e6fc07bfaf54235bcb6e34727a2a20ae586620064a16de834dc2
3
+ metadata.gz: 4ca86b8693a69b67fa1864f055fb547d881d62979a047a7fa24e43aa0688cc01
4
+ data.tar.gz: b4af87cbe5e36edcf852c5465e686e477cb8ae301cd00c4dd8a38f56aa23f6e2
5
5
  SHA512:
6
- metadata.gz: 4a4f1df2cafeee50e8c82a1755e8f0836f7c2b685f5372df1461cdac183d43cf3ad19b1dfa9a516ab3698e0ad1837f050be0e86b1b4944dbd5d3c625665f2b5d
7
- data.tar.gz: f2b9d2cb5172cc4e09eba1ae2ec499bce9972b54028e0b89e6d26e6f66f16918254d3d643dc49d4caed17fe45ffc3278737431864de1d9a87bc429bf4c345c5b
6
+ metadata.gz: 8f87e2b27466bcb3dfb2b910b1fb2fafcec06beef6d4aa49c9dad2acdf170c9d5db8631b9c08097b97334ec3797043c89b96b138c363805205407d0cc0b08590
7
+ data.tar.gz: 0efcfca9e94dae981be03cfd191265d10c348241b243c2fd7f7ae0fa07b63781ddcf70853dea07889294fd85794fbbc34f7b00b2de67de2b16950b882fe302f2
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'github-actions'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
@@ -0,0 +1,22 @@
1
+ name: test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
+ strategy:
9
+ matrix:
10
+ ruby: [ 2.7, 2.6, 2.5, 2.4, head ]
11
+ os: [ ubuntu-latest, macos-latest ]
12
+ runs-on: ${{ matrix.os }}
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: bundle install
21
+ - name: Run test
22
+ run: rake test
data/Rakefile CHANGED
@@ -7,4 +7,11 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.test_files = FileList["test/**/test_*.rb"]
8
8
  end
9
9
 
10
+ task :sync_tool do
11
+ require 'fileutils'
12
+ FileUtils.cp "../ruby/tool/lib/core_assertions.rb", "./test/lib"
13
+ FileUtils.cp "../ruby/tool/lib/envutil.rb", "./test/lib"
14
+ FileUtils.cp "../ruby/tool/lib/find_executable.rb", "./test/lib"
15
+ end
16
+
10
17
  task :default => :test
data/lib/pstore.rb CHANGED
@@ -10,88 +10,324 @@
10
10
 
11
11
  require "digest"
12
12
 
13
- #
14
- # PStore implements a file based persistence mechanism based on a Hash. User
15
- # code can store hierarchies of Ruby objects (values) into the data store file
16
- # by name (keys). An object hierarchy may be just a single object. User code
17
- # may later read values back from the data store or even update data, as needed.
13
+ # \PStore implements a file based persistence mechanism based on a Hash.
14
+ # User code can store hierarchies of Ruby objects (values)
15
+ # into the data store by name (keys).
16
+ # An object hierarchy may be just a single object.
17
+ # User code may later read values back from the data store
18
+ # or even update data, as needed.
18
19
  #
19
20
  # The transactional behavior ensures that any changes succeed or fail together.
20
- # This can be used to ensure that the data store is not left in a transitory
21
- # state, where some values were updated but others were not.
21
+ # This can be used to ensure that the data store is not left in a transitory state,
22
+ # where some values were updated but others were not.
23
+ #
24
+ # Behind the scenes, Ruby objects are stored to the data store file with Marshal.
25
+ # That carries the usual limitations. Proc objects cannot be marshalled,
26
+ # for example.
27
+ #
28
+ # There are three important concepts here (details at the links):
29
+ #
30
+ # - {Store}[rdoc-ref:PStore@The+Store]: a store is an instance of \PStore.
31
+ # - {Entries}[rdoc-ref:PStore@Entries]: the store is hash-like;
32
+ # each entry is the key for a stored object.
33
+ # - {Transactions}[rdoc-ref:PStore@Transactions]: each transaction is a collection
34
+ # of prospective changes to the store;
35
+ # a transaction is defined in the block given with a call
36
+ # to PStore#transaction.
37
+ #
38
+ # == About the Examples
39
+ #
40
+ # Examples on this page need a store that has known properties.
41
+ # They can get a new (and populated) store by calling thus:
42
+ #
43
+ # example_store do |store|
44
+ # # Example code using store goes here.
45
+ # end
46
+ #
47
+ # All we really need to know about +example_store+
48
+ # is that it yields a fresh store with a known population of entries;
49
+ # its implementation:
50
+ #
51
+ # require 'pstore'
52
+ # require 'tempfile'
53
+ # # Yield a pristine store for use in examples.
54
+ # def example_store
55
+ # # Create the store in a temporary file.
56
+ # Tempfile.create do |file|
57
+ # store = PStore.new(file)
58
+ # # Populate the store.
59
+ # store.transaction do
60
+ # store[:foo] = 0
61
+ # store[:bar] = 1
62
+ # store[:baz] = 2
63
+ # end
64
+ # yield store
65
+ # end
66
+ # end
67
+ #
68
+ # == The Store
69
+ #
70
+ # The contents of the store are maintained in a file whose path is specified
71
+ # when the store is created (see PStore.new).
72
+ # The objects are stored and retrieved using
73
+ # module Marshal, which means that certain objects cannot be added to the store;
74
+ # see {Marshal::dump}[https://docs.ruby-lang.org/en/master/Marshal.html#method-c-dump].
75
+ #
76
+ # == Entries
77
+ #
78
+ # A store may have any number of entries.
79
+ # Each entry has a key and a value, just as in a hash:
80
+ #
81
+ # - Key: as in a hash, the key can be (almost) any object;
82
+ # see {Hash Keys}[https://docs.ruby-lang.org/en/master/Hash.html#class-Hash-label-Hash+Keys].
83
+ # You may find it convenient to keep it simple by using only
84
+ # symbols or strings as keys.
85
+ # - Value: the value may be any object that can be marshalled by \Marshal
86
+ # (see {Marshal::dump}[https://docs.ruby-lang.org/en/master/Marshal.html#method-c-dump])
87
+ # and in fact may be a collection
88
+ # (e.g., an array, a hash, a set, a range, etc).
89
+ # That collection may in turn contain nested objects,
90
+ # including collections, to any depth;
91
+ # those objects must also be \Marshal-able.
92
+ # See {Hierarchical Values}[rdoc-ref:PStore@Hierarchical+Values].
93
+ #
94
+ # == Transactions
95
+ #
96
+ # === The Transaction Block
97
+ #
98
+ # The block given with a call to method #transaction#
99
+ # contains a _transaction_,
100
+ # which consists of calls to \PStore methods that
101
+ # read from or write to the store
102
+ # (that is, all \PStore methods except #transaction itself,
103
+ # #path, and Pstore.new):
104
+ #
105
+ # example_store do |store|
106
+ # store.transaction do
107
+ # store.keys # => [:foo, :bar, :baz]
108
+ # store[:bat] = 3
109
+ # store.keys # => [:foo, :bar, :baz, :bat]
110
+ # end
111
+ # end
112
+ #
113
+ # Execution of the transaction is deferred until the block exits,
114
+ # and is executed _atomically_ (all-or-nothing):
115
+ # either all transaction calls are executed, or none are.
116
+ # This maintains the integrity of the store.
117
+ #
118
+ # Other code in the block (including even calls to #path and PStore.new)
119
+ # is executed immediately, not deferred.
120
+ #
121
+ # The transaction block:
122
+ #
123
+ # - May not contain a nested call to #transaction.
124
+ # - Is the only context where methods that read from or write to
125
+ # the store are allowed.
126
+ #
127
+ # As seen above, changes in a transaction are made automatically
128
+ # when the block exits.
129
+ # The block may be exited early by calling method #commit or #abort.
130
+ #
131
+ # - Method #commit triggers the update to the store and exits the block:
132
+ #
133
+ # example_store do |store|
134
+ # store.transaction do
135
+ # store.keys # => [:foo, :bar, :baz]
136
+ # store[:bat] = 3
137
+ # store.commit
138
+ # fail 'Cannot get here'
139
+ # end
140
+ # store.transaction do
141
+ # # Update was completed.
142
+ # store.keys # => [:foo, :bar, :baz, :bat]
143
+ # end
144
+ # end
145
+ #
146
+ # - Method #abort discards the update to the store and exits the block:
147
+ #
148
+ # example_store do |store|
149
+ # store.transaction do
150
+ # store.keys # => [:foo, :bar, :baz]
151
+ # store[:bat] = 3
152
+ # store.abort
153
+ # fail 'Cannot get here'
154
+ # end
155
+ # store.transaction do
156
+ # # Update was not completed.
157
+ # store.keys # => [:foo, :bar, :baz]
158
+ # end
159
+ # end
160
+ #
161
+ # === Read-Only Transactions
162
+ #
163
+ # By default, a transaction allows both reading from and writing to
164
+ # the store:
165
+ #
166
+ # store.transaction do
167
+ # # Read-write transaction.
168
+ # # Any code except a call to #transaction is allowed here.
169
+ # end
170
+ #
171
+ # If argument +read_only+ is passed as +true+,
172
+ # only reading is allowed:
173
+ #
174
+ # store.transaction(true) do
175
+ # # Read-only transaction:
176
+ # # Calls to #transaction, #[]=, and #delete are not allowed here.
177
+ # end
178
+ #
179
+ # == Hierarchical Values
180
+ #
181
+ # The value for an entry may be a simple object (as seen above).
182
+ # It may also be a hierarchy of objects nested to any depth:
183
+ #
184
+ # deep_store = PStore.new('deep.store')
185
+ # deep_store.transaction do
186
+ # array_of_hashes = [{}, {}, {}]
187
+ # deep_store[:array_of_hashes] = array_of_hashes
188
+ # deep_store[:array_of_hashes] # => [{}, {}, {}]
189
+ # hash_of_arrays = {foo: [], bar: [], baz: []}
190
+ # deep_store[:hash_of_arrays] = hash_of_arrays
191
+ # deep_store[:hash_of_arrays] # => {:foo=>[], :bar=>[], :baz=>[]}
192
+ # deep_store[:hash_of_arrays][:foo].push(:bat)
193
+ # deep_store[:hash_of_arrays] # => {:foo=>[:bat], :bar=>[], :baz=>[]}
194
+ # end
195
+ #
196
+ # And recall that you can use
197
+ # {dig methods}[https://docs.ruby-lang.org/en/master/dig_methods_rdoc.html]
198
+ # in a returned hierarchy of objects.
199
+ #
200
+ # == Working with the Store
201
+ #
202
+ # === Creating a Store
203
+ #
204
+ # Use method PStore.new to create a store.
205
+ # The new store creates or opens its containing file:
206
+ #
207
+ # store = PStore.new('t.store')
208
+ #
209
+ # === Modifying the Store
210
+ #
211
+ # Use method #[]= to update or create an entry:
212
+ #
213
+ # example_store do |store|
214
+ # store.transaction do
215
+ # store[:foo] = 1 # Update.
216
+ # store[:bam] = 1 # Create.
217
+ # end
218
+ # end
219
+ #
220
+ # Use method #delete to remove an entry:
221
+ #
222
+ # example_store do |store|
223
+ # store.transaction do
224
+ # store.delete(:foo)
225
+ # store[:foo] # => nil
226
+ # end
227
+ # end
228
+ #
229
+ # === Retrieving Values
230
+ #
231
+ # Use method #fetch (allows default) or #[] (defaults to +nil+)
232
+ # to retrieve an entry:
233
+ #
234
+ # example_store do |store|
235
+ # store.transaction do
236
+ # store[:foo] # => 0
237
+ # store[:nope] # => nil
238
+ # store.fetch(:baz) # => 2
239
+ # store.fetch(:nope, nil) # => nil
240
+ # store.fetch(:nope) # Raises exception.
241
+ # end
242
+ # end
243
+ #
244
+ # === Querying the Store
245
+ #
246
+ # Use method #key? to determine whether a given key exists:
22
247
  #
23
- # Behind the scenes, Ruby objects are stored to the data store file with
24
- # Marshal. That carries the usual limitations. Proc objects cannot be
25
- # marshalled, for example.
248
+ # example_store do |store|
249
+ # store.transaction do
250
+ # store.key?(:foo) # => true
251
+ # end
252
+ # end
26
253
  #
27
- # == Usage example:
254
+ # Use method #keys to retrieve keys:
255
+ #
256
+ # example_store do |store|
257
+ # store.transaction do
258
+ # store.keys # => [:foo, :bar, :baz]
259
+ # end
260
+ # end
261
+ #
262
+ # Use method #path to retrieve the path to the store's underlying file;
263
+ # this method may be called from outside a transaction block:
264
+ #
265
+ # store = PStore.new('t.store')
266
+ # store.path # => "t.store"
267
+ #
268
+ # == Transaction Safety
269
+ #
270
+ # For transaction safety, see:
271
+ #
272
+ # - Optional argument +thread_safe+ at method PStore.new.
273
+ # - Attribute #ultra_safe.
274
+ #
275
+ # Needless to say, if you're storing valuable data with \PStore, then you should
276
+ # backup the \PStore file from time to time.
277
+ #
278
+ # == An Example Store
28
279
  #
29
280
  # require "pstore"
30
281
  #
31
- # # a mock wiki object...
282
+ # # A mock wiki object.
32
283
  # class WikiPage
33
- # def initialize( page_name, author, contents )
284
+ #
285
+ # attr_reader :page_name
286
+ #
287
+ # def initialize(page_name, author, contents)
34
288
  # @page_name = page_name
35
289
  # @revisions = Array.new
36
- #
37
290
  # add_revision(author, contents)
38
291
  # end
39
292
  #
40
- # attr_reader :page_name
41
- #
42
- # def add_revision( author, contents )
43
- # @revisions << { :created => Time.now,
44
- # :author => author,
45
- # :contents => contents }
293
+ # def add_revision(author, contents)
294
+ # @revisions << {created: Time.now,
295
+ # author: author,
296
+ # contents: contents}
46
297
  # end
47
298
  #
48
299
  # def wiki_page_references
49
300
  # [@page_name] + @revisions.last[:contents].scan(/\b(?:[A-Z]+[a-z]+){2,}/)
50
301
  # end
51
302
  #
52
- # # ...
53
303
  # end
54
304
  #
55
- # # create a new page...
56
- # home_page = WikiPage.new( "HomePage", "James Edward Gray II",
57
- # "A page about the JoysOfDocumentation..." )
305
+ # # Create a new wiki page.
306
+ # home_page = WikiPage.new("HomePage", "James Edward Gray II",
307
+ # "A page about the JoysOfDocumentation..." )
58
308
  #
59
- # # then we want to update page data and the index together, or not at all...
60
309
  # wiki = PStore.new("wiki_pages.pstore")
61
- # wiki.transaction do # begin transaction; do all of this or none of it
62
- # # store page...
310
+ # # Update page data and the index together, or not at all.
311
+ # wiki.transaction do
312
+ # # Store page.
63
313
  # wiki[home_page.page_name] = home_page
64
- # # ensure that an index has been created...
314
+ # # Create page index.
65
315
  # wiki[:wiki_index] ||= Array.new
66
- # # update wiki index...
316
+ # # Update wiki index.
67
317
  # wiki[:wiki_index].push(*home_page.wiki_page_references)
68
- # end # commit changes to wiki data store file
69
- #
70
- # ### Some time later... ###
318
+ # end
71
319
  #
72
- # # read wiki data...
73
- # wiki.transaction(true) do # begin read-only transaction, no changes allowed
74
- # wiki.roots.each do |data_root_name|
75
- # p data_root_name
76
- # p wiki[data_root_name]
320
+ # # Read wiki data, setting argument read_only to true.
321
+ # wiki.transaction(true) do
322
+ # wiki.keys.each do |key|
323
+ # puts key
324
+ # puts wiki[key]
77
325
  # end
78
326
  # end
79
327
  #
80
- # == Transaction modes
81
- #
82
- # By default, file integrity is only ensured as long as the operating system
83
- # (and the underlying hardware) doesn't raise any unexpected I/O errors. If an
84
- # I/O error occurs while PStore is writing to its file, then the file will
85
- # become corrupted.
86
- #
87
- # You can prevent this by setting <em>pstore.ultra_safe = true</em>.
88
- # However, this results in a minor performance loss, and only works on platforms
89
- # that support atomic file renames. Please consult the documentation for
90
- # +ultra_safe+ for details.
91
- #
92
- # Needless to say, if you're storing valuable data with PStore, then you should
93
- # backup the PStore files from time to time.
94
328
  class PStore
329
+ VERSION = "0.1.2"
330
+
95
331
  RDWR_ACCESS = {mode: IO::RDWR | IO::CREAT | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
96
332
  RD_ACCESS = {mode: IO::RDONLY | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
97
333
  WR_ACCESS = {mode: IO::WRONLY | IO::CREAT | IO::TRUNC | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
@@ -100,21 +336,38 @@ class PStore
100
336
  class Error < StandardError
101
337
  end
102
338
 
103
- # Whether PStore should do its best to prevent file corruptions, even when under
104
- # unlikely-to-occur error conditions such as out-of-space conditions and other
105
- # unusual OS filesystem errors. Setting this flag comes at the price in the form
106
- # of a performance loss.
339
+ # Whether \PStore should do its best to prevent file corruptions,
340
+ # even when an unlikely error (such as memory-error or filesystem error) occurs:
341
+ #
342
+ # - +true+: changes are posted by creating a temporary file,
343
+ # writing the updated data to it, then renaming the file to the given #path.
344
+ # File integrity is maintained.
345
+ # Note: has effect only if the filesystem has atomic file rename
346
+ # (as do POSIX platforms Linux, MacOS, FreeBSD and others).
347
+ #
348
+ # - +false+ (the default): changes are posted by rewinding the open file
349
+ # and writing the updated data.
350
+ # File integrity is maintained if the filesystem raises
351
+ # no unexpected I/O error;
352
+ # if such an error occurs during a write to the store,
353
+ # the file may become corrupted.
107
354
  #
108
- # This flag only has effect on platforms on which file renames are atomic (e.g.
109
- # all POSIX platforms: Linux, MacOS X, FreeBSD, etc). The default value is false.
110
355
  attr_accessor :ultra_safe
111
356
 
357
+ # Returns a new \PStore object.
358
+ #
359
+ # Argument +file+ is the path to the file in which objects are to be stored;
360
+ # if the file exists, it should be one that was written by \PStore.
361
+ #
362
+ # path = 't.store'
363
+ # store = PStore.new(path)
112
364
  #
113
- # To construct a PStore object, pass in the _file_ path where you would like
114
- # the data to be stored.
365
+ # A \PStore object is
366
+ # {reentrant}[https://en.wikipedia.org/wiki/Reentrancy_(computing)].
367
+ # If argument +thread_safe+ is given as +true+,
368
+ # the object is also thread-safe (at the cost of a small performance penalty):
115
369
  #
116
- # PStore objects are always reentrant. But if _thread_safe_ is set to true,
117
- # then it will become thread-safe at the cost of a minor performance hit.
370
+ # store = PStore.new(path, true)
118
371
  #
119
372
  def initialize(file, thread_safe = false)
120
373
  dir = File::dirname(file)
@@ -145,169 +398,160 @@ class PStore
145
398
  end
146
399
  private :in_transaction, :in_transaction_wr
147
400
 
401
+ # Returns the value for the given +key+ if the key exists.
402
+ # +nil+ otherwise;
403
+ # if not +nil+, the returned value is an object or a hierarchy of objects:
148
404
  #
149
- # Retrieves a value from the PStore file data, by _name_. The hierarchy of
150
- # Ruby objects stored under that root _name_ will be returned.
405
+ # example_store do |store|
406
+ # store.transaction do
407
+ # store[:foo] # => 0
408
+ # store[:nope] # => nil
409
+ # end
410
+ # end
151
411
  #
152
- # *WARNING*: This method is only valid in a PStore#transaction. It will
153
- # raise PStore::Error if called at any other time.
412
+ # Returns +nil+ if there is no such key.
154
413
  #
155
- def [](name)
414
+ # See also {Hierarchical Values}[rdoc-ref:PStore@Hierarchical+Values].
415
+ #
416
+ # Raises an exception if called outside a transaction block.
417
+ def [](key)
156
418
  in_transaction
157
- @table[name]
419
+ @table[key]
158
420
  end
421
+
422
+ # Like #[], except that it accepts a default value for the store.
423
+ # If the +key+ does not exist:
159
424
  #
160
- # This method is just like PStore#[], save that you may also provide a
161
- # _default_ value for the object. In the event the specified _name_ is not
162
- # found in the data store, your _default_ will be returned instead. If you do
163
- # not specify a default, PStore::Error will be raised if the object is not
164
- # found.
425
+ # - Raises an exception if +default+ is +PStore::Error+.
426
+ # - Returns the value of +default+ otherwise:
165
427
  #
166
- # *WARNING*: This method is only valid in a PStore#transaction. It will
167
- # raise PStore::Error if called at any other time.
428
+ # example_store do |store|
429
+ # store.transaction do
430
+ # store.fetch(:nope, nil) # => nil
431
+ # store.fetch(:nope) # Raises an exception.
432
+ # end
433
+ # end
168
434
  #
169
- def fetch(name, default=PStore::Error)
435
+ # Raises an exception if called outside a transaction block.
436
+ def fetch(key, default=PStore::Error)
170
437
  in_transaction
171
- unless @table.key? name
438
+ unless @table.key? key
172
439
  if default == PStore::Error
173
- raise PStore::Error, format("undefined root name `%s'", name)
440
+ raise PStore::Error, format("undefined key `%s'", key)
174
441
  else
175
442
  return default
176
443
  end
177
444
  end
178
- @table[name]
445
+ @table[key]
179
446
  end
447
+
448
+ # Creates or replaces the value for the given +key+:
180
449
  #
181
- # Stores an individual Ruby object or a hierarchy of Ruby objects in the data
182
- # store file under the root _name_. Assigning to a _name_ already in the data
183
- # store clobbers the old data.
184
- #
185
- # == Example:
186
- #
187
- # require "pstore"
188
- #
189
- # store = PStore.new("data_file.pstore")
190
- # store.transaction do # begin transaction
191
- # # load some data into the store...
192
- # store[:single_object] = "My data..."
193
- # store[:obj_hierarchy] = { "Kev Jackson" => ["rational.rb", "pstore.rb"],
194
- # "James Gray" => ["erb.rb", "pstore.rb"] }
195
- # end # commit changes to data store file
450
+ # example_store do |store|
451
+ # temp.transaction do
452
+ # temp[:bat] = 3
453
+ # end
454
+ # end
196
455
  #
197
- # *WARNING*: This method is only valid in a PStore#transaction and it cannot
198
- # be read-only. It will raise PStore::Error if called at any other time.
456
+ # See also {Hierarchical Values}[rdoc-ref:PStore@Hierarchical+Values].
199
457
  #
200
- def []=(name, value)
458
+ # Raises an exception if called outside a transaction block.
459
+ def []=(key, value)
201
460
  in_transaction_wr
202
- @table[name] = value
461
+ @table[key] = value
203
462
  end
463
+
464
+ # Removes and returns the value at +key+ if it exists:
204
465
  #
205
- # Removes an object hierarchy from the data store, by _name_.
466
+ # example_store do |store|
467
+ # store.transaction do
468
+ # store[:bat] = 3
469
+ # store.delete(:bat)
470
+ # end
471
+ # end
206
472
  #
207
- # *WARNING*: This method is only valid in a PStore#transaction and it cannot
208
- # be read-only. It will raise PStore::Error if called at any other time.
473
+ # Returns +nil+ if there is no such key.
209
474
  #
210
- def delete(name)
475
+ # Raises an exception if called outside a transaction block.
476
+ def delete(key)
211
477
  in_transaction_wr
212
- @table.delete name
478
+ @table.delete key
213
479
  end
214
480
 
481
+ # Returns an array of the existing keys:
215
482
  #
216
- # Returns the names of all object hierarchies currently in the store.
483
+ # example_store do |store|
484
+ # store.transaction do
485
+ # store.keys # => [:foo, :bar, :baz]
486
+ # end
487
+ # end
217
488
  #
218
- # *WARNING*: This method is only valid in a PStore#transaction. It will
219
- # raise PStore::Error if called at any other time.
489
+ # Raises an exception if called outside a transaction block.
220
490
  #
221
- def roots
491
+ # PStore#roots is an alias for PStore#keys.
492
+ def keys
222
493
  in_transaction
223
494
  @table.keys
224
495
  end
496
+ alias roots keys
497
+
498
+ # Returns +true+ if +key+ exists, +false+ otherwise:
225
499
  #
226
- # Returns true if the supplied _name_ is currently in the data store.
500
+ # example_store do |store|
501
+ # store.transaction do
502
+ # store.key?(:foo) # => true
503
+ # end
504
+ # end
227
505
  #
228
- # *WARNING*: This method is only valid in a PStore#transaction. It will
229
- # raise PStore::Error if called at any other time.
506
+ # Raises an exception if called outside a transaction block.
230
507
  #
231
- def root?(name)
508
+ # PStore#root? is an alias for PStore#key?.
509
+ def key?(key)
232
510
  in_transaction
233
- @table.key? name
511
+ @table.key? key
234
512
  end
235
- # Returns the path to the data store file.
513
+ alias root? key?
514
+
515
+ # Returns the string file path used to create the store:
516
+ #
517
+ # store.path # => "flat.store"
518
+ #
236
519
  def path
237
520
  @filename
238
521
  end
239
522
 
523
+ # Exits the current transaction block, committing any changes
524
+ # specified in the transaction block.
525
+ # See {Committing or Aborting}[rdoc-ref:PStore@Committing+or+Aborting].
240
526
  #
241
- # Ends the current PStore#transaction, committing any changes to the data
242
- # store immediately.
243
- #
244
- # == Example:
245
- #
246
- # require "pstore"
247
- #
248
- # store = PStore.new("data_file.pstore")
249
- # store.transaction do # begin transaction
250
- # # load some data into the store...
251
- # store[:one] = 1
252
- # store[:two] = 2
253
- #
254
- # store.commit # end transaction here, committing changes
255
- #
256
- # store[:three] = 3 # this change is never reached
257
- # end
258
- #
259
- # *WARNING*: This method is only valid in a PStore#transaction. It will
260
- # raise PStore::Error if called at any other time.
261
- #
527
+ # Raises an exception if called outside a transaction block.
262
528
  def commit
263
529
  in_transaction
264
530
  @abort = false
265
531
  throw :pstore_abort_transaction
266
532
  end
533
+
534
+ # Exits the current transaction block, discarding any changes
535
+ # specified in the transaction block.
536
+ # See {Committing or Aborting}[rdoc-ref:PStore@Committing+or+Aborting].
267
537
  #
268
- # Ends the current PStore#transaction, discarding any changes to the data
269
- # store.
270
- #
271
- # == Example:
272
- #
273
- # require "pstore"
274
- #
275
- # store = PStore.new("data_file.pstore")
276
- # store.transaction do # begin transaction
277
- # store[:one] = 1 # this change is not applied, see below...
278
- # store[:two] = 2 # this change is not applied, see below...
279
- #
280
- # store.abort # end transaction here, discard all changes
281
- #
282
- # store[:three] = 3 # this change is never reached
283
- # end
284
- #
285
- # *WARNING*: This method is only valid in a PStore#transaction. It will
286
- # raise PStore::Error if called at any other time.
287
- #
538
+ # Raises an exception if called outside a transaction block.
288
539
  def abort
289
540
  in_transaction
290
541
  @abort = true
291
542
  throw :pstore_abort_transaction
292
543
  end
293
544
 
545
+ # Opens a transaction block for the store.
546
+ # See {Transactions}[rdoc-ref:PStore@Transactions].
294
547
  #
295
- # Opens a new transaction for the data store. Code executed inside a block
296
- # passed to this method may read and write data to and from the data store
297
- # file.
298
- #
299
- # At the end of the block, changes are committed to the data store
300
- # automatically. You may exit the transaction early with a call to either
301
- # PStore#commit or PStore#abort. See those methods for details about how
302
- # changes are handled. Raising an uncaught Exception in the block is
303
- # equivalent to calling PStore#abort.
304
- #
305
- # If _read_only_ is set to +true+, you will only be allowed to read from the
306
- # data store during the transaction and any attempts to change the data will
307
- # raise a PStore::Error.
548
+ # With argument +read_only+ as +false+, the block may both read from
549
+ # and write to the store.
308
550
  #
309
- # Note that PStore does not support nested transactions.
551
+ # With argument +read_only+ as +true+, the block may not include calls
552
+ # to #transaction, #[]=, or #delete.
310
553
  #
554
+ # Raises an exception if called within a transaction block.
311
555
  def transaction(read_only = false) # :yields: pstore
312
556
  value = nil
313
557
  if !@thread_safe
data/pstore.gemspec CHANGED
@@ -1,17 +1,22 @@
1
- lib = File.expand_path("lib", __dir__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "pstore/version"
1
+ # frozen_string_literal: true
2
+
3
+ name = File.basename(__FILE__, ".gemspec")
4
+ version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
5
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
6
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
7
+ end rescue nil
8
+ end
4
9
 
5
10
  Gem::Specification.new do |spec|
6
- spec.name = "pstore"
7
- spec.version = PStore::VERSION
8
- spec.authors = ["Hiroshi SHIBATA"]
9
- spec.email = ["hsbt@ruby-lang.org"]
11
+ spec.name = name
12
+ spec.version = version
13
+ spec.authors = ["Yukihiro Matsumoto"]
14
+ spec.email = ["matz@ruby-lang.org"]
10
15
 
11
16
  spec.summary = %q{Transactional File Storage for Ruby Objects}
12
17
  spec.description = spec.summary
13
18
  spec.homepage = "https://github.com/ruby/pstore"
14
- spec.license = "BSD-2-Clause"
19
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
15
20
 
16
21
  spec.metadata["homepage_uri"] = spec.homepage
17
22
  spec.metadata["source_code_uri"] = "https://github.com/ruby/pstore"
@@ -19,7 +24,7 @@ Gem::Specification.new do |spec|
19
24
  # Specify which files should be added to the gem when it is released.
20
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
26
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
28
  end
24
29
  spec.bindir = "exe"
25
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
metadata CHANGED
@@ -1,24 +1,25 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pstore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
- - Hiroshi SHIBATA
8
- autorequire:
7
+ - Yukihiro Matsumoto
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-06 00:00:00.000000000 Z
11
+ date: 2022-12-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Transactional File Storage for Ruby Objects
14
14
  email:
15
- - hsbt@ruby-lang.org
15
+ - matz@ruby-lang.org
16
16
  executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - ".github/dependabot.yml"
21
+ - ".github/workflows/test.yml"
20
22
  - ".gitignore"
21
- - ".travis.yml"
22
23
  - Gemfile
23
24
  - LICENSE.txt
24
25
  - README.md
@@ -26,15 +27,15 @@ files:
26
27
  - bin/console
27
28
  - bin/setup
28
29
  - lib/pstore.rb
29
- - lib/pstore/version.rb
30
30
  - pstore.gemspec
31
31
  homepage: https://github.com/ruby/pstore
32
32
  licenses:
33
+ - Ruby
33
34
  - BSD-2-Clause
34
35
  metadata:
35
36
  homepage_uri: https://github.com/ruby/pstore
36
37
  source_code_uri: https://github.com/ruby/pstore
37
- post_install_message:
38
+ post_install_message:
38
39
  rdoc_options: []
39
40
  require_paths:
40
41
  - lib
@@ -49,8 +50,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
49
50
  - !ruby/object:Gem::Version
50
51
  version: '0'
51
52
  requirements: []
52
- rubygems_version: 3.0.3
53
- signing_key:
53
+ rubygems_version: 3.4.0.dev
54
+ signing_key:
54
55
  specification_version: 4
55
56
  summary: Transactional File Storage for Ruby Objects
56
57
  test_files: []
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.6.3
7
- before_install: gem install bundler -v 2.0.2
@@ -1,3 +0,0 @@
1
- class PStore
2
- VERSION = "0.1.0"
3
- end