Class: Commenter::Parser::TrackChangeDocxParser

Inherits:
Object
  • Object
show all
Defined in:
lib/commenter/parser/track_change_docx_parser.rb

Overview

Extracts tracked changes from a redlined Word document into an ISO 2012-03 comment sheet.

Captured track changes (w:ins, w:del, w:moveFrom, w:moveTo):

  • proposed_change renders the change itself, e.g. Insert: "text"
  • locality.clause is resolved from the nearest preceding heading
  • locality.element is resolved from caption/inline references (Table N, Figure N, Formula (N), NOTE n) within the current clause
  • observations can be stamped via the observations or accept_all options

Reviewer comment threads (word/comments.xml w:comment) are emitted after the track changes with -CNNN ids: the remark verbatim in comments, its instruction reworded as the proposed change, and empty observations for the owner to draft.

Self-closing markers (paragraph-mark insertions inside rPr) carry no content and are skipped.

word/document.xml is streamed with Nokogiri::XML::Reader because redline documents can exceed 100 MB.

Defined Under Namespace

Classes: ParagraphState

Constant Summary collapse

W_NS =
"http://schemas.openxmlformats.org/wordprocessingml/2006/main"
HEADING_STYLE =
/\A(?:Heading[1-6]|h[2-5]annex\d*|ANNEX|BaseHeading)\z/i
KIND_COMMENT =
{ "ins" => "insertion", "del" => "deletion", "moveFrom" => "move (from)",
"moveTo" => "move (to)" }.freeze
KIND_LABEL =
{ "ins" => "Insert", "del" => "Delete", "moveFrom" => "Move from",
"moveTo" => "Move to" }.freeze
DEFAULT_BODY =
"CS"
WHOLE_DOCUMENT =
"_whole document"
ACCEPT_ALL =
"Accepted. Tracked change accepted."

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#skipped_markersObject (readonly)

Returns the value of attribute skipped_markers.



43
44
45
# File 'lib/commenter/parser/track_change_docx_parser.rb', line 43

def skipped_markers
  @skipped_markers
end

Class Method Details

.reword_remark(text) ⇒ Object

Turns a reviewer's remark phrased as a request ("Please remove this NOTE...") into the corresponding proposed change ("Remove this NOTE...").



73
74
75
# File 'lib/commenter/parser/track_change_docx_parser.rb', line 73

def self.reword_remark(text)
  text.to_s.strip.sub(/\APlease\s+/i, "").sub(/\A[a-z]/, &:upcase)
end

Instance Method Details

#parse(path, options = {}) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/commenter/parser/track_change_docx_parser.rb', line 45

def parse(path, options = {})
  body = options[:body] || DEFAULT_BODY
  changes = []
  remarks = {}
  anchors = {}
  @skipped_markers = 0

  Zip::File.open(path) do |zip|
    entry = zip.glob("word/document.xml").first
    raise Commenter::Error, "word/document.xml not found in #{path}" unless entry

    remarks = read_remarks(zip)
    changes = stream_changes(entry.get_input_stream, anchors)
  end

  CommentSheet.new(
    version: "2012-03",
    date: sheet_date(changes),
    document: options[:document],
    stage: options[:stage],
    comments: build_change_comments(changes, body, options) +
              build_remark_comments(remarks, anchors, body, options)
  )
end