diff --git a/lib/xlsxtream/core_extension.rb b/lib/xlsxtream/core_extension.rb
new file mode 100644
index 0000000..d7e839e
--- /dev/null
+++ b/lib/xlsxtream/core_extension.rb
@@ -0,0 +1,79 @@
+class Object
+ def to_xslx_value(cid, _, sst)
+ to_s.to_xslx_value(cid, false, sst)
+ end
+end
+
+class Numeric
+ def to_xslx_value(cid, _, _)
+ %Q{#{self}}
+ end
+end
+
+class TrueClass
+ def to_xslx_value(cid, _, _)
+ %Q{1}
+ end
+end
+
+class FalseClass
+ def to_xslx_value(cid, _, _)
+ %Q{0}
+ end
+end
+
+class Time
+ def to_xslx_value(cid, _, _)
+ # Local dates are stored as UTC by truncating the offset:
+ # 1970-01-01 00:00:00 +0200 => 1970-01-01 00:00:00 UTC
+ # This is done because SpreadsheetML is not timezone aware.
+ oa_date = (to_f + utc_offset) / 86400 + 25569
+
+ %Q{#{oa_date}}
+ end
+end
+
+class DateTime
+ def to_xslx_value(cid, _, _)
+ _, jd, df, sf, of = marshal_dump
+ oa_date = jd - 2415019 + (df + of + sf / 1e9) / 86400
+
+ %Q{#{oa_date}}
+ end
+end
+
+class Date
+ if RUBY_ENGINE == 'ruby'
+ def to_xslx_value(cid, _, _)
+ oa_date = (jd - 2415019).to_f
+ %Q{#{oa_date}}
+ end
+ else
+ def to_xslx_value(cid, _, _)
+ oa_date = jd - 2415019 + (hour * 3600 + sec + sec_fraction.to_f) / 86400
+ %Q{#{oa_date}}
+ end
+ end
+end
+
+class String
+ def to_xslx_value(cid, auto_format, sst)
+ if empty?
+ ""
+ elsif auto_format
+ Xlsxtream::Row.auto_format(self).to_xslx_value(cid, false, sst)
+ else
+ if encoding != Xlsxtream::Row::ENCODING
+ value = encode(Xlsxtream::Row::ENCODING)
+ else
+ value = self
+ end
+
+ if sst
+ %Q{#{sst[value]}}
+ else
+ %Q{#{Xlsxtream::XML.escape_value(value)}}
+ end
+ end
+ end
+end
diff --git a/lib/xlsxtream/row.rb b/lib/xlsxtream/row.rb
index afba661..a7720a9 100644
--- a/lib/xlsxtream/row.rb
+++ b/lib/xlsxtream/row.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
require "date"
+require "xlsxtream/core_extension"
require "xlsxtream/xml"
module Xlsxtream
@@ -31,85 +32,33 @@ def to_xml
xml = String.new(%Q{})
@row.each do |value|
- cid = "#{column}#{@rownum}"
- column.next!
-
- if @auto_format && value.is_a?(String)
- value = auto_format(value)
- end
-
- case value
- when Numeric
- xml << %Q{#{value}}
- when TrueClass, FalseClass
- xml << %Q{#{value ? 1 : 0}}
- when Time
- xml << %Q{#{time_to_oa_date(value)}}
- when DateTime
- xml << %Q{#{datetime_to_oa_date(value)}}
- when Date
- xml << %Q{#{date_to_oa_date(value)}}
- else
- value = value.to_s
-
- unless value.empty? # no xml output for for empty strings
- value = value.encode(ENCODING) if value.encoding != ENCODING
-
- if @sst
- xml << %Q{#{@sst[value]}}
- else
- xml << %Q{#{XML.escape_value(value)}}
- end
- end
+ unless value.nil?
+ xml << value.to_xslx_value("#{column}#{@rownum}", @auto_format, @sst)
end
+ column.next!
end
xml << '
'
end
- private
-
# Detects and casts numbers, date, time in text
- def auto_format(value)
- case value
- when TRUE_STRING
- true
- when FALSE_STRING
- false
- when NUMBER_PATTERN
- value.include?('.') ? value.to_f : value.to_i
- when DATE_PATTERN
- Date.parse(value) rescue value
- when TIME_PATTERN
- DateTime.parse(value) rescue value
- else
- value
- end
- end
-
- # Converts Time instance to OLE Automation Date
- def time_to_oa_date(time)
- # Local dates are stored as UTC by truncating the offset:
- # 1970-01-01 00:00:00 +0200 => 1970-01-01 00:00:00 UTC
- # This is done because SpreadsheetML is not timezone aware.
- (time.to_f + time.utc_offset) / 86400 + 25569
- end
-
- # Converts DateTime instance to OLE Automation Date
- if RUBY_ENGINE == 'ruby'
- def datetime_to_oa_date(date)
- _, jd, df, sf, of = date.marshal_dump
- jd - 2415019 + (df + of + sf / 1e9) / 86400
- end
- else
- def datetime_to_oa_date(date)
- date.jd - 2415019 + (date.hour * 3600 + date.sec + date.sec_fraction.to_f) / 86400
+ class << self
+ def auto_format(value)
+ case value
+ when TRUE_STRING
+ true
+ when FALSE_STRING
+ false
+ when NUMBER_PATTERN
+ value.include?('.') ? value.to_f : value.to_i
+ when DATE_PATTERN
+ Date.parse(value) rescue value
+ when TIME_PATTERN
+ DateTime.parse(value) rescue value
+ else
+ value
+ end
end
end
-
- # Converts Date instance to OLE Automation Date
- def date_to_oa_date(date)
- (date.jd - 2415019).to_f
- end
end
end