class Keen::CSV

Public Class Methods

new(response, options = {}) click to toggle source
# File lib/keen-csv.rb, line 11
def initialize(response, options = {})
  @rawResponse = response
  @options = options.is_a?(Hash) ? @@defaultOptions.merge(options) : @@defaultOptions
end

Public Instance Methods

csvString() click to toggle source

csvString Generates and returns a CSV for this Keen response


# File lib/keen-csv.rb, line 20
def csvString
  resultColumns = self.generateResultColumns
  headers = resultColumns[:columns].keys
  # Start off instantiating the csv string with the header values
  csvString = headers.map{|s| self.filterValue(s)}.join(@options[:delimiter])

  # Now iterate over each row, sticking its value under each header
  (0..resultColumns[:maxRowIndex]).each do |rowIndex|
    csvString << "\r\n"
    csvString << headers.map{ |header|
      self.filterValue(resultColumns[:columns][header][rowIndex])
    }.join(@options[:delimiter])
  end
  return csvString
end

Protected Instance Methods

columnIsFiltered?(header) click to toggle source

columnIsFiltered? Takes a column header, and determines whether that column should be filtered out


# File lib/keen-csv.rb, line 103
def columnIsFiltered?(header)
  return @options[:filteredColumns] &&
         @options[:filteredColumns].is_a?(Array) &&
         @options[:filteredColumns].include?(header)
end
filterValue(value) click to toggle source

filterValue Takes a scalar value, and returns a CSV-compatible one


# File lib/keen-csv.rb, line 113
def filterValue(value)
  if value == nil
    return ''
  else
    return value.to_s.gsub(/#{Regexp.escape(@options[:delimiter])}/, @options[:delimiterSub])
  end
end
flatten(object, flattened = {}, prefix = "") click to toggle source

flatten Converts any nested dictionaries into a flattened/delimited one.


# File lib/keen-csv.rb, line 125
def flatten(object, flattened = {}, prefix = "")
  handleValue = lambda do |value, newPrefix|
    if value.is_a?(Hash) || value.is_a?(Array)
      # recurse!
      flatten(value, flattened, newPrefix + @options[:nestedDelimiter])
    else
      flattened[newPrefix] = value
    end
  end

  if object.is_a? Hash
    object.each do |key, value|
      handleValue.call(value, prefix + key)
    end
  elsif object.is_a? Array
    object.each_with_index do |value, index|
      handleValue.call(value, prefix + index.to_s)
    end
  else
    return object
  end

  return flattened
end
generateResultColumns() click to toggle source

generateResultColumns Transforms the Keen result columnar Map, keyed by header


# File lib/keen-csv.rb, line 42
def generateResultColumns
  resultColumns = {
    columns: {},
    maxRowIndex: 0 # We're going to count the rows, for future use
  }

  # Using a lambda to add the right columns into resultColumns, and keep track
  # of maxRowIndex
  setColumnValue = lambda do |column, rowIndex, value|
    unless self.columnIsFiltered?(column)
      resultColumns[:columns][column] ||= []
      resultColumns[:columns][column][rowIndex] = value
    end

    # Gotta keep track of how many rows we're working with.
    resultColumns[:maxRowIndex] = rowIndex if rowIndex > resultColumns[:maxRowIndex]
  end

  # Exit early if this is a simple math operation
  if @rawResponse.is_a? Numeric
    resultColumns[:columns]['result'] = [@rawResponse]
    resultColumns[:maxRowIndex] = 1
    return resultColumns
  end

  rowIndex = 0
  @rawResponse.each do |object|
    if object["value"].is_a? Array
      # This result is grouped! We're gonna have to create alot more columns and rows
      object["value"].each do |group|

        # iterate over each value grouping, and store the values
        self.flatten(group).each do |column, value|
          setColumnValue.call(column, rowIndex, value)
        end
        if object["timeframe"]
          self.flatten({"timeframe" => object["timeframe"]}).each do |column, value|
            setColumnValue.call(column, rowIndex, value)
          end
        end
        rowIndex += 1

      end
    else
      # Not grouped: This either an Extraction or a math operation on an interval.
      self.flatten(object).each do |column, value|
        setColumnValue.call(column, rowIndex, value)
      end
      rowIndex += 1

    end
  end

  resultColumns
end