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.

Files changed (54) hide show
  1. checksums.yaml +5 -13
  2. data/.document +5 -0
  3. data/CHANGELOG.markdown +4 -0
  4. data/Gemfile +2 -8
  5. data/README.rdoc +55 -47
  6. data/Rakefile +10 -49
  7. data/VERSION +1 -1
  8. data/lib/csv_madness/builder.rb +95 -10
  9. data/lib/csv_madness/column.rb +30 -0
  10. data/lib/csv_madness/column_methods/core_methods.rb +6 -0
  11. data/lib/csv_madness/column_methods/default_value_methods.rb +7 -0
  12. data/lib/csv_madness/column_methods/error_methods.rb +19 -0
  13. data/lib/csv_madness/column_methods/fetch_methods.rb +11 -0
  14. data/lib/csv_madness/column_methods/typing_methods.rb +24 -0
  15. data/lib/csv_madness/column_set.rb +5 -0
  16. data/lib/csv_madness/column_type.rb +74 -0
  17. data/lib/csv_madness/column_types/date.rb +14 -0
  18. data/lib/csv_madness/column_types/float.rb +25 -0
  19. data/lib/csv_madness/column_types/integer.rb +17 -0
  20. data/lib/csv_madness/column_types/string.rb +9 -0
  21. data/lib/csv_madness/data_accessor_module.rb +79 -44
  22. data/lib/csv_madness/exceptions.rb +16 -0
  23. data/lib/csv_madness/gem_api.rb +11 -2
  24. data/lib/csv_madness/index_set.rb +36 -0
  25. data/lib/csv_madness/indexer.rb +105 -0
  26. data/lib/csv_madness/record.rb +68 -40
  27. data/lib/csv_madness/record_filter.rb +68 -0
  28. data/lib/csv_madness/record_methods/method_methods.rb +57 -0
  29. data/lib/csv_madness/sheet.rb +172 -442
  30. data/lib/csv_madness/sheet_methods/base.rb +6 -0
  31. data/lib/csv_madness/sheet_methods/class_methods.rb +84 -0
  32. data/lib/csv_madness/sheet_methods/column_methods.rb +175 -0
  33. data/lib/csv_madness/sheet_methods/file_methods.rb +44 -0
  34. data/lib/csv_madness/sheet_methods/indexing.rb +133 -0
  35. data/lib/csv_madness/sheet_methods/record_methods.rb +175 -0
  36. data/lib/csv_madness/sheet_methods/sorting_methods.rb +10 -0
  37. data/lib/csv_madness/utils/const_proc.rb +19 -0
  38. data/lib/csv_madness/utils/counter.rb +24 -0
  39. data/lib/csv_madness/utils/counter_proc.rb +31 -0
  40. data/lib/csv_madness/utils/looker_upper.rb +36 -0
  41. data/lib/csv_madness.rb +2 -2
  42. data/test/csv/nil_headers.csv +5 -0
  43. data/test/csv/out/.gitkeep +0 -0
  44. data/test/csv/pokemon.csv +9 -0
  45. data/test/csv/test_column_types.csv +2 -2
  46. data/test/helper.rb +13 -5
  47. data/test/test_builder.rb +43 -3
  48. data/test/test_csv_madness.rb +34 -25
  49. data/test/test_index_set.rb +30 -0
  50. data/test/test_indexer.rb +50 -0
  51. data/test/test_reloading_spreadsheet.rb +5 -2
  52. data/test/test_sheet.rb +184 -37
  53. data/test/test_utils.rb +99 -0
  54. 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
- lib_dir = __FILE__.fwf_filepath.dirname
7
- FunWith::Gems.make_gem_fun( "CsvMadness", :require => lib_dir.join( "csv_madness" ) )
7
+ FunWith::Gems.make_gem_fun( "CsvMadness" )
8
8
 
@@ -0,0 +1,5 @@
1
+ ,fname,,,
2
+ "1","Mary","Moore","27","1986-04-08 15:06:10"
3
+ "2","Bill","Paxton","39","1974-02-22"
4
+ "3","Charles","Darwin","72","Invalid Date"
5
+ "4","Chuck","Norris","57","1901-03-02"
File without changes
@@ -0,0 +1,9 @@
1
+ ID,PokemonType,CP,HP
2
+ 1,Jigglypuff,392,54
3
+ 2,Pikachu,408,29
4
+ 3,Charmander,392,35
5
+ 4,Tentacool,376,35
6
+ 5,Haunter,338,27
7
+ 6,Meowth,401,55
8
+ 7,Geodude,338,48
9
+ 8,Haunter,301,55
@@ -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.index_columns.first
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.index_columns.first
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.index_columns.first
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.index_columns.first
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
- else
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
@@ -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
- moduul = Module.new do
118
- def full_name
119
- "#{self.fname} #{self.lname}"
120
- end
118
+
119
+
120
+ @simple.add_extra_method( :full_name ) do |record|
121
+ "#{record.fname} #{record.lname}"
122
+ end
121
123
 
122
- def name_last_first
123
- "#{self.lname}, #{self.fname}"
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.add_record_methods do
137
- def full_name
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
- assert_equal nil, @norris.born
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
- v = "#{record.fname} #{record.lname} #{record.id}"
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)