Rubyist Rubyist - 1 year ago 126
Ruby Question

YAML file range, converting string to array throwing undefined method `to_a'

I have a YAML file that contains a bunch of ranges as the values:

Bulbasaur: (12.2..1071)
Ivysaur: (19.5..1632)
Venusaur: (32.2..2580)
Charmander: (10.7..955)
Charmeleon: (18.5..1557)
Charizard: (32.5..2602)
Squirtle: (11.4..1008)
Wartortle: (18.9..1582)
Blastoise: (31.7..2542)
Caterpie: (4.3..443)
Metapod: (4.7..477)
Butterfree: (17.2..1454)

While attempting to turn these ranges into an array I am getting an error:
<main>': undefined method to_a'

How I am attempting to do this is very simple:

require 'yaml'

data = YAML.load_file('./lib/lists/yamls/combat_power.yml')

print 'Enter a name: '
name = gets.chomp.capitalize

new_data = data['combat_power'][name]

puts new_data.to_a

When this is run:

Enter a name: Charmeleon
go.rb:10:in `<main>': undefined method `to_a' for "(18.5..1557)":String (NoMetho
Did you mean? to_yaml

My question being, how do I turn a range key into an array when it is being provided from a YAML file? Any other way you can just turn a range into an array using the
function, but it doesn't appear to be working. Is there a simple solution I am missing, or are ranges not allowed to be used in YAML files?

Answer Source

A few things:

  1. Ruby's YAML implementation doesn't unserialize ruby objects without you explicitly telling it to do so. This is both a security feature (some code is dangerous to unserialize), as well as a somewhat impossible task to accomplish (how is it supposed to know what you intend to be evaluated?). So, to turn the range string into an actual Ruby Range object, you need to eval it:

    require 'yaml'
    data = YAML.load_file('./yamls.yaml')
    print 'Enter a name: '
    name = gets.chomp.capitalize
    new_data = data['combat_power'][name]
    puts eval(new_data).class
    # => Range
    puts eval(new_data).to_a

    Note that you should only eval text that you explicitly wrote--evaling code from a random source, such as user input, can be a serious security issue. But as long as you are only evaling values from that YAML file that you wrote, you should be fine.

  2. Ruby doesn't know how to enumerate a range of floats, so your (17.2..1454).to_a will throw a TypeError. This is because the interpreter can't possibly know if you want to increment by +1, +0.1, etc. I'm not sure how you want to solve this issue, since the solution will be based on the meaning of your data specifically.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download