WebDriver 3: more PageObjects - PageFactory

在上篇中,大致介绍了PageObjects。其实为了对PageObjects更好的支持,webdriver中还有一个
PageFactory的概念。

There is a PageFactory in the support package that provides support for this pattern, and helps to remove some boiler-plate code from your Page Objects at the same time.

来看下,上篇中的百度搜索例子, 用PageFactory该如何实现。

  • 首先修改BaiduIndexPage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.ahchoo.automation.page;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
public class BaiduIndexPage {
private WebDriver driver;
private final String url = "http://www.baidu.com";
public BaiduIndexPage(WebDriver driver) {
this.driver = driver;
driver.get(url);
}
@FindBy(how = How.ID, using = "kw")
private WebElement searchField;
public SearchResultPage searchFor(String text) {
// We continue using the element just as before
searchField.sendKeys(text);
searchField.submit();
return new SearchResultPage(driver);
}
}

可以看到这里使用了注释@FindBy, 这是一个注释类,我们来看下它的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public @interface FindBy {
How how() default How.ID;
String using() default "";
String id() default "";
String name() default "";
String className() default "";
String css() default "";
String tagName() default "";
String linkText() default "";
String partialLinkText() default "";
String xpath() default "";
}

我们可以知道其实FindBy注释就是实现了driver.findElement(By),用FindBy可以从无数findElement方法中解脱出来(如果你页面有很多元素的时候)。

  • 然后要用工厂模式生成BaiduIndexPage对象

在SearchTest.java 里

1
2
BaiduIndexPage home = PageFactory.initElements(driver, BaiduIndexPage.class);
// BaiduIndexPage home = new BaiduIndexPage(driver);

将WebDriver实例和BaiduIndexPage.class传给initElements方法,该方法会更具反射生成BaiduIndexPage实例,必须注意的是,使用PageFactory,我们的页面对象必须有
一个带有WebDriver类型参数的构造方法。

This method will attempt to instantiate the class given to it, preferably using a constructor
which takes a WebDriver instance as its only argument or falling back on a no-arg constructor.

PageFactory基本需要关注的就是:

1. Findby注释
2. PageFactory.initElements

我们继续改造,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.ahchoo.automation.page;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;
public class BaiduIndexPage {
private WebDriver driver;
private final String url = "http://www.baidu.com";
public BaiduIndexPage(WebDriver driver) {
this.driver = driver;
driver.get(url);
PageFactory.initElements(driver, this);
}
@FindBy(how = How.ID, using = "kw")
private WebElement searchField;
@FindBy(how = How.ID, using = "lg")
private WebElement logo;
@FindBy(how = How.CLASS_NAME, using = "s_btn")
private WebElement baidYiXiauButton;
public SearchResultPage searchFor(String text) {
// We continue using the element just as before
searchField.sendKeys(text);
searchField.submit();
return new SearchResultPage(driver);
}
public boolean idLogoDisplay() {
return logo.isDisplayed();
}
public boolean hasBaidYiXiauButton() {
return baidYiXiauButton.isDisplayed();
}
}

我们将PageFactory.initElements(driver, this);放在页面类的构造函数里,这样就不需要将PageFactory暴露到TestCase中去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.ahchoo.automation.page;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;
public class SearchResultPage {
private WebDriver driver;
/* 推广链接所在位置 */
@FindBy(how=How.ID, using="ec_im_container")
private WebElement adDiv;
public SearchResultPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public String getTitle() {
return driver.getTitle();
}
public String getContent() {
return driver.getPageSource();
}
public boolean isAdDivDisplayed() {
return adDiv.isDisplayed();
}
}

下面是测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.ahchoo.automation;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.PageFactory;
import com.ahchoo.automation.page.BaiduIndexPage;
import com.ahchoo.automation.page.SearchResultPage;
/**
* Unit test for simple App.
*/
public class SearchTest {
private WebDriver driver;
@Before
public void setUp() {
driver = new FirefoxDriver();
}
@After
public void tearDown() {
driver.close();
}
@Test
public void searchTest() {
BaiduIndexPage home = new BaiduIndexPage(driver);
assertTrue(home.hasBaidYiXiauButton());
assertTrue(home.idLogoDisplay());
SearchResultPage searchResult = home.searchFor("pizza");
assertTrue(searchResult.isAdDivDisplayed());
assertTrue(searchResult.getTitle().contains("pizza"));
assertTrue(searchResult.getContent().contains("pizza"));
}
}

改造完毕,我可以保证这个Testcase能运行的很欢。

######总结
可以看到使用PageFactory可以使页面类代码更加清晰,维护也相对简单许多。如果你也使用PageObjects的话,
不妨试试看。如果你想多了解PageFactory的话,请移步PageFactory
一定能让你受益匪浅。

WebDriver 2: PageObject

在上篇中,已经搭建好了环境。假设我们已经有这样一个环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
── pom.xml
── src
   ├── main
   │   └── java
   │   └── com
   │   └── ahchoo
   │   └── automation
   │   └── App.java
   └── test
   └── java
   └── com
   └── ahchoo
   └── automation
   └── AppTest.java

在这个基础上,我们要实现一个访问百度,查询一个关键字之后,跳转到结果界面。

  • 开始之前,我们先想想传统的WebDriver代码应该怎么写?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.ahchoo.automation;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
public class SearchTest {
private WebDriver driver;
@Before
public void setUp() {
driver = new FirefoxDriver();
}
@After
public void tearDown() {
driver.close();
}
@Test
public void searchTest() {
driver.get("http://www.baidu.com");
WebElement input = driver.findElement(By.id("kw"));
input.clear();
input.sendKeys("Pizza");
input.submit();
assertTrue(driver.getTitle().contains("Pizza"));
assertTrue(driver.getContent().contains("Pizza"));
}
}

如果只有一个测试用例,这样写也很清爽,但是如果有许许多多这样的测试用例,如果input的id发生变化了,就要把
所有的用到这个input的用例找出来,一一修改,这无疑是个大工程。

  • 让我们再来看看PageObjects,首先,我们要创建页面对象, 整个过程涉及2个页面

    1. 百度首页
    2. search结果页

所以我们也就有两个pageobjects, 将pageobjects class放在main source下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.ahchoo.automation.page;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class BaiduIndexPage {
private WebDriver driver;
private final String url = "http://www.baidu.com";
public BaiduIndexPage(WebDriver driver) {
this.driver = driver;
driver.get(url);
}
public SearchResultPage searchFor(String term) {
// Baidu search input id is "kw"
WebElement searchField = driver.findElement(By.id("kw"));
searchField.clear();
searchField.sendKeys(term);
searchField.submit();
return new SearchResultPage(driver);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.ahchoo.automation.page;
import org.openqa.selenium.WebDriver;
public class SearchResultPage {
private WebDriver driver;
public SearchResultPage(WebDriver driver) {
this.driver = driver;
}
public String getTitle() {
return driver.getTitle();
}
public String getContent() {
return driver.getPageSource();
}
}
  • 接着创建testcase,把测试用例放在test source目录下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.ahchoo.automation;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import com.ahchoo.automation.page.BaiduIndexPage;
import com.ahchoo.automation.page.SearchResultPage;
public class SearchTest {
private WebDriver driver;
@Before
public void setUp() {
driver = new FirefoxDriver();
}
@After
public void tearDown() {
driver.close();
}
@Test
public void searchTest() {
BaiduIndexPage home = new BaiduIndexPage(driver);
SearchResultPage searchResult = home.searchFor("pizza");
assertTrue(searchResult.getTitle().contains("pizza"));
assertTrue(searchResult.getContent().contains("pizza"));
}
}

然后我们运行下看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
➜ ahcoo mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building ahcoo 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ ahcoo ---
[WARNING] Using platform encoding (EUC_CN actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Volumes/MacBackUp/ahcoo/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ ahcoo ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ ahcoo ---
[WARNING] Using platform encoding (EUC_CN actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Volumes/MacBackUp/ahcoo/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ ahcoo ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.7.2:test (default-test) @ ahcoo ---
[INFO] Surefire report directory: /Volumes/MacBackUp/ahcoo/target/surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.ahchoo.automation.SearchTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 21.474 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 25.953s
[INFO] Finished at: Fri Apr 20 21:53:03 CST 2012
[INFO] Final Memory: 5M/81M
[INFO] ------------------------------------------------------------------------

Pass!

这就是当下流行的pageobjects,将页面固有的属性和逻辑抽象成类。然后在测试代码里面调用,这样有一个很大的好处,
如果页面变动了,只需要变动页面对象,不需要去无数测试用例里去寻找并更改。

Within your web app’s UI there are areas that your tests interact with. A Page Object simply models these as objects within the test code. This reduces the amount of duplicated code and means that if the UI changes, the fix need only be applied in one place.



simon.m.stewart PageObject

使用 Capybara, Cucumber 和 WebDriver 实现自动化测试

我面试的时候,BOSS对我说,我们是要求自动化的。我想这我会啊。BOSS又说,我们也有一套自动化的框架。我想那更好。然后等我入职之后,发现毛框架也没有,只有四个完全不会代码的测试攻城狮。

老板说要自动化,我说自动化啊?我花了几天的时间温习了我熟悉的JAVA+Junit+SeleniumRC,否定了这个框架,一来语言太重,二来都不会coding。我很苦恼地向BOSS抱怨了,他说用脚本语言吧,于是我就想要不就用python+pyunit+webdriver,在google打工的时候,接触的就是这个框架。BOSS想了想,说用ruby吧。原因在他是ruby的超级粉丝。

于是我找到了cucumber+capybara+webdriver,这也是我第一次接触ruby,第一次接触BDD。而我选用这个框架的原因如下:

1. cucumber有一套自己的DSL,任何会写测试用例的人都会写。
2. 对于这套框架要学的ruby知识,学起来相对容易。
3. 公司文化。

前面都是废话,下面开始进入正题。

##功于善其事,必先利其器

  • 首先搭建环境,确定有ruby的环境。安装必要的gem
    1
    2
    3
    gem install cucumber
    gem install capybara
    gem ins tall selenium-webdriver

Cucumber Capybara WebDriver

  • 建立个空项目,将gem加入gemfile
1
2
3
4
source "http://ruby.taobao.org/"
gem 'cucumber', '>= 1.1.9'
gem "capybara", "~> 1.1.2"
gem 'selenium-webdriver', '>= 2.20.0'
  • 先简单介绍一下cucumber

我们在这个空项目下运行cucumber

1
2
3
zhangmatoMacBook-Pro:test lihuazhang$ cucumber
You don't have a 'features' directory. Please create one to get started.
See http://cukes.info/ for more information.

可以看出cucumber会去寻找features目录,先创建一个features目录。

1
2
3
4
5
6
7
zhangmatoMacBook-Pro:test lihuazhang$ mkdir features
zhangmatoMacBook-Pro:test lihuazhang$ ls
features
zhangmatoMacBook-Pro:test lihuazhang$ cucumber
0 scenarios
0 steps
0m0.000s

因为在features下面什么都没有,所以运行结果都是零。

那我们创建一个feature,cucumber把feature都命名为xxx.feature, 而每个feature有多个scenario。

1
2
3
4
5
6
7
8
9
10
Feature: Adding
Scenario: Add two numbers
Given the input "2+2"
When the calculator is run
Then the output should be "4"
Scenario: Minus two numbers
Given the input "2-1"
When the calculator is run
Then the output should be "0"

cucumber使用Given/When/Then这种叫做gherkin的可描述性语言(DSL)。

feature文件中的每个Given/When/Then步骤在Step文件中都有对应的Ruby执行代码,两类文件通过正则表达式相关联。后面马上讲到。

让我们再来运行一遍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
zhangmatoMacBook-Pro:test lihuazhang$ cucumber
Feature: Adding
Scenario: Add two numbers # features/test.feature:3
Given the input "2+2" # features/test.feature:4
When the calculator is run # features/test.feature:5
Then the output should be "4" # features/test.feature:6
Scenario: Minus two numbers # features/test.feature:7
Given the input "2-1" # features/test.feature:8
When the calculator is run # features/test.feature:9
Then the output should be "0" # features/test.feature:10
2 scenarios (2 undefined)
6 steps (6 undefined)
0m0.005s
You can implement step definitions for undefined steps with these snippets:
Given /^the input "([^"]*)"$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
When /^the calculator is run$/ do
pending # express the regexp above with the code you wish you had
end
Then /^the output should be "([^"]*)"$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
If you want snippets in a different programming language,
just make sure a file with the appropriate file extension
exists where cucumber looks for step definitions.

可以看到我们运行了2个scenarios,6个steps,都没有定义,于是cucumber仁慈的告诉了我们如何实现。于是我们就要开始写step了。

1
2
3
4
5
6
7
8
9
10
11
12
#小小作弊下,就不写的漂亮了。
Given /^the input "([^"]*)"$/ do |statement|
@answer = eval statement
end
When /^the calculator is run$/ do
puts "Run~"
end
Then /^the output should be "([^"]*)"$/ do |answer|
@answer == answer
end

我们再来运行一遍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
zhangmatoMacBook-Pro:test lihuazhang$ cucumber
Feature: Adding
Scenario: Add two numbers # features/test.feature:3
Given the input "2+2" # features/step_definitions/test_step.rb:1
When the calculator is run # features/step_definitions/test_step.rb:5
Run~
Then the output should be "4" # features/step_definitions/test_step.rb:9
Scenario: Minus two numbers # features/test.feature:7
Given the input "2-1" # features/step_definitions/test_step.rb:1
When the calculator is run # features/step_definitions/test_step.rb:5
Run~
Then the output should be "0" # features/step_definitions/test_step.rb:9
2 scenarios (2 passed)
6 steps (6 passed)
0m0.005s

哇,恭喜都通过了。

好,关于cucumber的介绍就到这里,具体可以去看看Cucumber的目录结构和执行过程

  • 在简单介绍下Capybara

Capybara是水豚的意思,在水豚之前有一个老鼠,叫做webrat,你如果在google上搜索capybara webrat的话,会发现一大推类似


Cucumber: Switching from Webrat to Capybara - cakebaker
cakebaker.42dh.com/…/cucumber-switching-from… - 网页快照 - 翻译此页
19 Sep 2010 – Fortunately, there is an alternative working with both Rails versions: Capybara. And so I decided to make the switch from Webrat to Capybara.

Webrat逐渐被Capybara取代,就像selenium逐渐被webdriver取代。

Capybara主要是用来测试rails和Rack应用的。官网上说


Capybara helps you test Rails and Rack applications by simulating how a real user would interact with your app. It is agnostic about the driver running your tests and comes with Rack::Test and Selenium support built in. WebKit is supported through an external gem.

我们主要用Capybara和Webdriver结合起来进行网页自动化测试。(注意:Capybara不支持selenium rc)

详细请见Capybara,里面讲的非常详细了。

##小试牛刀
在了解了cucumber和capybara之后,我们可以正式开始写点东西。 在空项目底下,建立类似的目录结构

1
2
3
4
5
6
7
8
├── features
   ├── example
      ├── example.feature
      ├── step_definitions
      │   └── example_steps.rb
      └── support
      └── env.rb

我们这个例子是访问百度

1
2
3
4
5
6
7
8
9
Feature: Using baidu
Scenario: Searching for a term
Given I am on baidu.com
When I enter "pizza"
And I press "百度一下"
Then I should see "pizza_百度百科"

Given/When/And/Then很明了的告诉我们,打开百度,输入pizza,然后点击百度一下,然后就能看到pizza_百度百科。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Given /^I am on baidu\.com$/ do
Capybara.app_host = "http://www.baidu.com"
visit('/')
end
When /^I enter "([^"]*)"$/ do |term|
fill_in('wd',:with => term)
end
When /^(?:|I )press "([^"]*)"$/ do |button|
puts button
click_button(button)
end
Then /^(?:|I )should see "([^"]*)"$/ do |text|
if page.respond_to? :should
page.should have_content(text)
else
assert page.has_content?(text)
end
end

接着就是值得一提的env.rb,这是cucumber的环境配置文件。


The file features/support/env.rb is always the very first file to be loaded when Cucumber starts a test run. You use it to prepare the environment for the rest of your support and step definition code to operate.
1
2
3
4
5
6
require 'capybara'
require 'capybara/cucumber'
require 'capybara/dsl'
Capybara.app_host = "http://www.baidu.com"
Capybara.default_driver = :selenium

让我们来运行一下

1
2
3
4
5
6
7
8
9
10
11
12
13
zhangmatoMacBook-Pro:features lihuazhang$ cucumber example/example.feature
Feature: Using baidu
Scenario: Searching for a term # example/example.feature:4
Given I am on baidu.com # example/step_definitions/example_steps.rb:1
When I enter "pizza" # example/step_definitions/example_steps.rb:6
And I press "百度一下" # example/step_definitions/example_steps.rb:10
百度一下
Then I should see "pizza_百度百科" # example/step_definitions/example_steps.rb:15
1 scenario (1 passed)
4 steps (4 passed)
0m9.184s

Nice!

至此,基本的框架搭好了。至于如何配置不同的浏览器,以及如何和page object配合,我们以后再讲。

WebDriver 1: Set up WebDriver using Maven3


1. Learn Maven3 first.


This is quite simple. Go through Maven in 5 Minutes
That’s quite enough.


2. Set up project


Using the command in Maven in 5 Minutes to create a project using your own groupId and artifactId.

mvn archetype:generate -DgroupId=com.ahchoo.automation -DartifactId=ahcoo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false


Change the pom.xml to add Junit and WebDriver dependencies


<project>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.20.0</version>
</dependency>
</dependencies></scope></version></artifactId></groupId>
</dependency>
</dependencies>

</project>

Then run mvn clean install


3. Using eclipse to import this project


install m2eclipse and
run command in the project root directory:

mvn eclipse:clean
mvn eclipse:eclipse


open eclise, click File and choose Import:




Choose Existing Projects into Workspace



After import, you will see the file tree in eclipse project explorer:




Thus the environment is set up.

vim学习 jsctags


ctags不能非常胜任对现在的javascript代码的解析,尤其是遇到:


Test.object.do = function(obj) {// …}
ajaxSetup: function( settings ) {//..}

网上搜索了下,发现了doctorjs.git (以前叫jsctags), 号称被应用于Cloud9 IDE’s Ace online editor.


  • 安装doctorjs需要nodejs环境,如何安装nodejs自己google去

  • 安装ctags,brew也好macports也好。

  • git clone https://github.com/mozilla/doctorjs.git –recursive

  • make install

  • Add export NODE_PATH=/usr/local/lib/jsctags/:$NODE_PATH to your .zshrc or .bashrc

  • 然后就可以使用了,直接jsctags your_js_dir

  • 配合vim的tagbar非常好用。




vim学习 shiftwidth, tabstop, softtabstop和expandtab


1. shiftwidth


这个是用于程序中自动缩进所使用的空白长度指示的。一般来说为了保持程序的美观,和下面的参数最好一致。同时它也是符号移位(>>)长度的制定者。



2. tabstop


定义tab所等同的空格长度,一般来说最好设置成8,因为如果是其它值的话,可能引起文件在打印之类的场合中看起来很别扭。
除非你设置了 expandtab模式,也就是把tabs转换成空格,这样的话就不会一起混淆,不过毕竟制表符为8是最常用最普遍的设置,所以一般还是不要改。
(lz总是把它设置为4个空格)




3. softtabstop


如果我们希望改变程序中的缩进怎么办?shiftwidth和tabstop不一样的话,你会发现程序比较难看的。
这时候,softtabstop就起作用了。可以从vim的说明中看到,一旦设置了softtabstop的值时,你按下tab键,
插入的是空格和tab制表符的混合,具体如何混合取决于你设定的softtabstop,举个例子,如果设定softtabstop=8,
那么按下tab键,插入的就是正常的一个制表符;如果设定 softtabstop=16,那么插入的就是两个制表符;如果softtabstop=12,
那么插入的就是一个制表符加上4个空格;如果 softtabstop=4呢?那么一开始,插入的就是4个空格,此时一旦你再按下一次tab,
这次的四个空格就会和上次的四个空格组合起来变成一个制表符。
换句话说,softtabstop是“逢8空格进1制表符”,前提是你tabstop=8。




4. expandtab


因为tab的大小不一样,在多人一起开发项目时,为了使代码风格尽量保持一致,
一般不允许在代码使用TAB符,而以4个空格代之。


一般的shiftwidth, tabstop, softtabstop和expandtab的配置

set shiftwidth=4                " use indents of 4 spaces
set tabstop=4                   " an indentation every four columns
set softtabstop=4               " let backspace delete indent
set expandtab                   " tabs are spaces, not tabs

vim学习 listchars


在ruby-china.org混,看到很多vimer,于是就请教了如何学习vim,@jinleileiking同学就给了建议,非常中用,他说:



  • vimcasts.org 类似railscasts

  • [学习vi和Vim编辑器(第7版)].(Learning.the.vi.and.Vim.Editors.7th.Edition).A.Robbins&E.Hannah&L.Lamb.文字版

  • [Hacking.Vim].[Hacking.Vim].[Hacking.Vim].Packt.Publishing.Hacking.Vim.May.2007

  • :help vim内置帮助




先看vimcasts.org, 第一章:[显示不可视的字符] (http://vimcasts.org/episodes/show-invisibles/)


“ 设置显示空格,tab的切换键
nmap <leader>l :set list!

“ 设置tab用小三角加重复的空格显示,换行用横折符号显示。可以:help listchars
set listchars=tab:▸\ ,eol:¬

oh my zsh

Mac自带zsh, 先设置你的默认shell为zsh



chsh -s /bin/zsh


然后使用oh-my-zsh的配置。参见oh my zsh


cd ~
curl -L https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh | sh


修改.zshrc,把你需要的环境变量配置全部加到.zshrc中去。定义自己的主题。可以在.oh-my-zsh/themes下面找到所有的主题
同时你也可以去themes里去找你喜欢的主题。个人比较喜欢gnzh.


zhangmatoMacBook-Pro.local ~/.oh-my-zsh/themes ‹master›
Soliah.zsh-theme daveverwer.zsh-theme frisk.zsh-theme josh.zsh-theme mikeh.zsh-theme rgm.zsh-theme suvash.zsh-theme
afowler.zsh-theme dieter.zsh-theme funky.zsh-theme jreese.zsh-theme miloshadzic.zsh-theme risto.zsh-theme takashiyoshida.zsh-theme



安装插件,在.zshrc文件里找到”plugins=”,然后在里面添加你所需要的插件,你安装的插件可以在.oh-my-zsh/plugins下面找到。


plugins=(rails3 rails git textmate ruby rvm gem git github brew bundler textmate pow)


重启下终端,然后就可以使用订制好的zsh了。




vim配置

一直用vi,也没仔细研究过,也不会配置,在网上发现 spf13-vim ,安装配置十分方便,于是便想推荐大家使用。


只需在终端敲打

curl https://raw.github.com/spf13/spf13-vim/3.0/bootstrap.sh -L -o - | sh 

等待数分钟,安装全部完成。具体细节不介绍,spf13-vim的网站上有详细介绍。


结束之后还需要.vimrc里加入


set t_Co=256


使用spf13-vim需要vim支持python,mac下的vim本身是不支持python的,如何验证vim支持python。


:python print “Hello, world!”

看到输出结果是Hello,world!就是支持python了。
如果不知道的话,那就要安装一个支持python的vim

sudo port install vim +python +ruby

安装之后,使用vi,如果发现有libiconv的问题,把你env里面的DYLD_LIBRARY_PATH去掉。

全部搞定,在用用你的vi看看,是不是很惊艳?


Add google pretty code support

Jekyll 本身是不支持语法高亮的。而用 Pygments 又要装插件,看上去也挺复杂的。于是去网上搜索“博客语法高亮”,
然后发现了 google code prettify,心想 google 出品,质量必定可靠.具体请看下google code prettify

这里就介绍一下,如何使用的。

  • http://code.google.com/p/google-code-prettify/downloads/list下载最新的代码。
  • 解压出来,得到

  • lang-apollo.js
    lang-clj.js
    lang-css.js
    lang-go.js
    lang-hs.js
    lang-lisp.js
    lang-lua.js
    lang-ml.js
    lang-n.js
    lang-proto.js
    lang-scala.js
    lang-sql.js
    lang-tex.js
    lang-vb.js
    lang-vhdl.js
    lang-wiki.js
    lang-xq.js
    lang-yaml.js
    prettify.css
    prettify.js
    sunburst.css

  • 把这些文件放到你的项目的目录下去。
  • 把css文件和js文件应用到页面上去。

  • <link href=”/js/google-code-prettify/sunburst.css” type=”text/css” rel=”stylesheet”/>
    <script type=”text/javascript” src=”/js/google-code-prettify/prettify.js”></script>

    在body上加一个onload函数


    <body onload=”prettyPrint()” >

  • 然后在要高亮的代码块使用提供的tag,比如:
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <pre class="prettyprint">
    #include <stdio.h>
    /* the n-th fibonacci number.
    */
    unsigned int fib(unsigned int n) {
    unsigned int a = 1, b = 1;
    unsigned int tmp;
    while (--n >= 0) {
    tmp = a;
    a += b;
    b = tmp;
    }
    return a;
    }
    main() {
    printf("%u", fib(10));
    }
    </pre>

    你不需要指定语言环境,因为 prettyprint() 会对此进行猜测. 你也可以使用 prettyprint 这个类通过指定语言的拓展名来指定语言。


  • 你看到的结果就是:
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <stdio.h>
    /* the n-th fibonacci number.
    */
    unsigned int fib(unsigned int n) {
    unsigned int a = 1, b = 1;
    unsigned int tmp;
    while (--n >= 0) {
    tmp = a;
    a += b;
    b = tmp;
    }
    return a;
    }
    main() {
    printf("%u", fib(10));
    }




    看上去不错吧,你也去试试吧!




    |