module LucaSupport::Code
implement Luca IDs convention
Public Instance Methods
# File lib/luca_support/code.rb, line 147 def decimalize(obj) case obj.class.name when 'Array' obj.map { |i| decimalize(i) } when 'Hash' obj.inject({}) { |h, (k, v)| h[k] = decimalize(v); h } when 'Integer' BigDecimal(obj.to_s) when 'String' /^[0-9\.]+$/.match(obj) ? BigDecimal(obj) : obj when 'Float' raise 'already float' else obj end end
# File lib/luca_support/code.rb, line 48 def decode_date(char) '0123456789ABCDEFGHIJKLMNOPQRSTUV'.index(char) end
Parse historical id into Array of date & transaction id.
# File lib/luca_support/code.rb, line 16 def decode_id(id_str) m = %r(^(?<year>[0-9]+)(?<month>[A-L])/?(?<day>[0-9A-V])(?<txid>[0-9A-Z]{,3})).match(id_str) ["#{m[:year]}-#{decode_month(m[:month])}-#{decode_date(m[:day])}", decode_txid(m[:txid])] end
# File lib/luca_support/code.rb, line 98 def decode_month(char) '0ABCDEFGHIJKL'.index(char) end
# File lib/luca_support/code.rb, line 112 def decode_term(char) m = /^([0-9]{4})([A-La-l])/.match(char) [m[1].to_i, decode_month(m[2])] end
# File lib/luca_support/code.rb, line 27 def decode_txid(id) txmap = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' l = txmap.length txmap.index(id[0]) * (l**2) + txmap.index(id[1]) * l + txmap.index(id[2]) end
Format number in 3-digit-group. Long decimal is just ommitted with floor().
# File lib/luca_support/code.rb, line 55 def delimit_num(num, decimal: nil, delimiter: nil) return nil if num.nil? decimal ||= LucaSupport::CONFIG['decimal_num'] delimiter ||= LucaSupport::CONFIG['thousands_separator'] case num when BigDecimal if decimal == 0 num.floor.to_s.reverse!.gsub(/(\d{3})(?=\d)/, '\1 ').reverse! .gsub(/\s/, delimiter) else fragments = num.floor(decimal).to_s('F').split('.') fragments[0].reverse!.gsub!(/(\d{3})(?=\d)/, '\1 ') fragments[0].reverse!.gsub!(/\s/, delimiter) fragments[1].gsub!(/(\d{3})(?=\d)/, '\1 ') fragments.join(LucaSupport::CONFIG['decimal_separator']) end else num.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\1 ').reverse! .gsub(/\s/, delimiter) end end
Day of month to code conversion. Date, DateTime, String, Integer is valid input. If nil, returns empty String for consistency.
# File lib/luca_support/code.rb, line 37 def encode_date(date) return '' if date.nil? index = date.day if date.respond_to?(:day) index ||= date.to_i if date.respond_to?(:to_i) index ||= 0 raise 'Invalid date specified' if index < 1 || index > 31 '0123456789ABCDEFGHIJKLMNOPQRSTUV'[index] end
encode directory name from year and month.
# File lib/luca_support/code.rb, line 80 def encode_dirname(date_obj) date_obj.year.to_s + encode_month(date_obj) end
Month to code conversion. Date, DateTime, String, Integer is valid input. If nil, returns empty String for consistency.
# File lib/luca_support/code.rb, line 87 def encode_month(date) return '' if date.nil? index = date.month if date.respond_to?(:month) index ||= date.to_i if date.respond_to?(:to_i) index ||= 0 raise 'Invalid month specified' if index < 1 || index > 12 '0ABCDEFGHIJKL'[index] end
Generate globbing phrase like [“2020”] for range search.
# File lib/luca_support/code.rb, line 104 def encode_term(start_year, start_month, end_year, end_month) (start_year..end_year).to_a.map do |y| g1 = y == start_year ? encode_month(start_month) : encode_month(1) g2 = y == end_year ? encode_month(end_month) : encode_month(12) g1 == g2 ? "#{y}#{g1}" : "#{y}[#{g1}-#{g2}]" end end
# File lib/luca_support/code.rb, line 21 def encode_txid(num) txmap = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' l = txmap.length txmap[num / (l**2)] + txmap[(num % (l**2)) / l] + txmap[num % l] end
# File lib/luca_support/code.rb, line 223 def has_status?(dat, status) return false if dat['status'].nil? dat['status'].map { |h| h.key?(status) } .include?(true) end
# File lib/luca_support/code.rb, line 117 def issue_random_id Digest::SHA1.hexdigest(SecureRandom.uuid) end
Convert Hash keys to string recursively. Required for YAML compatibility.
# File lib/luca_support/code.rb, line 124 def keys_stringify(dat) case dat when Array dat.map { |d| keys_stringify(d) } when Hash dat.map { |k, v| [k.to_s, keys_stringify(v)] }.to_h else dat end end
# File lib/luca_support/code.rb, line 135 def match_score(a, b, n = 2) split_factor = [a.length, b.length, n].min v_a = to_ngram(a, split_factor) v_b = to_ngram(b, split_factor) v_a.map { |item| v_b.include?(item) ? 1 : 0 }.sum / v_a.length.to_f end
convert effective/defunct data into current hash on @date. not parse nested children.
# File lib/luca_support/code.rb, line 186 def parse_current(dat) {}.tap do |processed| dat.each { |k, _v| processed[k] = take_current(dat, k) } end end
# File lib/luca_support/code.rb, line 164 def readable(obj, len = LucaSupport::CONFIG['decimal_num']) case obj when Array obj.map { |i| readable(i) } when Hash obj.inject({}) { |h, (k, v)| h[k] = readable(v); h } when BigDecimal if len == 0 obj.round # Integer is precise else parts = obj.round(len).to_s('F').split('.') "#{parts[0]}.#{parts[1][0, len]}" end else obj end end
return current value with effective/defunct on target @date For multiple attribues, return hash on other than 'val'. Examples are as bellows:
- effective: 2020-1-1 val: 3000 => 3000 - effective: 2020-1-1 rank: 5 point: 1000 => { 'effective' => 2020-1-1, 'rank' => 5, 'point' => 1000 } - defunct: 2020-1-1 val: 3000 => nil
# File lib/luca_support/code.rb, line 208 def take_current(dat, item) target = dat&.dig(item) return target unless target.is_a?(Array) keys = target.map(&:keys).flatten return target if !keys.include?('effective') && !keys.include?('defunct') latest = target .reject { |a| a['defunct'] && Date.parse(a['defunct'].to_s) < @date } .filter { |a| a['effective'] && Date.parse(a['effective'].to_s) < @date } .max { |a, b| Date.parse(a['effective'].to_s) <=> Date.parse(b['effective'].to_s) } latest&.dig('val') || latest end
# File lib/luca_support/code.rb, line 143 def to_ngram(str, n = 2) str.each_char.each_cons(n).map(&:join) end