class Rspreadsheet::Workbook

Constants

CONTENT_FILE_NAME
MANIFEST_FILE_NAME
TEMPLATE_FILE_NAME

Attributes

filename[R]
xmlnode[R]

Public Class Methods

new(afilename=nil) click to toggle source
# File lib/rspreadsheet/workbook.rb, line 56
def initialize(afilename=nil)
  @worksheets=[]
  @filename = afilename
  @content_xml = Zip::File.open(@filename || TEMPLATE_FILE_NAME) do |zip|
    LibXML::XML::Document.io zip.get_input_stream(CONTENT_FILE_NAME)
  end
  @xmlnode = @content_xml.find_first('//office:spreadsheet')
  @xmlnode.find('./table:table').each do |node|
    create_worksheet_from_node(node)
  end
end

Public Instance Methods

[](index_or_name) click to toggle source
# File lib/rspreadsheet/workbook.rb, line 47
def [](index_or_name); self.worksheets(index_or_name) end
add_worksheet(name = "Sheet
Alias for: create_worksheet
create_worksheet(name = "Sheet click to toggle source
# File lib/rspreadsheet/workbook.rb, line 17
def create_worksheet(name = "Sheet#{worksheets_count+1}")
  sheet = Worksheet.new(name,self)
  register_worksheet(sheet)
  return sheet
end
Also aliased as: add_worksheet
create_worksheet_from_node(source_node) click to toggle source

@!group Worksheet methods

# File lib/rspreadsheet/workbook.rb, line 12
def create_worksheet_from_node(source_node)
  sheet = Worksheet.new(source_node,self)
  register_worksheet(sheet)
  return sheet
end
flat_format?() click to toggle source
# File lib/rspreadsheet/workbook.rb, line 111
def flat_format?; false end
mime() click to toggle source

@return Mime of the file

# File lib/rspreadsheet/workbook.rb, line 51
def mime; 'application/vnd.oasis.opendocument.spreadsheet'.freeze end
mime_default_extension()
mime_preferred_extension() click to toggle source

@return [String] Prefered file extension

# File lib/rspreadsheet/workbook.rb, line 53
def mime_preferred_extension; 'ods'.freeze end
Also aliased as: mime_default_extension
normal_format?() click to toggle source
# File lib/rspreadsheet/workbook.rb, line 112
def normal_format?; true end
save(io=nil) click to toggle source

@param [String] Optional new filename Saves the worksheet. Optionally you can provide new filename or IO stream to which the file should be saved.

# File lib/rspreadsheet/workbook.rb, line 70
def save(io=nil)
  case
    when @filename.nil? && io.nil?
      raise 'New file should be named on first save.'
    when @filename.kind_of?(String) && io.nil?
      Tools.output_to_zip_stream(@filename) do |input_and_output_zip|                  # open old file
        update_zip_manifest_and_content_xml(input_and_output_zip,input_and_output_zip) # input and output are identical
      end
    when (@filename.kind_of?(String) && (io.kind_of?(String) || io.kind_of?(File)))
      io = io.path if io.kind_of?(File)                                           # convert file to its filename
      FileUtils.cp(@filename , io)                                                # copy file externally
      @filename = io                                                              # remember new name
      save_to_io(nil)                                                             # continue modyfying file on spot
    when io.kind_of?(IO) || io.kind_of?(String) || io.kind_of?(StringIO)
      Tools.output_to_zip_stream(io) do |output_io|                               # open output stream of file
        write_ods_to_io(output_io)
      end
      io.rewind if io.kind_of?(StringIO)
    else raise 'Ivalid combinations of parameter types in save'
  end
end
Also aliased as: save_to_io, save_as
save_as(io=nil)
Alias for: save
save_to_io(io=nil)
Alias for: save
sheet(index_or_name)
Alias for: worksheets
sheets(index_or_name)
Alias for: worksheets
to_io() click to toggle source
# File lib/rspreadsheet/workbook.rb, line 93
def to_io
  WorkbookIO.new(self)
end
worksheet(index_or_name)
Alias for: worksheets
worksheet_count()
Alias for: worksheets_count
worksheet_names() click to toggle source

@return [String] names of sheets in the workbook

# File lib/rspreadsheet/workbook.rb, line 27
def worksheet_names; @worksheets.collect{ |ws| ws.name } end
worksheets(index_or_name) click to toggle source

@param [Integer,String] @return [Worksheet] worksheet with given index or name

# File lib/rspreadsheet/workbook.rb, line 30
def worksheets(index_or_name)
  case index_or_name
    when Integer then begin
      case index_or_name
        when 0 then nil
        when 1..Float::INFINITY then @worksheets[index_or_name-1]
        when -Float::INFINITY..-1 then @worksheets[index_or_name]    # zaporne indexy znamenaji pocitani zezadu
      end
    end
    when String then @worksheets.select{|ws| ws.name == index_or_name}.first
    when NilClass then nil
    else raise 'method worksheets requires Integer index of the sheet or its String name'
  end
end
Also aliased as: worksheet, sheet, sheets
worksheets_count() click to toggle source

@return [Integer] number of sheets in the workbook

# File lib/rspreadsheet/workbook.rb, line 24
def worksheets_count; @worksheets.length end
Also aliased as: worksheet_count
write_ods_to_io(io) click to toggle source
# File lib/rspreadsheet/workbook.rb, line 97
def write_ods_to_io(io)
  if @filename.nil?
    Zip::File.open(TEMPLATE_FILE_NAME) do |empty_template_zip|         # open empty_template file
      copy_internally_without_content(empty_template_zip,io)           # copy empty_template internals
      update_zip_manifest_and_content_xml(empty_template_zip,io)           # update xmls + pictures
    end
  else
    Zip::File.open(@filename) do | old_zip |                           # open old file
      copy_internally_without_content(old_zip,io)                      # copy the old internals
      update_zip_manifest_and_content_xml(old_zip,io)                      # update xmls + pictures
    end
  end
end
xmldoc() click to toggle source
# File lib/rspreadsheet/workbook.rb, line 9
def xmldoc; @xmlnode.doc end

Private Instance Methods

copy_internally_without_content(input_zip,output_zip) click to toggle source
# File lib/rspreadsheet/workbook.rb, line 162
def copy_internally_without_content(input_zip,output_zip)
  input_zip.each do |entry|
    next unless entry.file? 
    next if entry.name == CONTENT_FILE_NAME 
    save_entry_to_zip(output_zip, entry.name, entry.get_input_stream.read)
  end
end
register_worksheet(worksheet) click to toggle source
# File lib/rspreadsheet/workbook.rb, line 184
def register_worksheet(worksheet)
  index = worksheets_count+1
  @worksheets[index-1]=worksheet
  @xmlnode << worksheet.xmlnode if worksheet.xmlnode.doc != @xmlnode.doc
end
save_entry_to_zip(zip,internal_filename,contents) click to toggle source
# File lib/rspreadsheet/workbook.rb, line 170
def save_entry_to_zip(zip,internal_filename,contents)
  if zip.kind_of? Zip::File
    zip.get_output_stream(internal_filename) do  |f|
      f.write contents
    end
  else
    zip.put_next_entry(internal_filename)
    zip.write(contents)
  end
end
update_content_xml(zip) click to toggle source
# File lib/rspreadsheet/workbook.rb, line 121
def update_content_xml(zip)
  save_entry_to_zip(zip,CONTENT_FILE_NAME,@content_xml.to_s(indent: false))
end
update_manifest_xml(input_zip,output_zip) click to toggle source
# File lib/rspreadsheet/workbook.rb, line 125
def update_manifest_xml(input_zip,output_zip)
  # read manifest
  @manifest_xml = LibXML::XML::Document.io input_zip.get_input_stream(MANIFEST_FILE_NAME)
  modified = false
  # save all pictures - iterate through sheets and pictures and check if they are saved and if not, save them
  @worksheets.each do |sheet|
    sheet.images.each do |image|
      # check if it is saved
      @ifname = image.internal_filename
      if @ifname.nil? or input_zip.find_entry(@ifname).nil?
        # if it does not have name -> make up unused name
        if @ifname.nil?
          @ifname = image.internal_filename = Rspreadsheet::Tools.get_unused_filename(input_zip,'Pictures/',File.extname(image.original_filename))
        end
        raise 'Could not set up internal_filename correctly.' if @ifname.nil?
        raise 'This should not happen' if image.original_filename.nil?
        
        # save it to zip file
        save_entry_to_zip(output_zip, @ifname, File.open(image.original_filename,'r').read)
        
        # make sure it is in manifest
        if @manifest_xml.find("//manifest:file-entry[@manifest:full-path='#{@ifname}']").empty?
          node = Tools.prepare_ns_node('manifest','file-entry')
          Tools.set_ns_attribute(node,'manifest','full-path',@ifname)
          Tools.set_ns_attribute(node,'manifest','media-type',image.mime)
          @manifest_xml.find_first("//manifest:manifest") << node
          modified = true
        end  
      end
    end
  end

  # write manifest if it was modified
  save_entry_to_zip(output_zip, MANIFEST_FILE_NAME, 
                    @manifest_xml.to_s) if modified
end
update_zip_manifest_and_content_xml(input_zip,output_zip) click to toggle source
# File lib/rspreadsheet/workbook.rb, line 116
def update_zip_manifest_and_content_xml(input_zip,output_zip)
  update_manifest_xml(input_zip,output_zip)
  update_content_xml(output_zip)
end