csv_party 0.0.1.pre

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. checksums.yaml +7 -0
  2. data/lib/csv_party.rb +149 -0
  3. metadata +44 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 475350af4d86e4c6586ea1752a731a888ddb336d
4
+ data.tar.gz: 679da67bcacd832eb394f0bd93f483babcf44ecc
5
+ SHA512:
6
+ metadata.gz: 9c91fdd4277ba7e80b9561333879386c115dbaa58df621705cdbfae8d517ab7a74b2298efdc8f45e32be014f2718d1c2fa8fcaba3adbb17db13b0e38ffda934b
7
+ data.tar.gz: 58597567ec2ab2e1950bbc32a7526fe57ebe632437074661dcfc7c3390a90f570ce90ce203acfd622f84dea4aedea5e9d429206953bd21eb59621e986cfd596e
data/lib/csv_party.rb ADDED
@@ -0,0 +1,149 @@
1
+ require 'csv'
2
+ require 'bigdecimal'
3
+ require 'ostruct'
4
+
5
+ class CSVParty
6
+ def initialize(csv_path)
7
+ @headers = CSV.new(File.open(csv_path)).shift
8
+ @csv = CSV.new(File.open(csv_path), headers: true)
9
+ raise_unless_named_parsers_are_valid
10
+ raise_unless_csv_has_all_headers
11
+ end
12
+
13
+ def import!
14
+ @csv.each do |row|
15
+ parsed_row = parse_row(row)
16
+ import_row(parsed_row)
17
+ end
18
+ end
19
+
20
+ def parse_row(row)
21
+ parsed_row = OpenStruct.new
22
+ parsed_row[:values] = OpenStruct.new
23
+
24
+ columns.each do |name, options|
25
+ header = options[:header]
26
+ parser = options[:parser]
27
+ parsed_row[name] = instance_exec(row[header], &parser)
28
+ parsed_row[:values][name] = row[header]
29
+ end
30
+
31
+ return parsed_row
32
+ end
33
+
34
+ def import_row(parsed_row)
35
+ importer.call(parsed_row)
36
+ end
37
+
38
+ def self.column(name, options, &block)
39
+ if columns.has_key?(name)
40
+ raise DuplicateColumnError, "A column named :#{name} has already been defined, choose a different name"
41
+ end
42
+ unless options.has_key?(:header)
43
+ raise MissingHeaderError, "A header must be specified for #{name}"
44
+ end
45
+
46
+ if block_given?
47
+ columns[name] = { header: options[:header], parser: block }
48
+ else
49
+ if options.has_key?(:as)
50
+ parser_method = "#{options[:as]}_parser".to_sym
51
+ else
52
+ parser_method = :string_parser
53
+ end
54
+ columns[name] = {
55
+ header: options[:header],
56
+ parser: Proc.new { |value| send(parser_method, value) },
57
+ parser_method: parser_method
58
+ }
59
+ end
60
+ end
61
+
62
+ def self.import(&block)
63
+ @importer = block
64
+ end
65
+
66
+ def self.columns
67
+ @columns ||= {}
68
+ end
69
+
70
+ def columns
71
+ self.class.columns
72
+ end
73
+
74
+ def self.importer
75
+ @importer
76
+ end
77
+
78
+ def importer
79
+ self.class.importer
80
+ end
81
+
82
+ private
83
+
84
+
85
+ def raw_parser(value)
86
+ value
87
+ end
88
+
89
+ def string_parser(value)
90
+ value.to_s.strip
91
+ end
92
+
93
+ def boolean_parser(value)
94
+ ['1', 't', 'true'].include? value.to_s.strip.downcase
95
+ end
96
+
97
+ def integer_parser(value)
98
+ value.to_i
99
+ end
100
+
101
+ def decimal_parser(value)
102
+ cleaned_value = value.to_s.strip.gsub(/[^0-9.]/, "")
103
+ BigDecimal.new(cleaned_value)
104
+ end
105
+
106
+ def named_parsers
107
+ (private_methods + methods).grep(/_parser$/)
108
+ end
109
+
110
+ def columns_with_named_parsers
111
+ columns.select { |name, options| options.has_key?(:parser_method) }
112
+ end
113
+
114
+ # This error has to be raised at runtime because, when the class body
115
+ # is being executed, the parser methods won't be available unless
116
+ # they are defined above the column definitions in the class body
117
+ def raise_unless_named_parsers_are_valid
118
+ columns_with_named_parsers.each do |name, options|
119
+ parser = options[:parser_method]
120
+ unless named_parsers.include? parser
121
+ raise UnknownParserError,
122
+ "You're trying to use the :#{parser.to_s.gsub('_parser', '')} parser for the :#{name} column, but it doesn't exist. Available parsers are: :#{named_parsers.map { |p| p.to_s.gsub('_parser', '') }.join(', :')}."
123
+ end
124
+ end
125
+ end
126
+
127
+ def defined_headers
128
+ columns.map { |name, options| options[:header] }
129
+ end
130
+
131
+ def raise_unless_csv_has_all_headers
132
+ missing_columns = defined_headers - @headers
133
+ unless missing_columns.empty?
134
+ raise MissingColumnError, "CSV file is missing column(s) with header(s) '#{missing_columns.join("', '")}'."
135
+ end
136
+ end
137
+ end
138
+
139
+ class UnknownParserError < ArgumentError
140
+ end
141
+
142
+ class MissingHeaderError < ArgumentError
143
+ end
144
+
145
+ class DuplicateColumnError < ArgumentError
146
+ end
147
+
148
+ class MissingColumnError < ArgumentError
149
+ end
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: csv_party
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre
5
+ platform: ruby
6
+ authors:
7
+ - Rico Jones
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-30 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A gem for making CSV imports a little more fun.
14
+ email: rico@toasterlovin.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/csv_party.rb
20
+ homepage: http://rubygems.org/gems/csv_party
21
+ licenses:
22
+ - MIT
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">"
36
+ - !ruby/object:Gem::Version
37
+ version: 1.3.1
38
+ requirements: []
39
+ rubyforge_project:
40
+ rubygems_version: 2.5.1
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: CSV Party
44
+ test_files: []