pstore 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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