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
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZGQ4MTA4MGJlYjA1MzIwOTU4NzEyODViMmFhYmYwMTA2YjQzMmY2MQ==
5
- data.tar.gz: !binary |-
6
- ZTRkOWNjMjYyNTNmMjA3YzMwZThlMzAyOWRjMTM0ZWYwMTQ3NWE0MA==
2
+ SHA256:
3
+ metadata.gz: 63380347571236804849e35c32c5463efc6e71151e992a3e3f18f8d2673fc110
4
+ data.tar.gz: 8c58382266af7f1091a80dc89eb6900a4efb8a5f956fe5801aa77ea5d5e4f05f
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MzAzNTJmNjU5YmM2NjUxODY4YjRkMDkwMDc5NTQxOWIxZWRjMjRmYmU1YzFh
10
- Zjg2ZjA5ZGZlZTEyNjg1NjFmNzE5NzY3NTFhNzY3ZTIyNDFhZGIzZTEzOGI5
11
- ZDUzMjZjYjJkODdiM2M1M2JiMjZiMGNlMTViNWE2Yzk1ZjU1YjI=
12
- data.tar.gz: !binary |-
13
- MjJlYzI1YTQxMzU4NzA0MmVlNzFkYzVmNDE3NjYyMDM5YmI3Y2JmMmQyOWZk
14
- OGQ0NzFhODUyMzRjNWI3ZWRlZDQ3YmQ0NGU0Zjc4ZDFmNWRkMWY4MDc4OTdi
15
- YjkwY2U1MGY3MmVhNTY2NTYzYzc1ZDViZWViMTg0OTE5OGU1ZTE=
6
+ metadata.gz: 3b8ca366e680bf629fbb081145a8b254e5a121102b0772a40095893e06bc1f46f1f081c64cfa60efb1cbe69e633685c65b406795601c237157a8af63a5ce4d3c
7
+ data.tar.gz: 298b6b68d6bed7254ae7177b6fd24f8bfccb765435df5fbd5e9bfabb618db3bf386c276c741ca5fbab2bd9d8168c011010579ccca3bbfe7af0a19a2cffe163ad
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/CHANGELOG.markdown CHANGED
@@ -1,6 +1,10 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ 0.0.10
5
+ ------
6
+
7
+
4
8
  0.0.6
5
9
  -----
6
10
 
data/Gemfile CHANGED
@@ -7,14 +7,8 @@ source "http://rubygems.org"
7
7
  # Include everything needed to run rake, tests, features, etc.
8
8
 
9
9
  group :development do
10
- # gem "shoulda", ">= 3.5"
11
- # gem "rdoc", "~> 3.12"
12
- # gem "bundler", "~> 1.5"
13
- # gem "jeweler", "~> 2"
14
10
  gem "fun_with_testing"
15
- # gem "debugger"
16
11
  end
17
12
 
18
- # gem "fun_with_files", "~> 0.0", ">= 0.0.7"
19
- # gem "fun_with_version_strings", "~> 0.0"
20
- gem 'fun_with_gems', '~> 0.0', ">= 0.0.2"
13
+ gem 'fun_with_gems', '~> 0.0', ">= 0.0.6"
14
+ gem 'csv' # removed from core
data/README.rdoc CHANGED
@@ -7,62 +7,62 @@ CSV Madness tries to remove what little pain is left from Ruby's CSV class. Loa
7
7
 
8
8
  == Why should I use it?
9
9
 
10
- I like brief code and I cannot lie.
10
+ I like brief code and I cannot lie.
11
11
 
12
12
 
13
13
  == Examples
14
14
 
15
15
  CsvMadness makes some assumptions about your CSV file. It does assume headers, for example.
16
16
 
17
- The simplest case is when your columns are nicely named. For example, if you have a csv file named <tt>~/data/people.csv</tt>:
17
+ The simplest case is when your columns are nicely named. For example, if you have a csv file named `~/data/people.csv`:
18
+
19
+ "id","fname","lname","age","born"
20
+ "1","Mary","Moore","27","1986-04-08 15:06:10"
21
+ "2","Bill","Paxton","39","1974-02-22"
22
+ "3","Charles","Darwin","72",""
23
+ "4","Chuck","Norris","57","1901-03-02"
18
24
 
19
- <code>
20
- "id","fname","lname","age","born"
21
- "1","Mary","Moore","27","1986-04-08 15:06:10"
22
- "2","Bill","Paxton","39","1974-02-22"
23
- "3","Charles","Darwin","72",""
24
- "4","Chuck","Norris","57","1901-03-02"
25
- </code>
26
25
 
27
26
  ... then you can write code like so:
28
27
 
29
- '''require 'csv_madness'
30
- sheet = CsvMadness.load( "~/data/people.csv" )
31
- sheet.columns # => [:id, :fname, :lname, :age, :born]
32
- sheet.records.map(&:id) # => ["1", "2", "3", "4"]
33
- sheet.set_column_type(:id, :float)
34
- sheet.records.map(&:id) # => [1.0, 2.0, 3.0, 4.0]
35
- sheet.alter_column(:id) do |id|
36
- id + rand() - 0.5
37
- end
28
+ require 'csv_madness'
29
+
30
+ sheet = CsvMadness.load( "~/data/people.csv" )
31
+ sheet.columns # => [:id, :fname, :lname, :age, :born]
32
+ sheet.records.map(&:id) # => ["1", "2", "3", "4"]
33
+ sheet.set_column_type(:id, :float)
34
+ sheet.records.map(&:id) # => [1.0, 2.0, 3.0, 4.0]
35
+ sheet.alter_column(:id) do |id|
36
+ id + rand() - 0.5
37
+ end
38
+
39
+ sheet.records.map(&:id) # => [0.7186, 2.30134, 2.90132, 4.30124] (your results may vary)
40
+ mary = sheet[0]
38
41
 
39
- sheet.records.map(&:id) # => [0.7186, 2.30134, 2.90132, 4.30124] (your results may vary)
40
- mary = sheet[0]
42
+ "#{mary.lname}, #{mary.fname} (#{mary.id})" # => "Moore, Mary (1)"
41
43
 
42
- "#{mary.lname}, #{mary.fname} (#{mary.id})" # => "Moore, Mary (1)"
43
- '''
44
44
 
45
45
  If you're not satisfied with your column names, you can send your own, in the column order. An index can also be provided, which will allow you to use <tt>.fetch()</tt> to find specific records quickly:
46
46
 
47
- '''require 'csv_madness'
48
- sheet = CsvMadness.load( "~/data/people.csv",
49
- columns: [:uid, :first_name, :last_name, :years_on_planet, :birthday],
50
- index: :uid )
47
+ require 'csv_madness'
48
+ sheet = CsvMadness.load( "~/data/people.csv",
49
+ columns: [:uid, :first_name, :last_name, :years_on_planet, :birthday],
50
+ index: :uid )
51
+
52
+ sheet.fetch("2").years_on_planet # => "39"
51
53
 
52
- sheet.fetch("2").years_on_planet # => "39"
53
- '''
54
54
 
55
55
  **Note:** you can provide multiple indexes as an array. However many columns you index, you'll run into trouble if the index isn't unique for each record. (that may change in the future)
56
56
 
57
57
 
58
58
  It's useful to clean up your files. Say you have:
59
59
 
60
- """"id","fname","lname","age"," born "
61
- "1 ","Mary ","Moore","27","1986-04-08 15:06:10"
62
- ""," Bill ","Paxton",," Feb. 22, 1974 "
63
- ,"Charles "," Darwin","72 ",
64
- "4","Chuck","Norris",," 2 March 1901 "
65
- """
60
+ "id","fname","lname","age"," born "
61
+ "1 ","Mary ","Moore","27","1986-04-08 15:06:10"
62
+ ""," Bill ","Paxton",," Feb. 22, 1974 "
63
+ "3","Charles "," Darwin","72 "
64
+ "4","Chuck","Norris",," 2 March 1901 "
65
+
66
66
 
67
67
  Ick. Missing IDs, inconsistent date formats, leading and trailing whitespace... We can fix this.
68
68
 
@@ -163,27 +163,35 @@ You could do something similar to clean and standardize phone numbers, detect an
163
163
 
164
164
  You have an array of objects. You want to write them to a spreadsheet.
165
165
 
166
- ```ruby
167
166
  sb = CsvMadness::Builder.new do |sb|
168
167
  sb.column( :id )
169
- sb.column( :addressee, "addressee_custom" )
170
- sb.column( :street_address, "primary_address.street_address" )
171
- sb.column( :supplemental_address_1, "primary_address.supplemental_address_1" )
172
- sb.column( :city, "primary_address.city" )
173
- sb.column( :state_code, "primary_address.state_code" )
174
- sb.column( :formatted_zip, "primary_address.formatted_zip" )
175
- sb.column( :phone, "phones.first.phone" )
176
- sb.column( :leader, "congregation_fieldset.congregation_leader" )
177
- sb.column( :denomination, "congregation_fieldset.denomination" )
178
- sb.column( :email, "emails.first.email" )
168
+ sb.column( :addressee, "addressee_custom" )
169
+ sb.column( :street, "primary_address.street_address" )
170
+ sb.column( :street2, "primary_address.supplemental_address_1" )
171
+ sb.column( :city, "primary_address.city" )
172
+ sb.column( :state_code, "primary_address.state_code" )
173
+ sb.column( :formatted_zip, "primary_address.formatted_zip" )
174
+ sb.column( :phone, "phones.first.phone" )
175
+ sb.column( :contact, "congregation_fieldset.congregation_leader" )
176
+ sb.column( :email, "emails.first.email" )
177
+ sb.column( :greeting ) do |contact|
178
+ if contact.business?
179
+ "To our friends at #{contact.organization_name},"
180
+ elsif contact.person?
181
+ "Dear #{ contact.title } #{ contact.last_name }"
182
+ end
183
+ end
184
+
179
185
  end
180
186
 
181
187
  sheet = sb.build( [address1, address2, address3...] )
182
- ```
188
+
189
+ outfile = FunWith::Files::FilePath.home.join( "Documents", "addresses", "address_records.csv" )
190
+ sheet.write_to_file( outfile )
183
191
 
184
192
  === Documentation is incomplete ===
185
193
 
186
- There are lots of other features, but they'll take time to test and document.
194
+ There are other features, but they'll take time to test and document.
187
195
 
188
196
 
189
197
 
data/Rakefile CHANGED
@@ -1,22 +1,13 @@
1
1
  # encoding: utf-8
2
+ require 'fun_with_gems'
3
+ require_relative File.join( "lib", "csv_madness" )
2
4
 
3
- require 'rubygems'
4
- require 'bundler'
5
+ self.extend( FunWith::Gems::Rakefile )
6
+ rakefile_setup CsvMadness
5
7
 
6
- begin
7
- Bundler.setup(:default, :development)
8
- rescue Bundler::BundlerError => e
9
- $stderr.puts e.message
10
- $stderr.puts "Run `bundle install` to install missing gems"
11
- exit e.status_code
12
- end
13
-
14
- require 'rake'
15
-
16
- require 'jeweler'
17
-
18
- Jeweler::Tasks.new do |gem|
19
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
8
+ gem_specification do |gem|
9
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
10
+ # dependencies defined in Gemfile
20
11
  gem.name = "csv_madness"
21
12
  gem.homepage = "http://github.com/darthschmoo/csv_madness"
22
13
  gem.license = "MIT"
@@ -24,39 +15,9 @@ Jeweler::Tasks.new do |gem|
24
15
  gem.description = "CSV Madness removes what little pain is left from Ruby's CSV class. Load a CSV file, and get back an array of objects with customizable getter/setter methods."
25
16
  gem.email = "keeputahweird@gmail.com"
26
17
  gem.authors = ["Bryce Anderson"]
27
-
28
- # dependencies defined in Gemfile
29
- gem.files = Dir.glob( File.join( ".", "lib", "**", "*.rb" ) ) +
30
- Dir.glob( File.join( ".", "test", "**", "*" ) ) +
31
- %w( Gemfile Rakefile LICENSE.txt README.rdoc VERSION CHANGELOG.markdown )
32
-
33
- end
34
18
 
35
- Jeweler::RubygemsDotOrgTasks.new
36
-
37
- require 'rake/testtask'
38
- Rake::TestTask.new(:test) do |test|
39
- test.libs << 'lib' << 'test'
40
- test.pattern = 'test/**/test_*.rb'
41
- test.verbose = true
19
+ # dependencies defined in Gemfile
20
+ add_specification_files( gem, :default )
42
21
  end
43
22
 
44
- # require 'rcov/rcovtask'
45
- # Rcov::RcovTask.new do |test|
46
- # test.libs << 'test'
47
- # test.pattern = 'test/**/test_*.rb'
48
- # test.verbose = true
49
- # test.rcov_opts << '--exclude "gems/*"'
50
- # end
51
-
52
- task :default => :test
53
-
54
- require 'rdoc/task'
55
- Rake::RDocTask.new do |rdoc|
56
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
57
-
58
- rdoc.rdoc_dir = 'rdoc'
59
- rdoc.title = "csv_madness #{version}"
60
- rdoc.rdoc_files.include('README*')
61
- rdoc.rdoc_files.include('lib/**/*.rb')
62
- end
23
+ setup_gem_boilerplate
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.6
1
+ 0.0.10
@@ -1,13 +1,18 @@
1
1
  module CsvMadness
2
2
  class Builder
3
+ attr_accessor :label
4
+
3
5
  def initialize( &block )
4
6
  @columns = {}
5
7
  @column_syms = []
8
+ @column_counters = {}
9
+
6
10
  @module = Module.new # for extending
7
11
  self.extend( @module )
8
- yield self
12
+ yield self if block_given?
9
13
  end
10
14
 
15
+
11
16
  def column( sym, method_path = nil, &block )
12
17
  warn( "#{sym} already defined. Overwriting." ) if @column_syms.include?( sym )
13
18
 
@@ -20,6 +25,24 @@ module CsvMadness
20
25
  Proc.new(&sym)
21
26
  end
22
27
  end
28
+
29
+ def column_names
30
+ @column_syms
31
+ end
32
+
33
+ def constant_column( sym, const )
34
+ cproc = Utils::ConstProc.proc_for( const )
35
+ column( sym, &cproc )
36
+ end
37
+
38
+ def blank_column( sym )
39
+ constant_column( sym, nil )
40
+ end
41
+
42
+ def counter_column( sym, initial_value = 0 )
43
+ column( sym, &Utils::CounterProc.counter( initial_value ) )
44
+ end
45
+
23
46
 
24
47
  # Three :on_error values:
25
48
  # :print => Put an error message in the cell instead of a value
@@ -27,23 +50,34 @@ module CsvMadness
27
50
  # :ignore => Hand back an empty cell
28
51
  #
29
52
  # Although ideally it should be configurable by column...
30
- def build( objects, opts = { :on_error => :print } )
53
+ def build( objects, opts = {} )
54
+ @progress_mode = choose_progress_mode( opts[:progress] )
55
+ debugger unless defined?( @show_progress )
56
+
57
+ @on_error = opts.fetch(:on_error){ :print }
58
+ @verbose = opts.fetch(:verbose){ false }
59
+
31
60
  spreadsheet = CsvMadness::Sheet.new( @column_syms )
61
+
62
+ @objects = objects
63
+ @objects = @objects.records if @objects.is_a?( CsvMadness::Sheet )
32
64
 
33
- for object in objects
34
- STDOUT << "."
65
+ for object in @objects
35
66
  record = {}
36
67
  for sym in @column_syms
37
68
  record[sym] = build_cell( object, sym, opts )
38
69
  end
39
-
70
+
40
71
  spreadsheet.add_record( record ) # hash form
72
+ show_progress
41
73
  end
74
+
75
+ _reset_counter_columns
42
76
 
43
77
  spreadsheet
44
78
  end
45
79
 
46
- def build_cell( object, sym, opts = { :on_error => :print } )
80
+ def build_cell( object, sym, opts = {} )
47
81
  column = @columns[sym]
48
82
 
49
83
  case column
@@ -52,10 +86,12 @@ module CsvMadness
52
86
  when Proc
53
87
  build_cell_by_proc( object, column, opts )
54
88
  else
55
- "no idea what to do"
89
+ debugger
90
+ "no idea what to do with #{column.inspect} (#{column.class})"
56
91
  end
57
92
  end
58
93
 
94
+ # ?????
59
95
  def def( method_name, &block )
60
96
  @module.send( :define_method, method_name, &block )
61
97
  end
@@ -63,7 +99,7 @@ module CsvMadness
63
99
  protected
64
100
  def build_cell_by_pathstring( object, str, opts )
65
101
  handle_cell_build_error( :build_cell_by_pathstring, opts ) do
66
- for method in str.split(".").map(&:to_sym)
102
+ for method in str.split(".")
67
103
  object = object.send(method)
68
104
  end
69
105
 
@@ -82,9 +118,9 @@ module CsvMadness
82
118
  yield
83
119
  end
84
120
  rescue Exception => e
85
- case opts[:on_error]
121
+ case @on_error
86
122
  when nil, :print
87
- puts "error #{e.message} #{caller}" if opts[:verbose]
123
+ puts "error #{e.message} #{caller}" if @verbose
88
124
  "ERROR: #{e.message} (#{caller}())"
89
125
  when :raise
90
126
  puts "Re-raisinge error #{e.message}. Set opts[:on_error] to :print or :ignore if you want Builder to continue on errors."
@@ -93,5 +129,54 @@ module CsvMadness
93
129
  ""
94
130
  end
95
131
  end
132
+
133
+ def _reset_counter_columns
134
+ for sym, column in @columns
135
+ column.reset if column.is_a?( Utils::CounterProc )
136
+ end
137
+ end
138
+
139
+ #
140
+ def choose_progress_mode( m )
141
+ case m
142
+ when true
143
+ @show_progress = true
144
+ @progress_mode = progress_bar_available? ? :tty : :stdout
145
+ when false, nil
146
+ @show_progress = false
147
+ @progress_mode = :none
148
+ when Symbol
149
+ @show_progress = (m == :none) ? false : true
150
+ @progress_mode = m
151
+ else
152
+ warn "unknown progress mode #{m.inspect}"
153
+ choose_progress_mode( false )
154
+ end
155
+ end
156
+
157
+ def show_progress
158
+ if @show_progress
159
+ @progress_mode ||= progress_bar_available? ? :tty : :stdout
160
+
161
+ case @progress_mode
162
+ when :tty
163
+ @tty_progress_bar ||= TTY::ProgressBar.new( "Building spreadsheet :current/:total (:percent) [:bar]", total: @objects.length )
164
+ @tty_progress_bar.advance(1)
165
+ when :stdout
166
+ STDOUT << "."
167
+ when :counter
168
+ unless defined?( @tty_progress_count )
169
+ puts ""
170
+ @tty_progress_count = 1
171
+ end
172
+
173
+ print "\r#{@tty_progress_count}/#{@objects.length} records written "
174
+ end
175
+ end
176
+ end
177
+
178
+ def progress_bar_available?
179
+ defined?(TTY) && defined?(TTY::ProgressBar)
180
+ end
96
181
  end
97
182
  end
@@ -0,0 +1,30 @@
1
+ module CsvMadness
2
+ class Column
3
+ include ColumnMethods::CoreMethods
4
+ include ColumnMethods::FetchMethods
5
+ include ColumnMethods::TypingMethods
6
+ include ColumnMethods::ErrorMethods
7
+ include ColumnMethods::DefaultValueMethods
8
+
9
+ attr_accessor :spreadsheet,
10
+ :index,
11
+ :name,
12
+ :type_conversion
13
+
14
+
15
+ def initialize( _sheet, _name, _index, _type )
16
+ self.name = convert_column_name( nm )
17
+ self.index = index
18
+ self.aliases = @opts[:aliases]
19
+ self.set_type( opts[:type] )
20
+ end
21
+
22
+ def get_cell( record )
23
+ record.data[self.index]
24
+ end
25
+
26
+ def set_cell( record, value )
27
+ record.data[self.index] = self.type_convert( value )
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ module CsvMadness
2
+ module ColumnMethods
3
+ module CoreMethods
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module CsvMadness
2
+ module ColumnMethods
3
+ module DefaultValueMethods
4
+ attr_accessor :default_value
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module CsvMadness
2
+ module ColumnMethods
3
+ module ErrorMethods
4
+ # When a conversion fails, what happens?
5
+ #
6
+ # debug : enters debugger (test mode)
7
+ # ignore : no message is given and the default value is returned ("" for string, 0 for integer, 0.0 for float)?
8
+ # stdout : message printed to stdout
9
+ # stderr : message printed to stderr
10
+ # cell : message appears in the cell
11
+ attr_accessor :warning_style
12
+
13
+
14
+ attr_accessor :error_message
15
+
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module CsvMadness
2
+ module ColumnMethods
3
+ module FetchMethods
4
+ def contents
5
+ self.spreadsheet.records.map do |record|
6
+ self.get_cell( record )
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module CsvMadness
2
+ module ColumnMethods
3
+ module TypingMethods
4
+ def type_convert( value )
5
+ if self.type_conversion
6
+ self.type_conversion.call( value )
7
+ else
8
+ value
9
+ end
10
+ end
11
+
12
+ def set_type( type )
13
+ self.type_conversion = TypeConversion[@opts[:type]]
14
+ self.convert_column_to_type
15
+ end
16
+
17
+ def convert_column_to_type
18
+ for record in self.spreadsheet.records
19
+ set_cell( record, get_cell( record ) )
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ module CsvMadness
2
+ class ColumnSet < Array
3
+
4
+ end
5
+ end
@@ -0,0 +1,74 @@
1
+ module CsvMadness
2
+ class ColumnType
3
+ COLUMN_TYPE_LOOKUP = {
4
+ :integer => ColumnTypes::IntegerType,
5
+ :date => ColumnTypes::DateType,
6
+ :string => ColumnTypes::StringType,
7
+ # :number => ColumnTypes::NumberType,
8
+ :float => ColumnTypes::FloatType
9
+ }
10
+
11
+ DEFAULT_ERROR_MESSAGES = {
12
+
13
+ }
14
+
15
+
16
+ # What is returned when a conversion fails?
17
+ #
18
+ # :default : the type conversion returns
19
+ # :blank : the cell becomes a nil
20
+ # :stderr : send warning message to stderr and return a nil
21
+ # :stdout : send warning message to stdout and return a nil
22
+ # :sheet : write the warning message into the sheet itself
23
+ attr_accessor :conversion_error_value
24
+
25
+
26
+ def self.[]( t )
27
+ COLUMN_TYPE_LOOKUP[t]
28
+ end
29
+
30
+ def initialize( opts = {} )
31
+
32
+ end
33
+
34
+ # default_hierarchy
35
+
36
+
37
+
38
+ def standard_opts( overrides )
39
+
40
+
41
+ end
42
+
43
+
44
+ def conversion_error_message( input )
45
+
46
+ end
47
+
48
+ def handle_conversion_errors( input, &block )
49
+ begin
50
+ yield if block_given?
51
+ rescue ArgumentError
52
+
53
+ end
54
+ end
55
+
56
+ def self.default_value
57
+ nil
58
+ end
59
+
60
+ def default
61
+ self.default_value || self.class.default_value || nil
62
+ end
63
+
64
+ protected
65
+ def build_error_message( input, e )
66
+ if input =~ /CsvMadness::TypeError/
67
+ input
68
+ else
69
+ "CsvMadness::TypeError::#{ }"
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ module CsvMadness
2
+ module ColumnTypes
3
+ class DateType < CsvMadness::ColumnType
4
+ # Blank inputs return nil. Other inputs may raise a date error
5
+ def self.convert( input )
6
+ if input.fwf_blank?
7
+ self.default_value
8
+ elsif input.is_a?(String)
9
+ Date.parse( input )
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end