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.
- checksums.yaml +7 -0
- data/lib/csv_party.rb +149 -0
- 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: []
|