csvision 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # CSVision
2
2
 
3
+ [![Build Status](https://secure.travis-ci.org/cloverinteractive/csvision.png?branch=master)](http://travis-ci.org/cloverinteractive/csvision)
4
+
3
5
  Convert a Hash into a CSV the easy way.
4
6
 
5
7
  ## Installation
@@ -18,20 +20,20 @@ Or install it yourself as:
18
20
 
19
21
  ## Usage
20
22
 
21
- CSVision has no prerequisites other than ruby itself, which is pretty cool just include the `CSVision` module into your app and you'll be good to go.
23
+ CSVision has no prerequisites other than ruby itself, which is pretty cool just include the `csvision` gem in your app and you'll be good to go.
22
24
 
23
25
  ### Hash
24
26
 
25
- CSVision adds to `Hash` the `to_csv` method, anything that inherits from `Hash` will inherit this method as well, you do not need to open `Hash` and include `CSVision` in it, just add it anywhere in your code.
27
+ CSVision adds to `Hash` the `to_csv` method, anything that inherits from `Hash` will inherit this method as well, you do not need to open `Hash` and include `CSVision` in it, just require the library in your code.
26
28
 
27
29
  ```ruby
28
- include CSVision
30
+ require 'csvision'
29
31
  sample = { :name => 'foo', :last_name => 'bar', :age => 10 }
30
32
  sample.to_csv #=> "\"last_name\",\"name\",\"age\"\n\"bar\",\"foo\",\"10\""
31
33
  ```
32
34
  ### Rails
33
35
 
34
- CSVision adds the Rails the methods:
36
+ CSVision adds the following methods to Rails:
35
37
 
36
38
  1. `to_csv` at the model instance
37
39
  2. `to_csv` at the model class
@@ -53,11 +55,147 @@ CSVision lets you customize the way your CSV is formed, you can use any of the f
53
55
  3. `:delimeter` this set the field delimeter and it defaults to `"`
54
56
  4. `:separator` this set the field separator and it defults to `,`
55
57
 
58
+ That's good and all but, you never want to just convert a single object to csv but collections instead, so imagine this model instead:
59
+
60
+ ```ruby
61
+ class User < ActiveRecord::Base
62
+ add_csvision :csv_headers => %w/street_cred nickname incognito/, :body => lambda { |u| [ u.street_cred, u.nickname, u.incognito ] }
63
+
64
+ scope :flunky, where( 'points <= 5' )
65
+
66
+ def incognito
67
+ nickname.reverse
68
+ end
69
+
70
+ def street_cred
71
+ points * 100 + ( nickname_cred )
72
+ end
73
+
74
+ private
75
+ def nickname_cred
76
+ nickname.unpack( 'U' * nickname.length ).sum # good nickname equals more street cred
77
+ end
78
+ end
79
+ ```
80
+
81
+ You can use the `:headers` option to set your header names, and the `:body` option to specify the methods or properties from the option you want
82
+ called in your csv, this gives you flexibility to choose how your csv is formed and from what it is formed, so this is an example of how this works.
83
+
84
+ ```ruby
85
+ 5.times { |i| User.create( :nickname => "user#{ i * 3 }", :points => i * 5 ) }
86
+ puts User.to_csv
87
+ ```
88
+
89
+ this will print:
90
+
91
+ ```
92
+ "street_cred","nickname","incognito"
93
+ "495","user0","0resu"
94
+ "998","user3","3resu"
95
+ "1501","user6","6resu"
96
+ "2004","user9","9resu"
97
+ "2546","user12","21resu"
98
+ ```
99
+
100
+ You can chain active record calls and even scopes in to your mix, so consider:
101
+
102
+ ```ruby
103
+ 5.times { |i| User.create( :nickname => "user#{ i * 3 }", :points => i *5 ) }
104
+ puts User.flunky.to_csv
105
+ ```
106
+ will print:
107
+
108
+ ```
109
+ "street_cred","nickname","incognito"
110
+ "495","user0","0resu"
111
+ "998","user3","3resu"
112
+ "1501","user6","6resu"
113
+ ```
114
+
115
+ Lastly, with the exception of `:except` and `:only` which will be ignore because you're setting the body manually all other option work:
116
+
117
+ ```ruby
118
+ 5.times { |i| User.create( :nickname => "user#{ i * 3 }", :points => i *5 ) }
119
+ puts User.to_csv( :headers => false )
120
+ ```
121
+
122
+ Will print:
123
+
124
+ ```
125
+ "495","user0","0resu"
126
+ "998","user3","3resu"
127
+ "1501","user6","6resu"
128
+ "2004","user9","9resu"
129
+ "2546","user12","21resu"
130
+ ```
131
+
132
+ ### Outside of Rails
133
+
134
+ Anything that inherits from `Hash` will `respond_to? :to_csv` however if you want to use this in any other regular class make sure you do the following:
135
+
136
+ 1. Create a `Hash` attribute named `attributes`.
137
+ 2. You'll need to have a class `count` and `find_each` methods if you want support for setting the `body`.
138
+ 3. `include CSVision` in your class.
139
+
140
+ ```ruby
141
+ class SampleStack
142
+ include CSVision
143
+ attr_accessor :attributes, :count
144
+
145
+ add_csvision :csv_headers => %w/price name/, :body => lambda { |s| [ s[:name], s[:price] ] }
146
+
147
+ def initialize( attributes={}, inventory = [] )
148
+ @attributes = attributes
149
+ @@inventory = inventory
150
+ end
151
+
152
+ def self.count
153
+ @@inventory.size
154
+ end
155
+
156
+ def self.find_each( opts={} )
157
+ @@inventory.each do |item|
158
+ yield item
159
+ end
160
+ end
161
+ end
162
+ ```
163
+
164
+ After wards imagine the following:
165
+
166
+ ```ruby
167
+ sample_stack = SampleStack.new( :foo => 'foo', :bar => 'bar' )
168
+ puts sample_stack.to_csv
169
+ ```
170
+
171
+ Will print:
172
+
173
+ ```
174
+ "foo","bar"
175
+ "foo","bar"
176
+ ```
177
+
178
+ But more importantly `to_csv` at the class level will:
179
+
180
+ ```ruby
181
+ inventory = [ { :name => 'beer', :price => 9 }, { :name => 'milk', :price => 5 }, { :name => 'tuna', :price => 3 } ]
182
+ sample_stack = SampleStack.new({ :name => 'groceries'}, inventory)
183
+ puts SampleStack.to_csv
184
+ ```
185
+
186
+ Prints:
187
+
188
+ ```
189
+ "price","name"
190
+ "beer","9"
191
+ "milk","5"
192
+ "tuna","3"
193
+ ```
194
+
56
195
  ## TODO:
57
196
 
58
- 1. Allow users to set their own list of parameters
59
- 2. Add support for other ORM's
60
- 3. Rails 3.x responder.
197
+ 1. Add support for other ORM's
198
+ 2. Rails 3.x responder.
61
199
 
62
200
 
63
201
  ## Contributing
data/csvision.gemspec CHANGED
@@ -19,7 +19,6 @@ Gem::Specification.new do |gem|
19
19
  gem.add_development_dependency 'activerecord'
20
20
  gem.add_development_dependency 'activesupport'
21
21
  gem.add_development_dependency 'sqlite3'
22
- gem.add_development_dependency 'mocha'
23
22
  gem.add_development_dependency 'rake'
24
23
  gem.add_development_dependency 'turn', '0.8.2'
25
24
  end
data/lib/csvision.rb CHANGED
@@ -2,6 +2,10 @@ require "csvision/version"
2
2
  require "csvision/csv_helper"
3
3
 
4
4
  module CSVision
5
- ::ActiveRecord::Base.send( :extend, CSVHelper ) if defined? ::ActiveRecord::Base
6
- ::Hash.send( :include, CSVHelper::InstanceMethods )
5
+ def self.included(base)
6
+ base.extend CSVHelper
7
+ end
7
8
  end
9
+
10
+ ActiveRecord::Base.send( :include, CSVision ) if defined? ActiveRecord::Base
11
+ Hash.send( :include, CSVision::CSVHelper::InstanceMethods )
@@ -1,38 +1,43 @@
1
1
  module CSVision
2
- def self.included(base)
3
- base.extend CSVHelper
4
- end
5
-
6
2
  module CSVHelper
7
3
  def add_csvision(options={})
8
4
  return if included_modules.include? InstanceMethods
9
- cattr_accessor :csv_except, :csv_only, :csv_delimeter, :csv_separator, :csv_headers
5
+ cattr_accessor :csv_except, :csv_only, :csv_delimeter, :csv_separator, :csv_headers, :body
10
6
 
11
7
  self.csv_only = options[:only]
12
8
  self.csv_except = options[:except]
13
9
  self.csv_delimeter = options[:delimeter] || '"'
14
10
  self.csv_separator = options[:separator] || ','
11
+ self.csv_headers = options[:csv_headers]
12
+ self.body = options[:body]
15
13
 
16
14
  include InstanceMethods
17
15
  extend ClassMethods
18
16
  end
19
17
 
20
18
  module ClassMethods
21
- def to_csv(options={})
22
- options[:headers] ||= true
23
- headers, csv_array = nil, []
19
+ def to_csv(options={ :headers => true, :batch_size => 100 })
20
+ options[:delimeter] ||= csv_delimeter
21
+ options[:separator] ||= csv_separator
22
+ options[:batch_size] ||= 100
24
23
 
25
- self.find_each(:batch_size => options[:batch_size]) do |object|
26
- headers ||= object.csvize( object.attributes.only( *csv_only ).keys, options ) if csv_only && !csv_only.empty?
27
- headers ||= object.csvize( object.attributes.except( *csv_except ).keys, options ) if csv_except && !csv_except.empty?
24
+ unless self.count < 1
25
+ headers, csv_array = nil, []
26
+ self.find_each :batch_size => options[:batch_size] do |object|
27
+ unless self.body
28
+ headers ||= object.csvize( object.attributes.only( *csv_only ).keys, options ) if csv_only && !csv_only.empty?
29
+ headers ||= object.csvize( object.attributes.except( *csv_except ).keys, options ) if csv_except && !csv_except.empty?
28
30
 
29
- csv_array << object.to_csv( options.merge(:headers => false) )
30
- end
31
- content = csv_array.join("\n")
31
+ csv_array << object.to_csv( options.merge(:headers => false) )
32
+ else
33
+ values = self.body.call object
34
+ headers ||= object.csvize( self.csv_headers, options ) if self.csv_headers
35
+ csv_array << object.csvize( values, options )
36
+ end
37
+ end
32
38
 
33
- if options[:headers]
34
- headers + "\n" + content
35
- else
39
+ content = csv_array.join("\n")
40
+ return headers + "\n" + content if options[:headers]
36
41
  content
37
42
  end
38
43
  end
@@ -61,7 +66,7 @@ module CSVision
61
66
  @csv += csvize(values, options)
62
67
  end
63
68
 
64
- def csvize(values, options)
69
+ def csvize(values, options={})
65
70
  delimeter = options[:delimeter] || csv_delimeter
66
71
  separator = options[:separator] || csv_separator
67
72
 
@@ -1,3 +1,3 @@
1
1
  module CSVision
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,21 @@
1
+ class SampleStack
2
+ include CSVision
3
+ attr_accessor :attributes
4
+
5
+ add_csvision :csv_headers => %w/price name/, :body => lambda { |s| [ s[:name], s[:price] ] }
6
+
7
+ def initialize( attributes={}, inventory = [] )
8
+ @attributes = attributes
9
+ @@inventory = inventory
10
+ end
11
+
12
+ def self.count
13
+ @@inventory.size
14
+ end
15
+
16
+ def self.find_each( opts={} )
17
+ @@inventory.each do |item|
18
+ yield item
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ class User < ActiveRecord::Base
2
+ add_csvision :csv_headers => %w/street_cred nickname incognito/, :body => lambda { |u| [ u.street_cred, u.nickname, u.incognito ] }
3
+
4
+ scope :flunky, where( 'points <= 5' )
5
+
6
+ def incognito
7
+ nickname.reverse
8
+ end
9
+
10
+ def street_cred
11
+ points * 100 + ( nickname_cred )
12
+ end
13
+
14
+ private
15
+ def nickname_cred
16
+ nickname.unpack( 'U' * nickname.length ).sum # good nickname equals more street cred
17
+ end
18
+ end
data/test/db/schema.rb CHANGED
@@ -8,4 +8,9 @@ ActiveRecord::Schema.define do
8
8
  t.datetime "created_at"
9
9
  t.datetime "updated_at"
10
10
  end
11
+
12
+ create_table "users", :force => true do |t|
13
+ t.string "nickname"
14
+ t.integer "points"
15
+ end
11
16
  end
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+
3
+ class OutsideOfRails < ActiveSupport::TestCase
4
+ EXPECTED_CSV = <<-CSV
5
+ "price","name"
6
+ "beer","9"
7
+ "milk","5"
8
+ "tuna","3"
9
+ CSV
10
+
11
+ EXPECTED_CSV_WITHOUT_HEADERS = <<-CSV
12
+ "beer","9"
13
+ "milk","5"
14
+ "tuna","3"
15
+ CSV
16
+
17
+ def setup
18
+ assert @inventory = [
19
+ { :name => 'beer', :price => 9 },
20
+ { :name => 'milk', :price => 5 },
21
+ { :name => 'tuna', :price => 3 } ]
22
+ end
23
+
24
+ test "can use csvsion on POROS" do
25
+ assert sample_stack = SampleStack.new( :foo => 'foo', :bar => 'bar' )
26
+ assert sample_stack.respond_to?( :to_csv )
27
+ assert csv = sample_stack.to_csv( :headers => false )
28
+ assert_match /foo/, csv
29
+ assert_match /bar/, csv
30
+ end
31
+
32
+ test "can make use of class methods" do
33
+ assert sample_stack = SampleStack.new({ :name => 'groceries'}, @inventory)
34
+ assert SampleStack.respond_to?( :to_csv )
35
+ assert csv = SampleStack.to_csv
36
+ assert_equal EXPECTED_CSV.chomp, csv
37
+ end
38
+
39
+ test "can use option filters on POROS" do
40
+ assert sample_stack = SampleStack.new({ :name => 'groceries'}, @inventory)
41
+ assert csv = SampleStack.to_csv( :headers => false )
42
+ assert_equal EXPECTED_CSV_WITHOUT_HEADERS.chomp, csv
43
+ end
44
+ end
data/test/test_helper.rb CHANGED
@@ -1,14 +1,12 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
- require 'csvision'
4
3
  require 'test/unit'
5
4
  require 'active_record'
6
5
  require 'active_support'
7
6
  require 'active_support/dependencies'
7
+ require 'csvision'
8
8
  require 'turn'
9
9
 
10
- include CSVision
11
-
12
10
  TEST_PATH = File.expand_path( File.join File.dirname( __FILE__ ) )
13
11
  config = YAML::load( IO.read( File.join TEST_PATH, 'config', 'database.yml' ) )['test']['sqlite']
14
12
 
@@ -19,3 +17,10 @@ ActiveRecord::Base.silence do
19
17
  ActiveRecord::Migration.verbose = false
20
18
  load File.join( TEST_PATH, 'db','schema.rb' )
21
19
  end
20
+
21
+ class ActiveSupport::TestCase
22
+ def teardown
23
+ User.delete_all
24
+ Product.delete_all
25
+ end
26
+ end
data/test/user_test.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'test_helper'
2
+
3
+ class UserTest < ActiveSupport::TestCase
4
+ EXPECTED_CSV = <<-CSV
5
+ "street_cred","nickname","incognito"
6
+ "495","user0","0resu"
7
+ "998","user3","3resu"
8
+ "1501","user6","6resu"
9
+ "2004","user9","9resu"
10
+ "2546","user12","21resu"
11
+ CSV
12
+
13
+ EXPECTED_CSV_WITH_SCOPE = <<-CSV
14
+ "street_cred","nickname","incognito"
15
+ "495","user0","0resu"
16
+ "998","user3","3resu"
17
+ "1501","user6","6resu"
18
+ CSV
19
+
20
+ EXPECTED_CSV_WITHOUT_HEADERS = <<-CSV
21
+ "495","user0","0resu"
22
+ "998","user3","3resu"
23
+ "1501","user6","6resu"
24
+ "2004","user9","9resu"
25
+ "2546","user12","21resu"
26
+ CSV
27
+
28
+ def setup
29
+ 5.times { |i| assert User.create( :nickname => "user#{ i * 3}", :points => i * 5 ) }
30
+ end
31
+
32
+ test "can call to_csv directly from model" do
33
+ assert User.respond_to?(:to_csv)
34
+ assert csv = User.to_csv
35
+ assert_equal EXPECTED_CSV.chomp, csv
36
+ end
37
+
38
+ test "can chain scopes into the csv call" do
39
+ assert csv = User.flunky.to_csv
40
+ assert EXPECTED_CSV_WITH_SCOPE.chomp, csv
41
+ end
42
+
43
+ test "can pass options to t_csv" do
44
+ assert csv = User.to_csv( :headers => false )
45
+ assert_equal EXPECTED_CSV_WITHOUT_HEADERS.chomp, csv
46
+ end
47
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csvision
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Enrique Vidal
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-04-10 00:00:00 Z
18
+ date: 2012-04-14 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activerecord
@@ -60,7 +60,7 @@ dependencies:
60
60
  type: :development
61
61
  version_requirements: *id003
62
62
  - !ruby/object:Gem::Dependency
63
- name: mocha
63
+ name: rake
64
64
  prerelease: false
65
65
  requirement: &id004 !ruby/object:Gem::Requirement
66
66
  none: false
@@ -73,24 +73,10 @@ dependencies:
73
73
  version: "0"
74
74
  type: :development
75
75
  version_requirements: *id004
76
- - !ruby/object:Gem::Dependency
77
- name: rake
78
- prerelease: false
79
- requirement: &id005 !ruby/object:Gem::Requirement
80
- none: false
81
- requirements:
82
- - - ">="
83
- - !ruby/object:Gem::Version
84
- hash: 3
85
- segments:
86
- - 0
87
- version: "0"
88
- type: :development
89
- version_requirements: *id005
90
76
  - !ruby/object:Gem::Dependency
91
77
  name: turn
92
78
  prerelease: false
93
- requirement: &id006 !ruby/object:Gem::Requirement
79
+ requirement: &id005 !ruby/object:Gem::Requirement
94
80
  none: false
95
81
  requirements:
96
82
  - - "="
@@ -102,7 +88,7 @@ dependencies:
102
88
  - 2
103
89
  version: 0.8.2
104
90
  type: :development
105
- version_requirements: *id006
91
+ version_requirements: *id005
106
92
  description: Gives Hash the ability to be turned into csv files
107
93
  email:
108
94
  - enrique@cloverinteractive.com
@@ -123,11 +109,15 @@ files:
123
109
  - lib/csvision/csv_helper.rb
124
110
  - lib/csvision/version.rb
125
111
  - test/app/models/product.rb
112
+ - test/app/models/sample_stack.rb
113
+ - test/app/models/user.rb
126
114
  - test/config/database.yml
127
115
  - test/csvision_test.rb
128
116
  - test/db/schema.rb
117
+ - test/outside_of_rails_test.rb
129
118
  - test/product_test.rb
130
119
  - test/test_helper.rb
120
+ - test/user_test.rb
131
121
  homepage: http://cloverinteractive.github.com/csvision/
132
122
  licenses: []
133
123
 
@@ -163,8 +153,13 @@ specification_version: 3
163
153
  summary: Adds support to hashes to be turned into csv
164
154
  test_files:
165
155
  - test/app/models/product.rb
156
+ - test/app/models/sample_stack.rb
157
+ - test/app/models/user.rb
166
158
  - test/config/database.yml
167
159
  - test/csvision_test.rb
168
160
  - test/db/schema.rb
161
+ - test/outside_of_rails_test.rb
169
162
  - test/product_test.rb
170
163
  - test/test_helper.rb
164
+ - test/user_test.rb
165
+ has_rdoc: