Module: LucaSupport::Code
- Included in:
- LucaRecord::Dict, LucaRecord::IO
- Defined in:
- lib/luca_support/code.rb
Overview
implement Luca IDs convention
Class Method Summary collapse
- .decimalize(obj) ⇒ Object
- .decode_date(char) ⇒ Object
-
.decode_id(id_str) ⇒ Object
Parse historical id into Array of date & transaction id.
- .decode_month(char) ⇒ Object
- .decode_term(char) ⇒ Object
- .decode_txid(id) ⇒ Object
-
.delimit_num(num, decimal: nil, delimiter: nil) ⇒ Object
Format number in 3-digit-group.
-
.encode_date(date) ⇒ Object
Day of month to code conversion.
-
.encode_dirname(date_obj) ⇒ Object
encode directory name from year and month.
-
.encode_month(date) ⇒ Object
Month to code conversion.
-
.encode_term(start_year, start_month, end_year, end_month) ⇒ Object
Generate globbing phrase like [“2020”] for range search.
- .encode_txid(num) ⇒ Object
- .has_status?(dat, status) ⇒ Boolean
- .issue_random_id ⇒ Object
-
.keys_stringify(dat) ⇒ Object
Convert Hash keys to string recursively.
- .match_score(a, b, n = 2) ⇒ Object
-
.parse_current(dat, date = @date) ⇒ Object
convert effective/defunct data into current hash on @date.
- .readable(obj, len = ) ⇒ Object
-
.take_current(dat, item, date = @date) ⇒ Object
return current value with effective/defunct on target @date For multiple attribues, return hash on other than ‘val’.
-
.take_history(dat, item) ⇒ Object
convert all effective/defunct data into Array not parse nested children.
- .to_ngram(str, n = 2) ⇒ Object
Class Method Details
.decimalize(obj) ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# 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' return obj if /^0[0-9]+$/.match(obj) # zero-prefixed code /^[0-9\.]+$/.match(obj) ? BigDecimal(obj) : obj when 'Float' raise 'already float' else obj end end |
.decode_date(char) ⇒ Object
48 49 50 |
# File 'lib/luca_support/code.rb', line 48 def decode_date(char) '0123456789ABCDEFGHIJKLMNOPQRSTUV'.index(char) end |
.decode_id(id_str) ⇒ Object
Parse historical id into Array of date & transaction id.
16 17 18 19 |
# 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 |
.decode_month(char) ⇒ Object
98 99 100 |
# File 'lib/luca_support/code.rb', line 98 def decode_month(char) '0ABCDEFGHIJKL'.index(char) end |
.decode_term(char) ⇒ Object
112 113 114 115 |
# 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 |
.decode_txid(id) ⇒ Object
27 28 29 30 31 |
# 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 |
.delimit_num(num, decimal: nil, delimiter: nil) ⇒ Object
Format number in 3-digit-group. Long decimal is just ommitted with floor().
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/luca_support/code.rb', line 55 def delimit_num(num, decimal: nil, delimiter: nil) return nil if num.nil? decimal ||= CONST.config['decimal_num'] delimiter ||= CONST.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(CONST.config['decimal_separator']) end else num.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\1 ').reverse! .gsub(/\s/, delimiter) end end |
.encode_date(date) ⇒ Object
Day of month to code conversion. Date, DateTime, String, Integer is valid input. If nil, returns empty String for consistency.
37 38 39 40 41 42 43 44 45 46 |
# 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_dirname(date_obj) ⇒ Object
encode directory name from year and month.
80 81 82 |
# File 'lib/luca_support/code.rb', line 80 def encode_dirname(date_obj) date_obj.year.to_s + encode_month(date_obj) end |
.encode_month(date) ⇒ Object
Month to code conversion. Date, DateTime, String, Integer is valid input. If nil, returns empty String for consistency.
87 88 89 90 91 92 93 94 95 96 |
# 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 |
.encode_term(start_year, start_month, end_year, end_month) ⇒ Object
Generate globbing phrase like [“2020”] for range search.
104 105 106 107 108 109 110 |
# 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 |
.encode_txid(num) ⇒ Object
21 22 23 24 25 |
# 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 |
.has_status?(dat, status) ⇒ Boolean
235 236 237 238 239 240 |
# File 'lib/luca_support/code.rb', line 235 def has_status?(dat, status) return false if dat['status'].nil? dat['status'].map { |h| h.key?(status) } .include?(true) end |
.issue_random_id ⇒ Object
117 118 119 |
# File 'lib/luca_support/code.rb', line 117 def issue_random_id Digest::SHA1.hexdigest(SecureRandom.uuid) end |
.keys_stringify(dat) ⇒ Object
Convert Hash keys to string recursively. Required for YAML compatibility.
124 125 126 127 128 129 130 131 132 133 |
# 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 |
.match_score(a, b, n = 2) ⇒ Object
135 136 137 138 139 140 141 |
# 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 |
.parse_current(dat, date = @date) ⇒ Object
convert effective/defunct data into current hash on @date. not parse nested children.
186 187 188 189 190 |
# File 'lib/luca_support/code.rb', line 186 def parse_current(dat, date = @date) {}.tap do |processed| dat.each { |k, _v| processed[k] = take_current(dat, k, date) } end end |
.readable(obj, len = ) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/luca_support/code.rb', line 165 def readable(obj, len = CONST.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 |
.take_current(dat, item, date = @date) ⇒ Object
return current value with effective/defunct on target @date For multiple attribues, return hash on other than ‘val’. Examples:
- 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
208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/luca_support/code.rb', line 208 def take_current(dat, item, date = @date) 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 |
.take_history(dat, item) ⇒ Object
convert all effective/defunct data into Array not parse nested children.
226 227 228 229 230 231 232 233 |
# File 'lib/luca_support/code.rb', line 226 def take_history(dat, item) target = dat&.dig(item) return Array(target) unless target.is_a?(Array) target .sort { |a, b| Date.parse(a['effective'].to_s) <=> Date.parse(b['effective'].to_s) } .map { |a| a['val'] } end |
.to_ngram(str, n = 2) ⇒ Object
143 144 145 |
# File 'lib/luca_support/code.rb', line 143 def to_ngram(str, n = 2) str.each_char.each_cons(n).map(&:join) end |