Posts Tagged 坚持100天学习Ruby

koding一个在线开发环境

Koding一个挺有意思的站点,它提供了在线的开发环境。每个人都可以使用免费的虚拟主机,采用Ubuntu,Python, PHP, java, Ruby各种开发环境,还有一个基于web的集成开发环境,同时采用社区模式,直接交流开发问题。

“Say goodbye to localhost.”你基本上可以直接在Koding做web开发,并马上能在线访问。当然唯一的限制是在你退出登录20分钟后,虚拟机会被关闭。因为它目标是提供开发环境,而不是做生产应用的托管主机。详细可以参见介绍

不过个人认为还是挺不过的一个产品,毕竟你有了一个真实的可以在互联网上访问的开发环境,免费,效率也不错。有兴趣的可以点击我的推荐注册。

, , ,

Leave a comment

学习一下git(四)

之前有关git的学习都是基于本地,除了版本的管理和控制外,和别人的协作一般还是需要远程服务器。你可以自己架设服务器,也可以用git托管服务,比如github,其他的可以参见git官方wiki上的托管服务列表

可以从git clone 开始,


$ git clone https://github.com/xbin999/gittest.git

git clone除了建立自己的本地分支master和远程分支origin/master外,并且会将他们都指向orgin上的master分支,这自动就是一个跟踪分支(从远程分支checkout出来)。


$ git remote -v
origin  https://github.com/xbin999/gittest.git (fetch)
origin  https://github.com/xbin999/gittest.git (push)
  • git remote add 可以添加远程仓库地址,指定别名。
  • git remote show 显示远程仓库信息。
  • git fetch 从远程仓库抓取信息。注意fetch出来只是更新remote索引。要在本地编辑需要merge到本地分支中或者checkout出一个新的分支。
  • git push 推送数据到远程仓库。

而和远程服务器最简单的协作方式之一:先在自己的特性分支中工作一段时间,完成后合并到自己的 master 分支;然后下载合并 origin/master 上的更新(如果有的话),再推回远程服务器。一般的协作流程如图所示:

对于自己拥有的项目,可以用git push推送。但如果要给公开项目作贡献,往往你并没有直接更新主仓库分支的权限,需要把工作成果交给项目维护人。

  • 一种方式使用 git 托管服务商提供的仓库复制功能,一般称作 fork,比如GitHub 都支持这样的操作,而且许多项目管理员都希望大家使用这样的方式。
  • 另一种方式是通过电子邮件寄送文件补丁。

, , ,

Leave a comment

学习一下git(三)

任何的版本管理控制系统都会有分支的管理,不过git的分支管理要简单地多,确实比较牛。这源于前面所说的设计,版本间的差异保存的不是文件差异或者变化量,而是一系列文件的快照。

看一个例子,git仓库中三个文件,git add加入暂存区域后,会把当前版本的文件快照保存到git仓库中,并将校验和(也就是SHA-1哈希串)加入暂存区域;git commit提交时,会计算每个目录的校验和,作为树(tree)对象保存,结果如图(这几个图真是太棒了,想不夸都不行):

每一次修改后,再提交,就有不同的commit对象指向不同的快照。

而对于git的分支,本质就是个指向commit对象的指针,默认是master分支,每次提交后移动master即可。

使用git branch testing创建一个新的分支testing,这时新分支也是一个指针,指向同一快照。至于你工作在哪个分支,则有HEAD的特别指针来标识。

可以使用git checkout testing来切换到新建分支。

有了分支后,你可以在不同的分支上分别进行版本的演进。而gi很t有意思的是可以很在同一个目录中,不同分支间进行随意地切换,切换到新的分支后,目录中的文件就都会自动更新到新版本,不象其他版本工具,你可能需要多个目录分别保存不同的版本。git的版本切换开销非常之低,可以几毫秒完成分支的创建和切换。所以Git鼓励开发者频繁使用分支。

在分支的使用中,除了branch,checkout创建和切换分支外,另外需要的就是分支代码的合并。

合并分支有两种方法:

  • 一是采用merge,如果遇到冲突,需要手工修改冲突的文件,再运行git add把它标记为已解决状态。

  • 二是采用rebase,参见示例,rebase是把分支experiment的C3版本在master分支上C4版本上重新打一遍,rebase比merge看起来主干线会更清晰,本质是把合并的工作责任交给主干线的提交了。

需要遵守一条准则:“一旦分支中的提交对象发布到公共仓库,就不要对该分支进行rebase操作。”

看来rebase还是少用为妙。以上的分支操作并不设计远程,下次整理一下有关远程仓库的操作和分支的管理。

, , ,

Leave a comment

学习一下git(二)

两种途径开始git,一是init初始化新仓库,再添加文件;二是从现有仓库clone。

  • git init
  • git clone

为什么是clone,而不是checkout,就是因为git和其他VCS不同的是git收取项目历史所有的数据,而不仅仅是某一个版本。

在有了git仓库后,常用的操作就是add, commit, log, status, diff, rm, mv,而这些操作还是需要理解三个区域,以及在区域间文件的状态变化周期。

文件的状态变化周期

  • git diff 比较工作目录中当前文件和暂存区域快照之间的差异。
  • git diff –cached 比较暂存区域和上次提交的快照之间的差异。
  • git diff –staged 同上。git diff采用合并格式diff的变体,带上下文,有关diff的格式详细参考阮一峰的读懂diff

diff --git a/yun.txt b/yun.txt
index de629e5..67ca091 100755
--- a/yun.txt
+++ b/yun.txt
@@ -13,3 +13,4 @@ pc-jfjwapp11 10.70.217.70
pc-jfjwapp12 10.70.217.71
$ test
second line
+add 8-21
  1. 第一行,a版本是变动前的,b版本是变动后的。
  2. 第二行,de629e5是a版本的哈希值,67ca091是b版本的哈希值,755表示文件权限。
  3. 第三、四行表示比较的两个文件,—是a版本,+++是b版本。
  4. 第五行@@和@@之间是两个文件的变化,-13,3 是a版本的第13行开始,一共3行,+13,4是表示b版本的第13行开始,一共4行。
  5. 之后是变化的文件内容,带有+号的是表示b版本内容,带有-号的是表示a版本的内容。
  • git commit
  • git commit -a 跳过使用暂存区域,也就是不要git add了。
  • git rm 移除文件
  • git rm –cached 从暂存区域移除,当前工作目录保留,比如编译中间文件。
  • git log -p -2 其中-p选项展开显示每次提交的内容差异,-2则仅显示最近的两次更新。
  • gitk 是随git一同发布,基于Tcl/Tk的,git log的图形化工具。

如果和常规的版本控制管理系统相比较,多人协同开发,还是需要一个代码托管的地方。github 就提供了免费软件项目git仓库托管服务,国内也有gitcafe。所以完整的git使用还涉及和托管服务之间的交互,和远程仓库的协作下次继续。

, , ,

2 Comments

学习一下git(一)

看ruby和写代码的时候,很难离得开git )和github,所以让自己也系统地看一下。

git )是一个分布式的版本控制和源代码管理系统,最开始是由Linus Torvalds为linux内核开发而设计实现的。

传统的版本控制管理,象CVS,SVN一般都会有一个中心服务器,本地check out代码,然后修改,提交合并代码,但这样的问题是依赖于中心服务器。而对于分布式版本控制系统则在本地都有完整的代码仓库,任何一台服务器发生故障,都可以使用镜像的本地仓库恢复。

git很大的一个特点是对于文件保存完整的数据,而非文件的增量差异,在不同版本时对于没有变化的文件不再保存,而仅做一个链接。

Git保存更新时的文件快照

由于其分布式的特点,每台机器上都是一个仓库,所以基本上操作都在本地,包括往库里提交修改、版本差异比较、查看更新日志等等。

对于git来说,任何一个文件流转过程中都存在三种状态:

  • 已提交(committed),表明文件已经提交到本地仓库中。
  • 已修改(modified),表明文件已经修改,但未提交。
  • 已暂存(staged),表明已修改的文件放在下次提交时要保存的清单中。

所以对于本地工作时,git有三个工作区域:git的工作目录,git本地仓库和暂存区域,一般在工作目录中会有一个.git目录,其中就保存了元数据和对象数据库,而暂存区域文件(index索引文件)也放在.git目录中。对于理解暂存区的作用,worldhello上有一篇很好的文章和一个图,引用一下:
git work area

如果我修改一个文件,增加一行”in stage”,然后使用git add 保存到暂存区,之后再增加一行”in work directory”,git status查看状态:


➜  /Users/yangbin/tmp/gittest git:(master) >git status -s
➜  /Users/yangbin/tmp/gittest git:(master) >git add yun.txt
➜  /Users/yangbin/tmp/gittest git:(master) ✗ >echo "in stage" >> yun.txt
➜  /Users/yangbin/tmp/gittest git:(master) ✗ >git status -s                        
M  yun.txt
➜  /Users/yangbin/tmp/gittest git:(master) ✗ >echo "in work directory" >> yun.txt
➜  /Users/yangbin/tmp/gittest git:(master) ✗ >git status -s
MM yun.txt

此时工作区、暂存区和本地仓库yun.txt文件的内容各不相同,可以使用:

  • git commit yun.txt 提交暂存区的内容到本地仓库,也就是增加“in stage”;
  • git rm — cached yun.txt 直接从暂存区删除内容,工作区不变;
  • git checkout . yun.txt 使用暂存区文件更新工作区文件;
  • git chekcout HEAD yun.txt 使用本地仓库文件更新工作区和暂存区文件。

当然我们要使用git一般都是从git init 和git clone开始的,这个下次再说。

, , ,

1 Comment

brew,gem,rvm and bundler

brew,gem,rvm 和 bundler都是软件包的管理工具,搞过来搞过去,有点晕,需要理理。

brew是OS X上提供软件包的管理。Homebrew将软件包安装到单独的目录,然后符号链接到/usr/local 中,完全基于git和ruby。使用gem来安装你的gems,用brew来搞定他们的依赖包。brew的安装:


ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"

RubyGems是一个包管理框架,提供了ruby社区gem的托管服务,用于方便地下载、安装和使用ruby软件包。ruby软件包被称为”gem”,包含了ruby应用或库。要升级到最新的RubyGems,运行:


$ gem update --system

如果没有安装RubyGems,则需要先下载安装包,然后解压开后运行ruby setup.rb。

gem常用的命令有search, install, list, uninstall。如果要看安装的gem文档,一是可以用ri,二是可以gem server启动一个web服务。详细的帮助参见RubyGems Guides

brew和gem不同,brew用于操作系统层面上软件包的安装,而gem只是管理ruby软件。

RVM(Ruby enVironment (Version) Manager)是一个命令行工具,提供在多个ruby环境中方便的安装、管理和工作,包括解释器和gem集合。rvm自己的安装通过curl命令执行,如:curl -L https://get.rvm.io | bash

RVM有一个非常灵活的gem管理系统,称为Gem Sets。RVM的’gemsets’管理横跨多个Ruby版本的gems包。

采用rvm安装ruby:


$ rvm list known
$ rvm install 1.9.3
$ rvm use 1.9.3

Bundler为ruby维持一个一致性的环境,跟踪应用代码和所需要的ruby gems,这样一个应用可以有所需要的精确的gems(和版本)。

$ gem install bundler

安装的顺序,先安装rvm,之后选择安装一个ruby版本,就可以提供一个完整的ruby运行环境。之后可以安装brew(brew虽然是管理os的,但基于ruby)和gem,分别管理操作系统和ruby的软件包。之后ruby重新编译的时候所依赖的包可以使用brew安装。有了gem之后,bundler只不过就是一个gem,直接通过gem install 即可。

, ,

Leave a comment

列出数据量大的文件或目录

一不小心发现机器的磁盘空间差不多用满了,空间紧张啊,虽然可以用du查看各个目录占用的情况,再进行清理,但往往需要一层层去查找占用空间最大的目录,比较累人。所以用ruby练练手,写了个递归便利目录中大的文件和目录,可以设定参数如下:


Usage: mydu [options] directory
Specific options:
    -d, --depth [depth]              Search directories depth
        --dsize [dsize Mbyte]        Directory size limit to display
        --fsize [fsize Mbyte]        File size limit to display
    -h, --help                       Display this message

代码也比较简单,有几点注意的:

  • %x(du -sm \’#{dir}\’/*) 执行os命令,注意dir用引号引起,防止特殊字符,而/在引号外面,否则特殊字符也会使得目录名无效。
  • 把目录和大小丢进hash,直接sort.reverse即可倒序排。
  • line.split(‘ ‘, 2) 也是防止带空格的目录名,保证后面的都作为第二个元素,得到完整的目录名。

详细代码如下:


require 'optparse'

def du(dir, all, depth, dsize, fsize)
    return if depth = dsize
            (all-depth).times {print "  "}
            puts "[d], #{k}, #{v}"
            du("#{v}", all, depth - 1, dsize, fsize) 
        end
        if File.file?("#{v}") && k >= fsize
            (all-depth).times {print "  "}
            puts "[f], #{k}, #{v}"
        end
        size += k
    }
    (all-depth-1).times {print "=="}
    puts "#{dir} size is #{size}M."
end

options = {}
optparse = OptionParser.new do|opts|
    opts.banner = "Usage: mydu [options] directory"
    opts.separator "Specific options:"
    options[:depth] = 2
    opts.on( '-d', '--depth [depth]', Integer, 'Search directories depth' ) do|depth|
        options[:depth] = depth
    end
    options[:dsize] = 1024
    opts.on( '--dsize [dsize Mbyte]', Integer, 'Directory size limit to display' ) do|dsize|
        options[:dsize] = dsize
    end
    options[:fsize] = 200
    opts.on( '--fsize [fsize Mbyte]', Integer, 'File size limit to display' ) do|fsize|
        options[:fsize] = fsize
    end
    opts.on( '-h', '--help', 'Display this message' ) do
        puts opts
        exit
    end
end

optparse.parse!(ARGV)
du(ARGV[0], options[:depth], options[:depth], options[:dsize], options[:fsize])

, ,

1 Comment

什么是RubyGem

RubyGems包管理系统(也称为Gems)已经成为Ruby代码包发布和管理的标准,在Ruby 1.9中已经打包在Ruby中提供。

每个gem有名称、版本和平台。比如rake gem版本是0.8.7,平台是ruby,可以在Ruby的任意平台上运行,其他平台还包括java(比如nokogiri)和mswin32(比如sqlite-ruby)。

Gems的结构,一般包括三部分:

  • 代码,包括测试和支持工具。
  • 文档
  • gemspec

每个gem有同样的标准代码组织结构:


% tree freewill
freewill/
├── bin/
│   └── freewill
├── lib/
│   └── freewill.rb
├── test/
│   └── test_freewill.rb
├── README
├── Rakefile
└── freewill.gemspec
  • lib包含gem的代码。
  • test或spec包含测试,取决于采用测试框架。
  • 一个gem通常有一个Rakefile,用于rake程序自动化测试、生成代码和执行其他一些任务。
  • 一般在bin目录下会有一个执行文件,gem安装后,该bin目录通常会在PATH路径中。
  • 文档一般包含在README和代码中。当安装gem时,文档会自动生成,大多数gems包括RDoc文档,有的也用YARD
  • 最后一部分是gemspec,包含有关这个gem的规格信息。包括文件、测试、平台、版本号和其他的作者邮件和姓名等等。

RubyGems修改了Ruby的装载路径,控制你的Ruby代码能被require找到。

一旦使用require请求一个gem,RubyGems
自动把lib目录加入到$LOAD_PATH中,有些gems也会增加其他目录,比如bin。这些是可选的,你可以把一个gem的多个目录加入到装载路径中。

Gemspec提供基本的信息,让你知道gem包含的内容,一个简单例子:


% cat freewill.gemspec
Gem::Specification.new do |s|
  s.name        = 'freewill'
  s.version     = '1.0.0'
  s.date        = '2010-04-27'
  s.summary     = "Freewill!"
  s.description = "I will choose Freewill!"
  s.authors     = ["Nick Quaranto"]
  s.email       = 'nick@quaran.to'
  s.homepage    = 'http://example.com'
  s.files       = ["lib/freewill.rb"]
end

来源What is a gem?

, , ,

Leave a comment

使用optparse改写post

之前写过”编写markdown文档直接发布到wordpress上“,当时还是自己解析ARGV,看了optparse后,把代码改一改。


   # Define the options, and what they do
   opts.on( '-s', '--title [BlogTitle]', 'Blog title' ) do|title|
     options[:title] = title
   end

   options[:tags] = nil
   opts.on( '-t', '--tags tag1,tag2,tag3', Array, 'Tags blog' ) do|tags|
     options[:tags] = tags
   end

   options[:categories] = nil
   opts.on( '-c', '--categories cat1,cat2,cat3', Array, 'Blog categories' ) do|categories|
     options[:categories] = categories
   end

第一个参数可选,后面的可以指定列表,挺好。修改后的代码

, ,

Leave a comment

ruby OptionParser

原先在看的Programming Ruby版本有点低,其中的代码有些在1.9中也不适合,比如说Net::HTTP.get,找了本Programming Ruby 1.9的,目录结构也有所不同了,所以补看部分。不过最近事情多,效率变低,每天都只是看一会,也缺少总结了。

今天记录一下看”Organizing Your Source”中的一个例子用的optparse,optparse是Ruby的一个库,不是gem。OptionParser类用于对命令行选项进行解析,有一些特色:

  • 参数规范说明和处理代码写在一起,便于关联。
  • 可以自动生成选项的汇总,不需要独立维护选项信息。
  • 可选和必选参数指定很简单优雅。
  • 输入参数能自动转换成所需类。
  • 输入参数能限制数据集。

有个简单例子:


require 'optparse'
options = {}
optparse = OptionParser.new do |opts|
  opts.banner = "Usage: example.rb [options]"
  
  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
    options[:verbose] = v
  end
end
optparse.parse!
p options
p ARGV

OptionParser.parse! 用于从ARGV中抽取选项,被抽取的选项会从ARGV中删除。

在上例中,options是一个空的hash,当命令行中遇到-v或–verbose,则会设置options[:verbose]为true。

optparse是一个OptionParser对象实例,传递了一个块,这个块构造了内部的数据结构,然后调用parse!。

有两篇不错的文章:

关于选项是可选还是必选,只需要看在选项后面的内容是否加上[]即可,比如下面的-r必选,-i可选。


      # Mandatory argument.
      opts.on("-r", "--require LIBRARY",
              "Require the LIBRARY before executing your script") do |lib|
        options.library 

对于必选的选项,如果在输入的命令行未指定选项参数值,则会报错:


optparsetest.rb:44:in `': missing argument: -r (OptionParser::MissingArgument)

代码中可以捕获OptionParser::MissingArgument。stack overflow有个问题How do you specify a required switch (not argument) with Ruby OptionParser?专门描述了对于强制选项的处理方法。

, ,

2 Comments