csv-omg 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2@csv-omg
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in csv-omg.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Gert Goet, ThinkCreate
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,70 @@
1
+ Overview [![stillmaintained](http://stillmaintained.com/eval/csv-omg.png)](http://stillmaintained.com/eval/csv-omg)
2
+ ========
3
+
4
+ CsvOmg (formerly known as [csvmapper](https://github.com/thinkcreate/csvmapper)) easily lets you map CSV to objects. Inspired by [happymapper](https://github.com/jnunemaker/happymapper).
5
+ Please check out the example below and included tests to see how it works.
6
+
7
+
8
+ Examples
9
+ -----
10
+
11
+ module Shop
12
+ class Product
13
+ include CsvOmg
14
+
15
+ column :name, 'product_name'
16
+ column :uid, 'product_uid', Integer
17
+ column :description, 2
18
+ column(:price_in_cents, 'product_price', Float){|float| (float * 100).round }
19
+
20
+ end
21
+ end
22
+
23
+ csv =<<-CSV.gsub(/^ +/,'')
24
+ product_uid,product_name,product_description,product_price
25
+ 1200,Ham,like you never tasted before,19.99
26
+ CSV
27
+
28
+ p1 = Shop::Product.parse(csv).first
29
+ p1.price_in_cents # 1999
30
+
31
+ Requirements
32
+ ------------
33
+
34
+ [FasterCSV](https://rubygems.org/gems/fastercsv)
35
+
36
+ Installation
37
+ ------------
38
+
39
+ $ gem install csv-omg
40
+
41
+ Author
42
+ ------
43
+
44
+ Gert Goet (eval) :: gert@thinkcreate.nl :: @gertgoet
45
+
46
+ License
47
+ ------
48
+
49
+ (The MIT license)
50
+
51
+ Copyright (c) 2011 Gert Goet, ThinkCreate
52
+
53
+ Permission is hereby granted, free of charge, to any person obtaining
54
+ a copy of this software and associated documentation files (the
55
+ "Software"), to deal in the Software without restriction, including
56
+ without limitation the rights to use, copy, modify, merge, publish,
57
+ distribute, sublicense, and/or sell copies of the Software, and to
58
+ permit persons to whom the Software is furnished to do so, subject to
59
+ the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be
62
+ included in all copies or substantial portions of the Software.
63
+
64
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
65
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
66
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
67
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
68
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
69
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
70
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.libs << 'lib' << 'test'
7
+ t.pattern = 'test/**/*_test.rb'
8
+ t.verbose = false
9
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "csv-omg/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "csv-omg"
7
+ s.version = CsvOmg::Version
8
+ s.date = Time.now.strftime('%Y-%m-%d')
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ["Gert Goet"]
11
+ s.email = ["gert@thinkcreate.nl"]
12
+ s.homepage = "http://github.com/eval/csv-omg"
13
+ s.summary = %q{Easily map CSV to objects}
14
+ s.description = <<desc
15
+ CsvOmg easily lets you map CSV to objects. Inspired by happymapper.
16
+ desc
17
+
18
+ s.rubyforge_project = "csv-omg"
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ s.require_paths = ["lib"]
24
+
25
+ s.add_dependency('fastercsv', '~>1.5.4')
26
+
27
+ s.add_development_dependency('test-spec', '~>0.10.0')
28
+ s.add_development_dependency('rr', '~>1.0.2')
29
+ s.add_development_dependency('activerecord', '~>3.0.6')
30
+ s.add_development_dependency('sqlite3', '~>1.3.3')
31
+ end
@@ -0,0 +1,92 @@
1
+ require 'fastercsv'
2
+
3
+ module CsvOmg
4
+
5
+ class Column < Struct.new(:attr, :source, :type, :conversion);end
6
+
7
+ def self.included(base)
8
+ base.instance_variable_set("@_columns", {})
9
+ base.instance_variable_set("@_parser_options", {
10
+ :headers => true,
11
+ :skip_blanks => true
12
+ })
13
+ base.extend ClassMethods
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ def parse(contents, parser_opts={})
19
+ @_parser_options.merge!(parser_opts)
20
+
21
+ instances = []
22
+ parser = FasterCSV.new(contents, @_parser_options)
23
+
24
+ parser.each do |line|
25
+ instance = new
26
+
27
+ @_columns.values.each do |column|
28
+ raw_value = line[column[:source]]
29
+
30
+ value = column_value(raw_value, column[:type], column[:conversion])
31
+
32
+ instance.send("#{column.attr.to_s}=", value)
33
+ end
34
+ instances << instance
35
+ end
36
+ instances
37
+ end
38
+
39
+ def column(attr, *args, &block)
40
+ attr = attr.to_s
41
+ type = args.delete(([String, Float, Integer, Date, DateTime] & args).first) || String
42
+ source = args.first || attr
43
+
44
+ @_columns[attr] = Column.new(attr, source, type, block)
45
+
46
+ create_accessor(attr)
47
+ end
48
+
49
+ private
50
+ def column_value(raw_value, type, conversion)
51
+ value = begin
52
+ case type.to_s
53
+ when 'Date'
54
+ Date.parse(raw_value) rescue ''
55
+ when 'DateTime'
56
+ DateTime.parse(raw_value) rescue ''
57
+ when 'Float'
58
+ Float(raw_value) rescue 0.0
59
+ when 'Integer'
60
+ Integer(raw_value) rescue 0
61
+ else
62
+ raw_value.to_s
63
+ end
64
+ end
65
+
66
+ conversion ? conversion.call(value) : value
67
+ end
68
+
69
+ def create_getter(name)
70
+ class_eval <<-EOS, __FILE__, __LINE__
71
+ def #{name}
72
+ @#{name}
73
+ end
74
+ EOS
75
+ end
76
+
77
+ def create_setter(name)
78
+ class_eval <<-EOS, __FILE__, __LINE__
79
+ def #{name}=(value)
80
+ @#{name} = value
81
+ end
82
+ EOS
83
+ end
84
+
85
+ def create_accessor(name)
86
+ unless respond_to?('column_names') && column_names.include?(name)
87
+ create_getter(name)
88
+ create_setter(name)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,3 @@
1
+ module CsvOmg
2
+ Version = VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,183 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+
4
+ shared_context 'CsvOmg' do
5
+
6
+ it 'should respond to parse' do
7
+ @klass.should.respond_to(:parse)
8
+ end
9
+
10
+ context '#parse' do
11
+ before { @collection = @klass.parse(@csv)}
12
+ it 'returns array of instances of correct class' do
13
+ @collection.class.should == Array
14
+ @collection.first.class.should == @klass
15
+ end
16
+ end
17
+
18
+ context 'instances' do
19
+ before{ @instance = @klass.new }
20
+
21
+ specify 'have a getter for every column' do
22
+ @instance_expectations.each do |expectations|
23
+ expectations.each do |name, value|
24
+ @instance.should.respond_to(name.to_s)
25
+ end
26
+ end
27
+ end
28
+
29
+ specify 'have a setter for every column' do
30
+ @instance_expectations.each do |expectations|
31
+ expectations.each do |name, value|
32
+ @instance.should.respond_to("#{name}=")
33
+ end
34
+ end
35
+ end
36
+
37
+ context 'returned by #parse' do
38
+
39
+ before { @instances = @klass.parse(@csv).first(@instance_expectations.size)}
40
+
41
+ specify 'have the correct types and values' do
42
+ @instance_expectations.each_with_index do |expectations, ix|
43
+ expectations.each do |name, value|
44
+ var = @instances[ix].send("#{name}")
45
+
46
+ var.class.should == value.class
47
+ var.should == value
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ module Shop
56
+ class Product
57
+ include CsvOmg
58
+
59
+ column(:category, 'product_category', Integer)
60
+ column(:created_on, 2, Date)
61
+ column(:price, 'product_price', Float)
62
+ column(:naam, 'name'){|name| "Mr. #{name}"}
63
+ end
64
+ end
65
+
66
+ context 'simple class' do
67
+ before{
68
+ @klass = Shop::Product
69
+ @csv =<<-CSV.gsub(/^ +/,'')
70
+ name,product_price,created,non_used_column,product_category
71
+ Brown,1000.0,13-12-2008,garbage,1
72
+ Pink,2000.0,14-12-2008,garbage2,2
73
+ CSV
74
+
75
+ @instance_expectations = [
76
+ {
77
+ :price => 1000.0,
78
+ :created_on => Date.parse('13-12-2008'),
79
+ :naam => 'Mr. Brown',
80
+ :category => 1
81
+ },
82
+ {
83
+ :naam => 'Mr. Pink',
84
+ :price => 2000.0,
85
+ :created_on => Date.parse('14-12-2008'),
86
+ :category => 2
87
+ }
88
+ ]
89
+ }
90
+ behaves_like 'CsvOmg'
91
+
92
+ end
93
+
94
+ class Transaction
95
+ include CsvOmg
96
+
97
+ # Price Paid,Stock Symbol,Regulator,Name,City,FDIC Number,Transaction Type,State,Program,Pricing Mechanism,Type of Institution,Total Assets,Date,OTS Number,Description
98
+
99
+ column :symbol, 'Stock Symbol'
100
+ column(:price_in_cents, 'Price Paid') {|raw| raw.to_f * 100 rescue 0.0 }
101
+ column :description, 'Description'
102
+ column :ots, 'OTS Number'
103
+ column :fdic, 'FDIC Number', Integer
104
+ end
105
+
106
+ context 'some more csv' do
107
+ before {
108
+ @klass = Transaction
109
+ @csv = File.open(File.dirname(__FILE__) + '/fixtures/large.csv').read
110
+
111
+ @instance_expectations = [
112
+ {
113
+ :symbol => 'STT',
114
+ :price_in_cents => 200000000000.0,
115
+ :description => 'Preferred Stock w/Warrants',
116
+ :ots => '',
117
+ :fdic => 1111435
118
+ },
119
+ {
120
+ :symbol => 'C',
121
+ :price_in_cents => 2500000000000.0,
122
+ :description => 'Preferred Stock w/Warrants',
123
+ :ots => '',
124
+ :fdic => 1951350
125
+ }
126
+ ]
127
+ }
128
+
129
+ behaves_like 'CsvOmg'
130
+ end
131
+
132
+ require 'active_record'
133
+ require 'sqlite3'
134
+
135
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
136
+
137
+ ActiveRecord::Migration.verbose = false
138
+ ActiveRecord::Schema.define do
139
+ create_table :ar_products do |t|
140
+ t.column :name, :string
141
+ t.column :price, :float
142
+
143
+ t.timestamps
144
+ end
145
+ end
146
+
147
+ class ARProduct < ActiveRecord::Base
148
+ include CsvOmg
149
+
150
+ attr_protected :name
151
+
152
+ column :name
153
+ column :price, 'product_price', Float
154
+ column :uid, 'product_uid', Integer
155
+ column(:created_at, 'product_created', DateTime)
156
+
157
+ end
158
+
159
+ context 'active record class' do
160
+ DBColumn = ActiveRecord::ConnectionAdapters::Column
161
+ before {
162
+ # stub(ARProduct).table_exists?{ true }
163
+ # stub(ARProduct).columns { [
164
+ # DBColumn.new("name", nil, "string", false),
165
+ # DBColumn.new("price", nil, "float", false)
166
+ # ] }
167
+
168
+ @klass = ARProduct
169
+ @csv =<<-CSV.gsub(/^ +/,'')
170
+ name,product_price,product_created,product_uid,product_category
171
+ naam,1000.0,13-12-2008 13:00,1200,1
172
+ line2,2000.0,14-12-2008 14:00,1201,2
173
+ CSV
174
+
175
+ @instance_expectations = [{
176
+ :name => 'naam',
177
+ :price => 1000.0,
178
+ :uid => 1200,
179
+ :created_at => DateTime.parse('13-12-2008 13:00')}
180
+ ]
181
+ }
182
+ behaves_like 'CsvOmg'
183
+ end
@@ -0,0 +1,5 @@
1
+ Price Paid,Stock Symbol,Regulator,Name,City,FDIC Number,Transaction Type,State,Program,Pricing Mechanism,Type of Institution,Total Assets,Date,OTS Number,Description
2
+ 2000000000.00,STT,Federal Reserve,"State
3
+ Street Corporation",Boston,1111435,Purchase,MA,CPP,Par,holding company,276290703000.00,2008-10-28,,Preferred Stock w/Warrants
4
+ 25000000000.00,C,Federal Reserve,Citigroup Inc.,New York,1951350,Purchase,NY,CPP,Par,holding company,1306041994000.00,2008-10-28,,Preferred Stock w/Warrants
5
+ 25000000000.00,WFC,Federal Reserve,Wells Fargo & Company,San Francisco,1120754,Purchase,CA,CPP,Par,holding company,569241620000.00,2008-10-28,,Preferred Stock w/Warrants
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'test/spec'
3
+ require 'rr'
4
+
5
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'csv-omg')
6
+
7
+ class Test::Unit::TestCase
8
+ include RR::Adapters::TestUnit
9
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: csv-omg
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease: !!null
6
+ platform: ruby
7
+ authors:
8
+ - Gert Goet
9
+ autorequire: !!null
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-04-08 00:00:00.000000000 +02:00
13
+ default_executable: !!null
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: fastercsv
17
+ requirement: &22794760 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 1.5.4
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *22794760
26
+ - !ruby/object:Gem::Dependency
27
+ name: test-spec
28
+ requirement: &22794260 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.10.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *22794260
37
+ - !ruby/object:Gem::Dependency
38
+ name: rr
39
+ requirement: &22793800 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 1.0.2
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *22793800
48
+ - !ruby/object:Gem::Dependency
49
+ name: activerecord
50
+ requirement: &22793340 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 3.0.6
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *22793340
59
+ - !ruby/object:Gem::Dependency
60
+ name: sqlite3
61
+ requirement: &22792880 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 1.3.3
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *22792880
70
+ description: ! 'CsvOmg easily lets you map CSV to objects. Inspired by happymapper.
71
+
72
+ '
73
+ email:
74
+ - gert@thinkcreate.nl
75
+ executables: []
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - .gitignore
80
+ - .rvmrc
81
+ - Gemfile
82
+ - LICENSE
83
+ - README.md
84
+ - Rakefile
85
+ - csv-omg.gemspec
86
+ - lib/csv-omg.rb
87
+ - lib/csv-omg/version.rb
88
+ - test/csv_omg_test.rb
89
+ - test/fixtures/large.csv
90
+ - test/test_helper.rb
91
+ has_rdoc: true
92
+ homepage: http://github.com/eval/csv-omg
93
+ licenses: []
94
+ post_install_message: !!null
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project: csv-omg
112
+ rubygems_version: 1.5.0
113
+ signing_key: !!null
114
+ specification_version: 3
115
+ summary: Easily map CSV to objects
116
+ test_files: []