dbmlite3 1.0.a1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 546ca0010f91757ca1346cd87ca9f2846318e65123668363239b61e8f1f5bbdd
4
+ data.tar.gz: 5500f44eec01f68da64ed8e8d8ec73a1325ffafeab274a2ae00604a68e16ae61
5
+ SHA512:
6
+ metadata.gz: 45e67ef18cff8f3f17610e888a7153bb83d83438334c8ce0d204fdda7c599926e5ec210e09cb67bf909dbfa829fb17046b46a540e5373960b049bccb77526cf1
7
+ data.tar.gz: 7c113a41818d9bdea1aec2b8e3d5fe1f54c4c134e8fa777a6e19a6c0f8546c326f6ef901caddc4b65985df1b50a89d809db6b32196eb157034e619fd9cebade5
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --markup markdown
2
+ --readme README.md
3
+ lib/*.rb
data/DBMLite3.gemspec ADDED
@@ -0,0 +1,39 @@
1
+
2
+ # Skeleton gemspec
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'dbmlite3'
6
+ s.version = '1.0.a1'
7
+ s.date = '2022-02-21'
8
+ s.summary = "A DBM-style key-value store using SQLite3"
9
+ s.description = <<-EOF
10
+ Lite3::DBM is an object that behaves like a Ruby Hash but stores
11
+ its data in a SQLite3 database table. It is a drop-in replacement
12
+ for DBM.
13
+
14
+ Values are optionally serialized with YAML or Marshal, allowing
15
+ (almost) any Ruby type to be stored. In addition, there is
16
+ rudimentary support for transactions with emphasis on simplicity
17
+ and safety.
18
+ EOF
19
+ s.authors = ["Chris Reuter"]
20
+ s.email = 'chris@isplitonyourgrave.com'
21
+
22
+ # I'm just going to add everything so that if you've got the gem,
23
+ # you've also got the source distribution. Yay! Open source!
24
+ s.files = ["README.md", "LICENSE.txt", "DBMLite3.gemspec",
25
+ "Rakefile", ".yardopts"] +
26
+ Dir.glob('doc/**/*') +
27
+ Dir.glob('{spec,lib}/*.rb')
28
+
29
+ s.required_ruby_version = '>= 2.7.0'
30
+ s.requirements << "sqlite3, the usual devtools"
31
+
32
+ s.add_runtime_dependency "sqlite3", '~> 1.4'
33
+
34
+ s.add_development_dependency "rspec", '~> 3.10', '>= 3.10.0'
35
+ s.add_development_dependency "yard", '~> 0.9.25', '>= 0.9.25'
36
+
37
+ s.homepage = 'https://codeberg.org/suetanvil/dbmlite3-ruby'
38
+ s.license = 'MIT'
39
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Chris Reuter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # Simple DBM-style key-value database using SQLite3
2
+
3
+ ## Description
4
+
5
+ `dbmlite3` is a simple key-value store built on top of SQLite3 that
6
+ provides a Hash-like interface. It is a drop-in replacement for `DBM`
7
+ or `YAML::DBM` that uses SQLite3 to do the underlying storage.
8
+
9
+ ## Why?
10
+
11
+ Because DBM is really simple and SQLite3 is solid, reliable,
12
+ ubiquitous, and file-format-compatible across all platforms. This gem
13
+ gives you the best of both worlds.
14
+
15
+
16
+ ## Synopsis
17
+
18
+ ```ruby
19
+ require 'dbmlite3'
20
+
21
+ # Open a table in a database
22
+ settings = Lite3::DBM.new("config.sqlite3", "settings")
23
+
24
+ # You use it like a hash
25
+ settings["speed"] = 88
26
+ settings["date"] = Date.new(1955, 11, 5) # Normal Ruby values are allowed
27
+ settings["power_threshold"] = 2.2
28
+
29
+ puts settings['power_threshold']
30
+
31
+ settings.each{|k,v| puts "setting: #{k} = #{v}" }
32
+
33
+ # But you also have transactions
34
+ settings.transaction{
35
+ settings["speed"] = settings["speed"] * 2
36
+ }
37
+
38
+ # You can open other tables in the same database if you want, as above
39
+ # or with a block
40
+ Lite3::DBM.open("config.sqlite3", "stats") { |stats|
41
+ stats["max"] = 42
42
+
43
+ # You can even open multiple handles to the same table if you need to
44
+ Lite3::DBM.open("config.sqlite3", "stats") { |stats2|
45
+ stats2["max"] += 1
46
+ }
47
+
48
+ puts "stats=#{stats["max"]}"
49
+ }
50
+
51
+ settings.close
52
+ ```
53
+
54
+ Complete documentation is available in the accompanying rdoc.
55
+
56
+ ## Installation
57
+
58
+ `dbmlite3` is available as a gem:
59
+
60
+ $ [sudo] gem install dbmlite3
61
+
62
+ Alternately, you can fetch the source code from GitLab and build it yourself:
63
+
64
+ $ git clone https://gitlab.com/suetanvil/dbmlite3
65
+ $ cd dbmlite3
66
+ $ rake
67
+
68
+ Obviously, it depends on the gem `sqlite3`.
69
+
70
+ ## Quirks and Hints
71
+
72
+ ### Remember that a `DBM` is a (potentially) shared file
73
+
74
+ It is important to keep in mind that while `Lite3::DBM` objects
75
+ look like Hashes, they are accessing files on disk that other
76
+ processes could modify at any time.
77
+
78
+ For example, an innocuous-looking expression like
79
+
80
+ db['foo'] = db['foo'] + 1
81
+
82
+ or its shorter equivalent
83
+
84
+ db['foo'] += 1
85
+
86
+ contains a race condition. If (e.g.) two copies of this script are
87
+ running at the same time, it is possible for both to perform the read
88
+ before one of them writes, losing the others' result.
89
+
90
+ There are two ways to deal with this. You can wrap the
91
+ read-modify-write cycle in a transaction:
92
+
93
+ db.transaction { db['foo'] += 1 }
94
+
95
+ Or, of course, you could just design your script or program so that
96
+ only one program accesses the table at a time.
97
+
98
+
99
+ ### Transactions and performance
100
+
101
+ If you need to do a large number of accesses in a short amount of
102
+ time (e.g. loading data from a file), it is significantly faster to
103
+ do these in batches in one or more transactions.
104
+
105
+ ### Forking safely
106
+
107
+ It is a documented limitation of SQLite3 that database objects
108
+ cannot be carried across a process fork. Either the parent or the
109
+ child process will keep the open handle and the other one must
110
+ forget it completely.
111
+
112
+ For this reason, if you need both the parent and child process to
113
+ be able to use `Lite3::DBM` after a `fork`, you must first call
114
+ `Lite3::SQL.close_all`. Not only will this make it safe but it
115
+ also lets the child and parent use the same `Lite3::DBM` objects.
116
+
117
+ ### `Lite3::DBM` objects act like file handles but are not
118
+
119
+ While it is generally safe to treat `Lite3::DBM` as a wrapper
120
+ around file handle (i.e. `open` and `close` work as expected), you
121
+ should be aware that this is not precisely the way things
122
+ actually work. Instead, the gem maintains a pool of database
123
+ handles, one per file, and associates them with `Lite3::DBM`
124
+ instances as needed. This is necessary for transactions to work
125
+ correctly.
126
+
127
+ See the reference doc for `Lite3::SQL` for more details.
128
+
129
+ Mostly, you don't need to worry about this but certain types of
130
+ bugs could behave in unexpected ways and knowing this may help you
131
+ make sense of them.
132
+
133
+
134
+
135
+
136
+
137
+
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+ require 'yard'
4
+
5
+ RSpec::Core::RakeTask.new(:test) do |t|
6
+ t.pattern = Dir.glob('spec/*_spec.rb')
7
+ end
8
+
9
+ YARD::Rake::YardocTask.new(:docs_via_yard) do |t|
10
+ t.files = ['lib/*.rb']
11
+ end
12
+
13
+ task :gem do
14
+ `gem build dbmlite3`
15
+ end
16
+
17
+ task :clean do
18
+ gems = Dir.glob("dbmlite3-*.gem")
19
+ rm gems if gems.size > 0
20
+ rm_rf "doc"
21
+ end
22
+
23
+ task :clobber => [:clean] do
24
+ rm_rf ".yardoc"
25
+ end
26
+
27
+ task :doc => :docs_via_yard
28
+
29
+ task :default => [:doc, :test, :gem]