Module: Peruby::Sprintf

Defined in:
lib/peruby/runtime/sprintf.rb

Overview

Perl-compatible formatting facade with version-vector support.

Constant Summary collapse

CONVERSION =
/%(?:(\d+)\$)?([-+ 0#]*)(\*|\d+)?(?:\.(\*|\d+))?(v[diuoxXbB]?|[sdiuoxXbBeEfgGc%n])/

Class Method Summary collapse

Class Method Details

.format(template, values) ⇒ Object

rubocop:disable-next Metrics/AbcSize



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/peruby/runtime/sprintf.rb', line 11

def format(template, values)
  index = 0
  template.gsub(CONVERSION) do |directive|
    match = Regexp.last_match
    conversion = match[5]
    raise PerlError, '%n is not supported' if conversion == 'n'
    next '%' if conversion == '%'

    resolved = directive.dup
    if match[3] == '*'
      resolved.sub!('*', Conv.to_num(values[index]).to_i.to_s)
      index += 1
    end
    if match[4] == '*'
      resolved.sub!('*', Conv.to_num(values[index]).to_i.to_s)
      index += 1
    end
    position = match[1] ? match[1].to_i - 1 : index
    index += 1 unless match[1]
    value = values.fetch(position, nil)
    conversion.start_with?('v') ? version(value, conversion[1] || 'd') : ruby_format(resolved, value)
  end
end

.ruby_format(directive, value) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/peruby/runtime/sprintf.rb', line 39

def ruby_format(directive, value)
  conversion = directive[-1]
  coerced = if conversion == 's'
              Conv.to_str(value)
            elsif conversion.match?(/[eEfgG]/)
              Conv.to_num(value).to_f
            else
              integer = Conv.to_num(value).to_i
              conversion.match?(/[uoxXbB]/) ? integer & ((1 << 64) - 1) : integer
            end
  Kernel.format(directive.sub(/%\d+\$/, '%'), coerced)
rescue ArgumentError, TypeError
  ''
end

.version(value, conversion) ⇒ Object



35
36
37
# File 'lib/peruby/runtime/sprintf.rb', line 35

def version(value, conversion)
  Conv.to_str(value).codepoints.map { |point| Kernel.format("%#{conversion}", point) }.join('.')
end