class MyDocx

クラス/MyDocx

docxを扱うクラスです
主な機能は次のとおりです
* テンプレートファイルの場所を指定してインスタンス化します
* keysメソッドでテンプレートファイルに含まれる変数(以下、テンプレートファイルで使う変数を単に変数といいます)を取得します
* setメソッドで変数に値を代入することができます
* generateメソッドでdocxファイルを生成します

Constants

VAR_REGEX

変数を定義する正規表現

変数の定義

* @@で始まり、@@で終わる
* 半角アルファベットの大文字・小文字またはアンダーバーで始まる
* 2文字目以降は半角アルファベットの大文字・小文字アンダーバーのほかに数字とピリオドを使うことができる
* 最初のピリオドから次のピリオドないし最後の@@までの文字列をプロパティという
  例:: @@hello.text@@
  - .checkboxプロパティ 値をStringの"1"に指定すると☑に置換えます。それ以外の値は☐に置換えます
  - .textプロパティ 改行も含めて再現します

Public Class Methods

new(path_to_template) click to toggle source

initialize

インスタンスの初期化
Param:: path_to_templateはテンプレートファイルの場所を指定します
テンプレートファイルに半角スペースなどを含んでいると生成されたdocxにエラーが出ます
# File lib/simple_docx_generator/mydocx.rb, line 30
def initialize(path_to_template)
  @keys_index = {}
  @filename = File.basename(path_to_template)
  @dir = File.dirname(path_to_template)
  set_document_xml(path_to_template)
  set_keys_index
end

Public Instance Methods

all_text() click to toggle source

all_text

すべてのテキストをArrayで返します。今のところヘッダー・フッターは未対応です。デバッグ用。
# File lib/simple_docx_generator/mydocx.rb, line 70
def all_text
  @document_xml.xpath("//w:t").map do |t_node|
    t_node.content
  end
end
document_xml() click to toggle source
# File lib/simple_docx_generator/mydocx.rb, line 114
def document_xml
  @document_xml.to_xml
end
generate(filename = 'output_' + @filename) click to toggle source

generate

@document_xmlを使ってdocxファイルを生成します
docxファイルはテンプレートファイルと同じディレクトリに生成されます
もし同じファイル名のファイルが存在していた場合はそのファイルを上書きします
Param:: filenameにdocx拡張子をつけた名前がファイル名となります
もしfilenameを指定しない場合はoutput_元のファイル名.docxというファイルになります
Return: パス付きのfilenameを値として返します
# File lib/simple_docx_generator/mydocx.rb, line 96
def generate(filename = 'output_' + @filename)
  File.delete(filename) if File.exist?(filename)
  buffer = Zip::OutputStream.write_buffer(::StringIO.new('')) do |out|
    Zip::InputStream.open(File.join(@dir, @filename)) do |input|
      while (entry = input.get_next_entry)
        out.put_next_entry(entry.name)
        if entry.name == 'word/document.xml'
          out.write @document_xml.to_xml
        else
          out.write input.read
        end
      end
    end
  end
  File.open(File.join(@dir, filename), 'wb') {|f| f.write(buffer.string)}
  File.join @dir, filename
end
keys() click to toggle source

keys

変数の一覧をArrayで返します
Return:: 変数の一覧をArrayで返します
# File lib/simple_docx_generator/mydocx.rb, line 55
def keys
  @keys_index.map do |key, value|
    key
  end
end
keys_index() click to toggle source

keys_index

変数と変数が含まれている場所です
Return:: 形式は変数をkey、対応する場所のArray(同じ変数がテンプレートファイル内に複数存在する可能性があります)をvalueとしたハッシュ形式です。デバッグ用。
# File lib/simple_docx_generator/mydocx.rb, line 64
def keys_index
  @keys_index
end
set(key, value = '') click to toggle source

set

変数に値を代入します
Params:: key, valueともにString valueを指定しない場合は''になります
Return:: setに成功したらtrue、失敗したらfalseが返ります
典型的にはkeyが存在しない場合を想定しています
# File lib/simple_docx_generator/mydocx.rb, line 43
def set(key, value = '')
  value = set_checkbox_value(key, value)
  if key.gsub(/@@/, '').split('.')[1] == 'text'
    replace_br(key, value)
  else
    replace(key, value)
  end
end
to_html(class_name='') click to toggle source

to_html

ydocxというパーサーを介して<div>タグで囲んだhtmlを返します
オプションで<div>タグのclass名を指定できます
# File lib/simple_docx_generator/mydocx.rb, line 79
def to_html(class_name='')
  ydocx = YDocx::Document.open File.join(@dir, @filename)
  html = Nokogiri::HTML ydocx.to_html
  nodes = html.xpath("//body").children
  myhtml = Nokogiri::HTML::DocumentFragment.parse "<div></div>"
  myhtml.child['class'] = class_name unless class_name.empty?
  myhtml.child << nodes
  myhtml.to_s
end
update_xml(xml_text) click to toggle source
# File lib/simple_docx_generator/mydocx.rb, line 118
def update_xml xml_text
  buffer = Zip::OutputStream.write_buffer(::StringIO.new('')) do |out|
    Zip::InputStream.open(File.join(@dir, @filename)) do |input|
      while (entry = input.get_next_entry)
        out.put_next_entry(entry.name)
        if entry.name == 'word/document.xml'
          out.write xml_text
        else
          out.write input.read
        end
      end
    end
  end
  File.open(File.join(@dir, @filename), 'wb') {|f| f.write(buffer.string)}
  initialize File.join(@dir, @filename)
end

Private Instance Methods

replace(key, value) click to toggle source
# File lib/simple_docx_generator/mydocx.rb, line 165
def replace(key, value)
  index = @keys_index[key]
  unless index == nil
    index.each do |num|
      text = @document_xml.xpath("//w:t")[num].content
      text.gsub!(key, value)
      @document_xml.xpath("//w:t")[num].content = text
    end
    true
  else
    false
  end
end
replace_br(key, value) click to toggle source
# File lib/simple_docx_generator/mydocx.rb, line 179
def replace_br(key, value)
  index = @keys_index[key]
  unless index == nil
    index.each do |num|
      index_node = @document_xml.xpath("//w:t")[num].parent
      index_p_node = index_node.parent
      @document_xml.xpath("//w:t")[num].remove
      frag = Nokogiri::XML::DocumentFragment.new @document_xml
      value.split("\n").each do |t|
        run_node = index_node.dup
        p_node = index_p_node.dup
        node = Nokogiri::XML::Node.new "t", @document_xml 
        node['prefix'] = "w"
        node.content = t
        run_node << node
        p_node << run_node
        frag << p_node
      end
      index_p_node.add_next_sibling frag
      index_p_node.remove
    end
    set_keys_index
    true
  else
    false
  end
end
set_checkbox_value(key, value) click to toggle source
# File lib/simple_docx_generator/mydocx.rb, line 158
def set_checkbox_value(key, value)
  if key.gsub(/@@/, '').split('.')[1] == 'checkbox'
    value = (value == "1") ? "☑" : "☐"
  end
  value
end
set_document_xml(path_to_template) click to toggle source
# File lib/simple_docx_generator/mydocx.rb, line 136
def set_document_xml(path_to_template)
  Zip::File.open(path_to_template) do |zip_files|
    document_file = zip_files.find_entry('word/document.xml')
    @document_xml = Nokogiri::XML document_file.get_input_stream.read
  end
end
set_keys_index() click to toggle source
# File lib/simple_docx_generator/mydocx.rb, line 143
def set_keys_index
  i = 0
  @document_xml.xpath("//w:t").each do |t_node|
    text = t_node.content
    if VAR_REGEX =~ text
      text.scan(VAR_REGEX).each do |t|
        @keys_index[t] ||= []
        @keys_index[t] << i
      end
    end
    # t_node.set_attribute("text_no" , i.to_s)
    i += 1
  end
end