??xml version="1.0" encoding="utf-8" standalone="yes"?> A Clojure library designed to render velocity template for ring in clojure. Adds dependency in leiningen project.clj: Create a directory named Create a template Use ring.velocity in your namespace: Use The Use ring.velocity in compojure: Use ring.velocity in ring: Custom velocity properties,just put a file named Copyright © 2012 dennis zhuang[killme2008@gmail.com] Distributed under the Eclipse Public License, the same as Clojure. // access flags 1 public invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; L0 LINENUMBER 14 L0 L1 LINENUMBER 14 L1 ALOAD 1 ACONST_NULL ASTORE 1 LDC "substring" ICONST_2 ANEWARRAY java/lang/Object DUP ICONST_0 ALOAD 2 ACONST_NULL ASTORE 2 AASTORE DUP ICONST_1 ALOAD 3 ACONST_NULL ASTORE 3 AASTORE INVOKESTATIC clojure/lang/Reflector.invokeInstanceMethod (Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object; L2 LOCALVARIABLE this Ljava/lang/Object; L0 L2 0 LOCALVARIABLE s Ljava/lang/Object; L0 L2 1 LOCALVARIABLE begin Ljava/lang/Object; L0 L2 2 LOCALVARIABLE end Ljava/lang/Object; L0 L2 3 ARETURN MAXSTACK = 0 MAXLOCALS = 0 public invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; L0 LINENUMBER 15 L0 L1 LINENUMBER 15 L1 ALOAD 1 ACONST_NULL ASTORE 1 CHECKCAST java/lang/String ALOAD 2 ACONST_NULL ASTORE 2 CHECKCAST java/lang/Number INVOKESTATIC clojure/lang/RT.intCast (Ljava/lang/Object;)I ALOAD 3 ACONST_NULL ASTORE 3 CHECKCAST java/lang/Number INVOKESTATIC clojure/lang/RT.intCast (Ljava/lang/Object;)I INVOKEVIRTUAL java/lang/String.substring (II)Ljava/lang/String; L2 LOCALVARIABLE this Ljava/lang/Object; L0 L2 0 LOCALVARIABLE s Ljava/lang/Object; L0 L2 1 LOCALVARIABLE begin Ljava/lang/Object; L0 L2 2 LOCALVARIABLE end Ljava/lang/Object; L0 L2 3 ARETURN MAXSTACK = 0 MAXLOCALS = 0 文Q?a style="color: #006699; ">https://github.com/killme2008/Metamorphosis/wiki
非常感谢blogjava提供q么优秀的^台。只是我今年l自q一个目标是建立自己的博客,因此现在要搬q,加上其实现在也写的少Q其实搬q不搬迁Q意义也不大了。算是一个通告Q有兴趣的可以订阅我的新博客Q没兴趣的请自行略过Q谢谢大家?br />
新博客地址Q?a >http://blog.fnil.net/
RSS地址Q?a >http://blog.fnil.net/index.php/feed
新博客的W一记忆是?a >Leiningen教程中文?/a>》,从现在开始,q个博客不再发布Q何新的文章,已有的也不会删除Q部分可能会导到我的知识库上厅R?br />
最后,福blogjava办好?br />
]]>
Is is written in NodeJS,using express.js for MVC framework,and using MySQL for storage and Redis for caching.
A demo online: http://fnil.me/
The project is at https://github.com/killme2008/node-shorten
Feel free to modify and use it.Have fun.
]]>
最q在公司大{的支持下Q徏立了一个Clojure语言中文斚w的博客和问答|站Q欢qQ何对Clojureq门ZJVM之上的函数式语言感兴的童鞋贡献原创文章或者资料,甌帐号Lq里?br />
博客地址Q? http://blog.clojure.cn/
问答|站Q? http://ask.clojure.cn/
Ƣ迎转发和注册用,谢谢?br />
邮g列表仍然使用google groupQ?a >https://groups.google.com/group/cn-clojure/
]]>Usage
[ring.velocity "0.1.0-SNAPSHOT"]
templates
in your project directory to keep all velocity templates.templates/test.vm
: hello,$name,your age is $age.
(use '[ring.velocity.core :only [render]])
render
function to render template with vars: (render "test.vm" :name "dennis" :age 29)
test.vm
will be interpreted equals to: hello,dennis,your age is 29.
(defroutes app-routes
(GET "/" [] (render "test.vm" :name "dennis" :age 29))
(route/not-found "Not Found")) (use '[ring.util.response])
(response (render "test.vm" :name "dennis" :age 29)) ring-velocity.properties
to your classpath or resource paths.The default velocity properties is in src/default/velocity.properties.License
Home: https://github.com/killme2008/ring.velocity
]]>
"lo"
user=> (.substring "hello" 0 3)
"hel"
上面的例子是在clojure里调用String的substringҎ做字W串截取。Clojure虽然是一门弱cd的语aQ但是它的Lisp Readerq是能识别大多数常见的类型,比如q里hello是一个字W串可以识别出?3是一个整C可以Q通过q些cd信息可以扑ֈ最匚w的substringҎQ在生成字节码的时候避免用反,而是直接调用substringҎQINVOKEVIRTUAL指oQ?br />
但是当你在函数里调用cL法的时候,情况变了,例如Q定义substr函数Q?br />
我们打开*warn-on-reflection*选项Q当有反的时候告警:
true
user=> (defn substr [s begin end] (.substring s begin end))
Reflection warning, NO_SOURCE_PATH:22 - call to substring can't be resolved.
#'user/substr
问题出现了,׃函数substr里没有Q何关于参数s的类型信息,Z调用s的substringҎQ必M用反来调用Qclojure~译器也警告我们调用substring没办法解析,只能通过反射调用。众所周知Q反调用是个相Ҏ늚操作Q对比于普通的Ҏ调用有)。这一切都是因为clojure本n是弱cd的语aQ对参数或者返回g不需要声明类型而直接?Clojure会自动处理类型的转换和调用。ps.?a >leiningen里启用反警告很单,在project.clj里设|:
:warn-on-reflection true
q多的反调用会影响效率Q有没有办法避免q种情况呢?有的QClojure提供了type hint机制Q允许我们帮助编译器来生成更高效的字节码。所谓type hint是l参数或者返回值添加一个提C:hi,clojure~译器,q是xxxcdQ我惌用它的yyyҎQ请生成最高效的调用代码,谢谢合作Q?br />
#'user/substr
q次没有警告Q^String是参数s的type hintQ提Cclojure~译器说s的类型是字符Ԍ那么clojure~译器会从java.lang.Stringc里查找名称为substringq且接收两个参数的方?/strong>Qƈ利用invokevirtual指o直接调用此方法,避免了反调用。除了target对象Q这里的s)可以dtype hintQ方法参数和q回g可以dtype hintQ?br />
#'user/substr
q回值添加type hint是利用tag元数据,提示substr的返回类型是StringQ其他函数在使用substr的时候可以利用这个类型信息来避免反射Q而参数的type hint跟target object的type hint一样以^开头加上类型,例如q里begin和end都提C是Integercd?br />
问题1Q什么时候应该ؓ参数dtype hint呢?我的观点是,在Q何ؓtarget objectdtype hint的地方,都应该相应地为参数添加type hintQ除非你事先不知道参数的cd?/strong>Z么呢Q因为clojure查找cL法的序是这P
1.从Stringc里查找出所有参CCؓ2q且名称为substringҎ
2.遍历W一步里查找出来的MethodQ如果你有设|参数的type hint,?
查找最匚w参数cd的MethodQ否则,如果W一步查扑և来的Method׃个,直接使用q个MethodQ相反就认ؓ没有扑ֈ对应的Method?br />
3.如果W二步没有找到MethodQ用反调用;否则Ҏ该Method元信息生成调用字节码?br />
因此Q如果substringҎ的两个参数版本刚好就一个,Ҏ参数有没有type hint都没有关p(有了错误的type hint反而促使反的发生Q,我们都会扑ֈq个唯一的方法;但是如果目标Ҏ的有多个重蝲Ҏq且参数相同Q而只是参数类型不同(Java里是允许Ҏ的参数类型重载的QClojure只允许函数的参数个数重蝲Q,那么如果没有Ҏ参数的type hintQClojure~译器仍然无法找到合适的调用ҎQ而只能通过反射?br />
看一个例?定义get-bytesҎ调用String.getBytesQ?br />
Reflection warning, NO_SOURCE_PATH:26 - call to getBytes can't be resolved.
#'user/get-bytes
user=> (defn get-bytes [^String s charset] (.getBytes s charset))
Reflection warning, NO_SOURCE_PATH:27 - call to getBytes can't be resolved.
#'user/get-bytes
W一ơ定义,s和charset都没有设|type hintQ有反射警告Q第二次Qs讄了type hintQ但是还是有反射警告。原因就在于String.getBytes有两个重载方法,参数个数都是一个,但是接收不同的参数类型,一个是String的charset名称Q一个Charset对象。如果我们明地知道q里charset是字W串Q那么还可以为charsetdtype hint:
#'user/get-bytes
q次才真正的没有警告了。ȝQ在讄type hint的时候,不要只考虑被调用的target objectQ也要考虑调用的方法参数?br />
问题2Q什么时候应该添加tag元数据呢Q理ZQ在M你明知道返回类型的地方都应该添加tagQ但是这不是教条Q如果一个偶被调用的方法是无需q样做的。这一点只对写库的童鞋要特别注意?br />
Type hint的原理在上文已经大概描述了下Q具体到clojure源码U别Q请参考clojure.lang.Compiler.InstanceMethodExprcȝ构造函数和emitҎ。最后,附送是否用type hint生成substr函数的字节码之间的差异对比:
未用type hint
使用type hint
Ҏ很明显,没有使用type hintQ调用clojure.lang.Reflector的invokeInstanceMethodҎQ用反调用(具体见clojure.lang.Reflector.java)Q而用了type hint之后Q则直接使用invokevirtual指oQ其他方法可能是invokestatic或者invokeinterface{指令)调用该方法,避免了反?br />
参考:
]]>
基本的安装和使用Lq篇文?a >UserGuide》,恕不重复。以下内定w假设你正安装了housemd?br />
本文主要介绍下怎么用housemd诊断跟踪clojureq程。Clojure的java实现也是跑在JVM里,当然也可以用housemd?br />
我们以一个简单的例子开始,假设我们有如下clojure代码Q?br />
(Thread/sleep 1000)
(prn x)
(recur (inc x)))
q段很简单,只是间隔一U不断地打印递增的数字x。我们准备用housemd跟踪q个E序的运行,首先q行q个E序Q你可以用leinQ也可以直接java命oq行Q?br />
q行时不断地在控制台打印数字Q通过jps或者ps查询到该q程的idQ假设ؓpidQ用housemdq接到该q程Q?br />
quit terminate the process.
help display this infomation.
trace display or output infomation of method invocaton.
loaded display loaded classes information.
要用housemd调试clojureQ你需要对clojure的实现有一点点了解Q有兴趣可以看过ȝ一blog?a href="http://www.dentisthealthcenter.com/killme2008/archive/2010/07/11/325775.html">clojure hacking guide》,单来_clojure的编译器会将clojure代码~译成javacdƈq行。对于JVM来说Qclojure生成的类Q跟java~译器生成类没有什么不同?br />
具体C面的clojure代码Q会生成一个名?strong>user$eval1的类Quser是默认的namespaceQ而eval1是clojure~译器自动生成的一个标C类名,通过loaded命o查询cȝ加蝲情况Q?br />
user$eval1 -> null
- clojure.lang.DynamicClassLoader@1d25d06e
- clojure.lang.DynamicClassLoader@1d96f4b5
- sun.misc.Launcher$AppClassLoader@a6eb38a
- sun.misc.Launcher$ExtClassLoader@69cd2e5f
通过-h选项打印了加载user$eval1的类加蝲器的层次关系Q因为user$eval1是动态生成的Qclojure启动q程中)Q因此它不在M一个class或者jar文g中。除了查询user namespace的类之外Q你q可以查询clojure.core,clojure.lang,clojure.java{Q何被加蝲q来的类Q例如查询clojure.core.prn的类,在clojure里这是一个函敎ͼ在jvm看来q只是一个类Q?br />
clojure.core$prn -> /Volumes/HDD/Users/apple/clojure/clojure.jar
- sun.misc.Launcher$AppClassLoader@a6eb38a
- sun.misc.Launcher$ExtClassLoader@69cd2e5f
接下来,我们试用trace命o跟踪Ҏ的运行,例如例子中的clojure代码用到了loop和recur两个sepcial formQ我们跟t下loop:
INFO : probe class clojure.core$loop
core$loop.doInvoke(Object, Object, Object, Object) sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
core$loop.getRequiredArity() sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
core$loop.doInvoke(Object, Object, Object, Object) sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
core$loop.getRequiredArity() sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
core$loop.doInvoke(Object, Object, Object, Object) sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
core$loop.getRequiredArity() sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
core$loop.doInvoke(Object, Object, Object, Object) sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
core$loop.getRequiredArity() sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
core$loop.doInvoke(Object, Object, Object, Object) sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
core$loop.getRequiredArity() sun.misc.Launcher$AppClassLoader@a6eb38a 0 -ms null
INFO : Ended by timeout
INFO : reset class clojure.core$loop
?U内Qclojure.core$loopcL两个Ҏ各被调用?ơ,doInvoke是实际的调用Q而getRequiredArity用来查询loop所需要的参数个数。traceq可以跟t到具体的方法,例如我们跟踪prn函数的调用情况:
INFO : probe class clojure.core$prn
core$prn.doInvoke(Object) sun.misc.Launcher$AppClassLoader@a6eb38a 1 1ms clojure.core$prn@3e4ac866
core$prn.doInvoke(Object) sun.misc.Launcher$AppClassLoader@a6eb38a 2 <1ms clojure.core$prn@3e4ac866
core$prn.doInvoke(Object) sun.misc.Launcher$AppClassLoader@a6eb38a 3 <1ms clojure.core$prn@3e4ac866
core$prn.doInvoke(Object) sun.misc.Launcher$AppClassLoader@a6eb38a 4 <1ms clojure.core$prn@3e4ac866
core$prn.doInvoke(Object) sun.misc.Launcher$AppClassLoader@a6eb38a 5 <1ms clojure.core$prn@3e4ac866
INFO : Ended by timeout
INFO : reset class clojure.core$prn
trace打印了方法的调用ơ数Q?U内Q和每次调用的时_毫秒U别Q,以及调用的target object。小技巧:没有可变参数的函数生成类最l调用的是invokeҎQ参C数可能重载)Q有可变参数的函数调用的是doInvokeҎ?br />
trace命oq支持打印调用堆栈到文gQ例如:
利用-s?d命o会将详细的调用信息输出到临时目录Q时目录的路径可以通过trace help命o查询刎ͼ在我的机器上?tmp/trace/<pid>@host目录下。调用堆栈的输出cMQ?br />
example$eval9.invoke(test.clj:11)
clojure.lang.Compiler.eval(Compiler.java:6465)
clojure.lang.Compiler.load(Compiler.java:6902)
clojure.lang.Compiler.loadFile(Compiler.java:6863)
clojure.main$load_script.invoke(main.clj:282)
clojure.main$script_opt.invoke(main.clj:342)
clojure.main$main.doInvoke(main.clj:426)
clojure.lang.RestFn.invoke(RestFn.java:421)
clojure.lang.Var.invoke(Var.java:405)
clojure.lang.AFn.applyToHelper(AFn.java:163)
clojure.lang.Var.applyTo(Var.java:518)
clojure.main.main(main.java:37)
上面q个单的例子展示了用housemd跟踪诊断clojureq程的方法?br />
自定义ns和函数的调试与此cMQ假设我们有下面的clojure代码Q?br />
(defn square [x]
(* x x))
(loop [x 1]
(Thread/sleep 1000)
(square x)
(recur (inc x)))
ns为exampleQ自定义函数squareq定期@环调用。用housemd诊断q段代码Q?br />
]]>
1.支持发送和订阅分离Q可以细_度地控制Broker或者某个Topic是否接收消息和接受订阅。服务端d新选项acceptPublish和acceptSubscribe?br />
2.更友好地关闭BrokerQ梳理关闭流Eƈ通过JMX调用Ҏ关闭替代原来单的kill?br />
3.更新python客户?/a>?.2版本Q可以通过pip安装: pip install metaq
4.发布ruby语言客户?a style="color: #006699; ">meta-ruby 0.1版本?br />
5.其他改q:升gecko?.1.1版本Q升Uquartz?.1.4版本Q添加集成测试工E和内部重构{?br />
6.新文?a >《用log4j扩展发送消息?/a>
介:https://github.com/killme2008/Metamorphosis/wiki/介绍
下蝲Q?a style="color: #006699; ">https://github.com/killme2008/Metamorphosis/downloads
]]>
1.首先Q查扑֒阅读该项目的博客和资料,通过google你能扑ֈ某个目大体介绍的博客,快速阅M下就能对目的目的、功能、基本用有个大概的了解?br />
2.阅读目的文,重点xcMGetting started、Example之类的文,从中学习如何下蝲、安装、甚臛_本用该目所需要的知识?br />
3.如果该项目有提供现成的example工程Q首先尝试按照开始文的介绍q行exampleQ如果运行顺利,那么恭喜你顺利开了个好头;如果遇到问题Q首先尝试在目?strong>FAQ{文里查找{案Q再ơ,可以问题(例如异常信息Q当成关键词L索,查找相关的解军_法,你遇CQ别Z般也会遇刎ͼ热心的朋友会记录下解决的q程;最后,可以问题提交到目的邮件列表,请大家帮你看看?strong>在没有成功运行example之前Q不要尝试修改example?br />
4.q行了第一个example之后Q尝试根据你的理解和需要修改exampleQ测试高U功能等?br />
5.在了解基本用后Q需要开始深入的了解该项目。例如项目的配置理、高U功能以及最佛_c通常一个运作良好的目会提供一份从到q用户指南Q你q不需要从头到N读这份指南,Ҏ旉和兴,特别是你自己d的需要,重点阅读部分章节q做W记Q推荐evernoteQ?br />
6.如果旉允许Q尝试从源码构徏该项目。通常开源项目都会提供一份构建指南,指导你如何搭Z个用于开发、调试和构徏的环境。尝试构Z个版本?br />
7.如果旉允许q且有兴,可以试阅读源码Q?br />Q?Q阅L码之前,查看该项目是否提供架构和设计文Q阅读这些文可以了解该目的大体设计和l构Q读源码的时候不会无从下手?br />Q?Q阅L码之前,一定要能构建ƈq行该项目,有个直观感受?br />Q?Q阅L码的W一步是抓主qԌ试理清一ơ正常运行的代码调用路径Q这可以通过debug来观察运行时的变量和行ؓ。修Ҏ码加入日志和打印可以帮助你更好的理解源码?br />Q?Q适当d来帮助你理解源码Q在理清d后,可以整个流E画成一张流E图或者标准的UML图,帮助记忆和下一步的阅读?br />Q?Q挑选感兴趣?#8220;枝干”代码来阅读,比如你对|络通讯感兴,阅ȝl层的代码,深入到实现细节,如它用了什么库Q采用了什么设计模式,Z么这样做{。如果可以,debugl节代码?br />Q?Q阅L码的时候,重视单元试Q尝试去q行单元试Q基本上一个好的单元测试会该代码的功能和边界描述清楚?br />Q?Q在熟悉源码后,发现有可以改q的地方Q有_֊、有意愿可以向该目的开发者提出改q的意见或者issueQ甚臛_他修复和实现Q参与该目的发展?br />
8.通常在阅L和源码之后Q你能对该项目有比较深入的了解了Q但是该目所在领域,你可能还x索相关的目和资料,看看有没有其他的更好的项目或者解x案。在q度和深度之间权衡?br />
以上是我个h的一些习惯,我自׃q没有完全按照这个来Q但是按照这个顺序,基本上能让你比较高效地学习和使用某个开源项目?img src ="http://www.dentisthealthcenter.com/killme2008/aggbug/378885.html" width = "1" height = "1" />
]]>
分n几个TipQ也期待大家分n你们的用心得?br />
首先是自动在打开clj后缀文g的时候启动执行clojure-jack-in与slimeq接Q可以在emacs配置里加上个callbackQ?br />
'(progn
(require 'slime)
(require 'clojure-mode)
(unless (slime-connected-p)
(save-excursion (clojure-jack-in)))))
clj后缀的文件自动关联到clojure-mode:
另外Q启动自动匹配括受字W串引号{的paredit模式一定要启动Q?br />
(add-hook 'clojure-mode-hook 'paredit-mode-enable)
(add-hook 'clojure-test-mode-hook 'paredit-mode-enable)
在用clojure-mode或者clojure-test-mode的时候自动启用paredit模式Q括号再也不是问题。括号匹配提CZ般是开启的Q如果没有,强制开启:
(show-paren-mode t)
(setq show-paren-style 'parentheses)
slime更多配置Q启用IO重定向(多线EIO输出都定向到SLIME replQ以及设|通讯字符~码{:
'(progn
(slime-setup '(slime-repl slime-fuzzy))
;;(setq slime-truncate-lines t)
(setq swank:*globally-redirect-io* t)
;; (setq slime-complete-symbol-function ' slime-fuzzy-complete-symbol)
(setq slime-net-coding-system 'utf-8-unix)))
l心的朋友可能注意到我注释了slime-fuzzy-complete的配|,q是一个支持更好的自动补全功能的SLIME插gQ可以用~写来自动补全)Q可惜在我机器上没有试配置成功Q有兴趣你可以尝试下?br />
在REPL里支持语法高亮,一定要配置上:
(defun clojure-mode-slime-font-lock ()
(require 'clojure-mode)
(let (font-lock-mode)
(clojure-mode-font-lock-setup))))
单独在clojure-modeQ在其他mode里这些快捷键不会起作用)里配|快捷键可以q样:
'(progn
(require 'slime)
(require 'clojure-mode)
(define-key clojure-mode-map (kbd "M-/") (quote slime-complete-symbol))
(define-key clojure-mode-map (kbd "C-c s") (quote slime-selector)))
例如我这里将M-/作ؓ自动补全的快捷键Q因为meta键在我的Mac机器上设|ؓcommand键,因此自动补全的操作习惯就跟EclipsecM。?strong>slime-selector是一个非常有用的函数Q用来蟩转到slime的一pdbufferQ因此我l定了C-c s快捷键?br />
额外一提,在Mac osx下,command作ؓmeta?
(setq mac-option-key-is-meta nil
mac-command-key-is-meta t
mac-command-modifier 'meta
mac-option-modifier 'none)
最后,期待大家不吝分n你的心得?br />
]]>
My weekend project clj.monitor is beta release,it's a clojure DSL for monitoring system and applications based on SSH.
Home:https://github.com/killme2008/clj.monitor
An example:
(:use [clj.monitor.core]
[control.core]
[clj.monitor.tasks]))
;;define a mysql cluster
(defcluster mysql
:clients [{:user "deploy" :host "mysql.app.com"}])
;;define a monitor for mysql cluster
(defmonitor mysql-monitor
:tasks [(ping-mysql "root" "password")
(system-load :5 3)]
:clusters [:mysql])
;;start monitors
(start-monitors
:cron "* 0/5 * * * ?"
:alerts [(mail :from "alert@app.com" :to "yourname@app.com")]
:monitors [mysql-monitor])
API document: http://fnil.net/clj.monitor
It is just a beta release,if you have any questions or find issues ,please let me know,thanks.
]]>