原文地址:http://blog.csdn.net/chaoyuan899/article/details/38703103
了解一个项目,恐怕首先都是通过其Readme文件了解信息。如果你以为Readme文件都是随便写写的那你就错了。github,oschina git gitcafe的代码托管平台上的项目的Readme.MD文件都是有其特有的语法的。称之为Markdown语法。基本规则如下:
Markdown 语法速查表
1 标题与文字格式
标题
# 这是 H1 <一级标题>
## 这是 H2 <二级标题>
###### 这是 H6 <六级标题>
文字格式
**这是文字粗体格式**
*这是文字斜体格式*
~~在文字上添加删除线~~
2 列表
无序列表
* 项目1
* 项目2
* 项目3
有序列表
1. 项目1
2. 项目2
3. 项目3
* 项目1
* 项目2
3 其它
图片
![图片名称](http://gitcafe.com/image.png)
链接
[链接名称](http://gitcafe.com)
引用
> 第一行引用文字
> 第二行引用文字
水平线
***
代码
`<hello world>`
代码块高亮
“`ruby
def add(a, b)
return a + b
end
“`
表格
表头 | 表头
————- | ————-
单元格内容 | 单元格内容
单元格内容l | 单元格内容
如果直接记语法,那似乎困难了些。这里OneCoder推荐两个Markdown的编辑器。
在线编辑器:stackedit
网址:https://stackedit.io/
Mac下离线编辑器Mou
下载地址:http://mouapp.com/
OneCoder这里使用的是后者为自己的shurnim-storage项目写Readme。至于这个项目是什么,见Readme文档,OneCoder也会在另外的博文做一些补充说明。成品Readme如下:
# shurnim-storage
![Shurnim icon](http://onecoder.qiniudn.com/8wuliao/DLPii2Jx/rEBO.jpg)
## 目录
* [背景介绍](#背景介绍)
* [项目介绍](#项目介绍)
* [使用说明](#使用说明)
* [获取代码](#获取代码)
* [开发插件](#开发插件)
* [使用ShurnimStorage接口](#使用ShurnimStorage接口)
* [接口介绍](#接口介绍)
* [使用样例](#使用样例)
* [其他](#其他)<a name="背景介绍"></a>
## 背景介绍*Shurnim*,是我和我老婆曾经养过的一只仓鼠的名字。<br/>
*shurnim-storage*,是一个插件式云存储/网盘同步管理工具。是在参加又拍云开发大赛的过程中设计并开发。<a name="项目介绍"></a>
## 项目介绍*shurnim-storage* 的设计初衷是给大家提供一个可方便扩展的云存储/网盘同步工具。分后端接口和前端UI界面两部分。<br>
由于目前各种云存储和网盘系统层出不穷,单一工具往往支持支持某几个特定存储之间的同步,如**又拍云**到**七牛云存储**的同步工具,此时如若想同步到其他存则可能需要新的工具,给用户带来不便。*shurnim-storage* 正是为了解决此问题而设计的。
在*shurnim-storage*中,用户使用的固定的统一的后端接口。而所有云存储/网盘API的支持则是以插件的形式部署到系统中的。如此,如果 用户想要一个从**又拍云**到**Dropbox**的同步工具,则只需要在原有基础上,增加**Dropbox**的插件,即可实现互通,方便快 捷。<br/>
同时,后端统一接口的设计也考虑到界面开发的需求,可直接通过后端提供的接口开发具有上述扩展功能的云存储UI工具。<br>
目前,后端整体框架的核心部分已经基本开发完成。只需逐步补充后端接口和插件开发接口的定义即可。但由于个人时间和能力所限,UI部分没有开发,有兴趣的同学可以一试。
<a name="使用说明"></a>
## 使用说明<a name="获取代码"></a>
### 获取代码* gitcafe项目主页: <https://gitcafe.com/onecoder/shurnim-storage-for-UPYUN>
* OSChina项目主页: <http://git.oschina.net/onecoder/shurnim-storage><br>
OSChina上的会持续更新。另外你也可以通过OSChina的Maven库获取依赖,或者自己编译jar包。
* maven
1. 加入OSC仓库
<repositories>
<repository>
<id>nexus</id>
<name>local private nexus</name>
<url>http://maven.oschina.net/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>2. 加入依赖
<dependency>
<groupId>com.coderli</groupId>
<artifactId>shurnim-storage</artifactId>
<version>0.1-alpha</version>
</dependency>
* Gradle 编译Jar在项目目录执行
gradle jar
<a name="开发插件"></a>
### 开发插件在*shurnim-storage*中,插件就像一块一块的积木,不但支撑着框架的功能,也是框架可扩展性的基石。开发一个插件,仅需两步:
1. 实现PluginAPI接口
“`
package com.coderli.shurnim.storage.plugin;import java.io.File;
import java.util.List;import com.coderli.shurnim.storage.plugin.model.Resource;
/**
* 各种云存储插件需要实现的通用接口
*
* @author OneCoder
* @date 2014年4月22日 下午9:43:41
* @website http://www.coderli.com
*/
public interface PluginAPI {/**
* 初始化接口
*
* @author OneCoder
* @date 2014年5月19日 下午10:47:40
*/
void init();/**
* 获取子资源列表
*
* @param parentPath
* @return
* @author OneCoder
* @date 2014年4月24日 下午11:29:14
*/
List<Resource> getChildResources(String parentPath);/**
* 下载特定的资源
*
* @param parentPath
* 目录路径
* @param name
* 资源名称
* @param storePath
* 下载资源保存路径
* @return
* @author OneCoder
* @date 2014年4月24日 下午11:30:19
*/
Resource downloadResource(String parentPath, String name, String storePath);/**
* 创建文件夹
*
* @param path
* 文件夹路径
* @param auto
* 是否自动创建父目录
* @return
* @author OneCoder
* @date 2014年5月15日 下午10:10:04
*/
boolean mkdir(String path, boolean auto);/**
* 上传资源
*
* @param parentPath
* 父目录路径
* @param name
* 资源名称
* @param uploadFile
* 待上传的本地文件
* @return
* @author OneCoder
* @date 2014年5月15日 下午10:40:13
*/
boolean uploadResource(String parentPath, String name, File uploadFile);
}
“`目前插件的接口列表仅为同步资源设计,如果想要支持更多操作(如删除,查找等),可扩展该接口定义。<br/><br/>
接口中,所有的参数和返回值均为*shurnim-storage*框架中定义的通用模型。因此,您在开发插件过程中需要将特定SDK中的模型转换成接口中提供的模型。<br/><br/>
插件实现类只要与*shurnim-storage*工程在同一个classpath即可使用。您既可以直接在源码工程中开发插件,就如工程里提供 的*upyun*和*qiniu*插件一样,也可以作为独立工程开发,打成jar,放置在同一个classpath 下。<br/><br/>
*upyun*插件样例(功能不完整):“`
package com.coderli.shurnim.storage.upyun.plugin;import java.io.File;
import java.util.List;import com.coderli.shurnim.storage.plugin.AbstractPluginAPI;
import com.coderli.shurnim.storage.plugin.model.Resource;
import com.coderli.shurnim.storage.plugin.model.Resource.Type;
import com.coderli.shurnim.storage.upyun.api.UpYun;public class UpYunPlugin extends AbstractPluginAPI {
private UpYun upyun;
private String username;
private String password;
private String bucketName;public UpYun getUpyun() {
return upyun;
}public void setUpyun(UpYun upyun) {
this.upyun = upyun;
}public String getUsername() {
return username;
}public void setUsername(String username) {
this.username = username;
}public String getPassword() {
return password;
}public void setPassword(String password) {
this.password = password;
}public String getBucketName() {
return bucketName;
}public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}/*
* (non-Javadoc)
*
* @see
* com.coderli.shurnim.storage.plugin.PluginAPI#getChildResources(java.lang
* .String)
*/
@Override
public List<Resource> getChildResources(String parentPath) {
return null;
}/*
* (non-Javadoc)
*
* @see
* com.coderli.shurnim.storage.plugin.PluginAPI#downloadResource(java.lang
* .String, java.lang.String, java.lang.String)
*/
@Override
public Resource downloadResource(String parentPath, String name,
String storePath) {
File storeFile = new File(storePath);
// if (!storeFile.exists()) {
// try {
// storeFile.createNewFile();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
String filePath = getFullPath(parentPath, name);
upyun.readDir("/api");
if (upyun.readFile(filePath, storeFile)) {
Resource result = new Resource();
result.setName(name);
result.setPath(parentPath);
result.setType(Type.FILE);
result.setLocalFile(storeFile);
return result;
}
return null;
}String getFullPath(String parentPath, String name) {
if (!parentPath.endsWith(File.separator)) {
parentPath = parentPath + File.separator;
}
return parentPath + name;
}/*
* (non-Javadoc)
*
* @see com.coderli.shurnim.storage.plugin.PluginAPI#mkdir(java.lang.String,
* boolean)
*/
@Override
public boolean mkdir(String path, boolean auto) {
// TODO Auto-generated method stub
return false;
}/*
* (non-Javadoc)
*
* @see
* com.coderli.shurnim.storage.plugin.PluginAPI#uploadResource(java.lang
* .String, java.lang.String, java.io.File)
*/
@Override
public boolean uploadResource(String parentPath, String name,
File uploadFile) {
// TODO Auto-generated method stub
return false;
}/*
* (non-Javadoc)
*
* @see com.coderli.shurnim.storage.plugin.AbstractPluginAPI#init()
*/
@Override
public void init() {
upyun = new UpYun(bucketName, username, password);
}}
“`
2. 编写插件配置文件“`
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<id>qiniu</id>
<name>七牛云存储</name>
<api>
<className>com.coderli.shurnim.storage.qiniu.QiniuPlugin</className>
<params>
<param name="access_key" displayName="ACCESS_KEY">EjREKHI_GFXbQzyrKdVhhXrIRyj3fRC1s9UmZPZO
</param>
<param name="secret_key" displayName="SECRET_KEY">88NofFWUvkfJ6T6rGRxlDSZOQxWkIxY2IsFIXJLX
</param>
<param name="bucketName" displayName="空间名">onecoder
</param>
</params>
</api>
</plugin>
“`
* **id** 为该插件在*shurnim-storage*框架下的唯一标识,不可重复,必填。
* **name** 为显示值,为UI开发提供可供显示的有语义的值。
* **className** 为插件接口实现类的完整路径。必填
* **params/param** 为插件需要用户配置的参数列表。其中
* *name* 代表参数名,需要与接口实现类中的参数名严格一致,且必须有相应的set方法的格式要求严格,即set+首字母大写的参数名。例如:setAccess_key(String arg); 目前只支持*String*类型的参数。
* *displayName* 为参数显示名,同样是为了UI开发的考虑,方便用户开发出可根据参数列表动态显示的UI界面。
* 参数的值可以直接配置在配置文件中,也可以在运行期动态赋值。直接配置值,对于直接使用后端接口来说较为方便。对于UI开发来说,运行期动态赋值更为合理。<br/></br>在使用源码工程时,插件配置文件统一放置在工程的*plugins*目录下。你也可以统一放置在任何位置。此时,在构造后端接口实例时,需要告知接口该位置。
<a name="使用ShurnimStorage接口"></a>
### 使用*ShurnimStorage*接口<a name="接口介绍"></a>
#### 接口介绍**ShurnimStorage**接口是*shurinm-storage*框架全局的也是唯一的接口,目前定义如
“`
package com.coderli.shurnim.storage;import java.util.List;
import java.util.Map;import com.coderli.shurnim.storage.plugin.model.Plugin;
import com.coderli.shurnim.storage.plugin.model.Resource;/**
* 后台模块的全局接口<br>
* 通过该接口使用后台的全部功能。<br>
* 使用方式:<br>
* <li>
* 1.先通过{@link #getSupportedPlugins()}方法获取所有支持的平台/插件列表。 <li>
* 2.将列表中返回的ID传入对应的接口参数中,进行对应的平台的相关操作。<br>
* 需要注意的是,不同平台的插件需要给不同的参数赋值,该值可以直接配置在配置文件中。<br>
* 也可以在运行期动态赋值。(会覆盖配置文件中的值。)<br>
*
* 参数列表的设计,方便UI开发人员动态的根据参数列表生成可填写的控件。并给参数赋值。增强了可扩展性。
*
* @author OneCoder
* @date 2014年4月22日 下午9:21:58
* @website http://www.coderli.com
*/
public interface ShurnimStorage {/**
* 获取当前支持的插件列表<br>
* 没有支持的插件的时候可能返回null
*
* @return
* @author OneCoder
* @date 2014年5月7日 下午8:53:25
*/
List<Plugin> getSupportedPlugins();/**
* 给指定的插件的对应参数赋值<br>
* 此处赋值会覆盖配置文件中的默认值
*
* @param pluginId
* 插件ID
* @param paramsKV
* 参数键值对
* @author OneCoder
* @date 2014年5月9日 上午12:41:53
*/
void setParamValues(String pluginId, Map<String, String> paramsKV);/**
* 获取插件对应目录下的资源列表
*
* @param pluginId
* 插件ID
* @param path
* 指定路径
* @return
* @author OneCoder
* @date 2014年5月11日 上午8:52:00
*/
List<Resource> getResources(String pluginId, String path);/**
* 同步资源
*
* @param fromPluginId
* 待同步的插件Id
* @param toPluginIds
* 目标插件Id
* @param resource
* 待同步的资源
* @return 同步结果
* @author OneCoder
* @date 2014年5月11日 上午11:41:24
*/
boolean sycnResource(String fromPluginId, String toPluginId,
Resource resource) throws Exception;
}
“`当前接口实际仅包含了获取资源列表*getResources*和同步资源*sycnResource*功 能,*getSupportedPlugins*和*setParamValues*实际为辅助接口,在UI开发时较为有 用。<br/><br/>
同样,您也可以扩展开发该接口增加更多的您喜欢的特性。例如,同时删除给定存储上的文件。当然,这需要插件接口的配合支持。<br/><br/>这里,*sycnResource*设计成插件间一对一的形式,是考虑到获取同步是否成功的结果的需求。如果您想开发一次同步到多个存储的功能,建议您重新开发您自己的接口实现类,因为默认实现会多次下次资源(每次同步后删除),造成网络资源的浪费。
接口的默认实现类是: **DefaultShurnimStorageImpl**
<a name="使用样例"></a>
#### 使用样例
“`
package com.coderli.shurnim.test.shurnimstorage;import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;import com.coderli.shurnim.storage.DefaultShurnimStorageImpl;
import com.coderli.shurnim.storage.ShurnimStorage;
import com.coderli.shurnim.storage.plugin.model.Resource;
import com.coderli.shurnim.storage.plugin.model.Resource.Type;/**
* 全局接口测试类<br>
* 时间有限,目前仅作整体接口测试。细粒度的单元测试,随开发补充。
*
* @author OneCoder
* @date 2014年5月19日 下午10:50:27
* @website http://www.coderli.com
*/
public class ShurnimStorageTest {private static ShurnimStorage shurnim;
@BeforeClass
public static void init() {
shurnim = new DefaultShurnimStorageImpl(
"/Users/apple/git/shurnim-storage-for-UPYUN/plugins");
}@Test
public void testSycnResource() {
Resource syncResource = new Resource();
syncResource.setPath("/api");
syncResource.setName("api.html");
syncResource.setType(Type.FILE);
try {
Assert.assertTrue(shurnim.sycnResource("upyun", "qiniu",
syncResource));
} catch (Exception e) {
e.printStackTrace();
}
}
}
“`
<a name="其他"></a>
## 其他时间仓促,功能简陋,望您包涵。OneCoder(Blog:[http://www.coderli.com](http://www.coderli.com))特别希望看到该项目对您哪怕一点点的帮助。任意的意见和建议,欢迎随意与我沟通,联系方式:
* Email: <wushikezuo@gmail.com>
* QQ:57959968
* Blog:[OneCoder](http://www.coderli.com)项目的Bug和改进点,可在OSChina上以issue的方式直接提交给我。
效果预览:
如非特别注明,本站内容均为OneCoder原创,转载请务必注明作者和原始出处。
本文地址:http://www.coderli.com/write-readme-for-your-project
相关推荐
本文将详细介绍一款名为Typora的开源Markdown编辑器,特别适合在Windows平台上编写README.md文件。 **Typora** Typora是一款设计精良、用户友好的Markdown编辑器,它提供了无缝的预览体验,使得编写Markdown文档...
本教程将详细介绍如何利用JavaScript和CSS相关技术将Readme.md文件转换为美观简单的HTML页面。 首先,你需要了解Markdown的基本语法。Markdown支持如标题、段落、斜体、粗体、列表、代码块等元素。例如,`#`符号...
在软件开发和开源项目中,`README.md` 文件是项目的重要组成部分,它提供了项目的基本信息、安装指南、使用方法、贡献方式等关键信息。`README.md` 使用Markdown语言编写,使得内容既易于阅读,也方便格式化。...
在"readme.md.zip"这个压缩包中,可能包含了关于Linux内核的详细文档或者教程,比如readme.md文件可能是对某个特定内核功能的介绍,或者是针对初学者的内核学习指南。通过阅读这份文档,你可以深入了解Linux内核的...
在`readme_styles-master`目录中,你将找到这些模板的示例,包括`.rst`和`.md`文件,可以根据自己的项目需求进行修改和定制。记得在创建`README`时,保持内容的清晰性和可读性,同时利用适当的格式和样式来提高用户...
在给定的“用于3D路径规划的AI项目。其他细节和运行说明可以在Readme.md文件中找到_Python_...以上是关于3D路径规划AI项目的一些核心知识点,具体实现和细节需要通过解压并分析项目源代码和Readme.md文件来深入了解。
“自述生成器,我使用简单的NodeJS应用程序来构建readme.md文件”表明该项目的核心功能是生成`readme.md`文件,通过Node.js实现。Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它允许开发者使用JavaScript...
Grip是一个用Python编写的命令行服务器应用程序,它使用呈现本地自述文件。 样式和渲染直接来自GitHub,因此您将确切知道它的外观。 您对自述文件所做的更改将立即反映在浏览器中,而无需刷新页面。 动机 有时,您...
标题 "cron00:每天00:00使用Python每天生成ReadMe.MD" 提到的是一个使用Python脚本在每天凌晨00:00自动创建或更新名为 "ReadMe.md" 的文件的任务。这个任务可能涉及到定时任务调度、文本处理和版本控制等多个方面。 ...
标题中的“modhelp”是一个模块,它专门设计用于在终端中以着色的方式显示README.md文件。这个模块的目的是为了提升在终端环境下阅读Markdown格式文档的体验,尤其是那些包含代码块、强调文本和链接的README文件。...
`readme.md` 文件通常包含项目介绍、使用说明、安装指南以及任何其他重要信息。在这个案例中,详细阅读`readme.md`将是我们理解这些改进思路的关键。可惜的是,由于这是一个文本描述,我们无法直接查看其内容。但...
自己编写的readme.md文件的简单示例,可以对md文件不了解的同学一点儿小借鉴
README.md文件通常会详述如何正确管理和使用这些配置文件,确保项目能够按预期运行。 【标签】:“profile-readme”表明这个存储库可能是个人或团队的配置文件模板,用于快速设置新项目。"readme"部分指示它与文档...
在软件开发领域,README文件是项目中的重要组成部分,它提供了关于项目的基本信息,帮助用户理解项目的用途、如何安装和使用,以及如何贡献代码等。"README文件模板-New.zip" 是一个压缩包,包含了两种类型的README...
该项目名为"README.md-Generator",主要目的是为了帮助开发者快速、方便地创建项目的README.md文件。README.md文件在软件开发中起着至关重要的作用,它提供了项目的基本信息,包括项目简介、安装指南、使用方法、...
readme-generator 可能支持用户自定义模板,通过预设变量和逻辑,让生成的README.md文件符合项目的特定需求和风格。 ### 7. 模板引擎 为了实现模板化,readme-generator 可能使用了诸如 `handlebars` 或 `ejs` ...
通过 `README.md_Generator`,用户可以避免手动编写这些格式,而是通过交互式界面或配置文件来输入项目信息,生成的 `README` 将自动采用标准格式。 该工具可能包含以下功能: 1. **模板选择**:提供了多种预设...
从文档注释生成README.md。 Cargo子命令,可从板条箱的文档注释中提取文档,可用于填充README.md。 安装 cargo install cargo-readme 动机 在编写文档时,通常必须显示如何使用软件的示例。 但是,如何确保所有示例...
11. **README.md** - 项目简介、安装指南和使用说明。 通过这个项目,学习者可以深入理解Django的工作原理,包括模型(Models)、视图(Views)、模板(Templates)以及URL路由(URLs)的交互,同时了解如何利用...