ruby

    Use paperclip without activerecord

    31 Oct 2013

    Recently I built an image upload api which didn't use activerecord, but I don't want to handle resizing image thumbnails by myself, so I decided to reuse paperclip.

    Paperclip is an easy file attachment management for ActiveRecord, but we used activemodel without activerecord, I found a gist which gave me a simple solution, but it was not enough. We continued the hacking work.

    1. defined the attachment path and url. Paperclip used AR id ...

    Read More

    Tags 


    mongoid 3.0.x not set relation properly

    08 Sep 2013

    I was trying to fix bullet test failure with mongoid 3.0.23, the failed test is to test the 1-1 relationship as follows

    it "should detect non preload association" do
      Mongoid::Company.all.each do |company|
        company.address.name
      end
      ......
    end

    After reading the logs, it generated 2 unexpected query

    MOPED: 127.0.0.1:27017 QUERY        database=bullet collection=mongoid_companies selector={} flags=[:slave_ok] limit=0 skip=0 batch_size=nil fields=nil (196.5840ms)
    MOPED: 127.0.0.1:27017 QUERY...
    Read More

    Tags 


    My presentation at reddotrubyconf 2013

    07 Jun 2013

    This is my presentation on reddotrubyconf 2013 with notes, building asynchronous apis.

    3. Several years ago when I started learning rails, many people said rails was not fast, but it can significantly speed up development, the famous words are "Hardware is cheap, Programmers are expensive".

    4. It is tru...

    Read More

    Tags 


    another redis automatic failover solution for ruby

    13 Jan 2013

    Redis gets more and more popular as a backend storage, so the redis failover solution becomes important before you use redis as a critical resource.

    Currently the most popular automatic master/slave failover solution for ruby is redis_failover, it's based on ZooKeeper, if you already have ZooKeeper in your infrastructure, it's great.

    But I noticed that redis already has a built-in automatic failover solution, called Redis Sentinel. In case you didn't heard of it, please read the official document, it's simple and no other external dependency. I searched on github...

    Read More

    Tags 


    How I find out a memory leak in grape

    16 Dec 2012

    I'm helping my customer build a high performance api service these weeks, we are close to release, but when I did load test this Wednesday, I found the memory kept growing when I sent traffic and never went down, it was obviously a memory leak.

    Lucky is I can reproduce the memory leak on my local machine, so I can detect it easily. Our api service is simple, only contains model layer (AR and redis) and api layer (based on grape). At first, I disabled model layer, but memory lea...

    Read More

    Tags 


    avoid using rubyzip

    02 Oct 2012

    More precisely I want to say allocating as less objects as you can, rubyzip is just an example.

    We have a background job compressing webui assets, uploading to S3, so mobile sdk can download assets to update webui dynamically.

    After iphone5 and ios6 came to the market, we received much more webui req...

    Read More

    Tags 


    redis mget/mset vs get/set

    05 Apr 2012

    Our application uses redis a lot to perform large numbers of data reads/writes. But we didn't use it well enough, e.g. we call redis get and set in loop, just like touching mysql and memcache many times, it takes a long time to send multiple redis commands, if we can reduce the commands, it saves on round trip time.

    The following script is used to bencharmark different commands count.

    require 'redis'
    require 'benchmark'
    
    redis = Redis.new
    Benchmark.bm(50) do |bm|
      bm.report "redis set" do
      ...
    Read More

    Tags 


    rubykaigi presentation

    17 Jul 2011

    My presentation in RubyKaigin 2011 today.

    and the video is here: http://www.ustream.tv/recorded/16051491

    Read More

    Tags 


    Upgrade Mongoid - Multiple databases

    22 Mar 2011

    My recent post Use different mongodb instances in mongoid tells you how to use multiple databases, it looks good, but mongoid began to support multiple databases itself from mongoid.2.0.0.rc.1, much better than my hack.

    It's really easy to use, first, you should define multiple databases in mongoid.yml like

    development:
      <<: *defaults
      host: localhost
      database: main_mongo_instance
      databases:
        other_mongo_instance_name:
          database: other_mongo_instance
          host: localhost

    As you seen, besides the common database param, I have defined a new param databases, you should define the mongo instance name with database and host name, and of course, you can define as many mongo instances as you ne...

    Read More

    Tags 


    Upgrade Mongoid - update_attribute

    21 Mar 2011

    Before mongoid 2.0.0.rc.6, there is no update_attribute method for Mongoid::Document, it makes me unhappy. As in ActiveRecord world, I always use update_attribute to change one attribute and use update_attributes to change two or more attributes.

    It's a good news that mongoid introduces the update_attribute method from 2.0.0.rc.6, now I can follow my practice in mongoid.

    post.update_attribute(:title => "New Post")
    
    post.update_attributes(:title => "New Post", :body => "New Body")
    Read More

    Tags 


    Upgrade Mongoid - Many to many association

    08 Mar 2011

    Before mongoid 2.0.0.rc1, there is no default support for many to many association. So we use join document (aka join table in relational database) to implement the many to many association.

    For example, we have two documents users and accounts, one user has many accounts and one account contains many users, to establish the many to many relationship between users and accounts, we create a new document named user_accounts, the document looks like

    {'_id': '4d76d3a70bdb822d08000001', 'user_id': BSON...
    Read More

    Tags 


    Upgrade Mongoid - Hash arguments for group

    01 Mar 2011

    You will receive a warning for the group method call after upgrading mongoid.

    Collection#group no longer take a list of paramters. This usage is deprecated.

    exactly this is because mongo gem changes the group method definition.

    Before

    key = ["ad_id"]
    conditions = { 'ad_id' => { '$in' => ad_ids } }
    initial = { "impressions" => 0.0, "clicks" => 0.0 }
    reduce = "a reduce javascript function"
    
    AdStat.collection.group(key, conditions, initial, reduce).each do |e|
      ......
    end

    After

    key = ["ad_i...
    Read More

    Tags 


    Upgrade Mongoid - Default Type for Field

    28 Jan 2011

    If you have watched the episode about mongoid from railscast, ryanb removed the default type String for field, like

    class Article
      field :name, :type => String
      field :content, :type => String
    end

    can be written as

    class Article
      field :name
      field :content
    end

    but it is not valid from mongoid.2.0.0.rc.1 again, the default type of field is changed from String to Object, that means we should explicitly set the type for each field.

    Read More

    Tags 


    Upgrade Mongoid - Write Tests First

    27 Jan 2011

    Mongoid is one of the popular Object Document Mappings between Ruby and Mongo, and it is still evolving. We began to use mongoid 2.0.0.beta.20 several weeks ago, the author of mongoid @durran said he wanted to release the 2.0.0 last week (As you know 2.0.0 is still not released yet, but he really did a lot of awesome work), so we tried the version 2.0.0.rc.6 to prepare upgrading to final 2.0.0.

    I'm working on upgrading mongoid from 2.0.0.beta.20 t...

    Read More

    Tags 


    Construct Nested Hash in Ruby

    18 Jan 2011

    I just received a post request on rails-bestpractices.com from hlxwell, he recommend "Nested hash simple initialization."

    Change From

    cache_data = {}
    cache_data['a'] ||= {}
    cache_data['a']['b'] ||= {}
    cache_data['a']['b']['c'] ||= {}
    cache_data['a']['b']['c']['d'] ||= {}
    cache_data['a']['b']['c']['d'] = something...

    To

    cache_data = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2| h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } }
    cache_data['a']['b']['c']['d'] = someth...
    Read More

    Tags 


    使用RubyParser检查Ruby代码的variable scope

    26 Jun 2010

    今天参加rubyconfchina,再次聆听ihower的演讲,再次收益匪浅。

    中间在听到Variable Scope突然想到可以使用RubyParser来检查,于是写了几行代码测试,果然是可行的。

    ihower提到在ruby代码中只有在module,class和def才会创建Varible Scope,比如:

    module MyDemo
      var = 1
      class Demo
        var = 2
        def foo
          var = 3
        end
      end
    end

    其中三个var都在不同的scope。这个在RubyParser的解析结果里面有体现出来。比如,ihower提到def会创建一个scope而define_method不会。我们可以用下面的代码来做个实验

    text=-EOF
    class Class
      def define_more_methods
        ["aaa", "bbb", "ccc"].each do |name|
          define_method(name) do
            puts name.upcase
          ...
    Read More

    Tags 


    Ruby1.9的中文问题

    15 May 2010

    今天在ruby 1.9.1的环境下试了一下1.8.7下面写的一段代码,结果报错:syntax error, unexpected $end, expecting '}',查看了一下代码,如下

    STATUS = {
      "400" => "在线",
      "300" => "离开",
      "600" => "繁忙",
      "0" => "脱机"
    }

    语法完全没有问题,判断是中文导致的问题,奇怪的是在1.8.7下面运行正常。google了一下,原来只要在文件开头加上coding就可以了

    #coding: utf-8
    Read More

    Tags 


    为resque写扩展

    13 May 2010

    resque是基于redis的ruby类库,用于创建后台任务,把这些后台任务放在多个队列中去,之后在处理它们。github就是使用resque来处理它们的后台任务的。

    对于需要长时间处理的任务,比如发送email,发tweet,图片resize等等,都是resque的用武之地。默认resque就是将任务加到redis的队列中去,然后定时取出来去处理,实际项目中我们往往需要对其增加额外的扩展,比如你需要增加日志功能,增加处理次数的限制,这个时候就可以给resque写一个plugin,就像rails的plugin一样。

    resque定义了非常良好的HOOK,使得为其写扩展变得更加容易。

    resque采取的是每隔n秒从队列中获取一个任务,然后fork一个子进程来执行这个任务。resque定义了before_fork, after_fork, before_perform, after_perform, around_perform, on_failure几个hook,执行顺序如下

    1. before_fork

    2. fork

    3. after_fork

    4. before_perform

    5. around_p...

    Read More

    Tags 


    使用princely生成pdf

    24 Mar 2010

    Prince是一个将html和xml转换为pdf的程序,最突出的特点是prince能够根据css来格式化转换之后的pdf,这实在是太适合web程序员了。princely是一个基于prince的rails插件,使用起来也非常方便。

    首先,下载prince并按照文档进行安装。

    其次,安装princely

    sudo gem install princely

    接着就是在rails项目中生成pdf并供用户下载。定义一个名字叫download的action

    def download
      # any logic
    
      respond_to do |format|
        format.html
        format.pdf do
          render :pdf => "pdf_file_name",
                 :stylesheets => "pdf_css"
        end
      end
    end

    然后就是定义download.pdf.erb文件,它就和平时定义html.erb是一样的,样式由pdf_css.css决定。

    这样,当用户点击一个链接进入这个download action,服务器就会在后台生成pdf,并发送response给用户,用...

    Read More

    Tags 


    webrick源码分析——http请求

    23 Feb 2010

    http服务器的主要工作就是解析http请求,然后返回http应答。http请求从socket读入,就是一段特定格式的字符串,下面是访问huangzhimn.com首页的http请求

    GET ...
    Read More

    Tags 


    webrick源码分析──路由

    25 Jan 2010

    webrick的路由是由WEBrick::HTTPServer::MountTable定义的

    MountTable由@tab和@scanner组成,@tab是一个由script_name到Servlet的Hash,@scanner一个可以匹配所有script_name的正则表达式。其定义如下:

    class MountTable
      def initialize
        @tab = Hash.new
        compile
      end
    
      def [](dir)
        dir = normalize(dir)
        @tab[dir]
      end
    
      def []=(dir, val)
        dir = normalize(dir)
        @tab[dir] = val
        compile
        val
      end
    
      def delete(dir)
        dir = normalize(dir)
        res = @tab.delete(dir)
        compile
        res
      end
    
      def scan(path)
        @sc...
    Read More

    Tags 


    webrick源码分析──主要流程

    10 Jan 2010

    webrick作为ruby自带的一个http server,很适合拿来作为学习之用。首先来看看最简单的使用webrick的示例吧

    require 'webrick'
    
    server = WEBrick::HTTPServer.new({:Port => 3000, :DocumentRoot => '/home/flyerhzm/public_html'})
    
    ['INT', 'TERM'].each { |signal|
       trap(signal) { server.shutdown }
    }
    
    server.start

    这段代码主要是定义了http服务器监听3000端口,根目录在/home/flyerhzm/public_html下,在接收INT或TERM信号时,关闭服务器,然后启动服务器。

    我们分两部分来看,首先看看服务器初始化时做了些什么

    class GenericServer
      attr_reader :status, :config, :logger, :tokens, :listeners
    
      def initialize(config={}, defa...
    Read More

    Tags 


    capistrano读取releases目录的错误

    04 Jan 2010

    新年刚开始工作就遇到capistrano读取releases目录的错误,deploy之后总是把最新的release目录删除,看来是判断哪个release目录是最新的时候出错了。

    看了下2.5.11源代码,capistrano是这样定义releases目录的

    _cset(:releases)          { capture("ls -x #{releases_path}").split.reverse }

    其中ls -x的结果是

    20091224074632  20091228080936  20091228082551  20100104023017  20100104025008

    也就是说releases的结果就是

    ['20100104025008', '20100104023017', '20091228082551', '20091228080936', '20091224074632']

    再看看删除release部分的代码

    directories = (releases - releases.last(count)).map { |release|
      ...
    Read More

    Tags 


    Fiber in Ruby 1.9

    28 Dec 2009

    Ruby 1.9新推出了Fiber这个新的概念,有人说它是轻量级的Thread,其实不然。它是一段代码块,可以停止、继续,可以有返回值、写入值,有多个Fiber时,它们的执行顺序是固定。它和Thread相似的是,它的执行不是线性的,它可以在中途停止,将控制权交给主程序或者是其它的Fiber,但是中控制权交接的过程是由你来控制的,而不是线程调度程序。所以有时候Fiber可以完成之前只能用Thread才能完成的任务(比如:Producer-Consumer)。

    先来看看一个例子吧:

    require 'fiber'
    
    fiber = Fiber.new do
      (1..3).each do |i|
        Fiber.yield(i)
      end
    end
    
    while fiber.alive?
      puts fiber.resume
    end

    运行结果是

    1
    2
    3
    1..3

    首先,Fiber.new定义了一个Fiber,但是并不会执行,直到调用这个Fiber的resume方法,这个Fiber才会执行,并且当执行到Fiber.yield时停止,并且把yield的参数返回给主程序,同时将控制权将给主程序。然后主程序继续执行,调用这个Fiber的resume方法,这个Fi...

    Read More

    Tags 


    ruby gserver源码阅读

    21 Dec 2009

    gserver作为通用服务器的实现,最关键的就是start方法

    def start(maxConnections = -1)
      raise "running" if !stopped?
      @shutdown = false
      @maxConnections = maxConnections if maxConnections > 0
      @@servicesMutex.synchronize  {
        if GServer.in_service?(@port,@host)
          raise "Port already in use: #{host}:#{@port}!"
        end
        @tcpServer = TCPServer.new(@host,@port)
        @port = @tcpServer.addr[1]
        @@services[@host] = {} unless @@services.has_key?(@host)
        @@services[@host][@port] = self;
      }
      @tc...
    Read More

    Tags 


    ruby通用服务器gserver

    17 Dec 2009

    之前随手翻了几页Programming Ruby 1.9,看到了gserver,查看ruby-doc,原来gserver是一个通用服务器的实现,提供了线程池管理,简单的日志和多服务器管理。

    先看看怎么使用吧

    require 'gserver'
    
    class TimeServer < GServer
      def initialize(port=10001, *args)
        super(port, *args)
      end
    
      def serve(io)
        io.puts(Time.now.to_i)
      end
    end
    
    server = TimeServer.new
    server.audit = true
    
    ['INT', 'TERM'].each { |signal|
      trap(signal) { server.stop }
    }
    server.start.join

    上面这段代码就是一个简单的tcp服务器,返回系统当前时间与1970年之间的秒数差。

    其中3-11行是定义服务器,继承GServer,必须实现serve方法,来实现服务器的行为。

    14行启动服务器的...

    Read More

    Tags 


    oauth for twitter

    02 Dec 2009

    twitter是Twitter的ruby gem,它提供了两种身份验证的方法,一是oauth,二是http auth。http auth非常简单,只要提供账号和密码就可以了,而oauth就稍微复杂一些了。

    首先,你需要到http://twitter.com/oauth_clients去注册你的应用,并得到相应的consumer token和consumer secret。

    接着就可以使用twitter gem了

    def oauth
      oauth = Twitter::OAuth.new(consumer_token, consumer_secret)
      request_token = oauth.set_callback_url 'http://www.huangzhimin.com/'
      session[:rtoken] = request_token.token
      session[:rsecret] = request_token.secret
    
      redirect_to request_token.authorize_url
    end

    注意,这里除了传入consumer_token和consumer_secret之外,还设置了callback_url,它表示twitter身份验...

    Read More

    Tags 


    ruby rescue

    23 Nov 2009

    ruby的异常处理和java很相似

    begin
      ...
    rescue
      ...
    end

    rescue默认只会接受StandardError

    irb(main):001:0> begin
    irb(main):002:1* 1 / 0
    irb(main):003:1> rescue
    irb(main):004:1> puts "divide 0"
    irb(main):005:1> end
    divide 0

    但是像SyntaxError并不是继承StandardError的,就无法被resuce

    irb(main):001:0> begin
    irb(main):002:1* eval("1 +")
    irb(main):003:1> rescue
    irb(main):004:1> puts "syntax error"
    irb(main):005:1> end
    SyntaxError: (eval):1:in `irb_binding': compile error
    (eval):1: syntax error, unexpected $end
       ...
    Read More

    Tags 


    autotest notify for Ubuntu

    04 Nov 2009

    一直很羡慕Mac下的growl,每次autotest都可以弹出个提示框,好眩。如今Ubuntu的用户也有了自己的通知系统notify OSD,赶紧用到自己的autotest上面。

    google了一下,已经有人做了gem来调用ubuntu notify osd,http://github.com/stack/autotest-notify-osd

    sudo gem install autotest-notify-osd

    安装好这个gem之后,在~/.autotest下增加下面一行

    require 'autotest/notify-osd'

    运行autotest,返回sh: notify-send: not found错误,原来少装了libnotify-bin

    sudo apt-get install libnotify-bin

    再次运行autotest,右上角显示所有的测试都通过,太cool了

    Read More

    Tags 


    Ruby triple equal

    28 Oct 2009

    今天读sexp_processor源代码,看到有多出调用 Class === Object 这样的语法,突然之间没想出来===是干嘛的了。网上搜索了一下,原来是判断后面这个对象是不是前面这个类的实例,比如

    >> Object === Object.new
    => true

    这个和is_a?不就没区别了吗?

    >> Object.new.is_a? Object
    => true

    google一把,好像是说===比is_a?更优雅,而且===被用在case...when的语法当中

    case shape
    when Square, Rectangle
      # ...
    when Triangle
      # ...
    else
      # ...
    end

    上面这段代码摘自Programming Ruby

    Read More

    Tags 


    require某个版本的gem

    25 Oct 2009

    一般我们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的用法蛮像的?

    Read More

    Tags 


    add executable to ruby gem

    26 Sep 2009

    刚刚给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...
    Read More

    Tags 


    在google app engine上做代理服务(for crawler)

    12 Sep 2009

    本来是想在GAE上做一个完整的代理服务器的,结果发现不可行,好像当HTTP的URL和HOST不匹配的时候,GAE就会把你拦截。怪不得GAE上找到的代理服务器都必须安装客户端或者是网页式的呢。

    但是我在hostmonster上的crawler还被挡在国门之外,没办法,只能通过QUERY_STRING来实现一个比较奇怪的代理了:

    package com.huangzhimin.gae.proxy;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.Enumeration;
    
    import javax.servlet.http.*;
    
    @SuppressWarnings("serial")
    public class RichardProxyServlet extends HttpServlet {
        public void doGet(HttpServletRequest req...
    Read More

    Tags 


    get_response_with_headers

    30 Aug 2009

    最近在用ruby的net/http写爬虫,发现net/http提供的接口还真不是一般不好用

    一开始我是用Net::HTTP.get_response方法,挺简单的,测试起来也不难

    http = mock(Net::HTTPSuccess)
    http.stubs(:is_a?).with(Net::HTTPSuccess).returns(true)
    http.stubs(:body).returns(content)
    Net::HTTP.expects(:get_response).with(URI.parse(remote_path)).returns(http)

    接着碰到有些网站必须指定User-Agent才能访问,发现get_response方法不能修改http headers,只能换Net::HTTP.start方法

    response = start(uri.host, uri.port) do |http|
      http.get(uri.request_uri, headers)
    end

    可是写测试的时候傻眼了,因为要根据不同的uri.request_u...

    Read More

    Tags 


    ruby数字的科学记数法显示

    26 Aug 2009

    当网页需要显示很长的数字时,比如:100000000, 0.00000001,有时候会影响页面布局,而且也不方便阅读。改用科学记数法就会方便很多,比如:1e+08, 1e-08。ruby和其它语言一样,可以通过String的format来格式化数字。

    def number_to_scientific(num)
      "%g" % num
    end
    
    >> number_to_scientific(100000000)
    => "1e+08"
    >> number_to_scientific(0.000000001)
    => "1e-09"
    Read More

    Tags 


    在github上发布gem

    02 Aug 2009

    现在ruby上流行的gem一般都在两个repository上,一个是rubyforge,一个是github。

    这几天在写regexp_crawler,通过正则表达式来爬取网上的数据。今天写得差不多了,就想在github上以gem的形式发布。

    首先,在自己项目的编辑页面,把RubyGem这项勾上。

    接着,就是生成gemspec文件。我是通过jeweler来管理自己gemspec的。

    1. 安装jeweler gem。
    $ gem install jeweler
    1. 在Rakefile文件中增加新的task
    require 'jeweler'
    
    Jeweler::Tasks.new do |gemspec|
      gemspec.name = "regexp_crawler"
      gemspec.summary = "RegexpCrawler is a Ruby library for crawl data from website using regular expression."
      gemspec.description = "RegexpCrawler is a Ruby library for crawl data from website using reg...
    Read More

    Tags 


    ruby正则的named capture

    08 Jul 2009

    之前用python re的时候,特别喜欢用named capture,主要是可读性好太多了,一个正则表达式写出来都不用再加注释了。

    可是ruby1.8并不支持,每次用$1, $2的时候都觉得很ugly,幸好ruby1.9开始支持named capture了。看看example:

    result = %r{(?\w+)\s(?\w+)}.match("Richard Huang") result.lastname

    => "Richard"

    result.firstname

    => "Huang"通过named capture,别人读你的正则表达式时,也能够轻松地理解你的意图

    Read More

    Tags 


    Less -- Css的Ruby扩展

    18 Jun 2009

    Less是对Css的一种Ruby扩展,使得Css可以支持变量,Mixin,内嵌规则和数字操作。

    Less的特点在官网上[]http://lesscss.org/]1写得很清楚,这里就不再重复了。试用了一天,还不错,不过和Sass比起来还是有些差距的:

    1. Less只支持单文件,没有Sass中的import功能,所以Css重用上也只能局限在单文件中。

    2. Less内嵌规则不支持单行css定义

    div {
      input {color:red;}
    }

    这样写lessc编译的时候会报错,必须改成下面的写法:

    div {
      input {
        color:red;
      }
    }

    觉得这个应该算是一个bug吧。

    3. Less不支持多元素嵌套

    div.style1, div.style2 {
      input {
        color:red;
      }
    }

    它会被解析成

    div.line1, div.line2 input {
      color:red;
    }

    而Sass会解析成

    div.line1 input, div.line2 input {
      col...
    Read More

    Tags 


    ActiveRecord Without Rails

    02 Jun 2009

    前几天写了个小程序,帮我选号买彩票。主要是去网上抓取历次的开奖号码,存到数据库,然后再做统计分析。

    因为程序很小,所以实在不想把Java这个大胖子叫出来,就简单地在vi下写了几十行的ruby代码。由于要用到数据库,自然想到了ActiveRecord,平时都是在Rails环境下用的,现在却是要让它脱离出来,闹独立。

    首先是在mysql中新建数据库:

    mysqladmin -uroot create caipiao

    接着当然应该是定义database.yml

    adapter: mysql
    encoding: utf8
    database: caipiao
    username: root
    password:
    socket: /var/run/mysqld/mysqld.sock

    定义migration,新建db/migrate目录,新建migration文件,注意前面加上数字前缀,001_xxx, 002_yyy,migration文件内容就和rails中的一模一样。

    class CreateRedBlueBalls < ActiveRecord::Migration
      def...
    Read More

    Tags 


    解决rubygems冲突的问题

    23 May 2009

    在hostmonster上面手动编译了ruby和rubygems,不过今天在尝试rake gems:unpack的时候报错,说是调用了nil.version,一跟踪,原来是找不到gem的spec。不过明明是装好没问题的呀,奇怪了。于是去irb中尝试:

    require 'rubygems'
    => true
    require 'spec'
    => no such file to load -- spec

    看来是rubygems路径的问题。可能是和hostmonster默认的rubygems路径冲突了,于是在.bashrc中显示指定GEM_PATH

    export GEM_HOME=$HOME/ruby/gems
    export GEM_PATH=$GEM_HOME:/usr/lib/ruby/gems/1.8

    重新在irb中执行require 'spec'返回true,执行rake gems:unpack也OK了!

    Read More

    Tags