Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory optimization (~30% less) #633

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# frozen_string_literal: true
source 'https://rubygems.org'
gemspec

Expand Down
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# frozen_string_literal: true
require File.expand_path(File.dirname(__FILE__) + '/lib/axlsx/version.rb')

task :build => :gendoc do
Expand Down
1 change: 1 addition & 0 deletions axlsx.gemspec
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# frozen_string_literal: true
require File.expand_path('../lib/axlsx/version', __FILE__)

Gem::Specification.new do |s|
Expand Down
14 changes: 8 additions & 6 deletions lib/axlsx.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# encoding: UTF-8
# frozen_string_literal: true
require 'htmlentities'
require 'axlsx/version.rb'
require 'mimemagic'
Expand Down Expand Up @@ -90,7 +91,7 @@ def self.name_to_indices(name)
# @note This follows the standard spreadsheet convention of naming columns A to Z, followed by AA to AZ etc.
# @return [String]
def self.col_ref(index)
chars = ''
chars = String.new
while index >= 26 do
index, char = index.divmod(26)
chars.prepend((char + 65).chr)
Expand All @@ -114,8 +115,8 @@ def self.range_to_a(range)
range.match(/^(\w+?\d+)\:(\w+?\d+)$/)
start_col, start_row = name_to_indices($1)
end_col, end_row = name_to_indices($2)
(start_row..end_row).to_a.map do |row_num|
(start_col..end_col).to_a.map do |col_num|
(start_row..end_row).map do |row_num|
(start_col..end_col).map do |col_num|
cell_r(col_num, row_num)
end
end
Expand All @@ -125,9 +126,10 @@ def self.range_to_a(range)
# @param [String] s The snake case string to camelize
# @return [String]
def self.camel(s="", all_caps = true)
s = s.to_s
s = s.capitalize if all_caps
s.gsub(/_(.)/){ $1.upcase }
s_copy = s.to_s.dup
s_copy = s_copy.capitalize! if all_caps
s_copy.gsub!(/_(.)/){ $1.upcase }
s_copy
end

# returns the provided string with all invalid control charaters
Expand Down
7 changes: 4 additions & 3 deletions lib/axlsx/content_type/abstract_content_type.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# frozen_string_literal: true
module Axlsx

# This class extracts the common parts from Default and Override
Expand All @@ -22,9 +23,9 @@ def content_type=(v) Axlsx::validate_content_type v; @content_type = v end
alias :ContentType= :content_type=

# Serialize the contenty type to xml
def to_xml_string(node_name = '', str = '')
str << "<#{node_name} "
str << instance_values.map { |key, value| Axlsx::camel(key) << '="' << value.to_s << '"' }.join(' ')
def to_xml_string(node_name = '', str = String.new)
str << "<#{node_name}"
instance_values.each { |key, value| str << " #{Axlsx::camel(key)}=\"#{value}\"" }
str << '/>'
end

Expand Down
7 changes: 4 additions & 3 deletions lib/axlsx/content_type/content_type.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# encoding: UTF-8
# frozen_string_literal: true
module Axlsx
require 'axlsx/content_type/abstract_content_type.rb'
require 'axlsx/content_type/default.rb'
Expand All @@ -14,9 +15,9 @@ def initialize
# Serializes the object
# @param [String] str
# @return [String]
def to_xml_string(str = '')
str << '<?xml version="1.0" encoding="UTF-8"?>'
str << ('<Types xmlns="' << XML_NS_T << '">')
def to_xml_string(str = String.new)
str << '<?xml version="1.0" encoding="UTF-8"?>'\
"<Types xmlns=\"#{XML_NS_T}\">"
each { |type| type.to_xml_string(str) }
str << '</Types>'
end
Expand Down
3 changes: 2 additions & 1 deletion lib/axlsx/content_type/default.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# encoding: UTF-8
# frozen_string_literal: true
module Axlsx

# An default content part. These parts are automatically created by for you based on the content of your package.
Expand All @@ -17,7 +18,7 @@ def extension=(v) Axlsx::validate_string v; @extension = v end
alias :Extension= :extension=

# Serializes this object to xml
def to_xml_string(str ='')
def to_xml_string(str = String.new)
super(NODE_NAME, str)
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/axlsx/content_type/override.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

# encoding: UTF-8
# frozen_string_literal: true
module Axlsx

# An override content part. These parts are automatically created by for you based on the content of your package.
Expand All @@ -18,7 +19,7 @@ def part_name=(v) Axlsx::validate_string v; @part_name = v end
alias :PartName= :part_name=

# Serializes this object to xml
def to_xml_string(str = '')
def to_xml_string(str = String.new)
super(NODE_NAME, str)
end
end
Expand Down
7 changes: 4 additions & 3 deletions lib/axlsx/doc_props/app.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# encoding: UTF-8
# frozen_string_literal: true
module Axlsx

# App represents the app.xml document. The attributes for this object are primarily managed by the application the end user uses to edit the document. None of the attributes are required to serialize a valid xlsx object.
Expand Down Expand Up @@ -220,9 +221,9 @@ def doc_security=(v) Axlsx::validate_int v; @doc_security = v; end

# Serialize the app.xml document
# @return [String]
def to_xml_string(str = '')
str << '<?xml version="1.0" encoding="UTF-8"?>'
str << ('<Properties xmlns="' << APP_NS << '" xmlns:vt="' << APP_NS_VT << '">')
def to_xml_string(str = String.new)
str << '<?xml version="1.0" encoding="UTF-8"?>'\
"<Properties xmlns=\"#{APP_NS}\" xmlns:vt=\"#{APP_NS_VT}\">"
instance_values.each do |key, value|
node_name = Axlsx.camel(key)
str << "<#{node_name}>#{value}</#{node_name}>"
Expand Down
20 changes: 11 additions & 9 deletions lib/axlsx/doc_props/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Axlsx
# @note Packages manage their own core object.
# @see Package#core
class Core

# Creates a new Core object.
# @option options [String] creator
# @option options [Time] created
Expand All @@ -24,14 +24,16 @@ def initialize(options={})
# serializes the core.xml document
# @return [String]
def to_xml_string(str = '')
str << '<?xml version="1.0" encoding="UTF-8"?>'
str << ('<cp:coreProperties xmlns:cp="' << CORE_NS << '" xmlns:dc="' << CORE_NS_DC << '" ')
str << ('xmlns:dcmitype="' << CORE_NS_DCMIT << '" xmlns:dcterms="' << CORE_NS_DCT << '" ')
str << ('xmlns:xsi="' << CORE_NS_XSI << '">')
str << ('<dc:creator>' << self.creator << '</dc:creator>')
str << ('<dcterms:created xsi:type="dcterms:W3CDTF">' << (created || Time.now).strftime('%Y-%m-%dT%H:%M:%S') << 'Z</dcterms:created>')
str << '<cp:revision>0</cp:revision>'
str << '</cp:coreProperties>'
str << <<-XML.gsub!("\n", '')
<?xml version="1.0" encoding="UTF-8"?>
<cp:coreProperties xmlns:cp="#{CORE_NS}" xmlns:dc="#{CORE_NS_DC}"
xmlns:dcmitype="#{CORE_NS_DCMIT}" xmlns:dcterms="#{CORE_NS_DCT}"
xmlns:xsi="#{CORE_NS_XSI}">
<dc:creator>#{self.creator}</dc:creator>
<dcterms:created xsi:type="dcterms:W3CDTF">#{(created || Time.now).strftime('%Y-%m-%dT%H:%M:%S')}Z</dcterms:created>
<cp:revision>0</cp:revision>
</cp:coreProperties>
XML
end

end
Expand Down
11 changes: 6 additions & 5 deletions lib/axlsx/drawing/area_chart.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# encoding: UTF-8
# frozen_string_literal: true
module Axlsx

# The AreaChart is a two dimentional line chart (who would have guessed?) that you can add to your worksheet.
Expand Down Expand Up @@ -75,16 +76,16 @@ def node_name
# Serializes the object
# @param [String] str
# @return [String]
def to_xml_string(str = '')
def to_xml_string(str = String.new)
super(str) do
str << ("<c:" << node_name << ">")
str << ('<c:grouping val="' << grouping.to_s << '"/>')
str << ('<c:varyColors val="' << vary_colors.to_s << '"/>')
str << "<c:#{node_name}>"\
"<c:grouping val=\"#{grouping}\"/>"\
"<c:varyColors val=\"#{vary_colors}\"/>"
@series.each { |ser| ser.to_xml_string(str) }
@d_lbls.to_xml_string(str) if @d_lbls
yield if block_given?
axes.to_xml_string(str, :ids => true)
str << ("</c:" << node_name << ">")
str << "</c:#{node_name}>"
axes.to_xml_string(str)
end
end
Expand Down
27 changes: 14 additions & 13 deletions lib/axlsx/drawing/area_series.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# encoding: UTF-8
# frozen_string_literal: true
module Axlsx
# A AreaSeries defines the title, data and labels for line charts
# @note The recommended way to manage series is to use Chart#add_series
Expand Down Expand Up @@ -71,30 +72,30 @@ def smooth=(v)
# Serializes the object
# @param [String] str
# @return [String]
def to_xml_string(str = '')
def to_xml_string(str = String.new)
super(str) do
if color
str << '<c:spPr><a:solidFill>'
str << ('<a:srgbClr val="' << color << '"/>')
str << '</a:solidFill>'
str << '<a:ln w="28800">'
str << '<a:solidFill>'
str << ('<a:srgbClr val="' << color << '"/>')
str << '</a:solidFill>'
str << '</a:ln>'
str << '<a:round/>'
str << '</c:spPr>'
str << '<c:spPr><a:solidFill>'\
"<a:srgbClr val=\"#{color}\"/>"\
'</a:solidFill>'\
'<a:ln w="28800">'\
'<a:solidFill>'\
"<a:srgbClr val=\"#{color}\"/>"\
'</a:solidFill>'\
'</a:ln>'\
'<a:round/>'\
'</c:spPr>'
end

if !@show_marker
str << '<c:marker><c:symbol val="none"/></c:marker>'
elsif @marker_symbol != :default
str << '<c:marker><c:symbol val="' + @marker_symbol.to_s + '"/></c:marker>'
str << "<c:marker><c:symbol val=\"#{@marker_symbol}\"/></c:marker>"
end

@labels.to_xml_string(str) unless @labels.nil?
@data.to_xml_string(str) unless @data.nil?
str << ('<c:smooth val="' << ((smooth) ? '1' : '0') << '"/>')
str << "<c:smooth val=\"#{smooth ? 1 : 0}\"/>"
end
end

Expand Down
1 change: 1 addition & 0 deletions lib/axlsx/drawing/ax_data_source.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# frozen_string_literal: true
module Axlsx

# An axis data source that can contain referenced or literal strings or numbers
Expand Down
11 changes: 6 additions & 5 deletions lib/axlsx/drawing/axes.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true
module Axlsx

# The Axes class creates and manages axis information and
# serialization for charts.
class Axes
Expand All @@ -16,7 +17,7 @@ def initialize(options={})
end

# [] provides assiciative access to a specic axis store in an axes
# instance.
# instance.
# @return [Axis]
def [](name)
axes.assoc(name)[1]
Expand All @@ -27,12 +28,12 @@ def [](name)
# @param [Hash] options
# @option options ids
# If the ids option is specified only the axis identifier is
# serialized. Otherwise, each axis is serialized in full.
def to_xml_string(str = '', options = {})
# serialized. Otherwise, each axis is serialized in full.
def to_xml_string(str = String.new, options = {})
if options[:ids]
# CatAxis must come first in the XML (for Microsoft Excel at least)
sorted = axes.sort_by { |name, axis| axis.kind_of?(CatAxis) ? 0 : 1 }
sorted.each { |axis| str << ('<c:axId val="' << axis[1].id.to_s << '"/>') }
sorted.each { |axis| str << "<c:axId val=\"#{axis[1].id}\"/>" }
else
axes.each { |axis| axis[1].to_xml_string(str) }
end
Expand Down
45 changes: 23 additions & 22 deletions lib/axlsx/drawing/axis.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# encoding: UTF-8
# frozen_string_literal: true
module Axlsx

# the access class defines common properties and values for a chart axis.
Expand Down Expand Up @@ -83,14 +84,14 @@ def initialize(options={})
# the title for the axis. This can be a cell or a fixed string.
attr_reader :title

# The color for this axis. This value is used when rendering the axis line in the chart.
# The color for this axis. This value is used when rendering the axis line in the chart.
# colors should be in 6 character rbg format
# @return [String] the rbg color assinged.
# @see color
def color=(color_rgb)
@color = color_rgb
end

# The crossing axis for this axis
# @param [Axis] axis
def cross_axis=(axis)
Expand Down Expand Up @@ -149,40 +150,40 @@ def title=(v)
# Serializes the object
# @param [String] str
# @return [String]
def to_xml_string(str = '')
str << ('<c:axId val="' << @id.to_s << '"/>')
def to_xml_string(str = String.new)
str << "<c:axId val=\"#{@id}\"/>"
@scaling.to_xml_string str
str << ('<c:delete val="' << @delete.to_s << '"/>')
str << ('<c:axPos val="' << @ax_pos.to_s << '"/>')
str << '<c:majorGridlines>'
str << "<c:delete val=\"#{@delete}\"/>"\
"<c:axPos val=\"#{@ax_pos}\"/>"\
'<c:majorGridlines>'
# TODO shape properties need to be extracted into a class
if gridlines == false
str << '<c:spPr>'
str << '<a:ln>'
str << '<a:noFill/>'
str << '</a:ln>'
str << '</c:spPr>'
str << '<c:spPr>'\
'<a:ln>'\
'<a:noFill/>'\
'</a:ln>'\
'</c:spPr>'
end
str << '</c:majorGridlines>'
@title.to_xml_string(str) unless @title == nil
# Need to set sourceLinked to 0 if we're setting a format code on this row
# otherwise it will never take, as it will always prefer the 'General' formatting
# of the cells themselves
str << ('<c:numFmt formatCode="' << @format_code << '" sourceLinked="' << (@format_code.eql?('General') ? '1' : '0') << '"/>')
str << '<c:majorTickMark val="none"/>'
str << '<c:minorTickMark val="none"/>'
str << ('<c:tickLblPos val="' << @tick_lbl_pos.to_s << '"/>')
str << "<c:numFmt formatCode=\"#{@format_code}\" sourceLinked=\"#{@format_code.eql?('General') ? 1 : 0}\"/>"\
'<c:majorTickMark val="none"/>'\
'<c:minorTickMark val="none"/>'\
"<c:tickLblPos val=\"#{@tick_lbl_pos}\"/>"
# TODO - this is also being used for series colors
# time to extract this into a class spPr - Shape Properties
if @color
str << '<c:spPr><a:ln><a:solidFill>'
str << ('<a:srgbClr val="' << @color << '"/>')
str << '</a:solidFill></a:ln></c:spPr>'
str << '<c:spPr><a:ln><a:solidFill>'\
"<a:srgbClr val=\"#{@color}\"/>"\
'</a:solidFill></a:ln></c:spPr>'
end
# some potential value in implementing this in full. Very detailed!
str << ('<c:txPr><a:bodyPr rot="' << @label_rotation.to_s << '"/><a:lstStyle/><a:p><a:pPr><a:defRPr/></a:pPr><a:endParaRPr/></a:p></c:txPr>')
str << ('<c:crossAx val="' << @cross_axis.id.to_s << '"/>')
str << ('<c:crosses val="' << @crosses.to_s << '"/>')
str << "<c:txPr><a:bodyPr rot=\"#{@label_rotation}\"/><a:lstStyle/><a:p><a:pPr><a:defRPr/></a:pPr><a:endParaRPr/></a:p></c:txPr>"\
"<c:crossAx val=\"#{@cross_axis.id}\"/>"\
"<c:crosses val=\"#{@crosses}\"/>"
end

end
Expand Down
Loading