Class: Synthra::Export::Csv
Overview
Exports generated data as CSV
Instance Method Summary collapse
-
#escape_csv_formula(str) ⇒ Object
private
SECURITY (CSV injection): a string value beginning with = + - @ tab or CR is treated as a formula by spreadsheet apps that open the export.
- #export ⇒ Object
-
#export_headers ⇒ String
Export with headers only (no data).
- #flatten_record(record, prefix = "") ⇒ Object private
- #format_value(value) ⇒ Object private
Constructor Details
This class inherits a constructor from Synthra::Export::Base
Instance Method Details
#escape_csv_formula(str) ⇒ Object (private)
SECURITY (CSV injection): a string value beginning with = + - @ tab or CR is treated as a
formula by spreadsheet apps that open the export. Prefix it with a single quote so the cell
is rendered as literal text. The gem ships a hostile_payloads type that emits exactly these.
95 96 97 |
# File 'lib/synthra/export/csv.rb', line 95 def escape_csv_formula(str) str.match?(/\A[=+\-@\t\r]/) ? "'#{str}" : str end |
#export ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/synthra/export/csv.rb', line 15 def export count = [:count] || 10 seed = [:seed] mode = [:mode] || :random records = schema.generate_many(count, seed: seed, mode: mode, registry: registry) return "" if records.empty? # Flatten nested objects for CSV flat_records = records.map { |r| flatten_record(r) } # Get all possible headers headers = flat_records.flat_map(&:keys).uniq.sort CSV.generate do |csv| csv << headers flat_records.each do |record| csv << headers.map { |h| format_value(record[h]) } end end end |
#export_headers ⇒ String
Export with headers only (no data)
42 43 44 45 |
# File 'lib/synthra/export/csv.rb', line 42 def export_headers headers = schema.fields.map(&:name) CSV.generate { |csv| csv << headers } end |
#flatten_record(record, prefix = "") ⇒ Object (private)
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/synthra/export/csv.rb', line 49 def flatten_record(record, prefix = "") result = {} record.each do |key, value| full_key = prefix.empty? ? key : "#{prefix}.#{key}" case value when Hash result.merge!(flatten_record(value, full_key)) when Array if value.first.is_a?(Hash) # Array of objects - just count them result[full_key] = "[#{value.length} items]" else result[full_key] = value.join("; ") end else result[full_key] = value end end result end |
#format_value(value) ⇒ Object (private)
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/synthra/export/csv.rb', line 73 def format_value(value) case value when nil "" when true "true" when false "false" when Array escape_csv_formula(value.join("; ")) when Hash escape_csv_formula(JSON.generate(value)) when String escape_csv_formula(value) else value.to_s # numerics/dates are safe — never prefix them (would break -5, =NA values stay strings) end end |