csv_madness 0.0.9 → 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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.document +5 -0
  3. data/CHANGELOG.markdown +4 -0
  4. data/Gemfile +2 -7
  5. data/Rakefile +12 -78
  6. data/VERSION +1 -1
  7. data/lib/csv_madness/builder.rb +91 -9
  8. data/lib/csv_madness/column.rb +30 -0
  9. data/lib/csv_madness/column_methods/core_methods.rb +6 -0
  10. data/lib/csv_madness/column_methods/default_value_methods.rb +7 -0
  11. data/lib/csv_madness/column_methods/error_methods.rb +19 -0
  12. data/lib/csv_madness/column_methods/fetch_methods.rb +11 -0
  13. data/lib/csv_madness/column_methods/typing_methods.rb +24 -0
  14. data/lib/csv_madness/column_set.rb +5 -0
  15. data/lib/csv_madness/column_type.rb +74 -0
  16. data/lib/csv_madness/column_types/date.rb +14 -0
  17. data/lib/csv_madness/column_types/float.rb +25 -0
  18. data/lib/csv_madness/column_types/integer.rb +17 -0
  19. data/lib/csv_madness/column_types/string.rb +9 -0
  20. data/lib/csv_madness/data_accessor_module.rb +79 -79
  21. data/lib/csv_madness/gem_api.rb +11 -2
  22. data/lib/csv_madness/index_set.rb +36 -0
  23. data/lib/csv_madness/indexer.rb +105 -0
  24. data/lib/csv_madness/record.rb +68 -42
  25. data/lib/csv_madness/record_filter.rb +68 -0
  26. data/lib/csv_madness/record_methods/method_methods.rb +57 -0
  27. data/lib/csv_madness/sheet.rb +160 -76
  28. data/lib/csv_madness/sheet_methods/class_methods.rb +11 -4
  29. data/lib/csv_madness/sheet_methods/column_methods.rb +95 -107
  30. data/lib/csv_madness/sheet_methods/file_methods.rb +9 -6
  31. data/lib/csv_madness/sheet_methods/indexing.rb +104 -23
  32. data/lib/csv_madness/sheet_methods/record_methods.rb +123 -47
  33. data/lib/csv_madness/sheet_methods/sorting_methods.rb +10 -0
  34. data/lib/csv_madness/utils/const_proc.rb +19 -0
  35. data/lib/csv_madness/utils/counter.rb +24 -0
  36. data/lib/csv_madness/utils/counter_proc.rb +31 -0
  37. data/lib/csv_madness/utils/looker_upper.rb +36 -0
  38. data/lib/csv_madness.rb +1 -0
  39. data/test/csv/nil_headers.csv +5 -0
  40. data/test/csv/out/.gitkeep +0 -0
  41. data/test/csv/pokemon.csv +9 -0
  42. data/test/csv/test_column_types.csv +2 -2
  43. data/test/helper.rb +9 -6
  44. data/test/test_builder.rb +36 -0
  45. data/test/test_csv_madness.rb +28 -18
  46. data/test/test_index_set.rb +30 -0
  47. data/test/test_indexer.rb +50 -0
  48. data/test/test_reloading_spreadsheet.rb +4 -2
  49. data/test/test_sheet.rb +164 -27
  50. data/test/test_utils.rb +99 -0
  51. metadata +66 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f4f9b06af750b458f7eb43b10053dfce2b60a69cc55ea4410d4466c72680f0c
4
- data.tar.gz: 23ddbf472f0b52973769e21eb72939622bee0e5b13e43e8c292ae28203106145
3
+ metadata.gz: 63380347571236804849e35c32c5463efc6e71151e992a3e3f18f8d2673fc110
4
+ data.tar.gz: 8c58382266af7f1091a80dc89eb6900a4efb8a5f956fe5801aa77ea5d5e4f05f
5
5
  SHA512:
6
- metadata.gz: 1e44f1666c4118cf68a16f254ea5ad8808f9a0036b346755d187c74baf24a65cff718323d81741cd5478b036fcea3518daa3b2b5f72f6de2bf89b3b435392de8
7
- data.tar.gz: b44d0fa470ec59317f5a93b0e73d1ec6a032f300083734e2b0aef27b2077b51303dce1b504e77102e6cfb5f79cc2c229d136d4a5d7eca049402bb88e740e711a
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,13 +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 "csv"
19
- gem 'fun_with_gems', '~> 0.0', ">= 0.0.7"
13
+ gem 'fun_with_gems', '~> 0.0', ">= 0.0.6"
14
+ gem 'csv' # removed from core
data/Rakefile CHANGED
@@ -1,89 +1,23 @@
1
1
  # encoding: utf-8
2
2
  require 'fun_with_gems'
3
3
  require_relative File.join( "lib", "csv_madness" )
4
- self.extend( FunWith::Gems::Rakefile)
5
4
 
5
+ self.extend( FunWith::Gems::Rakefile )
6
6
  rakefile_setup CsvMadness
7
7
 
8
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
11
- gem.name = "csv_madness"
12
- gem.homepage = "http://github.com/darthschmoo/csv_madness"
13
- gem.license = "MIT"
14
- gem.summary = "CSV Madness turns your CSV rows into happycrazy objects."
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."
16
- gem.email = "keeputahweird@gmail.com"
17
- gem.authors = ["Bryce Anderson"]
9
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
10
+ # dependencies defined in Gemfile
11
+ gem.name = "csv_madness"
12
+ gem.homepage = "http://github.com/darthschmoo/csv_madness"
13
+ gem.license = "MIT"
14
+ gem.summary = "CSV Madness turns your CSV rows into happycrazy objects."
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."
16
+ gem.email = "keeputahweird@gmail.com"
17
+ gem.authors = ["Bryce Anderson"]
18
18
 
19
- # dependencies defined in Gemfile
20
- gem.files = Dir.glob( File.join( ".", "lib", "**", "*.rb" ) ) +
21
- Dir.glob( File.join( ".", "test", "**", "*" ) ) +
22
- %w( Gemfile Rakefile LICENSE.txt README.rdoc VERSION CHANGELOG.markdown )
23
- # csv_madness.gemspec )
19
+ # dependencies defined in Gemfile
20
+ add_specification_files( gem, :default )
24
21
  end
25
22
 
26
23
  setup_gem_boilerplate
27
-
28
- #
29
- #
30
- # require 'rubygems'
31
- # require 'bundler'
32
- #
33
- # begin
34
- # Bundler.setup(:default, :development)
35
- # rescue Bundler::BundlerError => e
36
- # $stderr.puts e.message
37
- # $stderr.puts "Run `bundle install` to install missing gems"
38
- # exit e.status_code
39
- # end
40
- #
41
- # require 'rake'
42
- #
43
- # require 'jeweler'
44
- #
45
- # Jeweler::Tasks.new do |gem|
46
- # # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
47
- # gem.name = "csv_madness"
48
- # gem.homepage = "http://github.com/darthschmoo/csv_madness"
49
- # gem.license = "MIT"
50
- # gem.summary = "CSV Madness turns your CSV rows into happycrazy objects."
51
- # 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."
52
- # gem.email = "keeputahweird@gmail.com"
53
- # gem.authors = ["Bryce Anderson"]
54
- #
55
- # # dependencies defined in Gemfile
56
- # gem.files = Dir.glob( File.join( ".", "lib", "**", "*.rb" ) ) +
57
- # Dir.glob( File.join( ".", "test", "**", "*" ) ) +
58
- # %w( Gemfile Rakefile LICENSE.txt README.rdoc VERSION CHANGELOG.markdown csv_madness.gemspec )
59
- #
60
- # end
61
- #
62
- # Jeweler::RubygemsDotOrgTasks.new
63
- #
64
- # require 'rake/testtask'
65
- # Rake::TestTask.new(:test) do |test|
66
- # test.libs << 'lib' << 'test'
67
- # test.pattern = 'test/**/test_*.rb'
68
- # test.verbose = true
69
- # end
70
- #
71
- # # require 'rcov/rcovtask'
72
- # # Rcov::RcovTask.new do |test|
73
- # # test.libs << 'test'
74
- # # test.pattern = 'test/**/test_*.rb'
75
- # # test.verbose = true
76
- # # test.rcov_opts << '--exclude "gems/*"'
77
- # # end
78
- #
79
- # task :default => :test
80
- #
81
- # require 'rdoc/task'
82
- # Rake::RDocTask.new do |rdoc|
83
- # version = File.exist?('VERSION') ? File.read('VERSION') : ""
84
- #
85
- # rdoc.rdoc_dir = 'rdoc'
86
- # rdoc.title = "csv_madness #{version}"
87
- # rdoc.rdoc_files.include('README*')
88
- # rdoc.rdoc_files.include('lib/**/*.rb')
89
- # end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.9
1
+ 0.0.10
@@ -5,12 +5,14 @@ module CsvMadness
5
5
  def initialize( &block )
6
6
  @columns = {}
7
7
  @column_syms = []
8
+ @column_counters = {}
8
9
 
9
10
  @module = Module.new # for extending
10
11
  self.extend( @module )
11
12
  yield self if block_given?
12
13
  end
13
14
 
15
+
14
16
  def column( sym, method_path = nil, &block )
15
17
  warn( "#{sym} already defined. Overwriting." ) if @column_syms.include?( sym )
16
18
 
@@ -23,6 +25,24 @@ module CsvMadness
23
25
  Proc.new(&sym)
24
26
  end
25
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
+
26
46
 
27
47
  # Three :on_error values:
28
48
  # :print => Put an error message in the cell instead of a value
@@ -30,23 +50,34 @@ module CsvMadness
30
50
  # :ignore => Hand back an empty cell
31
51
  #
32
52
  # Although ideally it should be configurable by column...
33
- 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
+
34
60
  spreadsheet = CsvMadness::Sheet.new( @column_syms )
61
+
62
+ @objects = objects
63
+ @objects = @objects.records if @objects.is_a?( CsvMadness::Sheet )
35
64
 
36
- for object in objects
37
- STDOUT << "."
65
+ for object in @objects
38
66
  record = {}
39
67
  for sym in @column_syms
40
68
  record[sym] = build_cell( object, sym, opts )
41
69
  end
42
-
70
+
43
71
  spreadsheet.add_record( record ) # hash form
72
+ show_progress
44
73
  end
74
+
75
+ _reset_counter_columns
45
76
 
46
77
  spreadsheet
47
78
  end
48
79
 
49
- def build_cell( object, sym, opts = { :on_error => :print } )
80
+ def build_cell( object, sym, opts = {} )
50
81
  column = @columns[sym]
51
82
 
52
83
  case column
@@ -55,10 +86,12 @@ module CsvMadness
55
86
  when Proc
56
87
  build_cell_by_proc( object, column, opts )
57
88
  else
58
- "no idea what to do"
89
+ debugger
90
+ "no idea what to do with #{column.inspect} (#{column.class})"
59
91
  end
60
92
  end
61
93
 
94
+ # ?????
62
95
  def def( method_name, &block )
63
96
  @module.send( :define_method, method_name, &block )
64
97
  end
@@ -66,7 +99,7 @@ module CsvMadness
66
99
  protected
67
100
  def build_cell_by_pathstring( object, str, opts )
68
101
  handle_cell_build_error( :build_cell_by_pathstring, opts ) do
69
- for method in str.split(".").map(&:to_sym)
102
+ for method in str.split(".")
70
103
  object = object.send(method)
71
104
  end
72
105
 
@@ -85,9 +118,9 @@ module CsvMadness
85
118
  yield
86
119
  end
87
120
  rescue Exception => e
88
- case opts[:on_error]
121
+ case @on_error
89
122
  when nil, :print
90
- puts "error #{e.message} #{caller}" if opts[:verbose]
123
+ puts "error #{e.message} #{caller}" if @verbose
91
124
  "ERROR: #{e.message} (#{caller}())"
92
125
  when :raise
93
126
  puts "Re-raisinge error #{e.message}. Set opts[:on_error] to :print or :ignore if you want Builder to continue on errors."
@@ -96,5 +129,54 @@ module CsvMadness
96
129
  ""
97
130
  end
98
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
99
181
  end
100
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
@@ -0,0 +1,25 @@
1
+ module CsvMadness
2
+ module ColumnTypes
3
+ class FloatType < CsvMadness::ColumnType
4
+
5
+ # I suspect that a blank string and a nil should be treated the same, and that
6
+ # 0.0 is the wrong choice for a default. Maybe these should return :default or :error,
7
+ # and leave it to the individual column definition to handle that.
8
+ def self.convert( input )
9
+ if input.fwf_blank?
10
+ :default
11
+ elsif input.is_a?( String )
12
+ Float( input )
13
+ elsif input.respond_to?( :to_f )
14
+ input.to_f
15
+ elsif input.respond_to?( :to_i )
16
+ input.to_i.to_f
17
+ else
18
+ :error
19
+ end
20
+ rescue ArgumentError
21
+ :error
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ module CsvMadness
2
+ module ColumnTypes
3
+ class IntegerType < CsvMadness::ColumnType
4
+ def self.convert( input )
5
+ if input.fwf_blank?
6
+ 0
7
+ elsif input.is_a?( String )
8
+ Float( input ).round
9
+ elsif input.respond_to?( :to_f )
10
+ input.to_f.round
11
+ elsif input.respond_to?( :to_i )
12
+ input.to_i
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module CsvMadness
2
+ module ColumnTypes
3
+ class StringType < CsvMadness::ColumnType
4
+ def self.convert( input )
5
+ input.to_s
6
+ end
7
+ end
8
+ end
9
+ end