csv-omg 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []