json_csv 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/json_csv/array_notation.rb +23 -0
- data/lib/json_csv/csv_to_json.rb +23 -7
- data/lib/json_csv/json_to_csv.rb +8 -3
- data/lib/json_csv/utils.rb +64 -0
- data/lib/json_csv/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cca6d71ea7947967ea15bfa7fd89195549e1f5b4
|
4
|
+
data.tar.gz: dca198bcf9db549b57a9c09bac5661194658b12e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8929b7911dbb7da2e29a56c8e6a2b93df9ab203d3202d435b3932c782654f7392b3dce1d27215021b53544864a8569a6e5b230a0bd029a21745dc27ace2e2989
|
7
|
+
data.tar.gz: c00fed1d0fbed0b41c0261005909290ea48990cf7b4532bc0ff60f16cbaa1251c3aaa5244f6cad0cf695d66e43f822abf9f92a881632da1acdf49143b8e37d8a
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module JsonCsv
|
2
|
+
module ArrayNotation
|
3
|
+
BRACKETS = 'BRACKETS'.freeze
|
4
|
+
DASH = 'DASH'.freeze
|
5
|
+
|
6
|
+
VALID_ARRAY_NOTATIONS = [BRACKETS, DASH].freeze
|
7
|
+
|
8
|
+
def self.bracket_header_to_dash_header(bracket_header)
|
9
|
+
# e.g. replace occurrences of '[1]' with '-1'
|
10
|
+
bracket_header.gsub(/(\[(\d+)\])/, '-\2')
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.dash_header_to_bracket_header(dash_header)
|
14
|
+
# e.g. replace occurrences of '-1' with '[1]'
|
15
|
+
dash_header.gsub(/(-(\d+))/, '[\2]')
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.raise_error_if_invalid_array_notation_value!(error_class, array_notation)
|
19
|
+
raise error_class, "Invalid array notation. Must be one of #{VALID_ARRAY_NOTATIONS.join(' or ')}." unless VALID_ARRAY_NOTATIONS.include?(array_notation)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/json_csv/csv_to_json.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json_csv/array_notation'
|
2
|
+
require 'json_csv/utils'
|
1
3
|
require 'csv'
|
2
4
|
|
3
5
|
module JsonCsv
|
@@ -13,19 +15,33 @@ module JsonCsv
|
|
13
15
|
# presenting that row as un-flattened json.
|
14
16
|
# This method works for large CSVs and uses very little memory
|
15
17
|
# because it only keeps one row in memory at a time.
|
16
|
-
def csv_file_to_hierarchical_json_hash(path_to_csv, field_casting_rules = {})
|
18
|
+
def csv_file_to_hierarchical_json_hash(path_to_csv, field_casting_rules = {}, array_notation = JsonCsv::ArrayNotation::BRACKETS, strip_value_whitespace = true)
|
17
19
|
i = 0
|
18
|
-
CSV.foreach(path_to_csv, headers: true
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
CSV.foreach(path_to_csv, headers: true, header_converters: lambda { |header|
|
21
|
+
if array_notation == JsonCsv::ArrayNotation::DASH
|
22
|
+
JsonCsv::ArrayNotation.dash_header_to_bracket_header(header).strip
|
23
|
+
else
|
24
|
+
header.strip
|
23
25
|
end
|
24
|
-
|
26
|
+
}) do |row_data_hash|
|
27
|
+
yield csv_row_hash_to_hierarchical_json_hash(row_data_hash, field_casting_rules, strip_value_whitespace), i
|
25
28
|
i += 1
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
32
|
+
def csv_row_hash_to_hierarchical_json_hash(row_data_hash, field_casting_rules, strip_value_whitespace = true)
|
33
|
+
hierarchical_hash = {}
|
34
|
+
row_data_hash.each do |key, value|
|
35
|
+
next if value.nil? || value == '' # ignore nil or empty string values
|
36
|
+
put_value_at_json_path(hierarchical_hash, key, value, field_casting_rules)
|
37
|
+
end
|
38
|
+
# Clean up empty array elements, which may have come about from CSV data
|
39
|
+
# that was 1-indexed instead of 0-indexed.
|
40
|
+
JsonCsv::Utils.recursively_remove_blank_fields!(hierarchical_hash)
|
41
|
+
JsonCsv::Utils.recursively_strip_value_whitespace!(hierarchical_hash) if strip_value_whitespace
|
42
|
+
hierarchical_hash
|
43
|
+
end
|
44
|
+
|
29
45
|
# For the given obj, puts the given value at the given json_path,
|
30
46
|
# creating nested elements as needed. This method calls itself
|
31
47
|
# recursively when placing a value at a nested path, and during
|
data/lib/json_csv/json_to_csv.rb
CHANGED
@@ -7,11 +7,16 @@ module JsonCsv
|
|
7
7
|
# strings (because CSVs are dumb and don't store info about data types)
|
8
8
|
# Set first_index to 1 if you want the first element in an array to
|
9
9
|
#
|
10
|
-
def json_hash_to_flat_csv_row_hash(json_hash)
|
10
|
+
def json_hash_to_flat_csv_row_hash(json_hash, array_notation = JsonCsv::ArrayNotation::BRACKETS)
|
11
11
|
flat = flatten_hash(json_hash)
|
12
12
|
# Convert values to strings because in the CSV file, all values are strings
|
13
13
|
flat.each { |key, val| flat[key] = val.nil? ? '' : val.to_s }
|
14
|
-
|
14
|
+
# If we're using dash array notation, convert the headers
|
15
|
+
if array_notation == JsonCsv::ArrayNotation::DASH
|
16
|
+
Hash[flat.map { |key, val| [JsonCsv::ArrayNotation.bracket_header_to_dash_header(key), val] }]
|
17
|
+
else
|
18
|
+
flat
|
19
|
+
end
|
15
20
|
end
|
16
21
|
|
17
22
|
# This method calls itself recursively while flattening a hash, and during
|
@@ -20,7 +25,7 @@ module JsonCsv
|
|
20
25
|
if obj.is_a?(Hash)
|
21
26
|
obj.each do |key, val|
|
22
27
|
if key_contains_unallowed_characters?(key)
|
23
|
-
raise ArgumentError, 'Cannot deal with hash keys that contain "[" or "]" because these
|
28
|
+
raise ArgumentError, 'Cannot deal with hash keys that contain "[" or "]" or "." because these characters have special meanings in CSV headers.'
|
24
29
|
end
|
25
30
|
path = parent_path + (parent_path.empty? ? '' : '.') + key
|
26
31
|
flatten_hash(val, path, flat_hash_to_build)
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module JsonCsv
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
# Returns true for empty strings, empty arrays, or empty hashes.
|
5
|
+
# Also returns true for strings that only contain whitespace.
|
6
|
+
# Returns false for all other values, including booleans and numbers.
|
7
|
+
def self.removable_value?(value)
|
8
|
+
return true if value.respond_to?(:empty?) && value.empty? # empty string, empty array, or empty hash
|
9
|
+
return true if value.is_a?(String) && value.strip.empty? # string that only contains whitespace
|
10
|
+
return true if value.nil?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.recursively_remove_blank_fields!(hash_or_array)
|
15
|
+
return if hash_or_array.frozen? # We can't modify a frozen value, so we won't.
|
16
|
+
|
17
|
+
if hash_or_array.is_a?(Array)
|
18
|
+
# Recurse through non-empty elements
|
19
|
+
hash_or_array.each do |element|
|
20
|
+
recursively_remove_blank_fields!(element) if element.is_a?(Hash) || element.is_a?(Array)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Delete blank array element values on this array level (including empty object ({}) values)
|
24
|
+
hash_or_array.delete_if do |element|
|
25
|
+
removable_value?(element)
|
26
|
+
end
|
27
|
+
elsif hash_or_array.is_a?(Hash)
|
28
|
+
hash_or_array.each_value do |value|
|
29
|
+
recursively_remove_blank_fields!(value) if value.is_a?(Hash) || value.is_a?(Array)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Delete blank hash values on this hash level (including empty object ({}) values)
|
33
|
+
hash_or_array.delete_if do |_key, value|
|
34
|
+
removable_value?(value)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
raise ArgumentError, 'Must supply a hash or array.'
|
38
|
+
end
|
39
|
+
|
40
|
+
hash_or_array
|
41
|
+
end
|
42
|
+
|
43
|
+
# Recursively goes through an object and strips whitespace,
|
44
|
+
# modifying the object's nested child hashes or array.
|
45
|
+
# Note: This method modifies hash values, but does not
|
46
|
+
# modify hash keys.
|
47
|
+
def self.recursively_strip_value_whitespace!(obj)
|
48
|
+
if obj.is_a?(Array)
|
49
|
+
obj.each do |element|
|
50
|
+
recursively_strip_value_whitespace!(element)
|
51
|
+
end
|
52
|
+
elsif obj.is_a?(Hash)
|
53
|
+
obj.each_value do |value|
|
54
|
+
recursively_strip_value_whitespace!(value)
|
55
|
+
end
|
56
|
+
elsif obj.is_a?(String)
|
57
|
+
obj.strip!
|
58
|
+
end
|
59
|
+
|
60
|
+
obj
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/json_csv/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_csv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric O'Hanlon
|
@@ -88,8 +88,10 @@ extra_rdoc_files: []
|
|
88
88
|
files:
|
89
89
|
- README.md
|
90
90
|
- lib/json_csv.rb
|
91
|
+
- lib/json_csv/array_notation.rb
|
91
92
|
- lib/json_csv/csv_to_json.rb
|
92
93
|
- lib/json_csv/json_to_csv.rb
|
94
|
+
- lib/json_csv/utils.rb
|
93
95
|
- lib/json_csv/version.rb
|
94
96
|
- lib/tasks/json_csv.rake
|
95
97
|
- lib/tasks/json_csv/ci.rake
|