Module: LucaRecord::IO::ClassMethods
- Defined in:
- lib/luca_record/io.rb
Instance Method Summary collapse
- #add_status!(id, status, basedir = @dirname) ⇒ Object
-
#all(basedir = @dirname) ⇒ Object
retrieve all data.
-
#asof(year, month = nil, day = nil, basedir = @dirname) ⇒ Object
search date based record.
-
#change_codes(id, new_codes, basedir = @dirname) ⇒ Object
change filename with new code set.
-
#create(obj, date: nil, codes: nil, basedir: @dirname) ⇒ Object
create record both of uuid/date identified.
-
#delete(id, basedir = @dirname) ⇒ Object
delete file by id.
-
#dir_digest(year, month, basedir = @dirname) ⇒ Object
Calculate md5sum under specific month directory.
-
#encode_hashed_path(id, split_factor = 3) ⇒ Object
Directory separation for performance.
-
#find(id, basedir = @dirname) ⇒ Object
find ID based record.
-
#find_secure(id, basedir = @dirname, prefix = 's_') ⇒ Object
Merge 2 files under plain & prefixed dirs.
-
#id2path(id) ⇒ Object
Convert ID to file directory/filename path.
-
#id_completion(phrase, label: 'name', basedir: @dirname) ⇒ Object
If multiple ID matched, return short ID and human readable label.
-
#latest_month(code = nil, basedir = @dirname) ⇒ Object
- year, month
-
pair of the latest record.
- #load_project(path, ext_conf: nil) ⇒ Object
- #new_record_id(basedir, date_obj) ⇒ Object
- #prefix_search(phrase, basedir: @dirname) ⇒ Object
- #prepare_dir!(basedir, date_obj) ⇒ Object
-
#save(obj, basedir = @dirname) ⇒ Object
update file with obj.
-
#search(year, month = nil, day = nil, code = nil, basedir = @dirname) ⇒ Object
search with date params & code.
-
#term(start_year, start_month, end_year, end_month, code = nil, basedir = @dirname) ⇒ Object
scan ranging data on multiple months.
-
#upsert(obj, basedir: @dirname) ⇒ Object
update uuid keyed record based on ‘id’ field.
-
#valid_project?(path = CONST.pjdir) ⇒ Boolean
test if having required dirs/files under exec path.
Instance Method Details
#add_status!(id, status, basedir = @dirname) ⇒ Object
203 204 205 206 207 208 209 210 |
# File 'lib/luca_record/io.rb', line 203 def add_status!(id, status, basedir = @dirname) path = abs_path(basedir) / id2path(id) origin = YAML.safe_load(File.read(path), permitted_classes: [Date]) newline = { status => DateTime.now.to_s } origin['status'] = [] if origin['status'].nil? origin['status'] << newline File.write(path, YAML.dump(origin.sort.to_h)) end |
#all(basedir = @dirname) ⇒ Object
retrieve all data
117 118 119 120 121 122 123 |
# File 'lib/luca_record/io.rb', line 117 def all(basedir = @dirname) return enum_for(:all, basedir) unless block_given? open_all(basedir) do |f| yield load_data(f) end end |
#asof(year, month = nil, day = nil, basedir = @dirname) ⇒ Object
search date based record.
-
data hash
-
data id. Array like [2020H, V001]
86 87 88 89 90 |
# File 'lib/luca_record/io.rb', line 86 def asof(year, month = nil, day = nil, basedir = @dirname) return enum_for(:search, year, month, day, nil, basedir) unless block_given? search(year, month, day, nil, basedir) { |data, path| yield data, path } end |
#change_codes(id, new_codes, basedir = @dirname) ⇒ Object
change filename with new code set
242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/luca_record/io.rb', line 242 def change_codes(id, new_codes, basedir = @dirname) raise 'invalid id' if id.split('/').length != 2 newfile = new_codes.empty? ? id : id + '-' + new_codes.join('-') Dir.chdir(abs_path(basedir)) do origin = Dir.glob("#{id}*") raise 'duplicated files' if origin.length != 1 File.rename(origin.first, newfile) end newfile end |
#create(obj, date: nil, codes: nil, basedir: @dirname) ⇒ Object
create record both of uuid/date identified.
139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/luca_record/io.rb', line 139 def create(obj, date: nil, codes: nil, basedir: @dirname) validate_keys(obj) if date create_record(obj, date, codes, basedir) else obj['id'] = LucaSupport::Code.issue_random_id open_hashed(basedir, obj['id'], 'w') do |f| f.write(YAML.dump(LucaSupport::Code.readable(obj.sort.to_h))) end obj['id'] end end |
#delete(id, basedir = @dirname) ⇒ Object
delete file by id
235 236 237 238 |
# File 'lib/luca_record/io.rb', line 235 def delete(id, basedir = @dirname) FileUtils.rm(Pathname(abs_path(basedir)) / id2path(id)) id end |
#dir_digest(year, month, basedir = @dirname) ⇒ Object
Calculate md5sum under specific month directory.
335 336 337 338 339 340 341 342 |
# File 'lib/luca_record/io.rb', line 335 def dir_digest(year, month, basedir = @dirname) subdir = year.to_s + LucaSupport::Code.encode_month(month) digest = String.new open_records(basedir, subdir).each do |f, path| digest = update_digest(digest, f.read, path[1]) end digest end |
#encode_hashed_path(id, split_factor = 3) ⇒ Object
Directory separation for performance. Same as Git way.
286 287 288 289 290 291 292 293 |
# File 'lib/luca_record/io.rb', line 286 def encode_hashed_path(id, split_factor = 3) len = id.length if len <= split_factor ['', id] else [id[0, split_factor], id[split_factor, len - split_factor]] end end |
#find(id, basedir = @dirname) ⇒ Object
find ID based record. Support uuid and encoded date.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/luca_record/io.rb', line 33 def find(id, basedir = @dirname) return enum_for(:find, id, basedir).first unless block_given? if id.length >= 40 open_hashed(basedir, id) do |f| yield load_data(f) end elsif id.length >= 7 parts = id.split('/') open_records(basedir, parts[0], parts[1]) do |f, path| yield load_data(f, path) end else raise 'specified id length is too short' end end |
#find_secure(id, basedir = @dirname, prefix = 's_') ⇒ Object
Merge 2 files under plain & prefixed dirs. prefixed contents will override duplicated keys. This function does not provide encryption/decryption.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/luca_record/io.rb', line 54 def find_secure(id, basedir = @dirname, prefix = 's_') if id.length >= 40 plain = open_hashed(basedir, id) do |f| load_data(f) end secure = begin open_hashed("#{prefix}#{basedir}", id) do |f| load_data(f) end rescue # No file exists, and so on. {} end elsif id.length >= 7 parts = id.split('/') plain = open_records(basedir, parts[0], parts[1]) do |f| load_data(f) end secure = open_records("#{prefix}#{basedir}", parts[0], parts[1]) do |f| load_data(f) end else raise 'specified id length is too short' end plain.merge(secure) end |
#id2path(id) ⇒ Object
Convert ID to file directory/filename path. 1st element of Array is used as directory, the others as filename. String without ‘/’ is converted as git-like structure. Normal argument is as follows:
['2020H', 'V001', 'a7b806d04a044c6dbc4ce72932867719']
=> '2020H/V001-a7b806d04a044c6dbc4ce72932867719'
'a7b806d04a044c6dbc4ce72932867719'
=> 'a7b/806d04a044c6dbc4ce72932867719'
'2020H/V001'
=> '2020H/V001'
270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/luca_record/io.rb', line 270 def id2path(id) if id.is_a?(Array) case id.length when 0..2 id.join('/') else [id[0], id[1..-1].join('-')].join('/') end elsif id.include?('/') id else encode_hashed_path(id).join('/') end end |
#id_completion(phrase, label: 'name', basedir: @dirname) ⇒ Object
If multiple ID matched, return short ID and human readable label.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/luca_record/io.rb', line 174 def id_completion(phrase, label: 'name', basedir: @dirname) list = prefix_search(phrase, basedir: basedir) case list.length when 1 list when 0 raise 'No match on specified phrase' else (3..list[0].length).each do |l| if list.map { |id| id[0, l] }.uniq.length == list.length return list.map { |id| { id: id[0, l], label: find(id).dig(label) } } end end end end |
#latest_month(code = nil, basedir = @dirname) ⇒ Object
- year, month
-
pair of the latest record
127 128 129 |
# File 'lib/luca_record/io.rb', line 127 def latest_month(code = nil, basedir = @dirname) LucaSupport::Code.decode_term(Dir.entries(abs_path(basedir)).max) end |
#load_project(path, ext_conf: nil) ⇒ Object
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'lib/luca_record/io.rb', line 295 def load_project(path, ext_conf: nil) CONST.set_pjdir(path) config = { 'decimal_separator' => '.', 'thousands_separator' => ',' } begin config.merge!(YAML.safe_load( File.read(Pathname(CONST.configdir) / 'config.yml'), permitted_classes: [Date] )) rescue Errno::ENOENT STDERR.puts "INFO: config.yml not found. Continue with default settings." end if ext_conf begin config.merge!(YAML.safe_load( File.read(Pathname(CONST.configdir) / ext_conf), permitted_classes: [Date] )) rescue Errno::ENOENT STDERR.puts "WARN: #{ext_conf} not found. Extended options are not effective." end end config['decimal_num'] ||= config['country'] == 'jp' ? 0 : 2 CONST.set_config(config) end |
#new_record_id(basedir, date_obj) ⇒ Object
329 330 331 |
# File 'lib/luca_record/io.rb', line 329 def new_record_id(basedir, date_obj) LucaSupport::Code.encode_txid(new_record_no(basedir, date_obj)) end |
#prefix_search(phrase, basedir: @dirname) ⇒ Object
190 191 192 193 194 195 |
# File 'lib/luca_record/io.rb', line 190 def prefix_search(phrase, basedir: @dirname) glob_str = phrase.length <= 3 ? "#{phrase}*/*" : "#{id2path(phrase)}*" Dir.chdir(abs_path(basedir)) do Dir.glob(glob_str).to_a.map! { |path| path.gsub!('/', '') } end end |
#prepare_dir!(basedir, date_obj) ⇒ Object
197 198 199 200 201 |
# File 'lib/luca_record/io.rb', line 197 def prepare_dir!(basedir, date_obj) dir_name = (Pathname(basedir) + LucaSupport::Code.encode_dirname(date_obj)).to_s FileUtils.mkdir_p(dir_name) unless Dir.exist?(dir_name) dir_name end |
#save(obj, basedir = @dirname) ⇒ Object
update file with obj
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/luca_record/io.rb', line 213 def save(obj, basedir = @dirname) if obj['id'].nil? create(obj, basedir) else validate_keys(obj) if obj['id'].length < 40 parts = obj['id'].split('/') raise 'invalid ID' if parts.length != 2 open_records(basedir, parts[0], parts[1], nil, 'w') do |f, path| f.write(YAML.dump(LucaSupport::Code.readable(obj.sort.to_h))) end else open_hashed(basedir, obj['id'], 'w') do |f| f.write(YAML.dump(LucaSupport::Code.readable(obj.sort.to_h))) end end end obj['id'] end |
#search(year, month = nil, day = nil, code = nil, basedir = @dirname) ⇒ Object
search with date params & code.
106 107 108 109 110 111 112 113 |
# File 'lib/luca_record/io.rb', line 106 def search(year, month = nil, day = nil, code = nil, basedir = @dirname) return enum_for(:search, year, month, day, code, basedir) unless block_given? subdir = year.to_s + LucaSupport::Code.encode_month(month) open_records(basedir, subdir, LucaSupport::Code.encode_date(day), code) do |f, path| yield load_data(f, path), path end end |
#term(start_year, start_month, end_year, end_month, code = nil, basedir = @dirname) ⇒ Object
scan ranging data on multiple months
94 95 96 97 98 99 100 101 102 |
# File 'lib/luca_record/io.rb', line 94 def term(start_year, start_month, end_year, end_month, code = nil, basedir = @dirname) return enum_for(:term, start_year, start_month, end_year, end_month, code, basedir) unless block_given? LucaSupport::Code.encode_term(start_year, start_month, end_year, end_month).each do |subdir| open_records(basedir, subdir, nil, code) do |f, path| yield load_data(f, path) end end end |
#upsert(obj, basedir: @dirname) ⇒ Object
update uuid keyed record based on ‘id’ field. If not found, just create
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/luca_record/io.rb', line 155 def upsert(obj, basedir: @dirname) return nil if obj['id'].nil? validate_keys(obj) merged = begin open_hashed(basedir, obj['id'], 'r') do |f| load_data(f).merge(obj) end rescue obj end open_hashed(basedir, obj['id'], 'w') do |f| f.write(YAML.dump(LucaSupport::Code.readable(merged.sort.to_h))) end obj['id'] end |
#valid_project?(path = CONST.pjdir) ⇒ Boolean
test if having required dirs/files under exec path
324 325 326 327 |
# File 'lib/luca_record/io.rb', line 324 def valid_project?(path = CONST.pjdir) project_dir = Pathname(path) FileTest.directory?( (project_dir / 'data').to_s) end |