Err the Blog Atom Feed Icon
Err the Blog
Rubyisms and Railities
  • “Be Dee Dee and Me”
    – Chris on May 02, 2007

    Advertisement

    Since before January (I don’t know how far before), I’ve been writing all my tests using the Cool New Way. Not because it’s cool, or new, but because it really helps me write better code. Let me tell you about it.

    A Brief and Subtle Introduction

    Be dee dee. Behavior driven development. BDD is a way of writing code by testing what the code should do rather than testing the code itself. Does that make sense?

    Here’s an example:

    require 'test/spec'
    
    context "This blog post" do
      setup do
        @post = BlogPost.find_by_title('Be Dee Dee')
      end
    
      specify "should mention bdd" do
        @post.body.should.include 'behavior driven development'
      end
    
      specify "should be concise" do
        @post.body.word_count.should.be < 1000
      end
    
      specify "should contain at least four hyperlinks" do
        @post.body.scan('a href').size.should.be >= 4
      end
    
      specify "should be written by me" do
        @post.author.should.equal Author.find_by_name('Chris Wanstrath')
      end
    end
    

    So, BDD is just writing tests with a special syntax and describing them in plain jane English. “What’s the big deal, then?” Nothing. There is no big deal.

    However, if you’ve a bit of time and an inclination for writing awesomely readable tests (which may ultimately help you write better code), continue.

    Say, for instance, the above was real code. I could run it with a special test runner and get this output:

    This blog post:
    - should mention bdd
    - should be concise
    - should contain at least four hyperlinks
    - should be written by me
    
    Finished in 0.0083 seconds.
    
    4 specifications (4 requirements), 0 failures
    

    Nice. Let’s see where this goes.

    Choose Your Weapon

    A super popular BBD framework is RSpec, which I’m sure you’ve heard of. Those guys are leading the Ruby BDD revolution, more or less, with their code and blog posts.

    RSpec is catching on with some big time projects adopting it, among them Rubinius and caboose(read: court3nay)’s sample app. Originally mofo used RSpec, but I’ve since moved on.

    To test/spec, by Christian Neukirchen (of Anarchaia fame). His announcement of test/spec 0.3 is a very thorough explanation of the library’s features. This is the library I’ll be focusing on hereafter.

    The test/spec library is great because it simply wraps test/unit, meaning most of your test/unit tools work right out of the box with it. No need to do anything special to test Rails (rake test, et al). ZenTest’s autotest “just works.” Heckle and it get along amazingly well. You can use plain ol’ assert_equal in specs. Etc.

    As a result, you can start slipping test/spec into your existing project, alongside your existing tests, without doing anything special. A spec here, a spec there, and before you know it the whole damn crew is BDDin’.

    But, don’t let me boss you around. A compulsory search on Rubyforge reveals two more BDD libraries: SpecUnit and RBehave, the latter being developed by the dude who coined the ‘BDD’ term: Dan North. Worth a look or, at least, a gander.

    Digging a Rails Model BDD-Style

    For now we’re going with test/spec: $ sudo gem install test-spec

    (Yes, a dash. But you require it with a slash. You’ll get used to it.)

    Luke Redpath posted an article on BDDing a Rails model using RSpec back in August. It’s good and thorough, so I’m not going to re-say what he said. Read it.

    Anyway, let’s write a model. Digg got all crazy the other day with this HD-DVD bidness, so we’re gonna start our own Digg to make sure we can consistently get news about the stuff we’re interested in: Obama, the Wii, and Apple rumors.

    (If you’d like to follow along at home, the completed source can be found at require. Check it out with svn and set everything up with $ rake db:bootstrap.)

    $ svn co svn://errtheblog.com/svn/projects/dugg

    So! The first thing we’d do here is describe our model’s ideal behave. In English. With YAML.

    A User (in general):
      - should be able to digg a story
      - should not be able to digg a story twice
      - should be able to tell if he has dugg a story
    

    Simple enough. Save this as user_spec.yml and then run the yaml_to_spec rake task (this one) on it to generate a scaffold:

    $ rake -s yaml_to_spec FILE=user_spec.yml 
    context "A User (in general)" do
      xspecify "should be able to digg a story" do
      end
    
      xspecify "should not be able to digg a story twice" do
      end
    
      xspecify "should be able to tell if he has dugg a story" do
      end 
    end
    

    Put that into test/unit/user_test.rb and you’re mostly ready to roll. What’s xspecify? It means a spec is not yet ready to be tested—when you run this file, all the xspecify blocks will be ignored. Helpful when writing spec/tests before writing any code (which is exactly what we’re doing).

    Anyway, let’s fill in those specs:

    require File.dirname(__FILE__) + '/../test_helper'
    
    context "A User (in general)" do  
      setup do
        @user  = users(:defunkt)
        @story = stories(:undugg)
        @dugg_story = @user.dugg_stories.first
      end
    
      specify "should be able to digg a story" do
        @user.dugg_stories.should.not.include @story
        @user.digg(@story).should.equal true
        @user.dugg_stories(true).should.include @story
      end
    
      specify "should not be able to digg a story twice" do
        @user.digg(@dugg_story).should.equal false
      end
    
      specify "should be able to tell if he has dugg a story" do
        @user.should.have.dugg @dugg_story
        @user.should.not.have.dugg @story
      end   
    end
    

    This describes, to an extent, the behavior we want: digg should return true or false depending on whether or not it succeeds.

    Running this test at this point gives a whole grip o’ errors. Time to start writing code.

    Here’s our User, with the digg and dugg? methods simply wrapping our association:

    class User < ActiveRecord::Base
      has_many :dugg
      has_many :dugg_stories, :through => :dugg, :source => :story
    
      def digg(story)
        dugg_stories << story
      rescue ActiveRecord::RecordInvalid
        false
      else
        true
      end
    
      def dugg?(story)
        dugg_stories.include? story
      end
    end
    

    Then, of course, our Dugg model:

    class Dugg < ActiveRecord::Base
      set_table_name 'dugg'
    
      belongs_to :user
      belongs_to :story
    
      validates_uniqueness_of :story_id, 
        :scope   => :user_id, 
        :message => "can't be dugg again!" 
    end  
    

    The Story class has nothing in it (yet).

    Running the tests now gives us the green. Fantastics.

    Finding Dugg’d Stories

    Let’s add another feature, something to the Story class. How about finding the most dugg stories?

    Here, a spec for that:

    A Story (in general):
      - should return its title when sent #to_s
    Trying to find the most dugg stories:
      - should return a list of popular stories
      - should respect an arbitrary limit
    

    Now, a test/spec for that:

    require File.dirname(__FILE__) + '/../test_helper'
    
    context "A Story (in general)" do
      setup do
        @story = Story.find(:first)
      end
    
      specify "should return its title when sent #to_s" do
        @story.to_s.should.equal @story.title
      end
    end
    
    context "Trying to find the most dugg stories" do
      setup do
        @second_most_popular, @most_popular = Story.find(:all).last(3)
      end
    
      specify "should return a list of popular stories" do
        popular = Story.most_dugg
        popular.size.should.equal 5
        popular.first.should.equal @most_popular
      end
    
      specify "should respect an arbitrary limit" do
        popular = Story.most_dugg(2)
        popular.size.should.equal 2
        popular.shift.should.equal @most_popular
        popular.shift.should.equal @second_most_popular
      end
    end
    

    I setup my fixtures to make the last story insert’d not dugg at all, second last story insert’d the most popular, the third last story insert’d the second most popular, etc. Keep that in mind; it’s clutch.

    This spec fails, of course. We don’t have a most_dugg method and our to_s method is the default. Let’s fix that.

    class Story < ActiveRecord::Base
      alias_attribute :to_s, :title
    
      def self.most_dugg(limit = 5)
        connection.select_all(<<-SQL).map { |row| find(row['story_id']) }
          SELECT story_id, count(1) as size 
          FROM dugg 
          GROUP BY story_id 
          ORDER BY size DESC 
          LIMIT #{limit}
        SQL
      end
    end  
    

    Lil’ bit of SQL never hurt no one. Not the most efficient query, but we just want to get our specs passing—we can focus on optimization later (with a counter_cache or something).

    And pass they do. Glory be, be dee dee.

    Gettin’ Railsy: BDDin’ Controllers

    What’s cool is we haven’t even started Mongrel yet. Web browsers are so last year. Let’s keep it up by adding a controller or two.

    Hold on. There’s a catch: functional tests in Rails are more than test cases with stock test/unit assertions. There’s assert_redirected_to and assert_select and all that webby goodness. Does test/spec give us this stuff? No, it doesn’t.

    However, test/spec/rails does. A plugin by Per Wigren, the README file explains it all quite well. So does the cheat sheet.

    Install it:

    $ cd vendor/plugins
    $ piston import http://svn.techno-weenie.net/projects/plugins/test_spec_on_rails
    

    Now add require ‘test/spec/rails’ to your test_helper.rb and you’re good to go.

    Stories Stories Stories

    Time to hussle. We want to list all the stories on a page, in order. Nothing fancy. We also want to show the user whether or not she’s already dugg the story.

    Some people like to do their controller specs a bit differently, so take this all with the same grain of salt you take everything on the internet.

    A page listing all stories:
      - should display every story
      - should show a 'digg' link if the viewing user has not dugg the story
      - should not show a 'digg' link if the viewing user has dugg the story  
    

    We’re going to sprinkle a bit of Mocha into this spec to pretend we’re always logged in as defunkt. Add require ‘mocha’ to your test_helper.rb after doing a $ sudo gem install mocha. (If you don’t know what the hell I’m talking about, check this chocolately post from the past.)

    Speccin’ it out:

    require File.dirname(__FILE__) + '/../test_helper'
    
    context "A page listing all stories" do
      use_controller StoriesController
    
      setup do
        @user     = users(:defunkt)
        @dugg     = stories(:digg)
        @not_dugg = stories(:undugg)
        @controller.stubs(:current_user).returns(@user)
    
        get :index
      end
    
      specify "should display every story" do
        status.should.be :success
        template.should.be 'stories/index'
        assigns(:stories).size.should.equal Story.count
        body.scan(/story_/).size.should.equal Story.count
      end
    
      specify "should show a 'digg' link if the viewing user has not dugg the story" do
        dom_id = "#story_#{@not_dugg.id}" 
        should.select "#{dom_id}>.digg" 
      end
    
      specify "should not show a 'digg' link if the viewing user has dugg the story" do
        dom_id = "#story_#{@dugg.id}" 
        should.not.select "#{dom_id}>.digg" 
      end
    end  
    

    Reads nicely, huh? And not too distant from a test/unit functional test.

    The use_controller method will setup all the instance variables we normally set ourselves: the request, response, and controller objects.

    In our first spec we make sure the response is a-okay, then make sure we have the same number of ‘story_x’ ids as we do stories. Pagination is for sissies.

    In the next two tests we ensure the ‘digg’ link works as planned.

    The cheat sheet, again, has all the info you could want about the stuff test/spec/rails gives you. It’s pretty much ripped straight from the README.

    With all that done, it’s simply a matter of making the tests pass. And we do, of course.

    The first thing to setup are our RESTful routes:

    ActionController::Routing::Routes.draw do |map|
      map.resources :stories do |story|
        story.resources :diggs
      end
    
      map.home '', :controller => 'stories'
    end  
    

    Next we create our controller:

    class StoriesController < ApplicationController
      def index
        @stories = Story.find(:all, :order => 'created_at DESC')
      end
    end
    

    Then, if you will, the view:

    <h1>All Stories!</h1>
    
    <% @stories.each do |story| %>
      <div id="<%= dom_id story %>"><%= digg_link story %><%= story %></div>
    <% end %>
    

    Finally, the helpers:

    module ApplicationHelper
      def digg_link(story)
        return if current_user.dugg? story
        link_to 'Digg!', story_diggs_url(story), :class => 'digg', :method => :post
      end
    
      def dom_id(record)
        "#{record.class.name.underscore}_#{record.id}" 
      end
    end
    
    

    See that digg_link method? The link itself doesn’t actually work yet, but we can do it. I know we can.

    Diggin’ It

    Okay, the DiggsController. What we want to assert first is our ability to digg a story. So, to create a digg:

    Successfully digging a story:
      - should redirect to the stories listing page
    

    Which brings us to:

    require File.dirname(__FILE__) + '/../test_helper'
    
    context "Successfully digging a story" do
      use_controller DiggsController
    
      setup do
        @user  = users(:defunkt)
        @story = stories(:undugg)
        @controller.expects(:current_user).returns(@user)
        @user.expects(:digg).with(@story).returns(true)
        post :create, { :story_id => @story.id }
      end
    
      specify "should redirect to the stories listing page" do
        flash[:notice].should.equal 'Dugg!'
        should.redirect_to stories_url
      end 
    end
    

    Simple and beautiful, one hopes.

    The first error is test/spec bemoaning the lack of a DiggsController constant, so go ahead and add that. Make an empty create method while you’re in there, too. Remember, we’re just trying to make stuff pass at this point. We’ll cross every bridge as we come to it.

    Now it’s complaining about the create.html.erb template not existing—time to write our create method:

    class DiggsController < ApplicationController
      def create
        story = Story.find(params[:story_id])
        if current_user.digg(story)
          flash[:notice] = 'Dugg!'
          redirect_to stories_path
        end
      end
    end  
    

    Disco. But, remember, digg can fail. Let’s handle that case with another context:

    context "A failed story digging attempt" do
      use_controller DiggsController
    
      setup do
        @user  = users(:defunkt)
        @story = stories(:dugg)
        @controller.expects(:current_user).returns(@user)
        @user.expects(:digg).with(@story).returns(false)
        post :create, { :story_id => @story.id }
      end
    
      specify "should render with an error message" do
        flash[:notice].should.match /error/i
        should.redirect_to stories_url    
      end
    end  
    

    Here, the new controller code:

    class DiggsController < ApplicationController
      def create
        story = Story.find(params[:story_id])  
        if current_user.digg(story)
          flash[:notice] = 'Dugg!'
        else
          flash[:notice] = 'Error digging :('
        end
        redirect_to stories_path
      end
    end
    

    And just like that, we’re passing. Apple rumors, here we come.

    The Full Spec

    Oh, for bonus, remember that “special test runner” I told you about? You are now fully qualified to use it:

    $ ruby test/functional/diggs_controller_test.rb -r s
    
    Successfully digging a story
    - should redirect to the stories listing page
    
    A failed story digging attempt
    - should render with an error message
    
    Finished in 0.101304 seconds.
    
    2 specifications (8 requirements), 0 failures  
    

    Rad. But there’s more, given you download these double bonus test/spec/rails tasks:

    $ rake spec
    A Story (in general)
    - should give its title when asked for a string representation of itself
    
    Trying to find the most dugg stories
    - should return a list of popular stories
    - should respect an arbitrary limit
    
    A User (in general)
    - should be able to digg a story
    - should not be able to digg a story twice
    - should be able to tell if he has dugg a story
    
    Finished in 0.136295 seconds.
    
    6 specifications (10 requirements), 0 failures
    
    Successfully digging a story
    - should redirect to the stories listing page
    
    A failed story digging attempt
    - should render with an error message
    
    A page listing all stories
    - should display every story
    - should show a 'digg' link if the viewing user has not dugg the story
    - should not show a 'digg' link if the viewing user has dugg the story
    
    Finished in 0.186009 seconds.
    
    5 specifications (9 requirements), 0 failures  
    

    That’s it, that’s everything our app does. Right there.

    Testing is Fun Again!

    If you want to feel around some more examples check out the cache_fu specs or the Gibberish specs or even the mofo specs. Mephisto, I hear, has some test/spec action these days.

    Wanting to test/spec integration tests in Rails? Brian has the solution, which he busted out at a SF Ruby Meetup hackfest.

    Let me know if I missed anything, if I broke anything, or if you know of any public projects using test/spec. The best way to get into this stuff, as always, is to just do it. Go go go!

  • Erik Kastner, 2 days later:

    This is great stuff. I’ve been dying for a test/spec err post! Working on any cool projects that are digg-like these days?

  • Kevin Marsh, 2 days later:

    Another great post from a prolific Rails blogger! Keep it up defunkt. You da man.

  • Dave O., 2 days later:

    Great post.

  • Curtis, 2 days later:

    I didn’t even know test/spec existed, rock on. Thanks.

  • Ruby on Rails, 2 days later:

    Another Great post from errtheblog. Excellent writeup on BDD. Your test concepts are quite clean.

  • Daniel Fischer, 2 days later:

    Exactly what I was needing to read. Thank you very much for this excellent post!

  • James H, 2 days later:

    F’n great post. Thank you very much.

  • atmos, 4 days later:

    You guys fuckin’ suck. Top notch as always. :)

  • mike, 6 days later:

    Thanks for the post. I’ve already written and implemented my first spec thanks to you! Thanks as well for posting the source code.

    I did find one problem for any of those folks like me that started from scratch with test/spec after reading your post. In your specs near the top, you use “should.have” and “should.not.have” without noting that “have” is just an alias for “be”. I found that out by poking through your test_helper.rb in the dugg project.

    Thanks again!

  • James H, 18 days later:

    When using the usual test/unit framework for functional tests we can define helper methods within the class for doing specialized tasks. For example, in one of my functional tests I have a method for helping to upload photographs. How do you handle these sorts of specialized methods in test/spec?

  • Aaron Wheeler, about 1 month later:

    This might be obvious, but the strings that come after the ‘context’ method call should be unique. If they are not, then the calls to ‘setup’ will be compounded, which can cause issues with instance variables with similar names.

    This is especially problematic with functional tests, where the @controller will be corrupted.

  • David Chelimsky, about 1 month later:

    “The test/spec library is great because it simply wraps test/unit, meaning most of your test/unit tools work right out of the box with it. No need to do anything special to test Rails (rake test, et al). ZenTest’s autotest “just works.” Heckle and it get along amazingly well. You can use plain ol’ assert_equal in specs. Etc.”

    Actually, this is true of spec/rails (RSpec’s Rails plugin). There is rcov, heckle and autotest integration and spec/rails wraps test/unit so you get all of the test/unit assertions as well.

    If you prefer test/spec’s style, that’s one thing, but I hate to see people making a choice based on inaccurate information.

  • Matt, 3 months later:

    Has anyone found a way around the:

    Unable to map class New signup for mailing list to a file

    ...when using autotest with test/spec? Particularly with big test files, this can be a dealbreaker, for me. This is pretty much the last hurdle I have to total adoption.

  • Heart Tattoos, about 1 year later:

    Tattoos Celtic Tattoos Lower Back Tattoos Dragon Tattoos Skull Tattoos Heart Tattoos Butterfly Tattoos Chinese Tattoos Layered Hair Styles Layered Hairstyles Emo Hairstyles Medium Hairstyles Bang Hairstyle Prom Hairstyle Hair Coloring Heart Lower Back Tattoos

  • sik, about 1 year later:

    sikiş porno sex video izle iyi porno uzun porno yeni pornolar porno seyret sex seyret porno filmler sex izleyin sex izle porno sex erotik porn video türk porno canlı porno porno izle porno porno film sex filmleri porn video porno film sex seyret porno video seyret orgazm porno seks izle erotik video sex videolar yetişkin video sex video izle porno video izle bedava porno 18 video seks porno sıcak izle yetişkin film sikiş seyret sex amatör videolar teen video erotik videolar yetişkin video yetişkin videolar pornolar porno video teen kızlık bozma sikiş sikiş video seks türban sex sex erotik seks izle sıcak ateşli

  • asd, about 1 year later:

    modern abstract art sofa manufacturer гранит 净水器 混合机 过滤机 DHL快递 保险箱 法兰 法兰标准 牛皮癣 皮肤病 北京快递公司 北京国际快递 传世私服 传奇世界私服 天龙八部私服 天龙私服 网络电话 免费网络电话 假发 补发 织发 植发 上海搬家公司 上海搬场公司 大众搬家 大众搬场 张家界旅游 香港旅游 深圳旅行社 打包机 收缩机 萎缩性胃炎 neoprene laptop bags SEO优化 SEO优化 计量泵 胃炎 胃病 冷水机 冰水机 工业冷水机 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 油罐车 北京办证 办证 北京特价机票 北京打折计票 北京国际机票 北京机票预定 北京飞机票 北京订机票 北京机票查询 血糖仪 血糖仪 银杏 水培花卉 企业宣传片 空分设备 机电设备安装 代孕 代孕网 代孕 代孕 代孕 试管婴儿 代孕 电话交换机 程控交换机 集团电话 集装袋 混合机混合机 混合机捏合机 捏合机 捏合机导热油炉 导热油炉 导热油炉 反应釜 反应釜 反应釜 回流焊 波峰焊 spherical roller bearing 搬运车 搬运车 电动搬运车 油桶搬运车 堆高车 电动堆高车 半电动堆高车 堆垛车 高空作业平台车 电动叉车 平衡重叉车 前移叉车 电瓶叉车 苗木价格 苗木信息 标牌制作 深圳标牌 儿童摄影 北京儿童摄影 防静电鞋 淘宝刷信誉 威海凤凰湖 威海海景房 大庆密封件 打标机 淘宝刷信誉 TESOL/TEFL国际英语教师证书 英语教师进修及培训 韩国饰品批发 代写论文 代写论文 代写论文 代写代发 论文代写 电源模块 模块电源 X架 超薄灯箱> 易拉宝 展柜制作 代理服务器 游戏加速器 网络加速器 网通加速器 电信加速器 电信网通转换器 电信网通加速器 网通电信互转 网通电信互通 网络游戏加速器 美国VPN代理 美国独享VPN 美国独享IP pvc ceiling panel Spherical roller bearings 天龙八部私服 SEO优化 安全鞋 劳保鞋 防砸鞋 电绝缘鞋 上海安全鞋 上海劳保鞋 江苏劳保鞋 服装软件 服装管理软件 进销存软件 进销存管理软件 服装管理系统 服装进销存软件 进销存系统 进销存管理系统 免费进销存软件 吉林中医 东北特产 打包机 dhl 阳痿 阴茎短小 阴茎增大 早泄 前列腺炎 阴茎增粗 阴茎延长 国际机票 上海国际机票 国际打折机票 国际特价机票 CRM 客户管理软件 客户关系管理 免费客户管理软件 客户管理软件下载 客户信息管理系统 销售管理系统 销售管理 CRM系统 CRM软件 客户关系管理系统 客户关系管理软件 客户管理 客户管理系统 营销管理系统 客户资源管理 销售管理软件 客户资料管理软件 客户资源管理软件 客户信息管理软件 客户资料管理 客户资源管理 客户信息管理 客户资料管理系统 客户资源管理系统 客户管理软件免费版 砂磨机 砂磨机 砂磨机 卧式砂磨机 卧式砂磨机 卧式砂磨机 三辊研磨机 三辊研磨机 三辊研磨机 混合机 混合机 混合机 锥形混合机 锥形混合机 锥形混合机 行星动力混合机 行星动力混合机 行星动力混合机 无重力混合机 无重力混合机 无重力混合机 干粉砂浆设备 干粉砂浆设备 干粉砂浆设备 捏合机 捏合机 捏合机 导热油炉 导热油炉 导热油炉 反应釜 反应釜 反应釜 搪玻璃反应釜 搪玻璃反应釜 搪玻璃反应釜 乳化机 涂料设备 干混砂浆设备 无重力混合机 胶体磨 涂料成套设备 双螺旋混合机 北京婚庆 北京婚庆公司 400电话 办证 呼吸机 制氧机 亚都 亚都加湿器 亚都净化器 亚都装修卫士 饰品批发 小饰品批发 韩国饰品 韩国饰品批发 premature ejaculation penis enlargement 破碎机 制砂机 球磨机 雷蒙磨 雷蒙磨粉机 鄂式破碎机 鄂式破碎机 免烧砖机 加气混凝土设备 反击式破碎机 选矿设备 安利产品 马来西亚留学 网站优化 网站推广 衬布 代写论文 代写论文 代写论文 论文代写 代写论文 代写硕士论文 代写毕业论文 磁力泵 离心泵 化工泵 隔膜泵 螺杆泵 潜水泵 油泵 耐腐蚀泵 泵 水泵 拖链 防护罩 排屑机 塑料拖链 钢铝拖链 水泵 磁力泵 隔膜泵 离心泵 液下泵 自吸泵 多级泵 排污泵 螺杆泵 油泵 化工泵 电动隔膜泵 气动隔膜泵 自吸式磁力泵 氟塑料磁力泵 管道离心泵 导热油泵 深井泵 潜水泵 污水泵 潜水排污泵 深圳装饰 深圳装饰公司 深圳装修公司 特价机票 打折机票 国际机票 机票 新风换气机 换气机 立式新风换气机 风机箱 新风系统 能量回收机 搅拌机 混合机 乳化机 分散机 毛刷 毛刷辊 工业毛刷 刷子 钢丝刷 涂层测厚仪 硬度计 兆欧表 激光测距仪 测振仪 转速表 温湿度计 风速仪 超声波测厚仪 粗糙度仪 噪音计 红外测温仪 万用表 硬度计 万用表 美容院 美容加盟 澳洲留学 澳大利亚留学 什么是法兰 电烤箱 酒店预定 北京酒店预定 北京酒店 离心机 nail equipment nail products nail product nail uv lamp nail uv lamp nail uv lamps uv nail lamp nail brush nail file nail tool nail tip nail gel curing uv lamps lights 万用表 风速仪 红外测温仪 噪音计

  • 123, about 1 year later:

    情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣,情趣,情趣,情趣,情人歡愉用品,情惑用品性哥,情人用品性哥,情趣用品,AIO交友愛情館,情人歡愉用品,美女視訊,情色交友,情人用品性哥,視訊交友,辣妹視訊,美女交友,性愛,嘟嘟成人網,按摩棒,震動按摩棒,微調按摩棒,情趣按摩棒,逼真按摩棒,G點,跳蛋,跳蛋,跳蛋,性感內衣,飛機杯,充氣娃娃,情趣娃娃,角色扮演,性感睡衣,後庭區,SM,潤滑液,情趣禮物,威而柔,香水,精油,芳香精油,自慰,自慰套,性感吊帶襪,情趣用品加盟,情人節禮物,情人節,吊帶襪,辣妹視訊,美女交友,情色交友,成人交友,視訊聊天室,美女視訊,視訊美女,情色視訊,免費視訊聊天,視訊交友,視訊聊天,AIO交友愛情館,嘟嘟成人網,成人貼圖,成人網站,AIO交友愛情館,情色,情色貼圖,情色文學,情色交友,色情聊天室,色情小說,七夕情人節,色情,A片,A片下載,免費A片,免費A片下載,情色視訊,情色電影,色情網站,辣妹視訊,視訊聊天室,情色視訊,免費視訊聊天,視訊聊天,美女視訊,視訊美女,美女交友,美女,情色交友,成人交友,自拍,本土自拍,情人視訊網,視訊交友90739,生日禮物,情色論壇,正妹牆,正妹,成人網站,A片,免費A片,A片下載,免費A片下載,AV女優,成人影片,色情A片,成人論壇,情趣,免費成人影片,成人電影,成人影城,愛情公寓,色情影片,保險套

  • 888, about 1 year later:

    花美姬情趣用品..情人視訊網..高雄轉角情趣用品..情人節禮物..

    台中情趣用品 台北情趣用品 高雄轉角情趣用品 ~情人用品性哥 花美姬情趣用品

  • qw, about 1 year later:

    Thanks so much for this! This is exactly what I was looking for

    mirc mırc mırç mirç mirc indir mirc yükle mirc yukle türkçe mirc mirc indir mirc islami sohbet kelebek kelebek script kelebek sohbet kelebek mirc chat çet cet çet odaları sohbet kanalları sohbet odaları kameralı sohbet kameralı chat sohbet eğlence mirc sohbet odaları sevgili arkadaş arkadaş bul arkaraş ara oto araba şarkı sözleri astroloji ikinci el telefon gazete gazeteler günlük gazeteler marifetname bedava domain ücretsiz domain benimurl parça kontör parça kontör radyo dinle bedava blog ücretsiz blog

  • noname, about 1 year later:

    video ödev indir şarkı sözleri video izle şiir türkü indir güzel sözler fıkra porno izle pornolar 18

  • , about 1 year later:

    Victorias Secret Victoria’s Secret Fashion show Victorias Secret Pink Victorias Secret Model Victorias Secret Credit Card Victorias Secret Coupon Code Victorias Secret Lingerie Victorias Secret Fashion Show 2005 Victorias Secret Fashion Show 2006 Victorias Secret Bra Victorias Secret Catalog Victorias Secret Pantie Victorias Secret Online Coupon Victorias Secret Fashion Show 2007 Victorias Secret Girl Free Shipping Victorias Secret Victorias Secret Home Victorias Secret Christmas Victoria’S Secret Pink Dog Victorias Secret Music Victorias Secret Semi Annual Sale Victorias Secret Jobs Victorias Secret Free Shipping Code Victorias Secret Shoes Victorias Secret Thong Victorias Secret Commercial Victorias Secret Promotional Code Victorias Secret Love Spell Victorias Secret Boots Victorias Secret Employment Victorias Secret Reviews Victorias Secret Jeans Victorias Secret Brasil Victorias Secret Bag

  • , about 1 year later:

    情人用品,情人用品性哥,情 人用品,情趣用品,視訊交友,視訊美女,視訊美女,視訊交友網,視訊聊天室,視訊聊天室,視訊 交友網,免費視訊聊天,辣妹視訊,辣妹視訊,情人視訊網

  • dd, about 1 year later:

    徵信社,案件討論,男女專區,法律諮詢,相關新聞,情趣用品,情趣用品,情趣精品,情趣用品,情趣用品,情趣用品,情趣用品,威而柔,自慰套,自慰套,SM,充氣娃娃,充氣娃娃,潤滑液,飛機杯,按摩棒,跳蛋,性感睡衣

    威而柔,自慰套,自慰套,SM,充氣娃娃,充氣娃娃,潤滑液,飛機杯,按摩棒,跳蛋,性感睡衣,視訊交友90739,情人視訊網,情色交友,視訊交友,辣妹視訊,美女視訊,aio交友愛情館,情色論壇,成人論壇,免費視訊聊天,辣妹視訊,視訊交友網,美女視訊,視訊交友,成人視訊,情趣用品,成人聊天室,情趣,情趣,視訊聊天室,視訊聊天,視訊聊天室,情色視訊,情人視訊網,免費視訊聊天室,aio交友愛情館,色情遊戲,寄情築園小遊戲,情色文學,一葉情貼圖片區

  • Twenty-three people have commented.
    Chime in.



    Textile is permitted.

Projects

  • Cheat! Sheets
  • Subtlety: RSSin' Your SVN
  • cache_fu
  • acts_as_textiled
  • mofo [microformat parsing]
  • require 'errtheblog'

Information

  • Dynamite! — The Err Free Weblog
  • Err Free: Ruby Development & Consulting
  • Err on GitHub
  • Err on Twitter
  • Report Err Plugin Bugs (Lighthouse Tracker)
  • Contact
This is Err, the weblog of PJ Hyett and Chris Wanstrath.
All original content copyright ©2006-2008 the aforementioned.