# # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'liquid' require 'pygments' module Jekyll class IncludeExampleTag < Liquid::Tag def initialize(tag_name, markup, tokens) @markup = markup super end def render(context) site = context.registers[:site] config_dir = '../examples/src/main' @code_dir = File.join(site.source, config_dir) clean_markup = @markup.strip @file = File.join(@code_dir, clean_markup) @lang = clean_markup.split('.').last code = File.open(@file).read.encode("UTF-8") code = select_lines(code) rendered_code = Pygments.highlight(code, :lexer => @lang) hint = "
Find full example code at " \ "\"examples/src/main/#{clean_markup}\" in the Spark repo.
" rendered_code + hint end # Trim the code block so as to have the same indention, regardless of their positions in the # code file. def trim_codeblock(lines) # Select the minimum indention of the current code block. min_start_spaces = lines .select { |l| l.strip.size !=0 } .map { |l| l[/\A */].size } .min lines.map { |l| l.strip.size == 0 ? l : l[min_start_spaces .. -1] } end # Select lines according to labels in code. Currently we use "$example on$" and "$example off$" # as labels. Note that code blocks identified by the labels should not overlap. def select_lines(code) lines = code.each_line.to_a # Select the array of start labels from code. startIndices = lines .each_with_index .select { |l, i| l.include? "$example on$" } .map { |l, i| i } # Select the array of end labels from code. endIndices = lines .each_with_index .select { |l, i| l.include? "$example off$" } .map { |l, i| i } raise "Start indices amount is not equal to end indices amount, see #{@file}." \ unless startIndices.size == endIndices.size raise "No code is selected by include_example, see #{@file}." \ if startIndices.size == 0 # Select and join code blocks together, with a space line between each of two continuous # blocks. lastIndex = -1 result = "" startIndices.zip(endIndices).each do |start, endline| raise "Overlapping between two example code blocks are not allowed, see #{@file}." \ if start <= lastIndex raise "$example on$ should not be in the same line with $example off$, see #{@file}." \ if start == endline lastIndex = endline range = Range.new(start + 1, endline - 1) result += trim_codeblock(lines[range]).join result += "\n" end result end end end Liquid::Template.register_tag('include_example', Jekyll::IncludeExampleTag)