Chints Vadgama
Chints Vadgama

Reputation: 103

Why I am not getting right value when pushing it to an array?

I have some data in the following format.

  # AB Tests
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  abTests:
    productRanking:
      version: 4
      groups: [
        ratio:
          default: 1
          us: 0.90
          me: 0.0
        value: "LessPopularityEPC"
      ,
        ratio:
          default: 0
          us: 0.1
        value: "CtrEpcJob"
      ,
        ratio:
          default: 0
          me: 1.0
        value: "RandomPerVisitor"
      ]
  # Routes

I want the following output as a string array:

productRanking:LessPopularityEPC
productRanking:CtrEpcJob
productRanking:RandomPerVisitor

I am using the following code which will separate the key and values from the data & store them into an array

START_REGEXP = /# AB Tests/
END_REGEXP = /# Routes/
COMMENT_EXP = /#/

#Function to fetch the key:value & store them into array

def Automate_AB_tests.store_key_value(input_file)
    prev_line = ""
    curr_line = ""
    array = []
    flag = false

    IO.foreach(input_file) do |line|
      prev_line = curr_line
      curr_line = line
      flag = true if line =~ START_REGEXP

      if flag
        unless line =~ COMMENT_EXP
          if line.include? 'version: '
            key = prev_line
            puts key #productRanking: sabt:
          end

          if line.include? 'value: '
            value = line.delete('\n').delete('"').split[1] #LessPopularityEPC CtrlEpcJob RandomPerVisitor
            array << "#{key}:#{value}"
          end
        end

        flag = false if line =~ END_REGEXP
      end 
    end

    puts array
  end

It is fetching the keys but not storing those keys into stringArray. If anyone can point out what's wrong with my code then it would be really great. I am getting output as below:

    productRanking:
:LessPopularityEPC
:CtrEpcJob
:RadomPerVisitor

Upvotes: 0

Views: 71

Answers (1)

Jordan Running
Jordan Running

Reputation: 106027

Since for some reason you apparently can't or won't install Node.js, which would make really, really short work of this, you're stuck doing an ugly hack.

I propose an alternate ugly hack: CSON isn't all that different from YAML. Do some simple substitutions to turn it into YAML and then parse that in Ruby.

Caveat emptor: Like all ugly hacks, this is super fragile. It will probably break as soon as you try to take a vacation. Use at your own risk.

require "yaml"

data = <<END
  # AB Tests
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  abTests:
    productRanking:
      version: 4
      groups: [
        ratio:
          default: 1
          us: 0.90
          me: 0.0
        value: "LessPopularityEPC"
      ,
        ratio:
          default: 0
          us: 0.1
        value: "CtrEpcJob"
      ,
        ratio:
          default: 0
          me: 1.0
        value: "RandomPerVisitor"
      ]
  # Routes
END

AB_TESTS_SECTION_EXPR = /^( +)abTests:\n.+(?=^\1[^ ])/m

# Extract text between "# AB Tests" and "# Routes"
ab_tests = data[AB_TESTS_SECTION_EXPR]

# Turn the CSON array into a YAML array by removing the square brackets and
# commas and inserting a `-` before each "ratio:"
yaml = ab_tests.gsub(/\s+\[$/, '')
         .gsub(/  ratio:\s*$/, '- ratio:')
         .gsub(/^\s*[,\]]\s*$/, '')

puts yaml

This will print the following valid YAML:

abTests:
  productRanking:
    version: 4
    groups:
    - ratio:
        default: 1
        us: 0.90
        me: 0.0
      value: "LessPopularityEPC"

    - ratio:
        default: 0
        us: 0.1
      value: "CtrEpcJob"

    - ratio:
        default: 0
        me: 1.0
      value: "RandomPerVisitor"

Now we just need to parse the YAML into Ruby and extract the data we need:

hsh = YAML.load(yaml)

hsh["abTests"].each do |key, val|
  val["groups"].each do |group|
    puts "#{key}:#{group['value']}"
  end
end
# => productRanking:LessPopularityEPC
#    productRanking:CtrEpcJob
#    productRanking:RandomPerVisitor

Upvotes: 2

Related Questions