2

I have a Ruby array (don't ask me why it is not hash already, i can't do anything about it):

[{":cost=>100", ":size=>2"}]

What do i need to do to make it the classical Ruby hash with keys and values? What is my best option? Maybe there is some libraries for this kind of operations?

Thanks.

9
  • 5
    You posted invalid code. I think you misplaced (or inserted) the {}. Commented Apr 5, 2016 at 20:05
  • Maybe eval('{' + [":cost=>100", ":size=>2"].join(',') + '}')? Commented Apr 5, 2016 at 20:13
  • Actually no. This is what i get with "puts" command when i try to validate the data visually. And i get the "Array" class when i'm printing the class name of this object with puts(MyClass.class). Commented Apr 5, 2016 at 20:15
  • @AlexSid, you mean, if you do you_obj.to_s you get "[{\":cost=>100\", \":size=>2\"}]"? Commented Apr 5, 2016 at 20:24
  • 1
    You show an array. If it's a string, show a string (I.e., enclose in single or double quotes). Commented Apr 5, 2016 at 20:27

2 Answers 2

1

First we need to clean the string to make it look like a valid array:

my_string = my_string[2..-3]
my_array = eval("[#{my_string}]")

Now you can join the strings, and then eval it into a hash:

elements = my_array.join(', ')
my_hash = eval("{ #{ elements } }")

(this can be done in fewer lines, but I separated them for clarity)

Sign up to request clarification or add additional context in comments.

1 Comment

It's worth noting that whenever using eval that you should be extra super careful not to execute arbitrary strings. Be absolutely sure this data comes from a trusted source.
1

You could use the JSON module to do that. That would arguably be safer than by using eval.

To see how JSON could be used, let's do some reverse-engineering. You want to create a hash:

h = { :cost=>100, :size=>2 }

from the string:

str = '[{":cost=>100", ":size=>2"}]'
  #=> "[{\":cost=>100\", \":size=>2\"}]"

Let's see how that hash would be encoded as a JSON string:

require 'json'
jstr = JSON.generate(h)
  #=> "{\"cost\":100,\"size\":2}" 

Once we have jstr (which is nothing more than a string) we can extract the desired hash:

JSON.parse(jstr)
  #=> {"cost"=>100, "size"=>2}

so the task reduces to converting str to jstr:

  "[{\":cost=>100\", \":size=>2\"}]" => "{\"cost\":100,\"size\":2}" 

Perhaps the easiest way is to first pull out the keys and values, which we can do with a regex:

r = /
    (       # start capture group 1
      [a-z] # match a lowercase letter
      \w*   # match >= 0 word characters
    )       # close capture group 1
    =>      # match characters
    (-?\d+) # optionally match a minus sign followed by > 0 digits in
            # capture group 2
    /x      # free-spacing regex definition mode

arr = str.scan r
  #=> [["cost", "100"], ["size", "2"]]

We can now form jstr:

jstr = "{#{ arr.map { |k,v| "\"#{k}\":#{v}" }.join(",") }}" 
  #=> "{\"cost\":100,\"size\":2}"

To confirm,

h = JSON.parse(jstr)
  #=> {"cost"=>100, "size"=>2}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.