Class: Creek::Styles::Converter

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/creek/styles/converter.rb

Constant Summary collapse

HEX_ESCAPE_REGEXP =

Excel non-printable character escape sequence

/_x[0-9A-Fa-f]{4}_/
DATE_TYPES =

The heart of typecasting. The ruby type is determined either explicitly from the cell xml or implicitly from the cell style, and this method expects that work to have been done already. This, then, takes the type we determined it to be and casts the cell value to that type.

types:

  • s: shared string (see #shared_string)

  • n: number (cast to a float)

  • b: boolean

  • str: string

  • inlineStr: string

  • ruby symbol: for when type has been determined by style

options:

  • shared_strings: needed for ā€˜sā€™ (shared string) type

  • base_date: from what date to begin, see method #base_date

[:date, :time, :date_time].to_set

Constants included from Constants

Creek::Styles::Constants::NumFmtMap

Class Method Summary collapse

Class Method Details

.call(value, type, style, options = {}) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
80
81
82
# File 'lib/creek/styles/converter.rb', line 33

def self.call(value, type, style, options = {})
  return nil if value.nil? || value.empty?

  # Sometimes the type is dictated by the style alone
  if type.nil? || (type == 'n' && DATE_TYPES.include?(style))
    type = style
  end

  case type

  ##
  # There are few built-in types
  ##

  when 's' # shared string
    options[:shared_strings][value.to_i]
  when 'n' # number
    value.to_f
  when 'b'
    value.to_i == 1
  when 'str'
    unescape_string(value)
  when 'inlineStr'
    unescape_string(value)

  ##
  # Type can also be determined by a style,
  # detected earlier and cast here by its standardized symbol
  ##

  when :string
    value
  when :unsupported
    convert_unknown(value)
  when :fixnum
    value.to_i
  when :float, :percentage
    value.to_f
  when :date
    convert_date(value, options)
  when :time, :date_time
    convert_datetime(value, options)
  when :bignum
    convert_bignum(value)

  ## Nothing matched
  else
    convert_unknown(value)
  end
end

.convert_bignum(value) ⇒ Object



113
114
115
116
117
118
119
# File 'lib/creek/styles/converter.rb', line 113

def self.convert_bignum(value)
  if defined?(BigDecimal)
    BigDecimal(value)
  else
    value.to_f
  end
end

.convert_date(value, options) ⇒ Object



100
101
102
103
104
105
# File 'lib/creek/styles/converter.rb', line 100

def self.convert_date(value, options)
  date = base_date(options) + value.to_i
  yyyy, mm, dd = date.strftime('%Y-%m-%d').split('-')

  ::Date.new(yyyy.to_i, mm.to_i, dd.to_i)
end

.convert_datetime(value, options) ⇒ Object



107
108
109
110
111
# File 'lib/creek/styles/converter.rb', line 107

def self.convert_datetime(value, options)
  date = base_date(options) + value.to_f.round(6)

  round_datetime(date.strftime('%Y-%m-%d %H:%M:%S.%N'))
end

.convert_unknown(value) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/creek/styles/converter.rb', line 84

def self.convert_unknown(value)
  begin
    if value.nil? or value.empty?
      return value
    elsif value.to_i.to_s == value.to_s
      return value.to_i
    elsif value.to_f.to_s == value.to_s
      return value.to_f
    else
      return value
    end
  rescue
    return value
  end
end

.unescape_string(value) ⇒ Object



121
122
123
124
125
# File 'lib/creek/styles/converter.rb', line 121

def self.unescape_string(value)
  # excel encodes some non-printable characters using a hex code in the format _xHHHH_
  # e.g. Carriage Return (\r) is encoded as _x000D_
  value.gsub(HEX_ESCAPE_REGEXP) { |match| match[2, 4].to_i(16).chr(Encoding::UTF_8) }
end