| # |
| # 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 = "<div><small>Find full example code at " \ |
| "\"examples/src/main/#{clean_markup}\" in the Spark repo.</small></div>" |
| |
| 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, please check the code." \ |
| unless startIndices.size == endIndices.size |
| |
| raise "No code is selected by include_example, please check the code." \ |
| 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." if start <= lastIndex |
| raise "$example on$ should not be in the same line with $example off$." 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) |