json_csv 0.0.5 → 0.0.6
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 +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
|