Skip to content

Commit

Permalink
First commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
ordinaryzelig committed Jul 20, 2011
0 parents commit d8ec7ef
Show file tree
Hide file tree
Showing 16 changed files with 231 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.gem
.bundle
Gemfile.lock
pkg/*
1 change: 1 addition & 0 deletions .rvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rvm use ruby-1.9.2-p0@mongoid_to_csv
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source "http://rubygems.org"

# Specify your gem's dependencies in mongoid_to_csv.gemspec
gemspec
59 changes: 59 additions & 0 deletions README.rdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
= Mongoid.to_csv

== Description

A simple Mongoid::Base to_csv() class method that preserves scopes.
to_csv() returns the entire contents including the header ready to be written to file.

== Usage

# Assuming a Movie model with title and director_id columns.
Movie.to_csv
# would return:
title,director_id
title,director_id
Black Swan,0
Inception,1
The Fighter,2
The King's Speech,3
The Kids Are All Right,4

Movie.bad.to_csv
# would return:
title,director_id
The Kids Are All Right,4

Note that #to_csv is called like a scope or query. The following will NOT give you the same results:

Movie.all.to_csv

This will use Ruby's Array#to_csv method.

=== Attribute#to_csv

After a model object's attributes are collected, to_csv is called on the resulting array. However, this poses a problem because it will blindly convert the attributes to a string -- i.e. call to_s on them. If one of your attributes is a Date, then calling to_s may produce unwanted output. For example, if you have Date::DATE_FORMATS[:default] = '%d %B, %Y' your dates will have the month written out like 'January', 'February', etc. To counter this, this gem will make an attempt to call to_csv() on each attribute. To get YYYY-MM-DD output, you could do something like:

class Date
def to_csv
strftime('%Y-%m-%d')
end
end

Note that object.send(attribute_name) is used, so datetime fields will be returned as ActiveSupport::TimeWithZone objects.

== TODO

* Options to specify columns to be included (currently, id and timestamp columns are excluded).
* Combine with active_record_to_csv somehow since they are essentially doing the same thing.

== Compatibility

Tested with Mongoid v2.0.2

http://gem-testers.org/gems/mongoid_to_csv

== Related gems

* https://github.com/ordinaryzelig/mongoid_csv
* https://github.com/ordinaryzelig/orm_from_csv
* https://github.com/ordinaryzelig/active_record_to_csv
2 changes: 2 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require 'bundler'
Bundler::GemHelper.install_tasks
35 changes: 35 additions & 0 deletions lib/mongoid_to_csv.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'mongoid'
require 'csv'

module MongoidToCSV
# Return full CSV content with headers as string.
# Defined as class method which will have chained scopes applied.
def to_csv
csv_columns = fields.keys - %w{_id created_at updated_at _type}
header_row = csv_columns.to_csv
records_rows = all.map do |record|
csv_columns.map do |column|
value = record.send(column)
value = value.to_csv if value.respond_to?(:to_csv)
value
end.to_csv
end.join
header_row + records_rows
end
end

module Mongoid::Document
def self.included(target)
target.extend MongoidToCSV
end
end

# Define Relation#to_csv so that method_missing will not
# delegate to array.
class Mongoid::Relation
def to_csv
scoping do
@klass.to_csv
end
end
end
3 changes: 3 additions & 0 deletions lib/mongoid_to_csv/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module MongoidToCSV
VERSION = "0.1.0"
end
27 changes: 27 additions & 0 deletions mongoid_to_csv.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "mongoid_to_csv/version"

Gem::Specification.new do |s|
s.name = "mongoid_to_csv"
s.version = MongoidToCSV::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ["Jared Ning"]
s.email = ["[email protected]"]
s.homepage = "https://github.com/ordinaryzelig/mongoid_to_csv"
s.summary = %q{Simple Mongoid Model to_csv() class method that preserves scopes}
s.description = %q{Simple Mongoid Model to_csv() class method that preserves scopes}

s.rubyforge_project = "mongoid_to_csv"

s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]

s.add_dependency 'mongoid', '>= 2.0.0.rc.7'

s.add_development_dependency 'rspec', '2.6.0'
s.add_development_dependency 'mongo', '>= 1.3.1'
s.add_development_dependency 'bson_ext'
end
9 changes: 9 additions & 0 deletions spec/database.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Initialize/connect.
host = 'localhost'
port = Mongo::Connection::DEFAULT_PORT
database_name = 'mongoid_to_csv'
connection = Mongo::Connection.new(host, port)
# Drop database if it exists.
connection.drop_database(database_name)
db = connection.db(database_name)
Mongoid.database = db
40 changes: 40 additions & 0 deletions spec/mongoid_to_csv_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'spec_helper'

describe MongoidToCSV do

before :all do
[
'Black Swan',
'Inception',
'The Fighter',
"The King's Speech",
'The Kids Are All Right'
].each_with_index do |title, i|
Movie.create!(
:title => title,
:released_on => Date.new(2010, 1, i + 1)
)
end
end

it 'should convert records to csv' do
Movie.to_csv.should eq(content_of(fixtures_file('movies.csv')))
end

it' should preserve scope' do
Movie.bad.to_csv.should eq(content_of(fixtures_file('movies_bad.csv')))
end

it 'should not include id and timestamp fields' do
header = Movie.to_csv.lines.first
header.should_not =~ /^id|created_at|updated_at/
end

it 'should call to_csv on each attribute if it responds to it' do
date = Movie.limit(1).first.released_on
csv_string = Movie.limit(1).to_csv
csv_string.should include(date.to_csv)
csv_string.should_not include(date.to_s)
end

end
12 changes: 12 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require 'pathname'

require File.join(Pathname(__FILE__).dirname.expand_path, '../lib/mongoid_to_csv')

require 'database'

# require support .rb files.
Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}

RSpec.configure do |config|
config.include Macros
end
6 changes: 6 additions & 0 deletions spec/support/fixtures/movies.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
title,released_on
Black Swan,2010/01/01
Inception,2010/01/02
The Fighter,2010/01/03
The King's Speech,2010/01/04
The Kids Are All Right,2010/01/05
2 changes: 2 additions & 0 deletions spec/support/fixtures/movies_bad.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
title,released_on
The Kids Are All Right,2010/01/05
11 changes: 11 additions & 0 deletions spec/support/macros.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Macros

def content_of(file)
file.read
end

def fixtures_file(file_name)
File.open(File.join(Pathname(__FILE__).dirname.expand_path, 'fixtures', file_name))
end

end
5 changes: 5 additions & 0 deletions spec/support/models/date.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Date
def to_csv
strftime('%Y/%m/%d')
end
end
11 changes: 11 additions & 0 deletions spec/support/models/movie.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Movie

include Mongoid::Document

field :title
field :released_on, type: Date
include Mongoid::Timestamps

scope :bad, where(:title => 'The Kids Are All Right')

end

0 comments on commit d8ec7ef

Please sign in to comment.