lucarecord 0.2.23 → 0.2.28
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/CHANGELOG.md +26 -0
- data/lib/luca_record/base.rb +2 -0
- data/lib/luca_record/dict.rb +20 -10
- data/lib/luca_record/io.rb +34 -21
- data/lib/luca_record/version.rb +1 -1
- data/lib/luca_support/code.rb +55 -32
- data/lib/luca_support/config.rb +9 -13
- data/lib/luca_support/range.rb +35 -0
- data/lib/luca_support/view.rb +5 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c52d38b86c9670e3358ef9e94553902a3a511f626689566a4dc0b1d5e480c041
|
4
|
+
data.tar.gz: 064b974bbeeaa1dbb8e644532c5e2bee67cdd5d697e1cdde99087204698aa665
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20ece81a5471e985bdc6b46aa341b3d859ad050b28a5976b0b20f15a44971ac0111b16a58db1053c91da73d91f8c37dc26e6bd825b4604a3c17ced65239a19b2
|
7
|
+
data.tar.gz: fc4af325295583e739fb972f3d96470f0a84d74ea4a4b330a16178d88de0c4700f64b28f36166539904c3b589c7540ec4486e36e74d6fd0d1e908da22e4cc685
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
## LucaRecord 0.2.28
|
2
|
+
|
3
|
+
* implement LucaSupport::Range, handle #by_month enumeration between several months.
|
4
|
+
* @record_type = 'raw' is deprecated in favor of overriding LucaRecord::IO.load_data
|
5
|
+
* change code search from exact match to prefix match
|
6
|
+
|
7
|
+
## LucaRecord 0.2.27
|
8
|
+
|
9
|
+
* Fix: update_digest
|
10
|
+
|
11
|
+
## LucaRecord 0.2.26
|
12
|
+
|
13
|
+
* Support #dig / #search for TSV dictionary
|
14
|
+
* Fix: shorten n-gram split factor on search word length < specified factor
|
15
|
+
|
16
|
+
## LucaRecord 0.2.25
|
17
|
+
|
18
|
+
* Implement `dir_digest()` for data validation.
|
19
|
+
* support defunct without effective history record
|
20
|
+
|
21
|
+
## LucaRecord 0.2.24
|
22
|
+
|
23
|
+
* Digit delimiter for `delimit_num` can be customized through `thousands_separator` and `decimal_separator` in config.yml.
|
24
|
+
* Const `CONFIG` and `PJDIR` is defined at `LucaRecord::Base`.
|
25
|
+
* add `LucaSupport::Code.keys_stringify()`
|
26
|
+
|
1
27
|
## LucaRecord 0.2.23
|
2
28
|
|
3
29
|
* Enhance Dictionary, supporting extensible options.
|
data/lib/luca_record/base.rb
CHANGED
data/lib/luca_record/dict.rb
CHANGED
@@ -17,10 +17,11 @@ module LucaRecord
|
|
17
17
|
set_driver
|
18
18
|
end
|
19
19
|
|
20
|
-
# Search
|
20
|
+
# Search code with n-gram word.
|
21
21
|
# If dictionary has Hash or Array, it returns [label, options].
|
22
22
|
#
|
23
23
|
def search(word, default_word = nil, main_key: 'label', options: nil)
|
24
|
+
definitions_lazyload
|
24
25
|
res, score = max_score_code(word.gsub(/[[:space:]]/, ''))
|
25
26
|
return default_word if score < 0.4
|
26
27
|
|
@@ -34,6 +35,12 @@ module LucaRecord
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
38
|
+
# Search with unique code.
|
39
|
+
#
|
40
|
+
def dig(*args)
|
41
|
+
@data.dig(*args)
|
42
|
+
end
|
43
|
+
|
37
44
|
# Separate main item from other options.
|
38
45
|
# If options specified as Array of string, it works as safe list filter.
|
39
46
|
#
|
@@ -49,7 +56,6 @@ module LucaRecord
|
|
49
56
|
[obj[main_key], options.compact]
|
50
57
|
end
|
51
58
|
|
52
|
-
#
|
53
59
|
# Load CSV with config options
|
54
60
|
#
|
55
61
|
def load_csv(path)
|
@@ -58,7 +64,6 @@ module LucaRecord
|
|
58
64
|
end
|
59
65
|
end
|
60
66
|
|
61
|
-
#
|
62
67
|
# load dictionary data
|
63
68
|
#
|
64
69
|
def self.load(file = @filename)
|
@@ -72,7 +77,6 @@ module LucaRecord
|
|
72
77
|
end
|
73
78
|
end
|
74
79
|
|
75
|
-
#
|
76
80
|
# generate dictionary from TSV file. Minimum assumption is as bellows:
|
77
81
|
# 1st row is converted symbol.
|
78
82
|
#
|
@@ -101,7 +105,7 @@ module LucaRecord
|
|
101
105
|
puts 'No error detected.'
|
102
106
|
nil
|
103
107
|
else
|
104
|
-
"Key #{errors.join(', ')} has nil #{target_key}."
|
108
|
+
puts "Key #{errors.join(', ')} has nil #{target_key}."
|
105
109
|
errors.count
|
106
110
|
end
|
107
111
|
end
|
@@ -109,13 +113,19 @@ module LucaRecord
|
|
109
113
|
private
|
110
114
|
|
111
115
|
def set_driver
|
112
|
-
|
113
|
-
@config =
|
114
|
-
@definitions =
|
116
|
+
@data = self.class.load(@path)
|
117
|
+
@config = @data['config']
|
118
|
+
@definitions = @data['definitions']
|
119
|
+
end
|
120
|
+
|
121
|
+
# Build Reverse dictionary for TSV data
|
122
|
+
#
|
123
|
+
def definitions_lazyload
|
124
|
+
@definitions ||= @data.each_with_object({}) { |(k, entry), h| h[entry[:label]] = k if entry[:label] }
|
115
125
|
end
|
116
126
|
|
117
127
|
def self.dict_path(filename)
|
118
|
-
Pathname(LucaSupport::
|
128
|
+
Pathname(LucaSupport::PJDIR) / 'dict' / filename
|
119
129
|
end
|
120
130
|
|
121
131
|
def self.reverse(dict)
|
@@ -124,7 +134,7 @@ module LucaRecord
|
|
124
134
|
|
125
135
|
def max_score_code(str)
|
126
136
|
res = @definitions.map do |k, v|
|
127
|
-
[v, match_score(str, k,
|
137
|
+
[v, match_score(str, k, 2)]
|
128
138
|
end
|
129
139
|
res.max { |x, y| x[1] <=> y[1] }
|
130
140
|
end
|
data/lib/luca_record/io.rb
CHANGED
@@ -64,11 +64,7 @@ module LucaRecord # :nodoc:
|
|
64
64
|
|
65
65
|
LucaSupport::Code.encode_term(start_year, start_month, end_year, end_month).each do |subdir|
|
66
66
|
open_records(basedir, subdir, nil, code) do |f, path|
|
67
|
-
|
68
|
-
yield f, path
|
69
|
-
else
|
70
|
-
yield load_data(f, path)
|
71
|
-
end
|
67
|
+
yield load_data(f, path)
|
72
68
|
end
|
73
69
|
end
|
74
70
|
end
|
@@ -80,11 +76,7 @@ module LucaRecord # :nodoc:
|
|
80
76
|
|
81
77
|
subdir = year.to_s + LucaSupport::Code.encode_month(month)
|
82
78
|
open_records(basedir, subdir, LucaSupport::Code.encode_date(day), code) do |f, path|
|
83
|
-
|
84
|
-
yield f, path
|
85
|
-
else
|
86
|
-
yield load_data(f, path), path
|
87
|
-
end
|
79
|
+
yield load_data(f, path), path
|
88
80
|
end
|
89
81
|
end
|
90
82
|
|
@@ -243,7 +235,7 @@ module LucaRecord # :nodoc:
|
|
243
235
|
end
|
244
236
|
|
245
237
|
# test if having required dirs/files under exec path
|
246
|
-
def valid_project?(path = LucaSupport::
|
238
|
+
def valid_project?(path = LucaSupport::PJDIR)
|
247
239
|
project_dir = Pathname(path)
|
248
240
|
FileTest.file?((project_dir + 'config.yml').to_s) and FileTest.directory?( (project_dir + 'data').to_s)
|
249
241
|
end
|
@@ -252,6 +244,17 @@ module LucaRecord # :nodoc:
|
|
252
244
|
LucaSupport::Code.encode_txid(new_record_no(basedir, date_obj))
|
253
245
|
end
|
254
246
|
|
247
|
+
# Calculate md5sum under specific month directory.
|
248
|
+
#
|
249
|
+
def dir_digest(year, month, basedir = @dirname)
|
250
|
+
subdir = year.to_s + LucaSupport::Code.encode_month(month)
|
251
|
+
digest = String.new
|
252
|
+
open_records(basedir, subdir).each do |f, path|
|
253
|
+
digest = update_digest(digest, f.read, path[1])
|
254
|
+
end
|
255
|
+
digest
|
256
|
+
end
|
257
|
+
|
255
258
|
private
|
256
259
|
|
257
260
|
# define new transaction ID & write data at once
|
@@ -302,6 +305,14 @@ module LucaRecord # :nodoc:
|
|
302
305
|
end
|
303
306
|
end
|
304
307
|
|
308
|
+
# Calculate md5sum with original digest, file content and filename(optional).
|
309
|
+
#
|
310
|
+
def update_digest(digest, str, filename = nil)
|
311
|
+
str = filename.nil? ? str : filename + str
|
312
|
+
content = Digest::MD5.new.update(str).hexdigest
|
313
|
+
Digest::MD5.new.update(digest + content).hexdigest
|
314
|
+
end
|
315
|
+
|
305
316
|
# git object like structure
|
306
317
|
#
|
307
318
|
def open_hashed(basedir, id, mode = 'r')
|
@@ -339,12 +350,11 @@ module LucaRecord # :nodoc:
|
|
339
350
|
# If specific decode is needed, override this method in each class.
|
340
351
|
#
|
341
352
|
def load_data(io, path = nil)
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
# TODO: implement JSON parse
|
353
|
+
if @record_type
|
354
|
+
case @record_type
|
355
|
+
when 'json'
|
356
|
+
# TODO: implement JSON parse
|
357
|
+
end
|
348
358
|
else
|
349
359
|
LucaSupport::Code.decimalize(YAML.load(io.read)).tap { |obj| validate_keys(obj) }
|
350
360
|
end
|
@@ -362,17 +372,20 @@ module LucaRecord # :nodoc:
|
|
362
372
|
|
363
373
|
# TODO: replace with data_dir method
|
364
374
|
def abs_path(base_dir)
|
365
|
-
Pathname(LucaSupport::
|
375
|
+
Pathname(LucaSupport::PJDIR) / 'data' / base_dir
|
366
376
|
end
|
367
377
|
|
368
|
-
#
|
369
|
-
#
|
378
|
+
# True when file doesn't have record on code.
|
379
|
+
# False when file may have one.
|
380
|
+
# If filename doesn't record codes, always return false,
|
381
|
+
# so later check is required. This is partial optimization.
|
382
|
+
#
|
370
383
|
def skip_on_unmatch_code(subpath, code = nil)
|
371
384
|
# p filename.split('-')[1..-1]
|
372
385
|
filename = subpath.split('/').last
|
373
386
|
return false if code.nil? || filename.length <= 4
|
374
387
|
|
375
|
-
|
388
|
+
filename.split('-')[1..-1].select { |fragment| /^#{code}/.match(fragment) }.empty?
|
376
389
|
end
|
377
390
|
|
378
391
|
# AUTO INCREMENT
|
data/lib/luca_record/version.rb
CHANGED
data/lib/luca_support/code.rb
CHANGED
@@ -5,8 +5,9 @@ require 'securerandom'
|
|
5
5
|
require 'digest/sha1'
|
6
6
|
require 'luca_support/config'
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
module LucaSupport # :nodoc:
|
9
|
+
# implement Luca IDs convention
|
10
|
+
#
|
10
11
|
module Code
|
11
12
|
module_function
|
12
13
|
|
@@ -54,21 +55,24 @@ module LucaSupport
|
|
54
55
|
def delimit_num(num, decimal: nil, delimiter: nil)
|
55
56
|
return nil if num.nil?
|
56
57
|
|
57
|
-
decimal ||= LucaSupport::
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
58
|
+
decimal ||= LucaSupport::CONFIG['decimal_num']
|
59
|
+
delimiter ||= LucaSupport::CONFIG['thousands_separator']
|
60
|
+
case num
|
61
|
+
when BigDecimal
|
62
|
+
if decimal == 0
|
63
|
+
num.floor.to_s.reverse!.gsub(/(\d{3})(?=\d)/, '\1 ').reverse!
|
64
|
+
.gsub(/\s/, delimiter)
|
65
|
+
else
|
66
|
+
fragments = num.floor(decimal).to_s('F').split('.')
|
67
|
+
fragments[0].reverse!.gsub!(/(\d{3})(?=\d)/, '\1 ')
|
68
|
+
fragments[0].reverse!.gsub!(/\s/, delimiter)
|
69
|
+
fragments[1].gsub!(/(\d{3})(?=\d)/, '\1 ')
|
70
|
+
fragments.join(LucaSupport::CONFIG['decimal_separator'])
|
71
|
+
end
|
72
|
+
else
|
73
|
+
num.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\1 ').reverse!
|
74
|
+
.gsub(/\s/, delimiter)
|
75
|
+
end
|
72
76
|
end
|
73
77
|
|
74
78
|
# encode directory name from year and month.
|
@@ -114,9 +118,24 @@ module LucaSupport
|
|
114
118
|
Digest::SHA1.hexdigest(SecureRandom.uuid)
|
115
119
|
end
|
116
120
|
|
121
|
+
# Convert Hash keys to string recursively.
|
122
|
+
# Required for YAML compatibility.
|
123
|
+
#
|
124
|
+
def keys_stringify(dat)
|
125
|
+
case dat
|
126
|
+
when Array
|
127
|
+
dat.map { |d| keys_stringify(d) }
|
128
|
+
when Hash
|
129
|
+
dat.map { |k, v| [k.to_s, keys_stringify(v)] }.to_h
|
130
|
+
else
|
131
|
+
dat
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
117
135
|
def match_score(a, b, n = 2)
|
118
|
-
|
119
|
-
|
136
|
+
split_factor = [a.length, b.length, n].min
|
137
|
+
v_a = to_ngram(a, split_factor)
|
138
|
+
v_b = to_ngram(b, split_factor)
|
120
139
|
|
121
140
|
v_a.map { |item| v_b.include?(item) ? 1 : 0 }.sum / v_a.length.to_f
|
122
141
|
end
|
@@ -142,7 +161,7 @@ module LucaSupport
|
|
142
161
|
end
|
143
162
|
end
|
144
163
|
|
145
|
-
def readable(obj, len = LucaSupport::
|
164
|
+
def readable(obj, len = LucaSupport::CONFIG['decimal_num'])
|
146
165
|
case obj
|
147
166
|
when Array
|
148
167
|
obj.map { |i| readable(i) }
|
@@ -170,7 +189,6 @@ module LucaSupport
|
|
170
189
|
end
|
171
190
|
end
|
172
191
|
|
173
|
-
#
|
174
192
|
# return current value with effective/defunct on target @date
|
175
193
|
# For multiple attribues, return hash on other than 'val'. Examples are as bellows:
|
176
194
|
#
|
@@ -183,18 +201,23 @@ module LucaSupport
|
|
183
201
|
# point: 1000
|
184
202
|
# => { 'effective' => 2020-1-1, 'rank' => 5, 'point' => 1000 }
|
185
203
|
#
|
204
|
+
# - defunct: 2020-1-1
|
205
|
+
# val: 3000
|
206
|
+
# => nil
|
207
|
+
#
|
186
208
|
def take_current(dat, item)
|
187
|
-
target = dat
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
209
|
+
target = dat&.dig(item)
|
210
|
+
return target unless target.is_a?(Array)
|
211
|
+
|
212
|
+
keys = target.map(&:keys).flatten
|
213
|
+
return target if !keys.include?('effective') && !keys.include?('defunct')
|
214
|
+
|
215
|
+
latest = target
|
216
|
+
.reject { |a| a['defunct'] && Date.parse(a['defunct'].to_s) < @date }
|
217
|
+
.filter { |a| a['effective'] && Date.parse(a['effective'].to_s) < @date }
|
218
|
+
.max { |a, b| Date.parse(a['effective'].to_s) <=> Date.parse(b['effective'].to_s) }
|
219
|
+
|
220
|
+
latest&.dig('val') || latest
|
198
221
|
end
|
199
222
|
|
200
223
|
def has_status?(dat, status)
|
data/lib/luca_support/config.rb
CHANGED
@@ -8,19 +8,15 @@ require 'yaml'
|
|
8
8
|
module LucaSupport
|
9
9
|
PJDIR = ENV['LUCA_TEST_DIR'] || Dir.pwd.freeze
|
10
10
|
CONFIG = begin
|
11
|
-
|
11
|
+
{
|
12
|
+
'decimal_separator' => '.',
|
13
|
+
'thousands_separator' => ','
|
14
|
+
}.merge(YAML.load_file(Pathname(PJDIR) / 'config.yml'))
|
12
15
|
rescue Errno::ENOENT
|
13
|
-
{
|
16
|
+
{
|
17
|
+
'decimal_separator' => '.',
|
18
|
+
'thousands_separator' => ','
|
19
|
+
}
|
14
20
|
end
|
15
|
-
|
16
|
-
module Config
|
17
|
-
# Project top directory.
|
18
|
-
Pjdir = ENV['LUCA_TEST_DIR'] || Dir.pwd.freeze
|
19
|
-
if File.exist?(Pathname(Pjdir) / 'config.yml')
|
20
|
-
# DECIMAL_NUM = YAML.load_file(Pathname(Pjdir) / 'config.yml', **{})['decimal_number']
|
21
|
-
COUNTRY = YAML.load_file(Pathname(Pjdir) / 'config.yml', **{})['country']
|
22
|
-
DECIMAL_NUM ||= 0 if COUNTRY == 'jp'
|
23
|
-
end
|
24
|
-
DECIMAL_NUM ||= 2
|
25
|
-
end
|
21
|
+
CONFIG['decimal_num'] ||= CONFIG['country'] == 'jp' ? 0 : 2
|
26
22
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LucaSupport # :nodoc:
|
4
|
+
# Partial range operation
|
5
|
+
#
|
6
|
+
module Range
|
7
|
+
def self.included(klass) # :nodoc:
|
8
|
+
klass.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
def by_month(step = nil, from: nil, to: nil)
|
12
|
+
return enum_for(:by_month, step, from: from, to: to) unless block_given?
|
13
|
+
|
14
|
+
from ||= @start_date
|
15
|
+
to ||= @end_date
|
16
|
+
self.class.term_by_month(from, to, step || 1).each do |date|
|
17
|
+
@cursor_start = date
|
18
|
+
@cursor_end = step.nil? ? date : [date.next_month(step - 1), to].min
|
19
|
+
yield @cursor_start, @cursor_end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
def term_by_month(start_date, end_date, step = 1)
|
25
|
+
Enumerator.new do |yielder|
|
26
|
+
each_month = start_date
|
27
|
+
while each_month <= end_date
|
28
|
+
yielder << each_month
|
29
|
+
each_month = each_month.next_month(step)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/luca_support/view.rb
CHANGED
@@ -34,9 +34,13 @@ module LucaSupport
|
|
34
34
|
out
|
35
35
|
end
|
36
36
|
|
37
|
+
# Search existing file and return path under:
|
38
|
+
# 1. 'templates/' in Project directory that data resides
|
39
|
+
# 2. 'templates/' in Library directory that calls LucaSupport::View#search_template
|
40
|
+
#
|
37
41
|
def search_template(file, dir = 'templates')
|
38
42
|
# TODO: load config
|
39
|
-
[
|
43
|
+
[LucaSupport::PJDIR, lib_path].each do |base|
|
40
44
|
path = (Pathname(base) / dir / file)
|
41
45
|
return path.to_path if path.file?
|
42
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lucarecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.28
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chuma Takahiro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mail
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- lib/luca_support/code.rb
|
87
87
|
- lib/luca_support/config.rb
|
88
88
|
- lib/luca_support/mail.rb
|
89
|
+
- lib/luca_support/range.rb
|
89
90
|
- lib/luca_support/view.rb
|
90
91
|
homepage: https://github.com/chumaltd/luca/tree/master/lucarecord
|
91
92
|
licenses:
|
@@ -109,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
110
|
- !ruby/object:Gem::Version
|
110
111
|
version: '0'
|
111
112
|
requirements: []
|
112
|
-
rubygems_version: 3.
|
113
|
+
rubygems_version: 3.2.3
|
113
114
|
signing_key:
|
114
115
|
specification_version: 4
|
115
116
|
summary: ERP File operation framework
|