如何创建单个Clojure源文件,可以安全地用作脚本和没有AOT编译的库?

时间:2012-01-26 23:54:40

标签: scripting clojure

我花了一些时间研究这个,虽然我找到了一些相关的信息,

这是我发现的:

但他们都没有令人满意地回答这个问题。

我的Clojure源代码文件定义了命名空间和一堆函数。当源文件作为脚本运行时,我还希望调用一个函数,但是当它作为库导入时,从不

所以:现在是2012年,有没有办法做到这一点,没有AOT编译?如果是的话,请赐教!

3 个答案:

答案 0 :(得分:2)

我假设通过作为脚本运行你的意思是通过clojure.main,如下所示:

java -cp clojure.jar clojure.main /path/to/myscript.clj

如果是这样,那么有一种简单的技术:将所有库函数放在一个单独的命名空间中,如mylibrary.clj。然后myscript.clj可以使用/ require这个库,你的其他代码也可以。但是myscript.clj中的特定函数只有在作为脚本运行时才会被调用。

作为奖励,这也为您提供了良好的项目结构,因为您不希望脚本特定的代码与您的常规库函数混合在一起。

编辑:

我不认为Clojure本身有一种强大的方法可以确定单个文件是作为脚本启动还是作为库加载 - 从Clojure的角度来看,之间没有区别两个(它们都以相同的方式通过Compiler加载。在Clojure源代码中加载(...)以供任何感兴趣的人使用。

选项,如果您真的想要检测启动的方式:

  • 在Java中编写一个主类,它设置一个静态标志,然后启动Clojure脚本。您可以从Clojure轻松测试此标志。
  • 使用AOT编译实现设置标志的Clojure主类
  • 使用*command-line-args*表示脚本使用情况。您需要在命令行上传递一个额外的参数,如“script”。
  • 使用特定于平台的方法来确定命令行(例如,来自Windows中的环境变量)
  • 使用clojure.main command line中的--eval选项加载clj文件并启动代表脚本的特定函数。然后,此函数可以根据需要设置特定于脚本的标志
  • 使用其中一个methods for detecting the Java main class at runtime

答案 1 :(得分:1)

我提出了一种方法,虽然存在严重缺陷,但似乎有效。

我确定程序作为脚本运行时已知哪些名称空间。然后我可以将该数字与运行时已知的命名空间数进行比较。我们的想法是,如果文件被用作lib,那么至少应该存在一个比脚本情况更多的命名空间。

当然,这非常黑客和脆弱,但似乎确实有效:

(defn running-as-script
    "This is hacky and brittle but it seems to work. I’d love a better
    way to do this; see http://stackoverflow.com/q/9027265"
    []
    (let
        [known-namespaces
            #{"clojure.set"
                "user"
                "clojure.main" 
                "clj-time.format" 
                "clojure.core" 
                "rollup" 
                "clj-time.core" 
                "clojure.java.io" 
                "clojure.string" 
                "clojure.core.protocols"}]
        (= (count (all-ns)) (count known-namespaces))))

答案 2 :(得分:1)

这可能会有所帮助:github项目lein-oneoff将自己描述为“对一次性单文件clojure程序的依赖管理。”

这允许您在一个文件中定义所有内容,但是您需要安装oneoff插件才能从命令行运行它。