diff --git a/README.adoc b/README.adoc index 8e9ad5e..43ae786 100644 --- a/README.adoc +++ b/README.adoc @@ -101,6 +101,28 @@ The script will automatically create the output file [path]_sample.adoc_, replac The converter is not perfect yet, but we'll get there with your help. You'll can find a list of tasks that need attention listed in the WORKLOG.adoc file. +=== Conditional attribute + +The DocBook conditional attribute "condition" is replaced to "ifdef" macro. + +Take note the marco is on a line by itself. + +For example, in the case of there is the DocBook inline element with condition. + + abc + +It is converted to below AsciiDoc format. + + a + ifdef::foo[] + b + endif::foo[] + c + +When it is converted to html format, the output is displayed with both a space before "b" and a space after "b". + + a b c + == About this Project === Authors diff --git a/lib/docbookrx.rb b/lib/docbookrx.rb index bc0c611..b6635ec 100644 --- a/lib/docbookrx.rb +++ b/lib/docbookrx.rb @@ -7,6 +7,7 @@ def self.convert str, opts = {} raise 'Not a parseable document' unless (root = xmldoc.root) visitor = DocbookVisitor.new opts root.accept visitor + visitor.after visitor.lines * "\n" end diff --git a/lib/docbookrx/docbook_visitor.rb b/lib/docbookrx/docbook_visitor.rb index c45a105..a48f59e 100644 --- a/lib/docbookrx/docbook_visitor.rb +++ b/lib/docbookrx/docbook_visitor.rb @@ -71,6 +71,8 @@ class DocbookVisitor UI_NAMES = ['guibutton', 'guilabel', 'menuchoice', 'guimenu', 'keycap'] + IGNORED_NAMES = ['title', 'subtitle', 'toc'] + attr_reader :lines def initialize opts = {} @@ -143,6 +145,10 @@ def visit node after_traverse node, visit_method_name if (respond_to? :after_traverse) end + def after + replace_ifdef_lines + end + def traverse_children node, opts = {} (opts[:using_elements] ? node.elements : node.children).each do |child| child.accept self @@ -291,6 +297,10 @@ def append_text text, unsub = false ## Lifecycle callbacks def before_traverse node, method + unless IGNORED_NAMES.include? node.name + append_ifdef_start_if_condition(node) + end + case method.to_s when "visit_itemizedlist", "visit_orderedlist" @list_depth += 1 @@ -336,6 +346,10 @@ def after_traverse node, method end end end + + unless IGNORED_NAMES.include? node.name + append_ifdef_end_if_condition(node) + end end ## Node visitor callbacks @@ -355,10 +369,10 @@ def ignore node false end # Skip title and subtitle as they're always handled by the parent visitor - alias :visit_title :ignore - alias :visit_subtitle :ignore - - alias :visit_toc :ignore + IGNORED_NAMES.each do |name| + method_name = "visit_#{name}".to_sym + alias_method method_name, :ignore + end ### Document node (article | book | chapter) & header node (articleinfo | bookinfo | info) visitors @@ -497,7 +511,9 @@ def process_section node, special = nil append_blank_line append_line %([#{special}]) end - title = if (title_node = (node.at_css '> title') || (node.at_css '> info > title')) + + title_node = (node.at_css '> title') || (node.at_css '> info > title') + title = if title_node if (subtitle_node = (node.at_css '> subtitle') || (node.at_css '> info > subtitle')) title_node.inner_html += %(: #{subtitle_node.inner_html}) end @@ -514,8 +530,10 @@ def process_section node, special = nil if (id = (resolve_id node, normalize: @normalize_ids)) && id != (generate_id title) append_line %([[#{id}]]) end + append_ifdef_start_if_condition(title_node) if title_node append_line %(#{'=' * @level} #{unwrap_text title}) lines.concat(text) unless text.nil? || text.empty? + append_ifdef_end_if_condition(title_node) if title_node yield if block_given? if (abstract_node = (node.at_css '> info > abstract')) append_line @@ -1035,6 +1053,7 @@ def process_table node append_blank_line end (node.css '> tgroup > tbody > row').each do |row| + append_ifdef_start_if_condition(row) append_blank_line row.elements.each do |cell| case cell.name @@ -1045,6 +1064,7 @@ def process_table node proceed cell end end + append_ifdef_end_if_condition(row) end if foot (foot.css '> row > entry').each do |cell| @@ -1563,5 +1583,42 @@ def lazy_quote text, seek = ',' def unwrap_text text text.gsub WrappedIndentRx, '' end + + def element_with_condition? node + node.type == ELEMENT_NODE && node.attr('condition') + end + + def append_ifdef_if_condition node + return unless element_with_condition?(node) + condition = node.attr('condition') + yield condition + end + + def append_ifdef_start_if_condition node + append_ifdef_if_condition node do |condition| + append_line "ifdef::#{condition}[]" + end + end + + def append_ifdef_end_if_condition node + append_ifdef_if_condition node do |condition| + append_line "endif::#{condition}[]" + end + end + + def replace_ifdef_lines + out_lines = [] + @lines.each do |line| + if (data = line.match(/^((ifdef|endif)::.+?\[\])(.+)$/)) + # data[1]: "(ifdef|endif)::someting[]" + out_lines << data[1] + # data[3]: a string after "[]" + out_lines << data[3] + else + out_lines << line + end + end + @lines = out_lines + end end end diff --git a/spec/lib/docbookrx/docbookrx_spec.rb b/spec/lib/docbookrx/docbookrx_spec.rb index f7f54cf..80d4b47 100644 --- a/spec/lib/docbookrx/docbookrx_spec.rb +++ b/spec/lib/docbookrx/docbookrx_spec.rb @@ -987,4 +987,417 @@ expect(output).to include(expected) end + + describe "of node with condition" do + ['phrase', 'foreignphrase', 'guiicon'].each do |name| + describe "for inline #{name}" do + it 'should convert from no condition' do + input = <<-EOS +a<#{name}>bc + EOS + expected = <<-EOS.rstrip + +ab +c + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + + it 'should convert to ifdef directive' do + input = <<-EOS +a<#{name} condition="foo">bc + EOS + expected = <<-EOS.rstrip + +a +ifdef::foo[] +b +endif::foo[] +c + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + + it 'should convert from new line tag to ifdef directive.' do + input = <<-EOS +a +<#{name} condition="foo">b +c + EOS + expected = <<-EOS.rstrip + +a +ifdef::foo[] +b +endif::foo[] + c + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + + it 'should convert to ifdef directives' do + input = <<-EOS +a<#{name} condition="foo">b<#{name} condition="bar">cd + EOS + expected = <<-EOS.rstrip + +a +ifdef::foo[] +b +endif::foo[] +ifdef::bar[] +c +endif::bar[] +d + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + end + end + + ['para', 'simpara'].each do |name| + describe "for block #{name}" do + it 'should convert from no condition' do + input = <<-EOS + + <#{name}>a + <#{name}>b + + EOS + expected = <<-EOS.rstrip + + +a + +b + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + + it 'should convert to ifdef directive' do + input = <<-EOS + + <#{name} condition="foo">a + <#{name} condition="bar">b + + EOS + expected = <<-EOS.rstrip + + +ifdef::foo[] + +a +endif::foo[] +ifdef::bar[] + +b +endif::bar[] + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + end + end + + describe "for block table, row" do + it 'should convert from no condition' do + input = <<-EOS + + + a1 + + + + + + a2 + + + + + + + a3 + + + + + +
+
+ EOS + expected = <<-EOS.rstrip + + + +.a1 +[cols="1"] +|=== +| + +a2 + +| + +a3 +|=== + + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + + it 'should convert from table condition to ifdef directive' do + input = <<-EOS + + + a1 + + + + + + a2 + + + + + +
+
+ EOS + expected = <<-EOS.rstrip + + +ifdef::foo[] + +.a1 +[cols="1"] +|=== +| + +a2 +|=== +endif::foo[] + + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + + it 'should convert from row condition to ifdef directive' do + input = <<-EOS + + + a1 + + + + + a2 + + + + + a3 + + + + +
+
+ EOS + expected = <<-EOS.rstrip + + + +.a1 +[cols="1"] +|=== +ifdef::foo[] +| + +a2 +endif::foo[] +ifdef::bar[] + +| + +a3 +endif::bar[] +|=== + + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + + end + end + + describe "for block figure" do + it 'should convert from no condition' do + input = <<-EOS + +
+ a1 + + + + + +
+
+ b1 + + + + + +
+
+ EOS + expected = <<-EOS + + + +.a1 +image::images/dummy.png[] + + +.b1 +image::images/dummy2.png[] + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + + it 'should convert to ifdef directive' do + input = <<-EOS + +
+ a1 + + + + + +
+
+ b1 + + + + + +
+
+ EOS + expected = <<-EOS + + +ifdef::foo[] + +.a1 +image::images/dummy.png[] + +endif::foo[] + +.b1 +image::images/dummy2.png[] + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + + end + end + + describe "for meta title" do + it 'should convert from no condition' do + input = <<-EOS +
+ a +
+ EOS + expected = <<-EOS.rstrip + += a + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + + it 'should convert from condition to ifdef directive' do + input = <<-EOS +
+ a +
+ EOS + expected = <<-EOS.rstrip + +ifdef::foo[] += a +endif::foo[] + EOS + output = Docbookrx.convert input + expect(output).to eq(expected) + end + end + + describe "for other nodes" do + let(:root) do + xmldoc = ::Nokogiri::XML::Document.parse(input) + xmldoc.root + end + let(:visitor) do + Docbookrx::DocbookVisitor.new({}) + end + + [ + { :name => 'note', :method => :process_admonition }, + { :name => 'important', :method => :process_admonition }, + { :name => 'warning', :method => :process_admonition }, + { :name => 'application', :method => :process_literal }, + { :name => 'classname', :method => :process_literal }, + { :name => 'command', :method => :process_literal }, + { :name => 'literal', :method => :process_literal }, + { :name => 'citetitle', :method => :process_keyword }, + { :name => 'filename', :method => :process_path }, + { :name => 'guilabel', :method => :process_ui }, + { :name => 'section', :method => :process_section }, + { :name => 'bridgehead', :method => :visit_bridgehead }, + { :name => 'example', :method => :visit_example }, + { :name => 'itemizedlist', :method => :visit_itemizedlist }, + { :name => 'listitem', :method => :visit_listitem }, + { :name => 'procedure', :method => :visit_procedure }, + { :name => 'programlisting', :method => :visit_programlisting }, + { :name => 'screen', :method => :visit_screen }, + { :name => 'step', :method => :visit_step }, + { :name => 'ulink', :method => :visit_ulink }, + { :name => 'varlistentry', :method => :visit_varlistentry }, + { :name => 'xref', :method => :visit_xref }, + ].each do |node_hash| + name = node_hash[:name] + describe name do + let(:input) do + <<-EOS + + <#{name} condition="foo">dummy + + EOS + end + + it "should convert to ifdef directive" do + allow(visitor).to receive(node_hash[:method]).and_return(false) + root.accept(visitor) + expect(visitor.lines.grep(/^ifdef/).length).to eq(1) + end + end + end + end + end end