carton_db 1.1.1 → 1.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
  SHA1:
3
- metadata.gz: ce323ba4a0df06b409f1b35a150a9a638740e586
4
- data.tar.gz: b2c95dca25fe7be9c0b7c8ff7ca2f8d3ea6e7ed0
3
+ metadata.gz: d16d6802fee28aa151d8eee4811d17d3a5dc00a5
4
+ data.tar.gz: 22cb133e4202c80ef89109a24163c41b666ec89c
5
5
  SHA512:
6
- metadata.gz: ed9890e79acc8c72d7005834b9ed6f8fec56ab941d9c078957cb2fa84c5e82f486ea876d981af6850bd2835ea9fc58789194e0e061087054def1a2a35ab25fdb
7
- data.tar.gz: 69de8aac4491cd13b67c3e2bb0a707961c8a359259278303a70e094c19fe7e60b3c5c3b2983f1b6268b74bc5045f762eeb7abb53b22e031049bfa6d2e962e06c
6
+ metadata.gz: 3ff1b4d0a6a5582d5903093e80051600e119f8c857b9ba32821081113b3cf90b3802c3f10f83a4fba0173b987ef55f699d3ae6289b1dfda47934b5105eb92b15
7
+ data.tar.gz: 04747d51836cc9864fc5e5245f884d42c585cb434ba7ce66441f19836c87d841ed74a60765d5b93a5767f13279ae93b3c81da2b59ec853fbda5082961841472e
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  /Gemfile.lock
4
4
  /_yardoc/
5
5
  /coverage/
6
+ /profiles/
6
7
  /doc/
7
8
  /pkg/
8
9
  /spec/reports/
data/README.md CHANGED
@@ -4,7 +4,7 @@ A pure Ruby key/value data storage system where the values may
4
4
  consist of simple data structures.
5
5
 
6
6
  The primary goals of this library are simplicity of implementation
7
- and reliable, predicatble behavior when used as intended, along
7
+ and reliable, predictable behavior when used as intended, along
8
8
  with documentation making it reasonably clear what is intended.
9
9
 
10
10
  ## Uses
@@ -53,11 +53,14 @@ filesystem containing the files that store the data.
53
53
 
54
54
  A database is accessed through an instance of a database class.
55
55
 
56
- An instance of a database class maintains no state in memory
56
+ An instance of a database class maintains no internal state
57
57
  between calls to its methods except for the database name and the
58
58
  expectation of a directory with that name existing in the
59
59
  filesystem.
60
60
 
61
+ Only instances of classes maintain any internal state. No global
62
+ internal state is maintained.
63
+
61
64
  An empty directory is a valid empty database.
62
65
 
63
66
  Concurrent reads from a database are supported and safe.
@@ -68,24 +71,25 @@ attempting to do that are unpredictable.
68
71
 
69
72
  Initializing a new database class instance creates its directory
70
73
  in the filesystem if it does not already exist. The parent of the
71
- database directory is expected to already exist, and an
72
- exception will be raised if it doesn't.
74
+ database directory is expected to already exist, and an exception
75
+ will be raised if it doesn't.
73
76
 
74
77
  The database structure is designed to effectively handle up to
75
- several million elements with entries containing up to 1 or 2
76
- thousand elements each.
78
+ several million elements with any entry containing up to around
79
+ 50 thousand characters (elements ⨉ chars in an entry's content).
77
80
 
78
- The speed of database operations is relatively good, but this is
79
- not a high performance database management system. See the
80
- code documentation in the classes for more details about the
81
- performance of particular database operations.
81
+ The speed of database operations is good, but this is not a high
82
+ performance database management system. See the code
83
+ documentation in the classes for more details about the
84
+ performance of each kind of database operation.
82
85
 
83
86
  ## Usage
84
87
 
85
- Currently, this gem includes only one kind of database, which is
86
- implemented by the `CartonDB::ListMapDb` class. It is a map of
87
- lists where each entry has a string for a key and a list of of 0
88
- or more string elements as content.
88
+ The primary kind of database provided by this gem is the one
89
+ implemented by `CartonDB::ListMapDb`. It is a map of lists where
90
+ each entry has a string for a key and a list of of 0 or more
91
+ string elements as content. Other kinds of database are
92
+ implemented on top of that and share the same storage format.
89
93
 
90
94
  The name of the database is the path of a directory in the
91
95
  filesystem that either already exists or shall be created as
data/carton_db.gemspec CHANGED
@@ -14,6 +14,8 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = "https://github.com/stevecj/carton_db.rb"
15
15
  spec.license = "MIT"
16
16
 
17
+ spec.required_ruby_version = '>= 2.3.0'
18
+
17
19
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
20
  f.match(%r{^(test|spec|features)/})
19
21
  end
@@ -24,4 +26,5 @@ Gem::Specification.new do |spec|
24
26
  spec.add_development_dependency "bundler", "~> 1.14"
25
27
  spec.add_development_dependency "rake", "~> 10.0"
26
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
+ spec.add_development_dependency "rspec-prof", "~> 0.0"
27
30
  end
@@ -71,6 +71,18 @@ module CartonDb
71
71
  end
72
72
  end
73
73
 
74
+ def each_first_element
75
+ first_entries = nil
76
+ each_entry_element_line do |key_d, elem_d, _line|
77
+ first_entries ||= {}
78
+ first_entries[key_d] ||= elem_d.plain
79
+ end
80
+ return unless first_entries
81
+ first_entries.each do |key_d, element|
82
+ yield key_d.plain, element
83
+ end
84
+ end
85
+
74
86
  def each_entry_element_line
75
87
  return if empty?
76
88
  each_line do |line|
@@ -6,7 +6,7 @@ require 'carton_db/list_map_db/segment_group'
6
6
 
7
7
  module CartonDb
8
8
 
9
- # A map with string keys lists of strings as contents.
9
+ # A map with strings as keys and lists of strings as contents.
10
10
  #
11
11
  # This is suitable for storing a total number of elements as
12
12
  # large as the low millions, with each entry containing a
@@ -215,6 +215,23 @@ module CartonDb
215
215
  end
216
216
  end
217
217
 
218
+ # For each entry in the database, yields the first element
219
+ # in the entry's content or nil if the content is an empty
220
+ # list.
221
+ #
222
+ # Performance is pretty much identical to that of #each.
223
+ #
224
+ # @yieldparam key [String] The key of the entry.
225
+ # @yeildparam array [String, nil] The first element of the
226
+ # entry's content.
227
+ def each_first_element
228
+ ListMapDb::Segment.each_in_db name do |segment|
229
+ segment.each_first_element do |key, element|
230
+ yield key, element
231
+ end
232
+ end
233
+ end
234
+
218
235
  # Removes an entry from the database. Has no effect if the
219
236
  # entry already does not exist.
220
237
  #
@@ -322,9 +339,13 @@ module CartonDb
322
339
  # necessary so the content has an element corresponding to
323
340
  # each of the given elements.
324
341
  #
342
+ # Performance is similar to #[] when no new elements need to
343
+ # be added and similar to #[] followed by #concat_elements
344
+ # when one or more new elements needs to be added.
345
+ #
325
346
  # @param key [String] The key identifying the entry.
326
347
  # @param elements [Array<String>] An array or other
327
- # enumerable collection of elements to appended as
348
+ # enumerable collection of elements to be appended as
328
349
  # applicable.
329
350
  def merge_elements(key, elements)
330
351
  key_d = CartonDb::Datum.for_plain(key)
@@ -0,0 +1,111 @@
1
+ require 'set'
2
+ require 'forwardable'
3
+
4
+ module CartonDb
5
+
6
+ class SetMapDb
7
+ extend Forwardable
8
+
9
+ def initialize(name)
10
+ self.list_map_db = CartonDb::ListMapDb.new(name)
11
+ end
12
+
13
+ # Creates a new entry or replaces the contents of the
14
+ # existing entry identified by the given key.
15
+ #
16
+ # The is a fairly fast operation, but can be somewhat
17
+ # slower in a large database.
18
+ #
19
+ # @param key [String] The key identifying the entry.
20
+ # @param content [Set<String>] A set or other enumerable
21
+ # collection of 0 or more list element string values to be
22
+ # stored.
23
+ def []=(key, content)
24
+ content = Set.new(content) unless content.is_a?(Set)
25
+ list_map_db[key] = content
26
+ end
27
+
28
+ # Returns the content of the entry identified by the given
29
+ # key or nil if no such entry exists.
30
+ #
31
+ # This operation is fast, but may be slower for a larger
32
+ # database.
33
+ #
34
+ # @param key [String] The key identifying the entry.
35
+ # @return [Set<String>] if a matching entry exists.
36
+ # @return [nil] if no matching entry exists.
37
+ def [](key)
38
+ list = list_map_db[key]
39
+ list && Set.new(list)
40
+ end
41
+
42
+ # See CartonDb::ListMapDb#empty?
43
+ def_delegator :list_map_db, :empty?
44
+
45
+ # see cartondb::listmapdb#count
46
+ def_delegator :list_map_db, :count
47
+
48
+ # See CartonDb::ListMapDb#Key?
49
+ def_delegator :list_map_db, :key?
50
+
51
+ # See CartonDb::ListMapDb#touch_element
52
+ def_delegator :list_map_db, :touch_element
53
+
54
+ # See CartonDb::ListMapDb#delete
55
+ def_delegator :list_map_db, :delete
56
+
57
+ # Creates an entry with an empty set as its content if no
58
+ # entry exists for the given key. Has no effect on the content
59
+ # of the entry if it already exists.
60
+ #
61
+ # See the documentation for CartonDb::ListMapDb#touch for
62
+ # performance characteristics.
63
+ #
64
+ # @param key [String] The key identifying the entry.
65
+ # @param optimization[:small, :fast] The optimization mode.
66
+ def_delegator :list_map_db, :touch
67
+
68
+ # See CartonDb::ListMapDb#clear
69
+ def_delegator :list_map_db, :clear
70
+
71
+ # Performs a set-wise merge of the given elements with the
72
+ # content of an entry. Adds whatever elements are necessary
73
+ # so the content has an element corresponding to unique
74
+ # given element.
75
+ #
76
+ # See the documentation for
77
+ # CartonDb::ListMapDb#merge_elements for performance
78
+ # characteristics.
79
+ #
80
+ # @param key [String] The key identifying the entry.
81
+ # @param elements [Set<String>] A set or other enumerable
82
+ # collection of elements to be added as applicable.
83
+ def merge_elements(key, elements)
84
+ elements = Set.new(content) unless elements.is_a?(Set)
85
+ list_map_db.merge_elements key, elements
86
+ end
87
+
88
+ # See CartonDb::ListMapDb#element?
89
+ def_delegator :list_map_db, :element?
90
+
91
+ # Yields each entry in the database as a key/array pair.
92
+ #
93
+ # See the documentation for CartonDb::ListMapDb#each for
94
+ # performance characteristics.
95
+ #
96
+ # @yieldparam key [String] The key of the entry.
97
+ # @yeildparam array [Array<String>] The elements of the list
98
+ # entry's content.
99
+ def each
100
+ list_map_db.each do |key, list|
101
+ yield key, Set.new(list)
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ attr_accessor :list_map_db
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,102 @@
1
+ require 'forwardable'
2
+
3
+ module CartonDb
4
+
5
+ # A map with strings as keys and values that can each be either
6
+ # a string or nil.
7
+ #
8
+ # Data storage is in the same form as ListMapDb, but string
9
+ # values are stored as single-element lists and nil values are
10
+ # stored as empty lists. Only the first element in an entry's
11
+ # content is significant when retrieving a value from a
12
+ # multi-element underlying entry.
13
+ #
14
+ # See the documentation for CartonDb::ListMapDb for additional
15
+ # details.
16
+ class SimpleMapDb
17
+ extend Forwardable
18
+ include Enumerable
19
+
20
+ # Initializes an instance that interacts with the database
21
+ # identified by the given name, which is the full path to a
22
+ # directory in the filesystem.
23
+ #
24
+ # See the documentation for CartonDb::ListMapDb#initialize
25
+ # for additional details.
26
+ #
27
+ # @param name [String] The full path of the directory in the
28
+ # filesystem in which the data is stored or will be stored.
29
+ def initialize(name)
30
+ self.list_map_db = CartonDb::ListMapDb.new(name)
31
+ end
32
+
33
+ # Creates a new entry or replaces the contents of the
34
+ # existing entry identified by the given key.
35
+ #
36
+ # See the documentation for CartonDb::ListMapDb#initialize
37
+ # for performance characteristics.
38
+ #
39
+ # @param key [String] The key identifying the entry.
40
+ # @param value [String, nil] The value to be stored.
41
+ def []=(key, value)
42
+ content = value.nil? ? [] : [value.to_s]
43
+ list_map_db[key] = content
44
+ end
45
+
46
+ # Returns the content of the entry identified by the given
47
+ # key or nil if no such entry exists.
48
+ #
49
+ # See the documentation for CartonDb::ListMapDb#initialize
50
+ # for performance characteristics.
51
+ #
52
+ # @param key [String] The key identifying the entry.
53
+ # @return [String, nil] if a matching entry exists.
54
+ # @return [nil] if no matching entry exists.
55
+ def [](key)
56
+ content = list_map_db[key]
57
+ content&.first
58
+ end
59
+
60
+ # See CartonDb::ListMapDb#empty?
61
+ def_delegator :list_map_db, :empty?
62
+
63
+ # see cartondb::listmapdb#count
64
+ def_delegator :list_map_db, :count
65
+
66
+ # See CartonDb::ListMapDb#Key?
67
+ def_delegator :list_map_db, :key?
68
+
69
+ # See CartonDb::ListMapDb#delete
70
+ def_delegator :list_map_db, :delete
71
+
72
+ # Creates an entry with a nil value if no entry exists for
73
+ # the given key. Has no effect on the value of the entry if
74
+ # it already exists.
75
+ #
76
+ # See the documentation for CartonDb::ListMapDb#touch for
77
+ # performance characteristics.
78
+ #
79
+ # @param key [String] The key identifying the entry.
80
+ # @param optimization[:small, :fast] The optimization mode.
81
+ def_delegator :list_map_db, :touch
82
+
83
+ # See CartonDb::ListMapDb#clear
84
+ def_delegator :list_map_db, :clear
85
+
86
+ # Yields each entry in the database as a key/value pair.
87
+ #
88
+ # See the documentation for CartonDb::ListMapDb#yield for
89
+ # performance characteristics.
90
+ #
91
+ # @yieldparam key [String] The key of the entry.
92
+ # @yeildparam array [Array<String>] The elements of the list
93
+ # entry's content.
94
+ def_delegator :list_map_db, :each_first_element, :each
95
+
96
+ private
97
+
98
+ attr_accessor :list_map_db
99
+
100
+ end
101
+
102
+ end
@@ -1,4 +1,4 @@
1
1
  # -*- coding: UTF-8 -*-
2
2
  module CartonDb
3
- VERSION = "1.1.1"
3
+ VERSION = "1.1.2"
4
4
  end
data/lib/carton_db.rb CHANGED
@@ -3,6 +3,8 @@ require "carton_db/version"
3
3
  require "carton_db/escaping"
4
4
  require "carton_db/datum"
5
5
  require "carton_db/list_map_db"
6
+ require "carton_db/simple_map_db"
7
+ require "carton_db/set_map_db"
6
8
 
7
9
  module CartonDb
8
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carton_db
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Jorgensen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-06 00:00:00.000000000 Z
11
+ date: 2017-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-prof
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.0'
55
69
  description:
56
70
  email:
57
71
  - stevej@stevej.name
@@ -76,6 +90,8 @@ files:
76
90
  - lib/carton_db/list_map_db.rb
77
91
  - lib/carton_db/list_map_db/segment.rb
78
92
  - lib/carton_db/list_map_db/segment_group.rb
93
+ - lib/carton_db/set_map_db.rb
94
+ - lib/carton_db/simple_map_db.rb
79
95
  - lib/carton_db/version.rb
80
96
  - tmp/.gitkeep
81
97
  homepage: https://github.com/stevecj/carton_db.rb
@@ -90,7 +106,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
106
  requirements:
91
107
  - - ">="
92
108
  - !ruby/object:Gem::Version
93
- version: '0'
109
+ version: 2.3.0
94
110
  required_rubygems_version: !ruby/object:Gem::Requirement
95
111
  requirements:
96
112
  - - ">="