存档

‘Coding’ 分类的存档

跨越浏览器的d3.js图表显示

2012年1月22日 没有评论
No Gravatar

最近一段时间对正在采用的图表组件不满意了。看过d3.js之后,别的图表显示确实很难入眼。问题的难度是d3.js采用的SVG技术导致它只能在几种浏览器里使用,在我们客户大量使用的IE,特别是IE6的客户里很难显示正常。SVG之于IE的问题要想解决有几个思路:
一个可以想像的方式是采用svgweb,不过在调试的时候发现IE在加载d3.js经常出非常小且2的问题。比如一个函数里使用了两次while(++i < j)之后,d3.js就不能正常载入,提示的错误居然是“缺少’)'”。
二一个是在后端生成图片,这样就不存在SVG格式的问题了。这个世界近两年来流行的node.js可以在后台执行javascript,这让人有柳暗花明的感觉。
第三个方式是我们后端生成svg文件,前端使用svgweb加载。

沿着第一个思路太耗费时间,不符合想快速解决问题的思路。所以第二、三个方法做了重点测试。
首先可以参照的方法是d3.js里自带的node-canvas例子us-counties。如果将这个图片通过http输出到客户端第二个方法的技术问题就解决了。
然后是@mattbaker提交的gist 1511770,这个例子通过node.js完成了svg文件的生成。加上svgweb,在IE里显示svg图表的问题也就完全不存在了。
@mattbaker提供的gist 1509145提供了直接通过http输出png图片的例子。
我们聊加改造,其实是去除了一些功能就可以得到如下代码:

var http = require('http'),
    url = require('url'),
    jsdom = require('jsdom'),
    child_proc = require('child_process'),
    w = 400,
    h = 400,
    scripts = ["file://"+__dirname+"/../d3.min.js",
               "file://"+__dirname+"/../d3.layout.min.js",
               "file://"+__dirname+"/pie.js"],
    htmlStub = '<!DOCTYPE html><div id="pie" style="width:'+w+'px;height:'+h+'px;"></div>';

http.createServer(function (req, res) {
  var values = (url.parse(req.url, true).query['values'] || ".5,.5")
        .split(",")
        .map(function(v){return parseFloat(v)});
  // 去除生成图片的代码
  //convert.stdout.on('data', function (data) {
  //  res.write(data);
  //});
  //convert.on('exit', function(code) {
  //  res.end();
  //});

  jsdom.env({features:{QuerySelector:true}, html:htmlStub, scripts:scripts, done:function(errors, window) {
    var svgsrc = window.insertPie("#pie", w, h, values).innerHTML;
    //jsdom's domToHTML will lowercase element names
    svgsrc = svgsrc.replace(/radialgradient/g,'radialGradient');
    res.writeHead(200, {'Content-Type': 'image/svg+xml'});
    res.write(svgsrc);
    res.end();
  // 去除生成图片的代码
  //  convert.stdin.write(svgsrc);
  //  convert.stdin.end();
  }});
}).listen(8888, "0.0.0.0");

console.log('Pie SVG server running at http://127.0.0.1:8888/');
console.log('ex. http://127.0.0.1:8888/?values=.4,.3,.2,.1');

用node.js运行后,使用下面页面即可:

<!DOCTYPE html>
<html>
  <!-- Tests using the OBJECT syntax to embed an SVG file -->

  <head>

    <!-- Optional meta tag; if left off, we default to only using the Flash
         renderer for Internet Explorer and using native support on other
         browsers. You can force the Flash renderer for all browsers by
         setting the META tag below to true. -->
    <!-- meta name="svg.render.forceflash" content="true" / -->  <!-- disabled  -->

    <script src="../../src/svg.js" data-path="../../src/"></script>
  </head>

  <body>
    <h1>Tests using the OBJECT syntax to embed an SVG file</h1>

    <!--[if !IE]>-->
      <object data="http://localhost:8888/?values=.4,.3,.2,.1" type="image/svg+xml"
              width="1250" height="750" id="mySVGObject"> <!--<![endif]-->
    <!--[if lt IE 9]>
      <object src="http://localhost:8888/?values=.4,.3,.2,.1" classid="image/svg+xml"
              width="1250" height="750" id="mySVGObject"> <![endif]-->
    <!--[if gte IE 9]>
      <object data="http://localhost:8888/?values=.4,.3,.2,.1" type="image/svg+xml"
              width="1250" height="750" id="mySVGObject"> <![endif]-->
      </object>

    <h1>Test HTML H1</h1>
  </body>
</html>

龙年将至,发文记之,期待腾飞。

分类: Coding, Linux, Ubuntu, 技巧 标签: ,

倚天出笼记

2012年1月22日 2 条评论
No Gravatar

持利器,事半而功倍。所以IT界以发明各种轮子为主要乐事。若器成则功利倍,没有人可以拒绝。在开始打造我们开发的目标团队之时,虽然还是孤身一人,但对各种使用利器之法也是有所耳闻。那段时间赋闲在家,研究一些好玩的技术,算是为某些事做准备,也可以调整自己的心态,积累精神。

一、高可用的管理平台
版本管理什么的以前都比较习惯了。从CVSSVN一路走来,就是在一个人编码的时候也在使用SVN。管理方面还对比过TracRedmine。虽然一直对Python的好感多于Ruby,但是经过比较之后还是觉得Redmine更好一些。就这样,其实在加入新公司之前,各种管理工具通过选择就已经确定了以redmine/Subversion为基础。这两种工具的结合有很多优点:
* Redmine的权限管理可以于Subversion集成。
* Subversion提交的内容与Redmine的问题可以有效地连接。
* Redmine还可以提供简单的BUG管理功能。
从某种意义上来说,我是“拒绝文档控”。一直以来想鼓吹的就是没有文档的软件开发、没有说明书的软件操作方式。但是计划还是要有的,对进度的控制也要在合理的范围内。Redmine正好提供了详细的管理能力。除了可以对项目提供计划和实施管理之外,它的问题条目还可以详细或者粗略地提供开发时间的一些细节。如果可以,使用它也可以生成项目的开发或者设计文档。

二、高可用的硬件
而且那段时间一直使用Ubuntu做为Desktop,两个显示器使用起来,调代码、测试输出效率非常高。以致于当时大致每天下午可以有一两个小时出去骑会自行车散心。所以团队组建初期就提了硬件的指标,这个配置现在看来水平也不算低。每台开发用的电脑都是4核心CPU/8G内存,显示器的概算是每个人都是双显。后来因为我们还要与其他部门一块办公,大致的双显比例是1/2强。原来的开发机都是台式机,在项目逐渐增多后后续的配置都是移动性较强的笔记本了。
我在与之前一些朋友的探讨过程中,他们不是十分理解为什么配置这么好。最多的质疑是这好的配置要多花钱,但是这个说法非常经不起推敲,以一台电脑三年的预算使用期来算,就算是花费6,000元来配置一台开发用机,一年的成本也只有2000,平均到每个月只有非常少的费用。而采用好工具对开发人员带来的,恐怕用这些钱是换不来的。比如:
* 心情的舒畅
* 工作效率的提高
* 对工作条件的满意程度
没经历过用烂机器开发过程的人永远也不能懂得执行编译似卡死的时候的那种感觉,特别是项目Deadline临近。

三、敏捷的开发框架
使用敏捷框架是必然会在突发的、时间有限的项目中被采用的。特别是新团队,原始积累不够丰富的团队。
我们常用的这两个CodeIgniter/Play框架基本上都是沿着这个思路来的。
选择CI是为了将来在虚拟主机上使用。选择Play则是由于客户要求使用Java。不过我们用absiege的测试结果PHP的还要好一些。

四、模板,一定要有的模板
对于我们来说模板程序员和美工最好的沟通工具。我们的美工甚至已经可以在程序员参与之前,就可以根据需要打造好用户的界面。以至于有个项目的甲方说这个系统你们是不是设计得太简单了?这么快就做好了?
模板系统在为我们以原型驱动的开发过程打造了一个良好的基础,客户可以更好的理解我们的想法,并给我们最真实的意见反馈。
CodeIgniter里采用Smarty模板、Play里采用了自带的Grails模板,虽然还有可以同时用于Java和PHP,甚至当我们使用了Python/Ruby都可以用得上的Mustache模板系统,但是指望一个模板系统在不同的语言下都完全保持一致是不可能的。特别是Play里那些@之类。

五、Flash,IE Killer
如果愿意享受,软件开发的乐趣非常多。但是注意有很多烦恼。我们目前最大的烦恼来自于IE6。当初我们在给客户展示图表的时候,一开始使用了HighCharts,一个基于JavaScript的图表系统,在展示单个图表的时候问题不大,但是多图表展示一度让我们怀疑系统出现了致命的问题。应该说在这个问题上Flash成为了我们开发时IE6的Killer。

六、有效的工具
有效的工具我们用过的真是很多,下面几个是常用的但不限于:
* Httpfox(Web调试)
* Notepad++(HTML开发的利器)
* Piwik(用来分析客户行为)
* Netbeans
* Eclipse

我们还在打造基于node.js和d3.js的图表系统。工具的便利,让我们开发时的倚天剑日趋成熟。
利器在手,快乐我有。

Cannot modify header information – headers already sent by

2011年10月23日 没有评论
No Gravatar

 

 

前几天Godaddy里布署应用,出现“Cannot modify header information – headers already sent by”错误,参照下文可以解决:

http://www.wuleilei.net/808.html

发现配置的php版本为5.x版本,所以配置文件php.ini必须更改为 php5.ini

output_buffering = 4096

分类: Coding 标签: ,

第一次Java,第一次反射

2011年8月30日 没有评论
No Gravatar

对Java不熟悉,如果要用PHP/Python之类来做,下面代码用不到这么复杂吧。过则不美,用了后悔。

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package others.commons.play;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import play.db.jpa.GenericModel.JPAQuery;

/**
 *
 * @author Administrator
 */
public class Paginator {
    public List data;
    public int page;
    public int pageSize = 10;
    public int pageCount;
    public String css;

    public Paginator(Class<? extends Model> aClass, long page, long pageSize, String css){
        this.page = (int)page;
        this.pageSize = (int)pageSize;
        this.css = css;
        this.pageCount = (int)count(aClass);
        this.data = getData(aClass, (int)page, (int)pageSize);
    }

    public String indicator() {
        return "html here";
    }

    private static List getData(Class<? extends Model> typeToken, int p1, int p2) {
        Method method;
        JPAQuery handle;
        try {
            method = typeToken.getMethod("all");
            handle = (JPAQuery) method.invoke(typeToken);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        //

        return handle.fetch(p1, p2);
    }
    private static long count(Class<? extends Model> typeToken) {
        Method method;
        Long count = new Long(0);
        try {
            method = typeToken.getMethod("count");     // 实在想不明白直接调用一下有什么问题
            count = (Long) method.invoke(typeToken);   // 这里需要invoke个鸟~~~~
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return count.longValue();

    }

}
分类: Coding, 技术 标签: , ,

ShowOff安装测试

2011年8月17日 1 条评论
No Gravatar

ShowOff是什么?showoff是一个用Sinatra开发的基于配置的简报系统。类似于Keynote。详细内容看它的主站吧:https://github.com/schacon/showoff

1.

sudo apt-get install libxml2-dev libxslt-dev

Reading package lists... Done
Building dependency tree
Reading state information... Done
Note, selecting 'libxslt1-dev' instead of 'libxslt-dev'
The following NEW packages will be installed:
  libxml2-dev libxslt1-dev
0 upgraded, 2 newly installed, 0 to remove and 1 not upgraded.
Need to get 1,412 kB of archives.
After this operation, 5,583 kB of additional disk space will be used.
Get:1 http://cn.archive.ubuntu.com/ubuntu/ natty-updates/main libxml2-dev amd64 2.7.8.dfsg-2ubuntu0.1 [835 kB]
Get:2 http://cn.archive.ubuntu.com/ubuntu/ natty/main libxslt1-dev amd64 1.1.26-6build1 [577 kB]
Fetched 1,412 kB in 4s (299 kB/s)
Selecting previously deselected package libxml2-dev.
(Reading database ... 249315 files and directories currently installed.)
Unpacking libxml2-dev (from .../libxml2-dev_2.7.8.dfsg-2ubuntu0.1_amd64.deb) ...
Selecting previously deselected package libxslt1-dev.
Unpacking libxslt1-dev (from .../libxslt1-dev_1.1.26-6build1_amd64.deb) ...
Processing triggers for man-db ...
Processing triggers for doc-base ...
Processing 1 added doc-base file(s)...
Registering documents with scrollkeeper...
Setting up libxml2-dev (2.7.8.dfsg-2ubuntu0.1) ...
Setting up libxslt1-dev (1.1.26-6build1) ...

2.

sudo gem install showoff

Building native extensions.  This could take a while...
Building native extensions.  This could take a while...
Building native extensions.  This could take a while...
Successfully installed rack-1.3.2
Successfully installed tilt-1.3.2
Successfully installed sinatra-1.2.6
Successfully installed bluecloth-2.1.0
Successfully installed nokogiri-1.5.0
Successfully installed json-1.5.3
Successfully installed gli-1.3.2
Successfully installed showoff-0.4.2
8 gems installed
Installing ri documentation for rack-1.3.2...
Installing ri documentation for tilt-1.3.2...
Installing ri documentation for sinatra-1.2.6...
Installing ri documentation for bluecloth-2.1.0...
Installing ri documentation for nokogiri-1.5.0...

No definition for get_options

No definition for set_options

No definition for parse_memory

No definition for parse_file

No definition for parse_with
Installing ri documentation for json-1.5.3...
Installing ri documentation for gli-1.3.2...
Installing ri documentation for showoff-0.4.2...
Installing RDoc documentation for rack-1.3.2...
Installing RDoc documentation for tilt-1.3.2...
Installing RDoc documentation for sinatra-1.2.6...
Installing RDoc documentation for bluecloth-2.1.0...
Installing RDoc documentation for nokogiri-1.5.0...

No definition for get_options

No definition for set_options

No definition for parse_memory

No definition for parse_file

No definition for parse_with
Installing RDoc documentation for json-1.5.3...
Installing RDoc documentation for gli-1.3.2...
Installing RDoc documentation for showoff-0.4.2...

3. 安装后缺省目录/var/lib/gems/1.8/bin

4. 创建(信赖RMagick,需安装libmagickwand-dev,再sudo gem install rmagick pdfkit)

/var/lib/gems/1.8/bin/showoff create presentname

5. 创建后进入presentname目录

/var/lib/gems/1.8/bin/showoff serve

image sizing disabled - install rmagick
pdf generation disabled - install pdfkit
== Sinatra/1.2.6 has taken the stage on 9090 for development with backup from WEBrick
[2011-08-17 04:39:17] INFO  WEBrick 1.3.1
[2011-08-17 04:39:17] INFO  ruby 1.8.7 (2010-08-16) [x86_64-linux]
[2011-08-17 04:39:24] INFO  WEBrick::HTTPServer#start: pid=13746 port=9090

参考文章:
1. Subjects covered include Ruby, ERROR, Libxml, Nokogiri, and Iconv.

2.How to install rmagick on Ubuntu 10.04?

分类: Coding, Linux, Ubuntu 标签: , , , ,

mustache — Logic-less templates

2011年8月15日 没有评论
No Gravatar

MUSTACHE(5)MUSTACHE MANUALMUSTACHE(5)
NAME/名称
mustache — Logic-less templates./少逻辑模板。

SYNOPSIS/摘要
A typical Mustache template:/一个典型的mustache模板:

Hello {{name}}
You have just won ${{value}}!
{{#in_ca}}
Well, ${{taxed_value}}, after taxes.
{{/in_ca}}
Given the following hash:/给定下面的hash数据:

{
“name”: “Chris”,
“value”: 10000,
“taxed_value”: 10000 – (10000 * 0.4),
“in_ca”: true
}

Will produce the following:/将会产生下面的结果:

Hello Chris
You have just won $10000!
Well, $6000.0, after taxes.

DESCRIPTION/描述
Mustache can be used for HTML, config files, source code – anything. It works by expanding tags in a template using values provided in a hash or object./Mustache可以用来产生HTML,配置文件,源码或者任何东西。它通过使用hash或者对象中的数据扩展模板中的标签来工作。

We call it “logic-less” because there are no if statements, else clauses, or for loops. Instead there are only tags. Some tags are replaced with a value, some nothing, and others a series of values. This document explains the different types of Mustache tags./我们称其为“无逻辑”,因为它没有if语句,else子句或者for循环。除此之外,仅有标签。一些标签会被值来替换,或者被替换成空,其它情况会产生一系列值。本文档解释了Mustache标签的不同类型。

TAG TYPES/标签类型
Tags are indicated by the double mustaches. {{person}} is a tag, as is {{#person}}. In both examples, we’d refer to person as the key or tag key. Let’s talk about the different types of tags.标签由双的胡子{}组成(这东西象胡子吗?)。{{person}}是一个标签,就象{{#person}}。这两个例子中,我们会认为person是一个键值或者是标签键。让我们来谈谈标签的类型吧。

Variables/变量
The most basic tag type is the variable. A {{name}} tag in a basic template will try to find the name key in the current context. If there is no name key, nothing will be rendered./最基本的标签类型就是变量。在基本的模板中出现的{{name}}标签会试图在当前的上下文中寻找名为name的键值。如果没有这个键值,则不会有任何内容会被渲染。

All variables are HTML escaped by default. If you want to return unescaped HTML, use the triple mustache: {{{name}}}./所有的变量缺省地都是HTML转义的。如果要你想返回未转义的HTML内容,可以使用三联标签:{{{name}}}。

You can also use & to unescape a variable: {{& name}}. This may be useful when changing delimiters (see “Set Delimiter” below)./你也可以使用&符号来非转义一个变量,如{{&name}}.这个在改变了分隔符的时候会非常有用(见下“设置分隔符”)。

By default a variable “miss” returns an empty string. This can usually be configured in your Mustache library. The Ruby version of Mustache supports raising an exception in this situation, for instance./默认的一个变量找不到时将返回一个空字符串。这个通常会在你的Mustache库配置。例如,Ruby版本的Mustacle支持在这种情况下抛出异常。

Template:/模板

* {{name}}
* {{age}}
* {{company}}
* {{{company}}}
Hash:/数据

{
“name”: “Chris”,
“company”: “GitHub
}
Output:/输出

* Chris
*
* <b>GitHub</b>
* <strong>GitHub</strong>

Sections/小节
Sections render blocks of text one or more times, depending on the value of the key in the current context./小节会将文本块渲染一次或者多次,这个要看在当前上下文中的键的值的情况。

A section begins with a pound and ends with a slash. That is, {{#person}} begins a “person” section while {{/person}} ends it./一个小节由#号标签开始,用/号标签结束。即:{{#person}会开始一个person小节,然后用{{/person}}结束。

The behavior of the section is determined by the value of the key./小节的行为取决于指定键的值。

False Values or Empty Lists/否定值或者空的列表

If the person key exists and has a value of false or an empty list, the HTML between the pound and slash will not be displayed./如果person键存在,但是有个否定值或者是一个空的列表,则在#和/之间的HTML内容不会被显示。

Template:/模板:

Shown.
{{#nothin}}
Never shown!
{{/nothin}}
Hash:/数据

{
“person”: true,
}
Output:

Shown.
Non-Empty Lists/非空列表

If the person key exists and has a non-false value, the HTML between the pound and slash will be rendered and displayed one or more times./如果一个person键存在,并且有一个非空的值,则在#和/标签之间的内容就会被渲染和显示一次或者多次。

When the value is a non-empty list, the text in the block will be displayed once for each item in the list. The context of the block will be set to the current item for each iteration. In this way we can loop over collections./当值是非空列表中的时候,块中的文本内容会按列表中的条目每一条显示一次。块的上下文会在每一次迭代的时候被设置成当前的条目。在这种情况下我们就可以对那些值进行循环了。

Template:/模板:

{{#repo}}
{{name}}
{{/repo}}
Hash:/值:

{
“repo”: [
{ "name": "resque" },
{ "name": "hub" },
{ "name": "rip" },
]
}
Output:/输出:

resque
hub
rip
Lambdas/匿名

When the value is a callable object, such as a function or lambda, the object will be invoked and passed the block of text. The text passed is the literal block, unrendered. {{tags}} will not have been expanded – the lambda should do that on its own. In this way you can implement filters or caching./当那个值是一个可调用的对象的时候,比如一个函数或者匿名函数,该对象就会被调用,然后对应块的文本内容就会被传入。传入原始块的文本内容不会被渲染。{{tags}}不会被扩展,在它基础上的匿名函数会被调用。这种情况下你可以实现过滤或者缓存。

Template:/模板:

{{#wrapped}}
{{name}} is awesome.
{{/wrapped}}
Hash:/值:

{
“name”: “Willy”,
“wrapped”: function() {
return function(text) {
return “” + render(text) + “
}
}
}
Output:/输出:

Willy is awesome.
Non-False Values/非否定值

When the value is non-false but not a list, it will be used as the context for a single rendering of the block./当一个变量是一个非否定值,但是不是一个列表,它会在块渲染时被当做上下文使用。

Template:/模板:

{{#person?}}
Hi {{name}}!
{{/person?}}
Hash:/值:

{
“person?”: { “name”: “Jon” }
}
Output:/输出:

Hi Jon!
Inverted Sections/反转的小节
An inverted section begins with a caret (hat) and ends with a slash. That is {{^person}} begins a “person” inverted section while {{/person}} ends it.反转的小节会以^(帽子)符号开始,以/号结束。即:{{^person}}开始了一个反转的person小节,用{{/person}}结束。

While sections can be used to render text one or more times based on the value of the key, inverted sections may render text once based on the inverse value of the key. That is, they will be rendered if the key doesn’t exist, is false, or is an empty list.就象小节会根据键的值将渲染内容渲染一次或者多次,一个反转的小节会在值相反的情况下渲染文本内容一次。即,它会在键值不存在,是否的情况或者是空列表的情况下才会被渲染。

Template:/模板:

{{#repo}}
{{name}}
{{/repo}}
{{^repo}}
No repos :(
{{/repo}}
Hash:/值:

{
“repo”: []
}
Output:/输出

No repos :(
Comments/注释
Comments begin with a bang and are ignored. The following template:/注释以感叹号开始,内容会被忽略,如下面模板:

Today{{! ignore me }}.

Will render as follows:/这个模板将被渲染如下:

Today.

Comments may contain newlines./注释中可以包含换行。

Partials/局部模板
Partials begin with a greater than sign, like {{> box}}./局部模板会由一个大于号开始,象{{>box}}。

Partials are rendered at runtime (as opposed to compile time), so recursive partials are possible. Just avoid infinite loops./局部模板会在运行时(与编译时相对)被渲染,所以递归的局部模板是可能的。仅仅需要避免无限循环。

They also inherit the calling context. Whereas in ERB you may have this:/它们也继承了调用的上下文。就象在RoR的ERB模板中你可以做的一样:

< %= partial :next_more, :start => start, :size => size %>
Mustache requires only this:/在Mustache模板中只需要:

{{> next_more}}
Why? Because the next_more.mustache file will inherit the size and start methods from the calling context./这是为什么呢?因为next_more.mustache文件会在上下文中继承size和start方法。

In this way you may want to think of partials as includes, or template expansion, even though it’s not literally true./这种情况下你可能想认为局部模板就是包含,模板扩展,不过它确切来说不是对的。

For example, this template and partial:/例如,下面的模板和局部模板:

base.mustache:

Names

{{#names}}
{{> user}}
{{/names}}

user.mustache:
{{name}}
Can be thought of as a single, expanded template:/这个user.mustache局部模板可以用来做为扩展模板的一个单独的部分,即:

Names

{{#names}}
{{name}}
{{/names}}
Set Delimiter/设置分隔符
Set Delimiter tags start with an equal sign and change the tag delimiters from {{ and }} to custom strings./设置分隔符标签会由等号标志开始,将标签分隔符从{{和}}修改成缺省的字符串。

Consider the following contrived example:/请看下面巧妙的例子:

* {{default_tags}}
{{=< % %>=}}
* < % erb_style_tags %>
< %={{ }}=%>
* {{ default_tags_again }}
Here we have a list with three items. The first item uses the default tag style, the second uses erb style as defined by the Set Delimiter tag, and the third returns to the default style after yet another Set Delimiter declaration.

According to ctemplates, this “is useful for languages like TeX, where double-braces may occur in the text and are awkward to use for markup.”

Custom delimiters may not contain whitespace or the equals sign.

COPYRIGHT/版权
Mustache is Copyright (C) 2009 Chris Wanstrath

Original CTemplate by Google

SEE ALSO/参见
mustache(1), mustache(7), http://mustache.github.com/

DEFUNKTAPRIL 2010MUSTACHE(5)

http://mustache.github.com/mustache.5.html

小注:胡乱翻译,有问题请反馈。多谢。

Switch to our mobile site