require某个版本的gem

一般我们require一个gem,都是require最新的版本

irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'activerecord'
=> true
irb(main):003:0> ActiveRecord::VERSION::STRING
=> "2.3.4"

如果需要require一个旧版本的gem该怎么办呢?只需要在require之前指定gem的版本即可

irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> gem 'activerecord', '2.3.2'
=> true
irb(main):003:0> require 'activerecord'
=> true
irb(main):004:0> ActiveRecord::VERSION::STRING
=> "2.3.2"

是不是看上去和rails的用法蛮像的?

Posted in  ruby rubygems


Kungfu Rails Conf

昨天Kungfu Rails会议还是收获很大的

早上匆匆跑去,正好赶上Yehuda Katz开讲Rails 3,介绍了很多在Rails 3即将推出的新功能,很期待年底Rails 3能够Release

接着是赵路介绍持续集成和代码质量,这些东西之前都接触过,对这样的开发过程很有同感

至于我关于plugin/gem的演讲,感觉比上次ruby conf要好些,毕竟实践过的东西比起理论的东西讲起来更顺手

下午張文鈿的Rails Best Practice的演讲,可以说是这次会议最大的收获了,真的都是金玉良言,以后在项目开发时一定要注意

Scott关于git的演讲也很不错,github也是我经常去的网站

Stone介绍自己写的ActiveDirect也不错,不过自己没怎么接触Ext,算是学习了吧

高桥征义的剪报式演讲让人耳目一新,不过通过中文表达有点打折扣

最后两个演讲没有听到,赶去参加同学的婚礼了,以后搜搜有没有ppt看看

Posted in  presentation


contact-list类库依赖包之gdata

gdata是google提供的获取其数据的api,analytics, calender, contacts, webmastertools, youtube等等。

对于contact-list从1.7.0开始,放弃原来通过模拟用户登录并爬取网页数据的做法,改用gdata api,使得获取google联系人列表变得简单了许多,同时使用api也保证联系人的获取不会因为网页的变动而失败。

contact-list使用gdata有一点小问题,那就是gdata没有maven repository,我不得不手动下载gdata的jar包,并手动安装到本地的maven类库中。下面是安装这些jar包的ruby脚本(shell脚本不熟)

[
  ['analytics', 2.0],
  ['appsforyourdomain', 1.0],
  ['base', 1.0],
  ['blogger', 2.0],
  ['books', 1.0],
  ['calendar', 2.0],
  ['client', 1.0],
  ['codesearch', 2.0],
  ['contacts', 3.0],
  ['core', 1.0],
  ['docs', 3.0],
  ['finance', 2.0],
  ['health', 2.0],
  ['maps', 2.0],
  ['media', 1.0],
  ['photos', 2.0],
  ['spreadsheet', 3.0],
  ['webmastertools', 2.0],
  ['youtube', 2.0]
].each do |pair|
  name, version = *pair
  system "mvn install:install-file -DgroupId=com.google.gdata -DartifactId=gdata-#{name} -Dversion=#{version} -Dfile=/home/flyerhzm/downloads/gdata/java/lib/gdata-#{name}-#{version}.jar -Dpackaging=jar -DgeneratePom=true"
  unless ['base', 'core', 'media'].include? name
    system "mvn install:install-file -DgroupId=com.google.gdata -DartifactId=gdata-#{name}-meta -Dversion=#{version} -Dfile=/home/flyerhzm/downloads/gdata/java/lib/gdata-#{name}-meta-#{version}.jar -Dpackaging=jar -DgeneratePom=true"
  end
end

接下来就可以在pom.xml下面指定依赖的gdata类库了

<dependency>
    <groupid>com.google.collections</groupid>
    <artifactid>google-collections</artifactid>
    <version>1.0-rc2</version>
</dependency>
<dependency>
    <groupid>com.google.gdata</groupid>
    <artifactid>gdata-base</artifactid>
    <version>1.0</version>
</dependency>
<dependency>
    <groupid>com.google.gdata</groupid>
    <artifactid>gdata-core</artifactid>
    <version>1.0</version>
</dependency>
<dependency>
    <groupid>com.google.gdata</groupid>
    <artifactid>gdata-core</artifactid>
    <version>1.0</version>
</dependency>
<dependency>
    <groupid>com.google.gdata</groupid>
    <artifactid>gdata-client</artifactid>
    <version>1.0</version>
</dependency>
<dependency>
    <groupid>com.google.gdata</groupid>
    <artifactid>gdata-client-meta</artifactid>
    <version>1.0</version>
</dependency>
<dependency>
    <groupid>com.google.gdata</groupid>
    <artifactid>gdata-contacts</artifactid>
    <version>3.0</version>
</dependency>
<dependency>
    <groupid>com.google.gdata</groupid>
    <artifactid>gdata-contacts-meta</artifactid>
    <version>3.0</version>
</dependency>

最后就是在java代码中调用gdata api来获取google联系人列表了

package com.huangzhimin.contacts.google;

import com.google.gdata.client.Query;
import com.google.gdata.client.contacts.ContactsService;
import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.contacts.ContactFeed;
import com.google.gdata.data.extensions.Email;
import com.google.gdata.util.AuthenticationException;
import com.huangzhimin.contacts.Contact;
import com.huangzhimin.contacts.ContactsImporter;
import com.huangzhimin.contacts.exception.ContactsException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author flyerhzm
 */
public class GoogleImporter implements ContactsImporter {

    // 用户名
    private String email

    // 密码
    private String password

    public GoogleImporter(String email, String password) {
        this.email = email;
        this.password = password;
    }

    public List getContacts() throws ContactsException {
        ContactsService service = new ContactsService("contactlist");
        try {
            service.setUserCredentials(email, password);
        } catch (AuthenticationException e) {
            throw new ContactsException("login failed", e);
        }
        try {
            URL feedUrl = new URL("http://www.google.com/m8/feeds/contacts/" + email + "/full");
            Query query = new Query(feedUrl);
            query.setMaxResults(Integer.MAX_VALUE);
            ContactFeed resultFeed = service.query(query, ContactFeed.class);
            List contacts = new ArrayList();
            for (ContactEntry entry : resultFeed.getEntries()) {
                for (Email email : entry.getEmailAddresses()) {
                    String address = email.getAddress();
                    String name = null;
                    if (entry.hasName()) {
                        name = entry.getName().getFullName().getValue();
                    } else {
                        name = getUsername(address);
                    }
                    contacts.add(new Contact(name, address));
                }
            }
            return contacts;
        } catch (Exception e) {
            throw new ContactsException("gmail protocol has changed", e);
        }
    }

    private String getUsername(String email) {
        return email.split("@")[0];
    }

}

其中需要注意的是,默认只能获取25个联系人信息,所以需要设置query.setMaxResults(int)为一个非常大的数值,来获取所有的联系人列表。

Posted in  contact-list java


add gem rake for rails

使用过rails插件的一定知道,只要在插件的tasks目录下面定义rake文件,rails就会自动加入其中定义的task。但是gem就不能这样用了,即使rake gems:unpack也没用。

解决的方法是将定义在gem中的task require到rails目录下。比如我在css_sprite gem的lib/css_sprite.rb中定义

unless Rake::Task.task_defined? "css_sprite:build"
  load File.join(File.dirname(__FILE__), '..', 'tasks', 'css_sprite_tasks.rake')
end

上面3行的意思是如果当前的tasks中没有css_sprite:build的话,就load gem中的tasks/css_sprite_tasks.rake。

然后在rails app中增加lib/tasks/css_sprite.rake

require 'css_sprite'

这样你就可以使用rake css_sprite:build task了。

更懒的方法是直接把require css_sprite'加到rails目录下的Rakefile。

Posted in  rails rubygems


add executable to ruby gem

刚刚给rfetion增加了executable,使得用户可以直接在shell下面发送短信。

首先,在gem目录下增加bin目录,并增加executable文件

require 'rfetion'
require 'rfetion/command'

接着新增command.rb文件来处理用户输入,用的是ruby类库自带的optparse

require 'optparse'

options = {}

OptionParser.new do |opts|
  # Set a banner, displayed at the top of the help screen.
  opts.banner = "Usage: rfetion [options]"

  opts.on('-m', '--mobile MOBILE', 'Fetion mobile number') do |mobile|
    options[:mobile_no] = mobile
  end

  opts.on('-p', '--password PASSWORD', 'Fetion password') do |f|
    options[:password] = f
  end

  opts.on('-c', '--content CONTENT', 'Fetion message content') do |f|
    options[:content] = f
  end

  options[:friends_mobile] = []
  opts.on('-f', '--friends MOBILE1,MOBILE2', Array, '(optional) Fetion friends mobile number, if no friends mobile number, send message to yourself') do |f|
    options[:friends_mobile] = f
  end

  opts.parse!
end

optparse用起来真的很方便,短短几行就能够很好地处理用户输入。

然后直接在gemspec增加

gemspec.executables  'rfetion'

最后就是升级gem version,发布到github上,再gem install flyerhzm-rfetion

这样在shell下面就可以直接发送短信了,看看命令行的帮助

rfetion -h

Usage: rfetion [options]
    -m, --mobile MOBILE              Fetion mobile number
    -p, --password PASSWORD          Fetion password
    -c, --content CONTENT            Fetion message content
    -f, --friends MOBILE1,MOBILE2    (optional) Fetion friends mobile number, if no friends mobile number, send message to yourself

Posted in  rubygems ruby


Fork me on GitHub