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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f70535d234603ac01375388383a3823da0f73673
4
- data.tar.gz: cdae7c0ddfa419662a18a097a7373e8d196a1f48
3
+ metadata.gz: cca6d71ea7947967ea15bfa7fd89195549e1f5b4
4
+ data.tar.gz: dca198bcf9db549b57a9c09bac5661194658b12e
5
5
  SHA512:
6
- metadata.gz: 8793368170c8003b8bea3af8b6e84e410973589458c8ac0d244702bed2d779ee914c24c028929053ef10e4cc4ce3d8cc054324700a453d3858a95401df4d402c
7
- data.tar.gz: 871e4bfcfb63b869b60f9bc413c32823f118f2bfaec4296032ea7b7bffa07876ff0db5e66cf782b2c9d76800a0fd81e8b38fd046120ee782f18390657c20fd69
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
@@ -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) do |row_data_hash|
19
- hierarchical_hash = {}
20
- row_data_hash.each do |key, value|
21
- next if value.nil? || value == '' # ignore nil or empty string values
22
- put_value_at_json_path(hierarchical_hash, key, value, field_casting_rules)
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
- yield hierarchical_hash, i
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
@@ -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
- flat
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 are used for internal processing.'
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
@@ -1,6 +1,6 @@
1
1
  module JsonCsv
2
2
 
3
- VERSION = '0.0.5'.freeze
3
+ VERSION = '0.0.6'.freeze
4
4
 
5
5
  def self.version
6
6
  VERSION
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.5
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