Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

A model factory - say no to fixtures.

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 lib
Octocat-spinner-32 spec
Octocat-spinner-32 .gemtest
Octocat-spinner-32 .gitignore
Octocat-spinner-32 .travis.yml
Octocat-spinner-32 Gemfile
Octocat-spinner-32 LICENSE
Octocat-spinner-32 README.md
Octocat-spinner-32 Rakefile
Octocat-spinner-32 letterpress.gemspec
README.md

Letterpress Build Status

Letterpress is a lightweight model generator that replaces fixture files.

Installation

Add this line to your application's Gemfile:

gem 'letterpress'

And then execute:

$ bundle

Or install it yourself as:

$ gem install letterpress

Usage

Rails, ActiveRecord and minitest

  1. Update Gemfile

    group :development, :test do
      gem 'letterpress', :require => 'letterpress/rails'
    end
    
  2. Install the gem

    $ bundle install
    
  3. Update config/application.rb

    config.generators do |g|
      g.test_framework :mini_test, :spec => true, :fixture_replacement => :letterpress
    end
    
  4. Generate (test|spec)/blueprint.rb file

    $ rails generate letterpress:install
    
  5. Generate a model object with its factory

    $ rails generate model Comment post_id:integer body:text
    
  6. It adds to the end of file (test|spec)/blueprint.rb

    class Comment < Blueprint(ProxyMethods)
      default do
        post_id { 1 }
        body { "MyText" }
      end
    end
    
  7. Modify the generated blueprint according to your preferences

    class Comment < Blueprint(ProxyMethods)
      default do
        post { Post.make.new }
        body { "MyText" }
      end
    end
    
  8. Write tests in test/comment_test.rb

    require "minitest_helper"
    
    class CommentTest < MiniTest::Rails::Model
      before do
        @comment = Comment.make.new
      end
    
      it "must be valid" do
        @comment.valid?.must_equal true
      end
    end
    

Rspec

Don't put the blueprint file in the support directory, if you do, the blueprint file will be required to early. It should be placed directly in the spec folder: spec/blueprint.rb If you do as describe below, the blueprint file is placed in the right place.

  1. Update config/application.rb
config.generators do |g|
  g.test_framework :rspec, :fixture_replacement => :letterpress
end
  1. Generate spec/blueprint.rb file
rails generate letterpress:install

Blueprint Class

A blueprint for a model is defined inside the Letterpress module; the class name of the blueprint must be the same as the models class name.

Below is an example of a Letterpress User class. Letterpress has two methods for defining blueprints: default and define; default can be used once in each class but define can be used as many time as you like. In this example the admin attribute is overridden by the admin block. The admin block will inherit the other attributes defined inside the default block.

module Letterpress
  class User < Blueprint(ProxyMethods)
    default do
      email { "user@example.com" }
      admin { false }
    end

    define(:admin) do
      admin { true }
    end
  end
end

user = User.make # => returns a proxy object (an instance of Letterpress::User)
user.admin # => false; itdelegates to an instance of the User class
user.email # => "user@example.com"

user = User.make(:admin)
user.admin # => true
user.email # => "user@example.com"

user = User.make(:admin, admin: false)
user.admin # => false
user.email # => "user@example.com"

Unique Attributes

For attributes that must be unique, you can call the sn method within the attribute block to get a unique serial number for the object.

email { "user-#{sn}@example.com" } # Each email gets a unique serial number.

user1 = User.make
user2 = User.make

user1.email # => "user1@example.com"
user2.email # => "user2@example.com"

Associations

When you create associations you don't have to persist them inside the blueprint.

  • has_many
# When defining a has_many association, you define it with an array.
# These 2 comments will only be persisted in the database when Post.make.save 
# is called, and not when Post.make or Post.make.new is called. 
comments { [ Comment.make.new, Comment.make.new ] }
  • belongs_to
# Post.make.new defines a non persisted post instance.
# The post instance will only be saved to the database if
# Comment.make.save is called.
post { Post.make.new }

What you must know to create a blueprint class:

  • The class methods default and define is used for defining default attribute values.
  • An attribute values must be defined inside a block: {}.
  • The sn method is used inside an attribute block to create unique attribute values, e.g if each user instance must have a unique email address.

Creating Object

Letterpress ads make to each ActiveRecord class; When make is called on an ActiveRecord class, it returns a proxy object that will delegate its received messages to the ActiveRecord instance.

The proxy object implements these methods:

  • new - returns the object under test or raises an exception if the object isn't valid.
  • new! - returns the object under test, even if not valid.
  • save - returns the persisted object under test or raises an exception if the object isn't valid.
User.make # Returns instance of Letterpress::User
User.make(:admin) # Returns instance of Letterpress::User
User.make(:admin, email: "foo@bar.com") # Returns instance of Letterpress::User


User.make.new # Returns a new User instance
User.make(:admin).save # Returns a persisted User instance
User.make(:admin, email: "foo@bar.com").new! # Returns a new User instance

Creating global ProxyMethods

Since each Letterpress class inherits from ProxyMethods, we can define methods in that module and they will be added to each proxy object.

In the code snippet below I have added a save_and_relod method that will be available on every proxy object.

module Letterpress
  module ProxyMethods
    def save_and_reload
      record = save
      @object = @object.class.find(record.id)
    end
  end
end

user = User.make.save_and_reload

Creating ProxyMethods on a class

If you want to add a method to only one proxy object, see code below.

module Letterpress
  class User < Blueprint(ProxyMethods)
    default do
      #...
    end

    def password(password)
      @object.password = "#{password} - in proxy" 
      @object
    end
  end
end

user = User.make.password("secret").save
user.password # => "secret - in proxy"

Overriding .make

If you for some reason want to do something with the proxy object before returning it, you can do that, see code below.

module Letterpress
  class User < Blueprint(ProxyMethods)
    default do
      #...
    end

    def self.make
     user = super
     # do something with the proxy object before returning it
     user.password =  "I always have this value"
     user
    end
  end
end

user = User.make.new
user.password # => "I always have this value"

Compatibility

Ruby version 1.9.2 and 1.9.3 and Rails version 3.1

GemTesters has more information on which platforms Letterpress is tested.

Test

gem install rubygems-test
gem test letterpress

For more info see: GemTesters

Where

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request
Something went wrong with that request. Please try again.