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-Za-z]{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


31
32
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
# File 'lib/creek/styles/converter.rb', line 31

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


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

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

.convert_date(value, options) ⇒ Object


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

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


105
106
107
108
109
# File 'lib/creek/styles/converter.rb', line 105

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


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

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


119
120
121
122
123
# File 'lib/creek/styles/converter.rb', line 119

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