diff --git a/.github/scripts/test-gem.sh b/.github/scripts/test-gem.sh index 75284644..36d30ec5 100755 --- a/.github/scripts/test-gem.sh +++ b/.github/scripts/test-gem.sh @@ -167,6 +167,7 @@ test_gem() { file="${workdir}/_site/index.html" + file_contains "${file}" "This is a fixture" file_contains "${file}" "class=\"${class}\"" file_contains "${file}" " plantuml, 'options' => options.to_h } + + <<~NEEDLE + + #{hash.to_json} + + NEEDLE + rescue StandardError => e + raise e if options.nil? || options.raise_errors? + + logger.error 'Error while placing needle.' + logger.error e.to_s + logger.debug_multiline plantuml + end + + def logger + @logger ||= ::Kramdown::PlantUml::LogWrapper.init + end + end + + private + + def do_process + logger.debug "Replacing Jekyll needles in #{@page.path}" + + html = @page.output + + return html if html.nil? || html.empty? || !html.is_a?(String) + + html.gsub(/(?.*?)/m) do + json = $LAST_MATCH_INFO ? $LAST_MATCH_INFO[:json] : nil + replace_needle(json) unless json.nil? + end + end + + def replace_needle(json) + logger.debug 'Replacing Jekyll needle.' + + needle_hash = JSON.parse(json) + options_hash = needle_hash['options'] + options = ::Kramdown::PlantUml::Options.new({ plantuml: options_hash }) + + begin + decode_and_convert(needle_hash, options) + rescue StandardError => e + raise e if options.raise_errors? + + logger.error 'Error while replacing Jekyll needle.' + logger.error e.to_s + logger.debug_multiline json + end + end + + def decode_and_convert(hash, options) + encoded_plantuml = hash['plantuml'] + plantuml = HTMLEntities.new.decode encoded_plantuml + diagram = ::Kramdown::PlantUml::Diagram.new(plantuml, options) + diagram.convert_to_svg + end + + def logger + @logger ||= ::Kramdown::PlantUml::LogWrapper.init + end + end + end +end diff --git a/lib/kramdown-plantuml/jekyll_provider.rb b/lib/kramdown-plantuml/jekyll_provider.rb index ab345a23..04914459 100644 --- a/lib/kramdown-plantuml/jekyll_provider.rb +++ b/lib/kramdown-plantuml/jekyll_provider.rb @@ -1,10 +1,7 @@ # frozen_string_literal: true -require 'json' -require 'English' -require 'htmlentities' require_relative 'log_wrapper' -require_relative 'diagram' +require_relative 'jekyll_page_processor' module Kramdown module PlantUml @@ -32,20 +29,7 @@ def installed? end def needle(plantuml, options) - hash = { 'plantuml' => plantuml, 'options' => options.to_h } - - <<~NEEDLE - - #{hash.to_json} - - NEEDLE - rescue StandardError => e - raise e if options.raise_errors? - - puts e - logger.error 'Error while placing needle.' - logger.error e.to_s - logger.debug_multiline plantuml + JekyllPageProcessor.needle(plantuml, options) end private @@ -63,54 +47,23 @@ def find_site_destination_dir def register_hook Jekyll::Hooks.register :site, :post_write do |site| - logger.debug ':site:post_write triggered.' - - @site_destination_dir ||= site.dest - - site.pages.each do |page| - page.output = replace_needles(page) - page.write(@site_destination_dir) - end + site_post_write(site) end end - def replace_needles(page) - logger.debug "Replacing Jekyll needle in #{page.path}" - - html = page.output - return html if html.nil? || html.empty? || !html.is_a?(String) + def site_post_write(site) + logger.debug 'Jekyll:site:post_write triggered.' + @site_destination_dir ||= site.dest - html.gsub(/(?.*?)/m) do - json = $LAST_MATCH_INFO[:json] - return replace_needle(json) - end - end + site.pages.each do |page| + processor = JekyllPageProcessor.new(page) - def replace_needle(json) - logger.debug 'Replacing Jekyll needle.' + next unless processor.should_process? - needle_hash = JSON.parse(json) - options_hash = needle_hash['options'] - options = ::Kramdown::PlantUml::Options.new({ plantuml: options_hash }) - - begin - decode_and_convert(needle_hash, options) - rescue StandardError => e - raise e if options.raise_errors? - - logger.error 'Error while replacing Jekyll needle.' - logger.error e.to_s - logger.debug_multiline json + processor.process(site.dest) end end - def decode_and_convert(hash, options) - encoded_plantuml = hash['plantuml'] - plantuml = HTMLEntities.new.decode encoded_plantuml - diagram = ::Kramdown::PlantUml::Diagram.new(plantuml, options) - diagram.convert_to_svg - end - def load_jekyll require 'jekyll' ::Jekyll diff --git a/spec/jekyll_page_processor_spec.rb b/spec/jekyll_page_processor_spec.rb new file mode 100644 index 00000000..a4746179 --- /dev/null +++ b/spec/jekyll_page_processor_spec.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'rspec/its' +require 'kramdown-plantuml/options' +require 'kramdown-plantuml/jekyll_page_processor' + +Options = Kramdown::PlantUml::Options +JekyllPageProcessor = ::Kramdown::PlantUml::JekyllPageProcessor + +describe JekyllPageProcessor do + let(:page) do + page = double('page') + allow(page).to receive(:output).and_return(output) + allow(page).to receive(:output=) + allow(page).to receive(:output_ext).and_return(output_ext) + allow(page).to receive(:data).and_return({}) + allow(page).to receive(:write) + allow(page).to receive(:path).and_return(File.join(__dir__, 'page.md')) + page + end + + subject { JekyllPageProcessor.new(page) } + + describe '#initialize' do + context 'when page is nil' do + let(:page) { nil } + it { expect { subject }.to raise_error(ArgumentError, 'page cannot be nil') } + end + end + + describe '#needle' do + subject { JekyllPageProcessor.needle(plantuml, options) } + + context 'with nil :options' do + let(:options) { nil } + let(:plantuml) { "@startuml\n@enduml" } + + it do + is_expected.to eq <<~NEEDLE + + {"plantuml":"@startuml\\n@enduml","options":{}} + + NEEDLE + end + end + + context 'with nil :plantuml' do + let(:options) { Options.new } + let(:plantuml) { nil } + + it do + is_expected.to eq <<~NEEDLE + + {"plantuml":null,"options":{}} + + NEEDLE + end + end + + context 'with valid :options and :plantuml' do + let(:options) { { theme: { name: 'custom' } } } + let(:plantuml) { "@startuml\n@enduml" } + + it do + is_expected.to eq <<~NEEDLE + + {"plantuml":"@startuml\\n@enduml","options":{"theme":{"name":"custom"}}} + + NEEDLE + end + end + end + + describe '#process' do + before { subject.process(__dir__) } + + context 'with HTML output' do + let(:output) { '

Hello

' } + let(:output_ext) { '.html' } + its(:should_process?) { is_expected.to eq false } + it { expect(page.output).to eq output } + end + end + + describe '#should_process?' do + context 'with HTML output' do + let(:output) { '

Hello

' } + let(:output_ext) { '.html' } + its(:should_process?) { is_expected.to eq true } + it { expect(page.output).to eq output } + end + + context 'with CSS output' do + let(:output) { 'body { display: none }' } + let(:output_ext) { '.css' } + its(:should_process?) { is_expected.to eq false } + end + end +end diff --git a/spec/jekyll_provider_spec.rb b/spec/jekyll_provider_spec.rb index 60b81b38..e1739875 100644 --- a/spec/jekyll_provider_spec.rb +++ b/spec/jekyll_provider_spec.rb @@ -51,7 +51,7 @@ 'config' => File.join(jekyll_source, '_config.yml'), 'incremental' => false, 'source' => jekyll_source, - 'verbose' => false, + 'verbose' => ENV.fetch('DEBUG', false), 'destination' => jekyll_destination }) end @@ -60,6 +60,7 @@ context 'when plantuml contains HTML entities', :jekyll do it { is_expected.to match(/
<\/div>/m) } + it { is_expected.to match(/This is a fixture<\/h1>/m) } end end end