Permalink
Browse files

Overhaul the docs

  • Loading branch information...
1 parent 843a3d5 commit 747bd3a926c3c07d3bea087d444d15964044cb01 @jonleighton jonleighton committed Nov 5, 2010
View
@@ -4,3 +4,5 @@
/pkg
Gemfile.lock
.bundle
+.yardoc
+doc
View
@@ -0,0 +1,2 @@
+-m markdown
+--no-private
File renamed without changes.
View
@@ -1,3 +1,5 @@
+Copyright (c) 2008-2010 Michael Bleigh
+
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
View
147 README.md
@@ -0,0 +1,147 @@
+Seed Fu
+=======
+
+Seed Fu is an attempt to once and for all solve the problem of inserting and maintaining seed data in a database. It uses a variety of techniques gathered from various places around the web and combines them to create what is hopefully the most robust seed data system around.
+
+Warning: API Changes
+--------------------
+
+Version 2.0.0 of Seed Fu introduces API changes. `Seed::Writer` has been completely overhauled and will require you to update your scripts. Some other deprecations have been introduced, but the methods will not be removed until version 2.1.0. Please see the [CHANGELOG](CHANGELOG.md) for details.
+
+Basic Example
+-------------
+
+### In `db/fixtures/users.rb`
+
+ User.seed do |s|
+ s.id = 1
+ s.login = "jon"
+ s.email = "jon@example.com"
+ s.name = "Jon"
+ end
+
+ User.seed do |s|
+ s.id = 2
+ s.login = "emily"
+ s.email = "emily@example.com"
+ s.name = "Emily"
+ end
+
+### To load the data:
+
+ $ rake db:seed_fu
+ == Seed from /path/to/app/db/fixtures/users.rb
+ - User {:id=>1, :login=>"jon", :email=>"jon@example.com", :name=>"Jon"}
+ - User {:id=>2, :login=>"emily", :email=>"emily@example.com", :name=>"Emily"}
+
+Installation
+------------
+
+### Rails 3
+
+Just add `gem 'seed-fu'` to your `Gemfile`
+
+### Active Record 3
+
+Seed Fu depends on Active Record, but doesn't have to be used with a full Rails app. Simply load and require the `seed-fu` gem and you're set.
+
+### Rails 2.3
+
+The current version is not backwards compatible with Rails 2.3. Please use Seed Fu [version 1.2.3](https://github.com/mbleigh/seed-fu/tree/v1.2.3).
+
+Constraints
+-----------
+
+Constraints are used to identify seeds, so that they can be updated if necessary. For example:
+
+ Point.seed(:x, :y) do |s|
+ s.x = 4
+ s.y = 7
+ s.name = "Home"
+ end
+
+The first time this seed is loaded, a `Point` record will be created. No suppose the name is changed:
+
+ Point.seed(:x, :y) do |s|
+ s.x = 4
+ s.y = 7
+ s.name = "Work"
+ end
+
+When this is run, Seed Fu will look for a `Point` based on the `:x` and `:y` constraints provided. It will see that a matching `Point` already exists and so update its attributes rather than create a new record.
+
+If you do not want seeds to be updated after they have been created, use `seed_once`:
+
+ Point.seed_once(:x, :y) do |s|
+ s.x = 4
+ s.y = 7
+ s.name = "Home"
+ end
+
+The default constraint just checks the `id` of the record.
+
+Where to put seed files
+-----------------------
+
+By default, seed files are looked for in the following locations:
+
+* `Rails.root/db/fixtures` and `Rails.root/db/fixtures/Rails.env` in a Rails app
+* `db/fixtures` when loaded without Rails
+
+You can change these defaults by modifying the `SeedFu.fixture_paths` array.
+
+Seed files can be named whatever you like, and are loaded in alphabetical order.
+
+Terser syntax
+-------------
+
+When loading lots of records, the above block-based syntax can be quite verbose. You can use the following instead:
+
+ User.seed(:id,
+ { :id => 1, :login => "jon", :email => "jon@example.com", :name => "Jon" },
+ { :id => 2, :login => "emily", :email => "emily@example.com", :name => "Emily" }
+ )
+
+Rake task
+---------
+
+Seed files can be run automatically using `rake db:seed_fu`. There are two options which you can pass:
+
+* `rake db:seed_fu FIXTURE_PATH=path/to/fixtures` -- Where to find the fixtures
+* `rake db:seed_fu FILTER=users,articles` -- Only run seed files with a filename matching the `FILTER`
+
+You can also do a similar thing in your code by calling `SeedFu.seed(fixture_paths, filter)`.
+
+Disable output
+--------------
+
+To disable output from Seed Fu, set `SeedFu.quiet = true`.
+
+Handling large seed files
+-------------------------
+
+Seed files can be huge. To handle large files (over a million rows), try these tricks:
+
+* Gzip your fixtures. Seed Fu will read .rb.gz files happily. `gzip -9` gives the best compression, and with Seed Fu's repetitive syntax, a 160M file can shrink to 16M.
+* Add lines reading `# BREAK EVAL` in your big fixtures, and Seed Fu will avoid loading the whole file into memory. If you use `SeedFu::Writer`, these breaks are built into your generated fixtures.
+* Load a single fixture at a time with the `FILTER` environment variable
+* If you don't need Seed Fu's ability to update seed with new data, then you may find that [activerecord-import](https://github.com/zdennis/activerecord-import) is faster
+
+Generating seed files
+---------------------
+
+If you need to programmatically generate seed files, for example to convert a CSV file into a seed file, then you can use [`SeedFu::Writer`](../SeedFu/Writer).
+
+Bugs / Feature requests
+-----------------------
+
+Please report them [on Lighthouse](http://mbleigh.lighthouseapp.com/projects/10223-seed-fu).
+
+Contributors
+------------
+
+* [Michael Bleigh](http://www.mbleigh.com/) is the original author
+* [Jon Leighton](http://jonathanleighton.com/) is the current maintainer
+* Thanks to [Matthew Beale](https://github.com/mixonic) for his great work in adding the writer, making it faster and better.
+
+Copyright © 2008-2010 Michael Bleigh, released under the MIT license
View
@@ -1,125 +0,0 @@
-= Seed Fu
-
-Seed Fu is an attempt to once and for all solve the problem of inserting and maintaining seed data in a database. It uses a variety of techniques gathered from various places around the web and combines them to create what is hopefully the most robust seed data system around.
-
-
-== Simple Usage
-
-Seed data is taken from the <tt>db/fixtures</tt> directory. Simply make descriptive .rb files in that directory (they can be named anything, but users.rb for the User model seed data makes sense, etc.). These scripts will be run whenever the <tt>db:seed</tt> (<tt>db:seed_fu</tt> for Rails 2.3.5 and greater) rake task is called, and in order (you can use <tt>00_first.rb</tt>, <tt>00_second.rb</tt>, etc). You can put arbitrary Ruby code in these files, but remember that it will be executed every time the rake task is called, so it needs to be runnable multiple times on the same database.
-
-You can also have environment-specific seed data placed in <tt>db/fixtures/ENVIRONMENT</tt> that will only be loaded if that is the current environment.
-
-Let's say we want to populate a few default users. In <tt>db/fixtures/users.rb</tt> we write the following code:
-
- User.seed(:login, :email) do |s|
- s.login = "bob"
- s.email = "bob@bobson.com"
- s.first_name = "Bob"
- s.last_name = "Bobson"
- end
-
- User.seed(:login, :email) do |s|
- s.login = "bob"
- s.email = "bob@stevenson.com"
- s.first_name = "Bob"
- s.last_name = "Stevenson"
- end
-
-That's all you have to do! You will now have two users created in the system and you can change their first and last names in the users.rb file and it will be updated as such.
-
-The arguments passed to the <tt><ActiveRecord>.seed</tt> method are the constraining attributes: these must remain unchanged between db:seed calls to avoid data duplication. By default, seed data will constrain to the id like so:
-
- Category.seed do |s|
- s.id = 1
- s.name = "Buttons"
- end
-
- Category.seed do |s|
- s.id = 2
- s.name = "Bobbins"
- s.parent_id = 1
- end
-
-Note that any constraints that are passed in must be present in the subsequent seed data setting.
-
-== Seed-many Usage
-
-The default <tt>.seed` syntax is very verbose. An alternative is the `.seed_many</tt> syntax. Look at this refactoring of the first seed usage example above:
-
- User.seed_many(:login, :email, [
- { :login => "bob", :email => "bob@bobson.com", :first_name => "Bob", :last_name = "Bobson" },
- { :login => "bob", :email => "bob@stevenson.com", :first_name => "Bob", :last_name = "Stevenson" }
- ])
-
-Not as pretty, but much more concise.
-
-== Handling Large SeedFu Files
-
-Seed files can be huge. To handle large files (over a million rows), try these tricks:
-
-* Gzip your fixtures. Seed Fu will read .rb.gz files happily. <tt>gzip -9</tt> gives the best compression, and with Seed Fu's repetitive syntax, a 160M file can shrink to 16M.
-* Add lines reading <tt># BREAK EVAL</tt> in your big fixtures, and Seed Fu will avoid loading the whole file into memory. If you use SeedFu::Writer, these breaks are built into your generated fixtures.
-* Load a single fixture with the <tt>SEED</tt> environment variable: <tt>SEED=cities,states rake db:seed > seed_log`. Each argument to `SEED</tt> is used as a regex to filter fixtures by filename.
-
-== Generating SeedFu Files
-
-Say you have a CSV you need to massage and store as seed files. You can create an import script using SeedFu::Writer.
-
- #!/usr/bin/env ruby
- #
- # This is: script/generate_cities_seed_from_csv
- #
- require 'rubygems'
- require 'fastercsv'
- require File.join( File.dirname(__FILE__), '..', 'vendor/plugins/seed-fu/lib/seed-fu/writer' )
-
- # Maybe SEEF_FILE could be $stdout, hm.
- #
- CITY_CSV = File.join( File.dirname(__FILE__), '..', 'city.csv' )
- SEED_FILE = File.join( File.dirname(__FILE__), '..', 'db', 'fixtures', 'cities.rb' )
-
- # Create a seed_writer, walk the CSV, add to the file.
- #
-
- seed_writer = SeedFu::Writer::SeedMany.new(
- :seed_file => SEED_FILE,
- :seed_model => 'City',
- :seed_by => [ :city, :state ]
- )
-
- FasterCSV.foreach( CITY_CSV,
- :return_headers => false,
- :headers => :first_row
- ) do |row|
-
- # Skip all but the US
- #
- next unless row['country_code'] == 'US'
-
- unless us_state
- puts "No State Match for #{row['region_name']}"
- next
- end
-
- # Write the seed
- #
- seed_writer.add_seed({
- :zip => row['zipcode'],
- :state => row['state'],
- :city => row['city'],
- :latitude => row['latitude'],
- :longitude => row['longitude']
- })
-
- end
-
- seed_writer.finish
-
-There is also a SeedFu::Writer::Seed in case you prefere the seed()
-syntax over the seen_many() syntax. Easy-peasy.
-
-== Contributors
-
-* Thanks to Matthew Beale for his great work in adding the writer, making it faster and better.
-
-Copyright (c) 2008-2009 Michael Bleigh released under the MIT license
View
@@ -9,19 +9,27 @@ module SeedFu
autoload :Runner, 'seed-fu/runner'
autoload :Writer, 'seed-fu/writer'
- # Turn off the output when seeding data
mattr_accessor :quiet
+
+ # Set `SeedFu.quiet = true` to silence all output
@@quiet = false
- # The locations of fixtures
mattr_accessor :fixture_paths
+
+ # Set this to be an array of paths to directories containing your seed files. If used as a Rails
+ # plugin, SeedFu will set to to contain `Rails.root/db/fixtures` and
+ # `Rails.root/db/fixtures/Rails.env`
@@fixture_paths = ['db/fixtures']
- def self.seed(fixture_paths = nil, filter = nil)
+ # Load seed data from files
+ # @param [Array] fixture_paths The paths to look for seed files in
+ # @param [Regexp] filter If given, only filenames matching this expression will be loaded
+ def self.seed(fixture_paths = SeedFu.fixture_paths, filter = nil)
Runner.new(fixture_paths, filter).run
end
end
+# @public
class ActiveRecord::Base
extend SeedFu::ActiveRecordExtension
end
@@ -1,14 +1,50 @@
module SeedFu
module ActiveRecordExtension
+ # Load some seed data. There are two ways to do this.
+ #
+ # Verbose syntax
+ # --------------
+ #
+ # This will seed a single record. The `:id` parameter ensures that if a record already exists
+ # in the database with the same id, then it will be updated with the name and age, rather
+ # than created from scratch.
+ #
+ # Person.seed(:id) do |s|
+ # s.id = 1
+ # s.name = "Jon"
+ # s.age = 21
+ # end
+ #
+ # Note that `:id` is the default attribute used to identify a seed, so it need not be
+ # specified.
+ #
+ # Terse syntax
+ # ------------
+ #
+ # This is a more succinct way to load multiple records. Note that both `:x` and `:y` are being
+ # used to identify a seed here.
+ #
+ # Point.seed(:x, :y,
+ # { :x => 3, :y => 10, :name => "Home" },
+ # { :x => 5, :y => 9, :name => "Office" }
+ # )
def seed(*args, &block)
SeedFu::Seeder.new(self, *parse_seed_fu_args(args, block)).seed
end
+ # Has the same syntax as {#seed}, but if a record already exists with the same values for
+ # constraining attributes, it will not be updated.
+ #
+ # @example
+ # Person.seed(:id, :id => 1, :name => "Jon") # => Record created
+ # Person.seed(:id, :id => 1, :name => "Bob") # => Name changed
+ # Person.seed(:id, :id => 1, :name => "Harry") # => Name *not* changed
def seed_once(*args, &block)
constraints, data = parse_seed_fu_args(args, block)
SeedFu::Seeder.new(self, constraints, data, :insert_only => true).seed
end
+ # @deprecated Use {#seed} instead
def seed_many(*args, &block)
puts "DEPRECATED: Model.seed_many is deprecated. You can now use Model.seed in exactly the same way." unless SeedFu.quiet
seed(*args, &block)
@@ -1,4 +1,5 @@
module SeedFu
+ # @private
class BlockHash
def initialize(proc)
@hash = {}
Oops, something went wrong.

0 comments on commit 747bd3a

Please sign in to comment.