poros 0.2.0 → 0.2.1
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 +4 -4
- data/.travis.yml +1 -0
- data/lib/poros.rb +6 -208
- data/lib/poros/class_methods.rb +169 -0
- data/lib/poros/info.rb +16 -0
- data/lib/poros/instance_methods.rb +25 -0
- data/lib/poros/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73a30daa683b2b3f91f9c1145d8a2c663431789e96c5007f1b768358dc984490
|
4
|
+
data.tar.gz: bb1a9241edf4c85b0b5029f5a8aedb9f5dc19338ea65bfdbe179c0087654f961
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4dc72766c3e755d7d8f60a28b9df09ee0dcd9caba027fb1d518daf796e9a9a2afe99b940b1876358e3712b5aad6e275e3b0450c9a10e34dd737195ccb032fe0
|
7
|
+
data.tar.gz: d0b24230f41db3041e993b52a79c52fdc4971024b259fb6b95f934924b8d116bca73ebea5f65cbee55021a3714938b8ae86c50e609177503003124a41da961dc
|
data/.travis.yml
CHANGED
data/lib/poros.rb
CHANGED
@@ -1,218 +1,16 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'securerandom'
|
3
3
|
|
4
|
+
require 'poros/instance_methods'
|
5
|
+
require 'poros/class_methods'
|
6
|
+
|
4
7
|
module Poros
|
5
|
-
|
8
|
+
include Poros::InstanceMethods
|
9
|
+
include Poros::ClassMethods
|
10
|
+
|
6
11
|
def self.included(base)
|
7
12
|
base.class_eval do
|
8
13
|
extend ClassMethods
|
9
14
|
end
|
10
15
|
end
|
11
|
-
|
12
|
-
def uuid
|
13
|
-
@uuid ||= SecureRandom.uuid
|
14
|
-
end
|
15
|
-
|
16
|
-
def poros
|
17
|
-
@poros ||= PorosInfo.new(self)
|
18
|
-
end
|
19
|
-
|
20
|
-
def destroy
|
21
|
-
File.delete(poros.file_path)
|
22
|
-
self.class.remove_from_index(self)
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
|
-
def save
|
27
|
-
File.write(poros.file_path, poros.to_h.to_yaml)
|
28
|
-
self.class.data_changed = true
|
29
|
-
self.class.update_index(self)
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
class PorosInfo
|
34
|
-
def initialize(object)
|
35
|
-
@object = object
|
36
|
-
end
|
37
|
-
|
38
|
-
def file_path
|
39
|
-
@object.class.file_path(@object.uuid)
|
40
|
-
end
|
41
|
-
|
42
|
-
def to_h
|
43
|
-
@object.class.poro_attrs.map { |column|
|
44
|
-
[column, @object.send(column.to_s)]
|
45
|
-
}.to_h
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
module ClassMethods
|
50
|
-
attr_accessor :in_transaction, :data_changed
|
51
|
-
|
52
|
-
def poro_attr(*attrs)
|
53
|
-
@poro_attrs = [:uuid] | attrs
|
54
|
-
attrs.each { |column|
|
55
|
-
class_eval "attr_accessor :#{column}"
|
56
|
-
}
|
57
|
-
end
|
58
|
-
|
59
|
-
def poro_attrs
|
60
|
-
@poro_attrs ||= []
|
61
|
-
end
|
62
|
-
|
63
|
-
def poro_index(*attrs)
|
64
|
-
@poro_indexes ||= []
|
65
|
-
@poro_indexes += attrs
|
66
|
-
end
|
67
|
-
|
68
|
-
def poro_indexes
|
69
|
-
@poro_indexes ||= []
|
70
|
-
end
|
71
|
-
|
72
|
-
def find(uuid)
|
73
|
-
attrs = YAML.load(File.read(file_path(uuid)))
|
74
|
-
attrs.delete(:uuid)
|
75
|
-
|
76
|
-
object = new(attrs)
|
77
|
-
object.uuid = uuid
|
78
|
-
object
|
79
|
-
end
|
80
|
-
|
81
|
-
def file_path(uuid)
|
82
|
-
FileUtils.mkdir_p(data_directory) unless File.exist?(data_directory)
|
83
|
-
File.join(data_directory, file_name(uuid))
|
84
|
-
end
|
85
|
-
|
86
|
-
def data_directory
|
87
|
-
"./db/#{self}/"
|
88
|
-
end
|
89
|
-
|
90
|
-
def file_name(uuid)
|
91
|
-
"#{uuid}.yml"
|
92
|
-
end
|
93
|
-
|
94
|
-
def index_file
|
95
|
-
File.join(data_directory, "indexes.yml")
|
96
|
-
end
|
97
|
-
|
98
|
-
def all
|
99
|
-
Dir.glob(File.join(data_directory, '*.yml')).map { |file|
|
100
|
-
next if file == index_file
|
101
|
-
data = YAML.load(File.read(file))
|
102
|
-
find(data[:uuid])
|
103
|
-
}.compact
|
104
|
-
end
|
105
|
-
|
106
|
-
def where(query)
|
107
|
-
indexed, table_scan = query.partition { |index, key| poro_indexes.include?(index) }
|
108
|
-
|
109
|
-
indexed_results = indexed.map { |key, value|
|
110
|
-
case value
|
111
|
-
when Regexp
|
112
|
-
index_data[key].keys.flat_map { |value_name|
|
113
|
-
index_data[key][value_name] if value =~ value_name
|
114
|
-
}.compact
|
115
|
-
when Array
|
116
|
-
value.flat_map { |value_name| index_data[key][value_name] }
|
117
|
-
when Proc
|
118
|
-
index_data[key].keys.flat_map { |value_name|
|
119
|
-
index_data[key][value_name] if value.call(value_name)
|
120
|
-
}.compact
|
121
|
-
else
|
122
|
-
index_data[key].has_key?(value) ?
|
123
|
-
index_data[key][value] : []
|
124
|
-
end
|
125
|
-
}.inject(:&)
|
126
|
-
|
127
|
-
if table_scan.size > 0
|
128
|
-
scanned_results = Dir.glob(File.join(data_directory, '*.yml')).map { |file|
|
129
|
-
next if file == index_file
|
130
|
-
data = YAML.load(File.read(file))
|
131
|
-
data[:uuid] if table_scan.all? { |key, value|
|
132
|
-
case value
|
133
|
-
when Regexp
|
134
|
-
value =~ data[key]
|
135
|
-
when Array
|
136
|
-
value.include?(data[key])
|
137
|
-
when Proc
|
138
|
-
value.call(data[key])
|
139
|
-
else
|
140
|
-
data[key] == value
|
141
|
-
end
|
142
|
-
}
|
143
|
-
}.compact
|
144
|
-
end
|
145
|
-
|
146
|
-
if indexed.size > 0 && table_scan.size > 0
|
147
|
-
results = indexed_results & scanned_results
|
148
|
-
elsif indexed.size > 0
|
149
|
-
results = indexed_results
|
150
|
-
else
|
151
|
-
results = scanned_results
|
152
|
-
end
|
153
|
-
|
154
|
-
results.map { |uuid| find(uuid) }
|
155
|
-
end
|
156
|
-
|
157
|
-
def index_data
|
158
|
-
return @index_data if @index_data
|
159
|
-
|
160
|
-
data = File.exist?(index_file) ? YAML.load(File.read(index_file)) : {}
|
161
|
-
# Make sure we always have every index as a key
|
162
|
-
poro_indexes.each do |index|
|
163
|
-
data[index] = {} unless data.has_key?(index)
|
164
|
-
end
|
165
|
-
|
166
|
-
@index_data = data
|
167
|
-
end
|
168
|
-
|
169
|
-
def write_index_data
|
170
|
-
File.write(index_file, @index_data.to_yaml)
|
171
|
-
end
|
172
|
-
|
173
|
-
def update_index(object)
|
174
|
-
remove_from_index(object, false)
|
175
|
-
|
176
|
-
index_data
|
177
|
-
|
178
|
-
poro_indexes.each do |index|
|
179
|
-
@index_data[index] = {} unless @index_data.has_key?(index)
|
180
|
-
value = object.send(index)
|
181
|
-
@index_data[index][value] ||= []
|
182
|
-
@index_data[index][value] = @index_data[index][value] | [object.uuid]
|
183
|
-
end
|
184
|
-
|
185
|
-
write_index_data unless @in_transaction
|
186
|
-
end
|
187
|
-
|
188
|
-
def remove_from_index(object, perist = true)
|
189
|
-
index_data
|
190
|
-
|
191
|
-
poro_indexes.each do |index|
|
192
|
-
@index_data[index] = {} unless @index_data.has_key?(index)
|
193
|
-
@index_data[index].keys.each do |value|
|
194
|
-
@index_data[index][value] ||= []
|
195
|
-
@index_data[index][value] -= [object.uuid]
|
196
|
-
end
|
197
|
-
end
|
198
|
-
write_index_data if !@in_transaction && perist
|
199
|
-
end
|
200
|
-
|
201
|
-
def rebuild_indexes
|
202
|
-
transaction do
|
203
|
-
@data_changed = true
|
204
|
-
@index_data = {}
|
205
|
-
File.delete(index_file) if File.exist?(index_file)
|
206
|
-
all.each { |object| update_index(object) }
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def transaction(&block)
|
211
|
-
@in_transaction = true
|
212
|
-
@data_changed = false
|
213
|
-
block.call
|
214
|
-
@in_transaction = false
|
215
|
-
write_index_data if @data_changed
|
216
|
-
end
|
217
|
-
end
|
218
16
|
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module Poros::ClassMethods
|
2
|
+
attr_accessor :in_transaction, :data_changed
|
3
|
+
|
4
|
+
def poro_attr(*attrs)
|
5
|
+
@poro_attrs = [:uuid] | attrs
|
6
|
+
attrs.each { |column|
|
7
|
+
class_eval "attr_accessor :#{column}"
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
def poro_attrs
|
12
|
+
@poro_attrs ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def poro_index(*attrs)
|
16
|
+
@poro_indexes ||= []
|
17
|
+
@poro_indexes += attrs
|
18
|
+
end
|
19
|
+
|
20
|
+
def poro_indexes
|
21
|
+
@poro_indexes ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
def find(uuid)
|
25
|
+
attrs = YAML.load(File.read(file_path(uuid)))
|
26
|
+
attrs.delete(:uuid)
|
27
|
+
|
28
|
+
object = new(attrs)
|
29
|
+
object.uuid = uuid
|
30
|
+
object
|
31
|
+
end
|
32
|
+
|
33
|
+
def file_path(uuid)
|
34
|
+
FileUtils.mkdir_p(data_directory) unless File.exist?(data_directory)
|
35
|
+
File.join(data_directory, file_name(uuid))
|
36
|
+
end
|
37
|
+
|
38
|
+
def data_directory
|
39
|
+
"./db/#{self}/"
|
40
|
+
end
|
41
|
+
|
42
|
+
def file_name(uuid)
|
43
|
+
"#{uuid}.yml"
|
44
|
+
end
|
45
|
+
|
46
|
+
def index_file
|
47
|
+
File.join(data_directory, "indexes.yml")
|
48
|
+
end
|
49
|
+
|
50
|
+
def all
|
51
|
+
Dir.glob(File.join(data_directory, '*.yml')).map { |file|
|
52
|
+
next if file == index_file
|
53
|
+
data = YAML.load(File.read(file))
|
54
|
+
find(data[:uuid])
|
55
|
+
}.compact
|
56
|
+
end
|
57
|
+
|
58
|
+
def where(query)
|
59
|
+
indexed, table_scan = query.partition { |index, key| poro_indexes.include?(index) }
|
60
|
+
|
61
|
+
indexed_results = indexed.map { |key, value|
|
62
|
+
case value
|
63
|
+
when Regexp
|
64
|
+
index_data[key].keys.flat_map { |value_name|
|
65
|
+
index_data[key][value_name] if value =~ value_name
|
66
|
+
}.compact
|
67
|
+
when Array
|
68
|
+
value.flat_map { |value_name| index_data[key][value_name] }
|
69
|
+
when Proc
|
70
|
+
index_data[key].keys.flat_map { |value_name|
|
71
|
+
index_data[key][value_name] if value.call(value_name)
|
72
|
+
}.compact
|
73
|
+
else
|
74
|
+
index_data[key].has_key?(value) ?
|
75
|
+
index_data[key][value] : []
|
76
|
+
end
|
77
|
+
}.inject(:&)
|
78
|
+
|
79
|
+
if table_scan.size > 0
|
80
|
+
scanned_results = Dir.glob(File.join(data_directory, '*.yml')).map { |file|
|
81
|
+
next if file == index_file
|
82
|
+
data = YAML.load(File.read(file))
|
83
|
+
data[:uuid] if table_scan.all? { |key, value|
|
84
|
+
case value
|
85
|
+
when Regexp
|
86
|
+
value =~ data[key]
|
87
|
+
when Array
|
88
|
+
value.include?(data[key])
|
89
|
+
when Proc
|
90
|
+
value.call(data[key])
|
91
|
+
else
|
92
|
+
data[key] == value
|
93
|
+
end
|
94
|
+
}
|
95
|
+
}.compact
|
96
|
+
end
|
97
|
+
|
98
|
+
if indexed.size > 0 && table_scan.size > 0
|
99
|
+
results = indexed_results & scanned_results
|
100
|
+
elsif indexed.size > 0
|
101
|
+
results = indexed_results
|
102
|
+
else
|
103
|
+
results = scanned_results
|
104
|
+
end
|
105
|
+
|
106
|
+
results.map { |uuid| find(uuid) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def index_data
|
110
|
+
return @index_data if @index_data
|
111
|
+
|
112
|
+
data = File.exist?(index_file) ? YAML.load(File.read(index_file)) : {}
|
113
|
+
# Make sure we always have every index as a key
|
114
|
+
poro_indexes.each do |index|
|
115
|
+
data[index] = {} unless data.has_key?(index)
|
116
|
+
end
|
117
|
+
|
118
|
+
@index_data = data
|
119
|
+
end
|
120
|
+
|
121
|
+
def write_index_data
|
122
|
+
File.write(index_file, @index_data.to_yaml)
|
123
|
+
end
|
124
|
+
|
125
|
+
def update_index(object)
|
126
|
+
remove_from_index(object, false)
|
127
|
+
|
128
|
+
index_data
|
129
|
+
|
130
|
+
poro_indexes.each do |index|
|
131
|
+
@index_data[index] = {} unless @index_data.has_key?(index)
|
132
|
+
value = object.send(index)
|
133
|
+
@index_data[index][value] ||= []
|
134
|
+
@index_data[index][value] = @index_data[index][value] | [object.uuid]
|
135
|
+
end
|
136
|
+
|
137
|
+
write_index_data unless @in_transaction
|
138
|
+
end
|
139
|
+
|
140
|
+
def remove_from_index(object, perist = true)
|
141
|
+
index_data
|
142
|
+
|
143
|
+
poro_indexes.each do |index|
|
144
|
+
@index_data[index] = {} unless @index_data.has_key?(index)
|
145
|
+
@index_data[index].keys.each do |value|
|
146
|
+
@index_data[index][value] ||= []
|
147
|
+
@index_data[index][value] -= [object.uuid]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
write_index_data if !@in_transaction && perist
|
151
|
+
end
|
152
|
+
|
153
|
+
def rebuild_indexes
|
154
|
+
transaction do
|
155
|
+
@data_changed = true
|
156
|
+
@index_data = {}
|
157
|
+
File.delete(index_file) if File.exist?(index_file)
|
158
|
+
all.each { |object| update_index(object) }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def transaction(&block)
|
163
|
+
@in_transaction = true
|
164
|
+
@data_changed = false
|
165
|
+
block.call
|
166
|
+
@in_transaction = false
|
167
|
+
write_index_data if @data_changed
|
168
|
+
end
|
169
|
+
end
|
data/lib/poros/info.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
class Poros::Info
|
2
|
+
def initialize(object)
|
3
|
+
@object = object
|
4
|
+
end
|
5
|
+
|
6
|
+
def file_path
|
7
|
+
@object.class.file_path(@object.uuid)
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_h
|
11
|
+
@object.class.poro_attrs.map { |column|
|
12
|
+
[column, @object.send(column.to_s)]
|
13
|
+
}.to_h
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'poros/info'
|
2
|
+
|
3
|
+
module Poros::InstanceMethods
|
4
|
+
attr_accessor :uuid
|
5
|
+
def uuid
|
6
|
+
@uuid ||= SecureRandom.uuid
|
7
|
+
end
|
8
|
+
|
9
|
+
def poros
|
10
|
+
@poros ||= Poros::Info.new(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def destroy
|
14
|
+
File.delete(poros.file_path)
|
15
|
+
self.class.remove_from_index(self)
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def save
|
20
|
+
File.write(poros.file_path, poros.to_h.to_yaml)
|
21
|
+
self.class.data_changed = true
|
22
|
+
self.class.update_index(self)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
data/lib/poros/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: poros
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Ross Earle
|
@@ -66,6 +66,9 @@ files:
|
|
66
66
|
- README.md
|
67
67
|
- Rakefile
|
68
68
|
- lib/poros.rb
|
69
|
+
- lib/poros/class_methods.rb
|
70
|
+
- lib/poros/info.rb
|
71
|
+
- lib/poros/instance_methods.rb
|
69
72
|
- lib/poros/version.rb
|
70
73
|
- poros.gemspec
|
71
74
|
homepage: https://github.com/HellRok/YAMLCache
|