csv_madness 0.0.6 → 0.0.10
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.
Potentially problematic release.
This version of csv_madness might be problematic. Click here for more details.
- checksums.yaml +5 -13
- data/.document +5 -0
- data/CHANGELOG.markdown +4 -0
- data/Gemfile +2 -8
- data/README.rdoc +55 -47
- data/Rakefile +10 -49
- data/VERSION +1 -1
- data/lib/csv_madness/builder.rb +95 -10
- data/lib/csv_madness/column.rb +30 -0
- data/lib/csv_madness/column_methods/core_methods.rb +6 -0
- data/lib/csv_madness/column_methods/default_value_methods.rb +7 -0
- data/lib/csv_madness/column_methods/error_methods.rb +19 -0
- data/lib/csv_madness/column_methods/fetch_methods.rb +11 -0
- data/lib/csv_madness/column_methods/typing_methods.rb +24 -0
- data/lib/csv_madness/column_set.rb +5 -0
- data/lib/csv_madness/column_type.rb +74 -0
- data/lib/csv_madness/column_types/date.rb +14 -0
- data/lib/csv_madness/column_types/float.rb +25 -0
- data/lib/csv_madness/column_types/integer.rb +17 -0
- data/lib/csv_madness/column_types/string.rb +9 -0
- data/lib/csv_madness/data_accessor_module.rb +79 -44
- data/lib/csv_madness/exceptions.rb +16 -0
- data/lib/csv_madness/gem_api.rb +11 -2
- data/lib/csv_madness/index_set.rb +36 -0
- data/lib/csv_madness/indexer.rb +105 -0
- data/lib/csv_madness/record.rb +68 -40
- data/lib/csv_madness/record_filter.rb +68 -0
- data/lib/csv_madness/record_methods/method_methods.rb +57 -0
- data/lib/csv_madness/sheet.rb +172 -442
- data/lib/csv_madness/sheet_methods/base.rb +6 -0
- data/lib/csv_madness/sheet_methods/class_methods.rb +84 -0
- data/lib/csv_madness/sheet_methods/column_methods.rb +175 -0
- data/lib/csv_madness/sheet_methods/file_methods.rb +44 -0
- data/lib/csv_madness/sheet_methods/indexing.rb +133 -0
- data/lib/csv_madness/sheet_methods/record_methods.rb +175 -0
- data/lib/csv_madness/sheet_methods/sorting_methods.rb +10 -0
- data/lib/csv_madness/utils/const_proc.rb +19 -0
- data/lib/csv_madness/utils/counter.rb +24 -0
- data/lib/csv_madness/utils/counter_proc.rb +31 -0
- data/lib/csv_madness/utils/looker_upper.rb +36 -0
- data/lib/csv_madness.rb +2 -2
- data/test/csv/nil_headers.csv +5 -0
- data/test/csv/out/.gitkeep +0 -0
- data/test/csv/pokemon.csv +9 -0
- data/test/csv/test_column_types.csv +2 -2
- data/test/helper.rb +13 -5
- data/test/test_builder.rb +43 -3
- data/test/test_csv_madness.rb +34 -25
- data/test/test_index_set.rb +30 -0
- data/test/test_indexer.rb +50 -0
- data/test/test_reloading_spreadsheet.rb +5 -2
- data/test/test_sheet.rb +184 -37
- data/test/test_utils.rb +99 -0
- metadata +82 -36
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module CsvMadness
|
|
2
|
+
module Utils
|
|
3
|
+
# Fast insert/remove/lookup indexing utility.
|
|
4
|
+
#
|
|
5
|
+
# For example, if you're keeping an index of a spreadsheet column, and you want to be able at any moment to get the records
|
|
6
|
+
# containing that value (id = 7124) or (name = 'Mary'),
|
|
7
|
+
#
|
|
8
|
+
# Is it a hash? Two hashes?
|
|
9
|
+
# It's like a hash because...
|
|
10
|
+
#
|
|
11
|
+
# It's like an array because order needs to be preserved.
|
|
12
|
+
#
|
|
13
|
+
# - insert( key, val )
|
|
14
|
+
# - add_to_result_index
|
|
15
|
+
# - add_position_in_result_index_to removal index
|
|
16
|
+
# -
|
|
17
|
+
# - update( key, val )
|
|
18
|
+
#
|
|
19
|
+
# - remove( val )
|
|
20
|
+
#
|
|
21
|
+
# - fetch_results( key )
|
|
22
|
+
#
|
|
23
|
+
# Is the order important? Definitely. But that means re-indexing whenever the record order changes?
|
|
24
|
+
#
|
|
25
|
+
# results_data
|
|
26
|
+
# removal_data
|
|
27
|
+
# ordering_data ... shared by multiple
|
|
28
|
+
|
|
29
|
+
# lu = LookerUpper.new
|
|
30
|
+
# lu.keep( )
|
|
31
|
+
|
|
32
|
+
class LookerUpper
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/csv_madness.rb
CHANGED
|
@@ -2,7 +2,7 @@ require 'csv'
|
|
|
2
2
|
require 'fun_with_gems'
|
|
3
3
|
# require 'fun_with_version_strings'
|
|
4
4
|
require 'time' # to use Time.parse to parse cells to get the date
|
|
5
|
+
require 'set'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
FunWith::Gems.make_gem_fun( "CsvMadness", :require => lib_dir.join( "csv_madness" ) )
|
|
7
|
+
FunWith::Gems.make_gem_fun( "CsvMadness" )
|
|
8
8
|
|
|
File without changes
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"id","number","integer","float","date"
|
|
1
|
+
"id","number","integer","float","date","string"
|
|
2
2
|
,,,,
|
|
3
|
-
12,134.2,100,123.4,2013-01-13
|
|
3
|
+
12,134.2,100,123.4,2013-01-13,"I am the very model of a coding individual"
|
data/test/helper.rb
CHANGED
|
@@ -33,23 +33,27 @@ class MadTestCase < FunWith::Testing::TestCase # Test::Unit::TestCase
|
|
|
33
33
|
set_spreadsheet_paths
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
def load_sheet( *args )
|
|
37
|
+
@sheet = CsvMadness.load( *args )
|
|
38
|
+
end
|
|
39
|
+
|
|
36
40
|
def load_mary
|
|
37
|
-
id = @simple.
|
|
41
|
+
id = @simple.columns.first
|
|
38
42
|
@mary = @simple.fetch( id, MARY_ID )
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
def load_bill
|
|
42
|
-
id = @simple.
|
|
46
|
+
id = @simple.columns.first
|
|
43
47
|
@bill = @simple.fetch( id, BILL_ID )
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
def load_darwin
|
|
47
|
-
id = @simple.
|
|
51
|
+
id = @simple.columns.first
|
|
48
52
|
@darwin = @simple.fetch( id, DARWIN_ID )
|
|
49
53
|
end
|
|
50
54
|
|
|
51
55
|
def load_chuck
|
|
52
|
-
id = @simple.
|
|
56
|
+
id = @simple.columns.first
|
|
53
57
|
@chuck = @simple.fetch( id, CHUCK_ID )
|
|
54
58
|
end
|
|
55
59
|
|
|
@@ -75,8 +79,12 @@ class MadTestCase < FunWith::Testing::TestCase # Test::Unit::TestCase
|
|
|
75
79
|
@simple.alter_column(:born) do |val|
|
|
76
80
|
if val.is_a?(String)
|
|
77
81
|
-1.0
|
|
78
|
-
|
|
82
|
+
elsif val.is_a?(Date)
|
|
83
|
+
val.wday
|
|
84
|
+
elsif val.is_a?(Time)
|
|
79
85
|
(Time.now - val).to_f
|
|
86
|
+
else
|
|
87
|
+
57.3
|
|
80
88
|
end
|
|
81
89
|
end
|
|
82
90
|
|
data/test/test_builder.rb
CHANGED
|
@@ -4,15 +4,19 @@ class TestBuilder < MadTestCase
|
|
|
4
4
|
context "testing simple cases" do
|
|
5
5
|
should "spreadsheetize integers" do
|
|
6
6
|
integers = [65, 66, 67, 68, 69, 70]
|
|
7
|
+
|
|
7
8
|
sb = CsvMadness::Builder.new do |s|
|
|
8
|
-
s.column( :even, "even?" )
|
|
9
|
+
s.column( :even, "even?" ) # calls the .even?() method on each object
|
|
9
10
|
s.column( :odd, "odd?" )
|
|
10
11
|
s.column( :hashh, "hash" )
|
|
11
|
-
s.column( :hashhash, "hash.hash" )
|
|
12
|
+
s.column( :hashhash, "hash.hash" ) # calls .hash(), then calls .hash() on result
|
|
12
13
|
s.column( :chr )
|
|
13
14
|
s.column( :not_a_valid_method )
|
|
15
|
+
s.column( :square ) do |i| # Stores the block as a proc, runs on each object.
|
|
16
|
+
i * i
|
|
17
|
+
end
|
|
14
18
|
end
|
|
15
|
-
|
|
19
|
+
|
|
16
20
|
ss = sb.build( integers )
|
|
17
21
|
|
|
18
22
|
for record in ss.records
|
|
@@ -27,7 +31,43 @@ class TestBuilder < MadTestCase
|
|
|
27
31
|
ss = sb.build( integers, :on_error => :ignore )
|
|
28
32
|
|
|
29
33
|
assert_equal "", ss.records.first.not_a_valid_method
|
|
34
|
+
assert_equal 4225, ss.records.first.square
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "testing convenience column methods" do
|
|
39
|
+
setup do
|
|
40
|
+
@builder = CsvMadness::Builder.new do |s|
|
|
41
|
+
s.constant_column :string, "String"
|
|
42
|
+
s.constant_column :int, 5
|
|
43
|
+
s.constant_column :sym, :sym
|
|
44
|
+
s.blank_column :blank
|
|
45
|
+
s.counter_column :line, 1
|
|
46
|
+
end
|
|
30
47
|
|
|
48
|
+
@sheet = @builder.build( [nil, nil, nil] )
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
should "calculate the resulting sheet accurately" do
|
|
52
|
+
assert_equal [nil,nil,nil], @sheet.column( :blank )
|
|
53
|
+
assert_equal ["String", "String", "String"], @sheet.column( :string )
|
|
54
|
+
assert_equal 3, @sheet.records.last.line
|
|
55
|
+
assert_equal :sym, @sheet.records[0].sym
|
|
56
|
+
assert_equal 5, @sheet.records[1].int
|
|
57
|
+
assert_equal 5, @sheet.records[0][1]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
should "add a record without a dumpster fire ensuing" do
|
|
61
|
+
data = [7] * @builder.column_names.length
|
|
62
|
+
|
|
63
|
+
@sheet.add_record( data )
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
r = @sheet.records.last
|
|
67
|
+
|
|
68
|
+
for sym in @builder.column_names
|
|
69
|
+
assert_equal 7, r.send( sym )
|
|
70
|
+
end
|
|
31
71
|
end
|
|
32
72
|
end
|
|
33
73
|
end
|
data/test/test_csv_madness.rb
CHANGED
|
@@ -55,9 +55,9 @@ class TestCsvMadness < MadTestCase
|
|
|
55
55
|
cell = "*#{cell}*"
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
bill = @simple.fetch(:id, "2")
|
|
59
|
-
mary = @simple.fetch(:id, "1")
|
|
60
|
-
|
|
58
|
+
bill = @simple.fetch(:id, "*2*")
|
|
59
|
+
mary = @simple.fetch(:id, "*1*")
|
|
60
|
+
|
|
61
61
|
assert_equal "*Bill*", bill.fname
|
|
62
62
|
assert_equal "*Moore*", mary.lname
|
|
63
63
|
assert_equal "*1*", mary.id
|
|
@@ -104,39 +104,47 @@ class TestCsvMadness < MadTestCase
|
|
|
104
104
|
|
|
105
105
|
should "parse a date column with one invalid date" do
|
|
106
106
|
@simple.set_column_type( :born, :date )
|
|
107
|
+
debugger
|
|
107
108
|
born1 = @simple[0].born
|
|
108
109
|
born3 = @simple[2].born
|
|
109
110
|
assert_kind_of Time, born1
|
|
110
111
|
assert_in_delta Time.parse("1986-04-08"), born1, 3600 * 24
|
|
111
112
|
|
|
112
113
|
assert_kind_of String, born3
|
|
113
|
-
assert_match /Invalid Time Format/, born3
|
|
114
|
+
assert_match( /Invalid Time Format/, born3 )
|
|
114
115
|
end
|
|
115
116
|
|
|
116
117
|
should "successfully decorate record objects with new functionality" do
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@simple.add_extra_method( :full_name ) do |record|
|
|
121
|
+
"#{record.fname} #{record.lname}"
|
|
122
|
+
end
|
|
121
123
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
end
|
|
124
|
+
@simple.add_extra_method( :name_last_first ) do |record|
|
|
125
|
+
"#{record.lname}, #{record.fname}"
|
|
125
126
|
end
|
|
126
|
-
|
|
127
|
-
@simple.add_record_methods( moduul )
|
|
128
|
-
|
|
127
|
+
|
|
129
128
|
assert @simple[0].respond_to?( :full_name )
|
|
130
129
|
assert_equal "Mary Moore", @simple[0].full_name
|
|
131
130
|
assert @simple[0].respond_to?( :name_last_first )
|
|
132
131
|
assert_equal "Moore, Mary", @simple[0].name_last_first
|
|
133
132
|
end
|
|
133
|
+
|
|
134
|
+
should "add extra method that takes an additional argument" do
|
|
135
|
+
@simple.add_extra_method( :excited ) do |record, mark_of_excitement = "!"|
|
|
136
|
+
"#{record.fname} #{record.lname}#{mark_of_excitement}"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
assert_equal "Mary Moore!", @simple[0].excited
|
|
141
|
+
assert_equal "Mary Moore?", @simple[0].excited("?")
|
|
142
|
+
end
|
|
143
|
+
|
|
134
144
|
|
|
135
145
|
should "add methods to record objects (block form)" do
|
|
136
|
-
@simple.
|
|
137
|
-
|
|
138
|
-
"#{self.fname} #{self.lname}"
|
|
139
|
-
end
|
|
146
|
+
@simple.add_extra_method( :full_name ) do |record|
|
|
147
|
+
"#{record.fname} #{record.lname}"
|
|
140
148
|
end
|
|
141
149
|
|
|
142
150
|
assert @simple[0].respond_to?( :full_name )
|
|
@@ -145,6 +153,7 @@ class TestCsvMadness < MadTestCase
|
|
|
145
153
|
|
|
146
154
|
should "return an array of objects when feeding fetch() an array" do
|
|
147
155
|
records = @simple.fetch(:id, ["1","2"])
|
|
156
|
+
|
|
148
157
|
assert_equal records.length, records.compact.length
|
|
149
158
|
assert_equal 2, records.length
|
|
150
159
|
assert_equal "1", records.first.id
|
|
@@ -202,7 +211,7 @@ class TestCsvMadness < MadTestCase
|
|
|
202
211
|
|
|
203
212
|
should "stomp away the nils" do
|
|
204
213
|
@norris = @nilsheet.fetch(:id, "4")
|
|
205
|
-
|
|
214
|
+
assert_nil @norris.born
|
|
206
215
|
assert_equal "Chuck", @norris.fname
|
|
207
216
|
|
|
208
217
|
@nilsheet.nils_are_blank_strings # should turn every nil into a ''
|
|
@@ -212,19 +221,18 @@ class TestCsvMadness < MadTestCase
|
|
|
212
221
|
|
|
213
222
|
should "to_csv properly" do
|
|
214
223
|
@to_csv = @nilsheet.to_csv( force_quotes: true )
|
|
215
|
-
assert_match /"Moore"/, @to_csv
|
|
216
|
-
assert_match /"age","born"/, @to_csv
|
|
224
|
+
assert_match( /"Moore"/, @to_csv )
|
|
225
|
+
assert_match( /"age","born"/, @to_csv )
|
|
217
226
|
end
|
|
218
227
|
|
|
219
228
|
should "write to an output file properly" do
|
|
220
|
-
# debugger
|
|
221
229
|
@outfile = @csv_output_path.join("output_nilfile.csv")
|
|
222
230
|
@nilsheet.write_to_file( @outfile, force_quotes: true )
|
|
223
231
|
|
|
224
232
|
assert File.exist?( @outfile )
|
|
225
233
|
@to_csv = File.read( @outfile )
|
|
226
|
-
assert_match /"Moore"/, @to_csv
|
|
227
|
-
assert_match /"age","born"/, @to_csv
|
|
234
|
+
assert_match( /"Moore"/, @to_csv )
|
|
235
|
+
assert_match( /"age","born"/, @to_csv )
|
|
228
236
|
end
|
|
229
237
|
end
|
|
230
238
|
|
|
@@ -236,7 +244,7 @@ class TestCsvMadness < MadTestCase
|
|
|
236
244
|
|
|
237
245
|
should "add column" do
|
|
238
246
|
@simple.add_column( :compound ) do |h, record|
|
|
239
|
-
|
|
247
|
+
"#{record.fname} #{record.lname} #{record.id}"
|
|
240
248
|
end
|
|
241
249
|
|
|
242
250
|
load_mary
|
|
@@ -245,6 +253,7 @@ class TestCsvMadness < MadTestCase
|
|
|
245
253
|
|
|
246
254
|
should "drop column" do
|
|
247
255
|
load_mary
|
|
256
|
+
|
|
248
257
|
assert @mary.respond_to?(:lname)
|
|
249
258
|
assert_equal "Moore", @mary.lname
|
|
250
259
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
|
|
3
|
+
class TestIndexSet < MadTestCase
|
|
4
|
+
include CsvMadness
|
|
5
|
+
|
|
6
|
+
context "testing set equality" do
|
|
7
|
+
setup do
|
|
8
|
+
@set0 = IndexSet.new( :even, true )
|
|
9
|
+
@set1 = IndexSet.new( :odd, false )
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
should "be unequal when empty" do
|
|
13
|
+
@set0 != @set1
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
should "be unequal when containing the same objects" do
|
|
17
|
+
@set0.add( 0 )
|
|
18
|
+
@set1.add( 0 )
|
|
19
|
+
|
|
20
|
+
@set0 != @set1
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
_should "do a thing" do
|
|
24
|
+
1000.times do
|
|
25
|
+
ix = IndexSet.new( :even, :true )
|
|
26
|
+
puts ix.object_id
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
|
|
3
|
+
class TestIndexer < MadTestCase
|
|
4
|
+
context "absolute basics" do
|
|
5
|
+
setup do
|
|
6
|
+
@ix = CsvMadness::Indexer.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
should "have created an Indexer" do
|
|
10
|
+
assert_kind_of CsvMadness::Indexer, @ix
|
|
11
|
+
|
|
12
|
+
assert_respond_to @ix, :index
|
|
13
|
+
assert_respond_to @ix, :unindex
|
|
14
|
+
assert_respond_to @ix, :lookup
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
should "add items to and retrieve items from an indexer" do
|
|
18
|
+
@ix.index( 5, :even?, 5.even? )
|
|
19
|
+
result = @ix.lookup( :even?, false )
|
|
20
|
+
assert_equal [5], result
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context "testing index " do
|
|
25
|
+
setup do
|
|
26
|
+
@ix = CsvMadness::Indexer.new
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
_should "add and remove items, with the lookup staying up-to-date" do
|
|
30
|
+
for i in 0..9
|
|
31
|
+
@ix.index( i, :even?, i.even? )
|
|
32
|
+
@ix.index( i, :odd?, i.odd? )
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
assert_equal( [0,2,4,6,8], @ix.lookup( :even?, true ) )
|
|
36
|
+
assert_equal( [1,3,5,7,9], @ix.lookup( :even?, false ) )
|
|
37
|
+
assert_equal( [0,2,4,6,8], @ix.lookup( :odd?, false ) )
|
|
38
|
+
assert_equal( [1,3,5,7,9], @ix.lookup( :odd?, true ) )
|
|
39
|
+
|
|
40
|
+
for i in 0..9
|
|
41
|
+
@ix.unindex( i )
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
assert_equal( [], @ix.lookup( :even?, true ) )
|
|
45
|
+
assert_equal( [], @ix.lookup( :even?, false ) )
|
|
46
|
+
assert_equal( [], @ix.lookup( :odd?, true ) )
|
|
47
|
+
assert_equal( [], @ix.lookup( :odd?, false ) )
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -12,9 +12,12 @@ class TestCsvMadness < MadTestCase
|
|
|
12
12
|
assert @mary.respond_to?(:lname)
|
|
13
13
|
assert @darwin.respond_to?(:fname)
|
|
14
14
|
assert @mary.born.is_a?(String)
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
muck_up_spreadsheet
|
|
17
|
-
set_person_records
|
|
17
|
+
# set_person_records
|
|
18
|
+
|
|
19
|
+
assert_kind_of CsvMadness::Record, @mary
|
|
20
|
+
assert_kind_of CsvMadness::Record, @darwin
|
|
18
21
|
|
|
19
22
|
assert !@mary.respond_to?(:lname)
|
|
20
23
|
assert !@darwin.respond_to?(:fname)
|