[英]clojure.spec custom generator for Java objects
I just saw one of Rich's talks on clojure.spec, and really want to give it a try on my project. 我刚看到Rich关于clojure.spec 的一次谈话 ,并且真的想尝试一下我的项目。 I'm writing a series of tools for parsing C code using the eclipse CDT library , and I would like to spec that my functions accept and emit AST objects.
我正在编写一系列使用eclipse CDT库解析C代码的工具,我想说明我的函数接受并发出AST对象。
I think a very basic spec could be written for a function that takes the root of an AST and emits all the tree's leaves like this: 我认为可以为一个函数编写一个非常基本的规范,它接受AST的根并发出所有树的叶子,如下所示:
(import '(org.eclipse.cdt.core.dom.ast IASTNode))
(require '[clojure.spec :as s])
(defn ast-node? [node] (instance? IASTNode node))
(s/def ::ast-node ast-node?)
(s/fdef leaves :args ::ast-node :ret (s/coll-of ::ast-node))
However when I try to exercise the code (s/exercise leaves)
I get an error: 但是,当我尝试练习代码
(s/exercise leaves)
我收到一个错误:
Unable to construct gen at: [] for:
xxx.x$leaves@xxx
#:clojure.spec{:path [], :form #function[xxx.xxx/leaves], :failure :no-gen}
How can I write a custom generator for Java objects to fully spec and exercise my code? 如何为Java对象编写自定义生成器以完全规范和运用我的代码?
You can attach a custom generator to a spec using s/with-gen . 您可以使用s / with-gen将自定义生成器附加到规范。 You'll need to write a generator that produces all the node variants that you need.
您需要编写一个生成器,生成您需要的所有节点变体。 You might find it easier to write one generator per node type and then combine them, either with
s/or
or possibly by using something like s/multi-spec
instead (which would make this open to extension). 您可能会发现每个节点类型编写一个生成器然后使用
s/or
或者可能使用类似s/multi-spec
组合它们会更容易(这将使其对扩展开放)。
An example of writing a generator that produces a Java object would be something like this: 编写生成Java对象的生成器的示例如下所示:
(s/def ::date
(s/with-gen #(instance? java.util.Date %)
(fn [] (gen/fmap #(java.util.Date. %) (s/gen pos-int?)))))
fmap takes a function and applies that to each result from the generator you give it. fmap接受一个函数并将其应用于您给它的生成器的每个结果。 If you have a Java object with a constructor that takes multiple values, you can use a source generator like
(s/gen (s/tuple int? string? int?))
. 如果你有一个带有多个值的构造函数的Java对象,你可以使用像
(s/gen (s/tuple int? string? int?))
这样的源生成器。
For completeness, here's my code after applying Alex's answer to spec a "LiteralExpression" AST node: 为了完整性,在将Alex的答案应用于规范“LiteralExpression”AST节点之后,这是我的代码:
(ns atom-finder.ast-spec
(:import [org.eclipse.cdt.internal.core.dom.parser.cpp CPPASTLiteralExpression])
(:require [clojure.spec :as s]
[clojure.spec.gen :as gen]))
(def gen-literal-expression-args
(gen/one-of
[
(gen/tuple (s/gen #{CPPASTLiteralExpression/lk_char_constant})
(gen/char-ascii))
(gen/tuple (s/gen #{CPPASTLiteralExpression/lk_float_constant})
(gen/double))
(gen/tuple (s/gen #{CPPASTLiteralExpression/lk_integer_constant})
(s/gen (s/int-in -2147483648 2147483647)))
(gen/tuple (s/gen #{CPPASTLiteralExpression/lk_string_literal})
(gen/string))]))
(def gen-literal-expression
(gen/fmap
(fn [[type val]]
(CPPASTLiteralExpression. type (.toCharArray (str val))))
gen-literal-expression-args))
(s/def ::literal-expression
(s/with-gen
(partial instance? CPPASTLiteralExpression)
(fn [] gen-literal-expression)))
(s/exercise :atom-finder.ast-spec/literal-expression 10
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.