fasterer-csv 0.0.1

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.
Files changed (3) hide show
  1. data/README +0 -0
  2. data/lib/fasterer_csv.rb +223 -0
  3. metadata +63 -0
data/README ADDED
File without changes
@@ -0,0 +1,223 @@
1
+ require 'rubygems'
2
+ require 'stringio'
3
+
4
+ module FastererCSV
5
+
6
+ class Table < Array
7
+
8
+ class << self
9
+ def format_headers(unformatted)
10
+ unformatted.map { |header| Row.to_key(header) }
11
+ end
12
+ end
13
+
14
+ attr_reader :headers
15
+
16
+ def initialize(headers, fail_on_malformed_columns = true)
17
+ @headers = Table.format_headers(headers)
18
+ @fail_on_malformed_columns = fail_on_malformed_columns
19
+ end
20
+
21
+ def <<(row)
22
+ if row.class != Row
23
+ row = Row.new(self, row)
24
+ end
25
+ if @headers.length != row.length
26
+ error = "*** WARNING - COLUMN COUNT MISMATCH - WARNING ***\n*** ROW #{size} : EXPECTED #{@headers.length} : FOUND #{row.length}\n\n"
27
+ len = 0
28
+ headers.each do |header|
29
+ len = header.to_s.length if header.to_s.length > len
30
+ end
31
+ headers.each_with_index do |header, i|
32
+ error << sprintf("%-32s : %s\n", header, row[i])
33
+ end
34
+ puts error
35
+ raise error if @fail_on_malformed_columns
36
+ end
37
+ super(row)
38
+ end
39
+
40
+ end
41
+
42
+ class Row < Array
43
+
44
+ class << self
45
+ def to_key(key)
46
+ key = "#{key}".downcase.gsub(/\s+/, '_')
47
+ key.empty? ? :_ : key.to_sym
48
+ end
49
+ end
50
+
51
+ def headers
52
+ @table.headers
53
+ end
54
+
55
+ def initialize(table, array)
56
+ @table = table
57
+ super(array)
58
+ end
59
+
60
+ def [](i)
61
+ if i.class == Fixnum
62
+ super
63
+ else
64
+ found = headers.index(Row::to_key(i))
65
+ found ? super(found) : nil
66
+ end
67
+ end
68
+
69
+ def []=(key, val)
70
+ if key.class == Fixnum
71
+ super
72
+ else
73
+ key = Row::to_key(key)
74
+ headers << key unless headers.include? key
75
+ found = headers.index(key)
76
+ super(found, val)
77
+ end
78
+ end
79
+
80
+ def in_order(columns)
81
+ columns.map do |column_name|
82
+ self[column_name].nil? ? '\N' : self[column_name]
83
+ end
84
+ end
85
+
86
+ def merge(hsh)
87
+ hsh.each do |key, value|
88
+ self[key] = value
89
+ end
90
+ self
91
+ end
92
+
93
+ def to_hash
94
+ headers.inject({}) do |memo, h|
95
+ memo[h] = self[h]
96
+ memo
97
+ end
98
+ end
99
+ end
100
+
101
+ class << self
102
+
103
+ def headers(file, quot = '~', sep = ',', &block)
104
+ parse_headers(File.open(file, 'r') {|io| io.gets }, quot, sep, &block)
105
+ end
106
+
107
+ def read(file, quot = '~', sep = ',', &block)
108
+ parse(File.open(file, 'r') { |io| io.sysread(File.size(file)) }, quot, sep, &block)
109
+ end
110
+
111
+ def parse_headers(data, quot = '~', sep = ',', &block)
112
+ parse(data, quot, sep, &block).headers
113
+ end
114
+
115
+ def parse(data, quot = '~', sep = ',')
116
+ q, s, row, column, inquot, clean, maybe, table, field = quot[0], sep[0], [], [], false, true, false, nil, true
117
+
118
+ data.each_byte do |c|
119
+ next if c == ?\r
120
+
121
+ if maybe && c == s
122
+ row << column.join
123
+ column.clear
124
+ clean, inquot, maybe, field = true, false, false, true
125
+ elsif maybe && c == ?\n && table.nil?
126
+ row << column.join
127
+ column.clear
128
+ table = Table.new(row)
129
+ row, clean, inquot, maybe, field = [], true, false, false, false
130
+ elsif maybe && c == ?\n
131
+ row << column.join
132
+ column.clear
133
+ table << row
134
+ row, clean, inquot, maybe, field = [], true, false, false, false
135
+ elsif clean && c == q
136
+ inquot, clean = true, false
137
+ elsif maybe && c == q
138
+ column << c.chr
139
+ clean, maybe = false, false
140
+ elsif c == q
141
+ maybe = true
142
+ elsif inquot
143
+ column << c.chr
144
+ clean = false
145
+ elsif c == s
146
+ row << (column.empty? ? nil : column.join)
147
+ column.clear
148
+ clean, field = true, true
149
+ elsif c == ?\n && table.nil?
150
+ row << (column.empty? ? nil : column.join)
151
+ column.clear
152
+ table = Table.new(row)
153
+ row, clean, inquot, field = [], true, false, false
154
+ elsif c == ?\n
155
+ row << (column.empty? ? nil : column.join)
156
+ column.clear
157
+ table << row
158
+ row, clean, inquot, field = [], true, false, false
159
+ else
160
+ column << c.chr
161
+ clean = false
162
+ end
163
+ end
164
+
165
+ if !clean
166
+ if maybe
167
+ row << column.join
168
+ else
169
+ row << (column.empty? ? nil :column.join)
170
+ end
171
+ table << row
172
+ elsif field
173
+ row << (column.empty? ? nil : column.join)
174
+ end
175
+
176
+ table.each do |line|
177
+ yield(line)
178
+ end if block_given?
179
+
180
+ table
181
+ end
182
+
183
+ def quot_row(row, q = '~', s = ',')
184
+ row.map do |val|
185
+ if val.nil?
186
+ ""
187
+ else
188
+ val = String(val)
189
+ if val.length == 0
190
+ q * 2
191
+ else
192
+ val[/[#{q}#{s}\n]/] ? q + val.gsub(q, q * 2) + q : val
193
+ end
194
+ end
195
+ end.join(s) + "\n"
196
+ end
197
+
198
+ class IOWriter
199
+ def initialize(file, quot = '~', sep = ',') @io = file; @quot = quot; @sep = sep end
200
+ def <<(row)
201
+ raise "can only write arrays! #{row.class} #{row.inspect}" unless row.class == Array || row.class == Row
202
+ @io.syswrite FastererCSV::quot_row(row, @quot, @sep);
203
+ row
204
+ end
205
+ end
206
+
207
+ def generate(quot = '~', sep = ',', &block)
208
+ builder = StringIO.new
209
+ write(builder, quot, sep, &block)
210
+ builder.string
211
+ end
212
+
213
+ def write(out, quot = '~', sep = ',', &block)
214
+ if out.class == String
215
+ File.open(out, "w") do |io|
216
+ write(io, quot, sep, &block)
217
+ end
218
+ else
219
+ yield(IOWriter.new(out, quot, sep))
220
+ end
221
+ end
222
+ end
223
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fasterer-csv
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Mason
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-03 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: CSV parsing awesomeness
22
+ email: mason@honk.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README
29
+ files:
30
+ - README
31
+ - lib/fasterer_csv.rb
32
+ has_rdoc: true
33
+ homepage: http://github.com/gnovos/fasterer-csv
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ requirements: []
56
+
57
+ rubyforge_project:
58
+ rubygems_version: 1.3.6
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: A faster implementation fo a CSV parser than FasterCSV
62
+ test_files: []
63
+