代码之家  ›  专栏  ›  技术社区  ›  clartaq

在Clojure中创建flexmark扩展

  •  3
  • clartaq  · 技术社区  · 6 年前

    我想写一个小的扩展到 flexmark . 我想创造一个 习俗 AttributeProvider 我试着通过这个例子 展示 here .

    我的问题是将两个类转换为Clojure。

    我将两个相关的示例类分离为单独的Java源文件,并将演示程序转换为clojure测试。

    这个 SampleAttributeProvider 在Java中:

    package cwiki.util;
    
    import com.vladsch.flexmark.ast.Link;
    import com.vladsch.flexmark.ast.Node;
    import com.vladsch.flexmark.html.AttributeProvider;
    import com.vladsch.flexmark.html.AttributeProviderFactory;
    import com.vladsch.flexmark.html.IndependentAttributeProviderFactory;
    import com.vladsch.flexmark.html.renderer.AttributablePart;
    import com.vladsch.flexmark.html.renderer.LinkResolverContext;
    import com.vladsch.flexmark.util.html.Attributes;
    
    class SampleAttributeProvider implements AttributeProvider {
        @Override
        public void setAttributes(final Node node, final AttributablePart part, final Attributes attributes) {
            if (node instanceof Link && part == AttributablePart.LINK) {
                Link link = (Link) node;
    
                if (link.getText().equals("...")) {
                    attributes.replaceValue("target", "_top");
                }
            }
        }
    
        static AttributeProviderFactory Factory() {
            return new IndependentAttributeProviderFactory() {
                @Override
                public AttributeProvider create(LinkResolverContext context) {
                    //noinspection ReturnOfInnerClass
                    return new SampleAttributeProvider();
                }
            };
        }
    }
    

    SampleExtension 在爪哇。

    package cwiki.util;
    
    import com.vladsch.flexmark.html.HtmlRenderer;
    import com.vladsch.flexmark.util.options.MutableDataHolder;
    
    public class SampleExtension implements HtmlRenderer.HtmlRendererExtension {
        @Override
        public void rendererOptions(final MutableDataHolder options) {
            // add any configuration settings to options you want to apply to everything, here
        }
    
        @Override
        public void extend(final HtmlRenderer.Builder rendererBuilder, final String rendererType) {
            rendererBuilder.attributeProviderFactory(cwiki.util.SampleAttributeProvider.Factory());
        }
    
        public static SampleExtension create() {
            return new SampleExtension();
        }
    }
    

    翻译示例中的演示程序很简单。Clojure中的测试文件:

    (ns cwiki.test.util.CWikiAttributeProviderTest
      (:require [clojure.test :refer :all])
      (:import (com.vladsch.flexmark.util.options MutableDataSet)
               (com.vladsch.flexmark.parser Parser Parser$Builder)
               (com.vladsch.flexmark.html HtmlRenderer HtmlRenderer$Builder)
               (cwiki.util SampleExtension)
               (java.util ArrayList)))
    
    (defn commonmark
      [markdown]
      (let [options (-> (MutableDataSet.)
                        (.set Parser/EXTENSIONS
                              (ArrayList. [(SampleExtension/create)]))
                        (.set HtmlRenderer/SOFT_BREAK "<br/>"))
            parser (.build ^Parser$Builder (Parser/builder options))
            document (.parse ^Parser parser ^String markdown)
            renderer (.build ^HtmlRenderer$Builder (HtmlRenderer/builder options))]
        (.render renderer document)))
    
    (deftest cwiki-attribute-provider-test
      (testing "The ability of the CWikiAttributeProvider to place the correct attributes in wikilinks."
        (let [test-output (commonmark "[...](http://github.com/vsch/flexmark-java)")]
          (is (= test-output
                 "<p><a href=\"http://github.com/vsch/flexmark-java\" target=\"_top\">...</a></p>\n")))))
    

    测试使用上面的两个Java类运行并通过。

    样本属性提供程序

    我在翻译示例中的扩展类时遇到问题。这是我到目前为止的想法。(类名已更改以避免冲突。)

    (ns cwiki.util.CWikiAttributeProviderExtension
      (:gen-class
        :implements [com.vladsch.flexmark.html.HtmlRenderer$HtmlRendererExtension]
        :methods [^:static [create [] cwiki.util.CWikiAttributeProviderExtension]])
      (:import (com.vladsch.flexmark.html HtmlRenderer$Builder)
               (com.vladsch.flexmark.util.options MutableDataHolder)
               (cwiki.util CWikiAttributeProvider CWikiAttributeProviderExtension)))
    
    (defn -rendererOptions
      [this ^MutableDataHolder options]
      ; Add any configuration option that you want to apply to everything here.
      )
    
    (defn -extend
      [this ^HtmlRenderer$Builder rendererBuilder ^String rendererType]
      (.attributeProviderFactory rendererBuilder (CWikiAttributeProvider.)))
    
    (defn ^CWikiAttributeProviderExtension -create [this]
      (CWikiAttributeProviderExtension.))
    

    $ lein compile CWikiAttributeProviderExtension ,它将生成一条错误消息,其开头为:

    Compiling cwiki.util.CWikiAttributeProviderExtension
    java.lang.ClassNotFoundException: cwiki.util.CWikiAttributeProviderExtension, compiling:(cwiki/util/CWikiAttributeProviderExtension.clj:1:1)
    Exception in thread "main" java.lang.ClassNotFoundException: cwiki.util.CWikiAttributeProviderExtension, compiling:(cwiki/util/CWikiAttributeProviderExtension.clj:1:1)
            at clojure.lang.Compiler.analyzeSeq(Compiler.java:7010)
            at clojure.lang.Compiler.analyze(Compiler.java:6773)
            at clojure.lang.Compiler.analyze(Compiler.java:6729)
            at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6100)
            at clojure.lang.Compiler$TryExpr$Parser.parse(Compiler.java:2307)
            at clojure.lang.Compiler.analyzeSeq(Compiler.java:7003)
     ...   
    

    IDE(IntelliJ上的草书)显示一条警告消息,说明无法解析 create 中的方法 :gen-class 但是我看不出声明或实现有什么问题。这种转换类似于我以前在其他程序中使用的构建Java类的方法,该类将方法添加到扩展Java接口的对象中。这与我在示例中创建其他相关类时使用的方法类似。但很明显有问题。

    试图只使用翻译的 CWikiAttributeProvider 如果不翻译扩展类,工具链会对首先在Clojure中编译对象,然后是Java部分,然后是Clojure程序的其余部分感到困惑。所以看来我必须同时翻译这两门课,否则就完全不翻译了。

    (ns cwiki.util.CWikiAttributeProvider
      (:gen-class
        :implements [com.vladsch.flexmark.html.AttributeProvider]
        :methods [^:static [Factory [] com.vladsch.flexmark.html.AttributeProviderFactory]])
      (:import (com.vladsch.flexmark.ast Node Link)
               (com.vladsch.flexmark.html AttributeProviderFactory
                                          IndependentAttributeProviderFactory)
               (com.vladsch.flexmark.html.renderer AttributablePart
                                                   LinkResolverContext)
               (com.vladsch.flexmark.util.html Attributes)
               (cwiki.util CWikiAttributeProvider)))
    
    (defn -setAttributes
      [this ^Node node ^AttributablePart part ^Attributes attributes]
      (when (and (= (type node) Link) (= part AttributablePart/LINK))
        (let [title (.getText ^Link node)]
          (println "node: " node)
          (println "title: " title)
          (when (= title "...")
            (.replaceValue attributes "target" "_top")))))
    
    (defn ^AttributeProviderFactory -Factory [this]
      (proxy [IndependentAttributeProviderFactory] []
        (create [^LinkResolverContext context]
          ;; noinspection ReturnOfInnerClass
          (CWikiAttributeProvider.))))
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Toni Vanhala    6 年前

    你需要一份远期申报单 CWikiAttributeProvider 作为返回值 gen-class Declare the class in two steps 在文件的顶部:1)仅使用构造函数,2)使用包含(静态)方法和状态的完整声明。

    (gen-class
      :name cwiki.util.CWikiAttributeProviderExtension
      :implements [com.vladsch.flexmark.html.HtmlRenderer$HtmlRendererExtension])
    
    (gen-class
      :name cwiki.util.CWikiAttributeProviderExtension
      :implements [com.vladsch.flexmark.html.HtmlRenderer$HtmlRendererExtension]
      :methods (^:static [create [] cwiki.util.CWikiAttributeProviderExtension]))
    

    gen类 声明和以下修改:

    • 通过类的完全限定名引用该类( cwiki.util.CWikiAttributeProvider
    • 移除 this

    还要注意,在项目中使用该类时,需要提前编译该类(AOT)。