How do I convert a String object into a Hash object?












118















I have a string which looks like a hash:



"{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }"


How do I get a Hash out of it? like:



{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }


The string can have any depth of nesting. It has all the properties how a valid Hash is typed in Ruby.










share|improve this question























  • I think eval will do something here. Let me test first. I posted the question too early I think. :)

    – Waseem
    Nov 3 '09 at 14:25











  • Ohh yeah just pass it to the eval. :)

    – Waseem
    Nov 3 '09 at 14:27
















118















I have a string which looks like a hash:



"{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }"


How do I get a Hash out of it? like:



{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }


The string can have any depth of nesting. It has all the properties how a valid Hash is typed in Ruby.










share|improve this question























  • I think eval will do something here. Let me test first. I posted the question too early I think. :)

    – Waseem
    Nov 3 '09 at 14:25











  • Ohh yeah just pass it to the eval. :)

    – Waseem
    Nov 3 '09 at 14:27














118












118








118


34






I have a string which looks like a hash:



"{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }"


How do I get a Hash out of it? like:



{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }


The string can have any depth of nesting. It has all the properties how a valid Hash is typed in Ruby.










share|improve this question














I have a string which looks like a hash:



"{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }"


How do I get a Hash out of it? like:



{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }


The string can have any depth of nesting. It has all the properties how a valid Hash is typed in Ruby.







ruby






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 3 '09 at 14:24









WaseemWaseem

4,29073448




4,29073448













  • I think eval will do something here. Let me test first. I posted the question too early I think. :)

    – Waseem
    Nov 3 '09 at 14:25











  • Ohh yeah just pass it to the eval. :)

    – Waseem
    Nov 3 '09 at 14:27



















  • I think eval will do something here. Let me test first. I posted the question too early I think. :)

    – Waseem
    Nov 3 '09 at 14:25











  • Ohh yeah just pass it to the eval. :)

    – Waseem
    Nov 3 '09 at 14:27

















I think eval will do something here. Let me test first. I posted the question too early I think. :)

– Waseem
Nov 3 '09 at 14:25





I think eval will do something here. Let me test first. I posted the question too early I think. :)

– Waseem
Nov 3 '09 at 14:25













Ohh yeah just pass it to the eval. :)

– Waseem
Nov 3 '09 at 14:27





Ohh yeah just pass it to the eval. :)

– Waseem
Nov 3 '09 at 14:27












12 Answers
12






active

oldest

votes


















70














The string created by calling Hash#inspect can be turned back into a hash by calling eval on it. However, this requires the same to be true of all of the objects in the hash.



If I start with the hash {:a => Object.new}, then its string representation is "{:a=>#<Object:0x7f66b65cf4d0>}", and I can't use eval to turn it back into a hash because #<Object:0x7f66b65cf4d0> isn't valid Ruby syntax.



However, if all that's in the hash is strings, symbols, numbers, and arrays, it should work, because those have string representations that are valid Ruby syntax.






share|improve this answer


























  • "if all that's in the hash is strings, symbols, and numbers,". This says a lot. So I can check the validity of a string to be evaluated as a hash by making sure that the above statement is valid for that string.

    – Waseem
    Nov 3 '09 at 14:38






  • 1





    Yes, but in order to do that you either need a full Ruby parser, or you need to know where the string came from in the first place and know that it can only generate strings, symbols, and numbers. (See also Toms Mikoss's answer about trusting the contents of the string.)

    – Ken Bloom
    Nov 3 '09 at 14:43






  • 8





    Be carefule where you use this. Using eval at the wrong place is a huge security hole. Anything inside the string, will be evaluated. So imagine if in an API someone injected rm -fr

    – Pithikos
    Apr 5 '16 at 14:23



















127














Quick and dirty method would be



eval("{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }") 


But it has severe security implications.

It executes whatever it is passed, you must be 110% sure (as in, at least no user input anywhere along the way) it would contain only properly formed hashes or unexpected bugs/horrible creatures from outer space might start popping up.






share|improve this answer





















  • 13





    I have a light saber with me. I can take care of those creatures and bugs. :)

    – Waseem
    Nov 3 '09 at 14:35






  • 11





    USING EVAL can be dangerous here, according to my teacher. Eval takes any ruby code and runs it. The danger here is analogous to SQL injection danger. Gsub is preferable.

    – boulder_ruby
    Jul 20 '12 at 17:37






  • 8





    Example string showing why David's teacher is correct: '{:surprise => "#{system "rm -rf * "}"}'

    – A. Wilson
    Jul 30 '12 at 18:09






  • 13





    I cannot emphasize the DANGER of using EVAL here enough! This is absolutely forbidden if user input can ever wind its way into your string.

    – Dave Collins
    Jan 11 '13 at 13:15











  • good idea. thanks

    – Alireza Rahmani Khalili
    May 28 '17 at 11:26



















118














For different string, you can do it without using dangerous eval method:



hash_as_string = "{"0"=>{"answer"=>"1", "value"=>"No"}, "1"=>{"answer"=>"2", "value"=>"Yes"}, "2"=>{"answer"=>"3", "value"=>"No"}, "3"=>{"answer"=>"4", "value"=>"1"}, "4"=>{"value"=>"2"}, "5"=>{"value"=>"3"}, "6"=>{"value"=>"4"}}"
JSON.parse hash_as_string.gsub('=>', ':')





share|improve this answer



















  • 1





    This answer should be selected for avoiding using eval.

    – Michael_Zhang
    Sep 4 '18 at 21:57











  • you should also replace nils, f.e. JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))

    – Yo Ludke
    Nov 9 '18 at 12:06



















22














This short little snippet will do it, but I can't see it working with a nested hash. I think it's pretty cute though



STRING.gsub(/[{}:]/,'').split(', ').map{|h| h1,h2 = h.split('=>'); {h1 => h2}}.reduce(:merge)


Steps
1. I eliminate the '{','}' and the ':'
2. I split upon the string wherever it finds a ','
3. I split each of the substrings that were created with the split, whenever it finds a '=>'. Then, I create a hash with the two sides of the hash I just split apart.
4. I am left with an array of hashes which I then merge together.



EXAMPLE INPUT: "{:user_id=>11, :blog_id=>2, :comment_id=>1}"
RESULT OUTPUT: {"user_id"=>"11", "blog_id"=>"2", "comment_id"=>"1"}






share|improve this answer



















  • 1





    That is one sick oneliner ! :) +1

    – blushrt
    May 23 '13 at 13:02






  • 3





    Won't this also strip away {}: characters from values inside the stringified hash?

    – Vladimir Panteleev
    Aug 7 '14 at 13:58



















18














Maybe YAML.load ?






share|improve this answer
























  • (load method supports strings)

    – silent
    Nov 3 '09 at 14:41






  • 4





    That requires a totally different string representation, but it much, much safer. (And the string representation is just as easy to generate -- just call #to_yaml, rather than #inspect)

    – Ken Bloom
    Nov 3 '09 at 14:46











  • Wow. I had no idea it was so easy to parse strings w/ yaml. It takes my chain of linux bash commands that generate data and intelligently turns it into a ruby Hash w/o any string format massaging.

    – labyrinth
    Aug 29 '17 at 20:56



















15














The solutions so far cover some cases but miss some (see below). Here's my attempt at a more thorough (safe) conversion. I know of one corner case which this solution doesn't handle which is single character symbols made up of odd, but allowed characters. For example {:> => :<} is a valid ruby hash.



I put this code up on github as well. This code starts with a test string to exercise all the conversions



require 'json'

# Example ruby hash string which exercises all of the permutations of position and type
# See http://json.org/
ruby_hash_text='{"alpha"=>{"first second > third"=>"first second > third", "after comma > foo"=>:symbolvalue, "another after comma > foo"=>10}, "bravo"=>{:symbol=>:symbolvalue, :aftercomma=>10, :anotheraftercomma=>"first second > third"}, "charlie"=>{1=>10, 2=>"first second > third", 3=>:symbolvalue}, "delta"=>["first second > third", "after comma > foo"], "echo"=>[:symbol, :aftercomma], "foxtrot"=>[1, 2]}'

puts ruby_hash_text

# Transform object string symbols to quoted strings
ruby_hash_text.gsub!(/([{,]s*):([^>s]+)s*=>/, '1"2"=>')

# Transform object string numbers to quoted strings
ruby_hash_text.gsub!(/([{,]s*)([0-9]+.?[0-9]*)s*=>/, '1"2"=>')

# Transform object value symbols to quotes strings
ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>s*:([^,}s]+s*)/, '12=>"3"')

# Transform array value symbols to quotes strings
ruby_hash_text.gsub!(/([[,]s*):([^,]s]+)/, '1"2"')

# Transform object string object value delimiter to colon delimiter
ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>/, '12:')

puts ruby_hash_text

puts JSON.parse(ruby_hash_text)


Here are some notes on the other solutions here





  • @Ken Bloom and @Toms Mikoss's solutions use eval which is too scary for me (as Toms rightly points out).


  • @zolter's solution works if your hash has no symbols or numeric keys.


  • @jackquack's solution works if there are no quoted strings mixed in with the symbols.


  • @Eugene's solution works if your symbols don't use all the allowed characters (symbol literals have a broader set of allowed characters).


  • @Pablo's solution works as long as you don't have a mix of symbols and quoted strings.






share|improve this answer


























  • Very cool solution. You could add a gsub of all :nil to :null to handle that particular weirdness.

    – SteveTurczyn
    May 6 '16 at 13:30






  • 1





    This solution also has the bonus of working on multi-level hashes recursively, since it leverages JSON#parse. I had some trouble with nesting on other solutions.

    – Patrick Read
    Dec 13 '16 at 15:50





















12














I had the same problem. I was storing a hash in Redis. When retrieving that hash, it was a string. I didn't want to call eval(str) because of security concerns. My solution was to save the hash as a json string instead of a ruby hash string. If you have the option, using json is easier.



  redis.set(key, ruby_hash.to_json)
JSON.parse(redis.get(key))


TL;DR: use to_json and JSON.parse






share|improve this answer


























  • This is the best answer by far. to_json and JSON.parse

    – ardochhigh
    Sep 2 '17 at 7:23






  • 3





    To whoever downvoted me. Why? I had the same issue, trying to convert a string representation of a ruby hash into an actual hash object. I realized that I was trying to solve the wrong problem. I realized that solving the question asked here was error prone and insecure. I realized that I needed to store my data differently and use a format that is designed to safely serialize and deserialize objects. TL;DR: I had the same question as OP, and realized that the answer was to ask a different question. Also, if you down-vote me, please provide feedback so we can all learn together.

    – Jared Menard
    Sep 22 '17 at 18:52






  • 3





    Downvoting without an explanatory comment is the cancer of Stack Overflow.

    – ardochhigh
    Sep 23 '17 at 6:25








  • 1





    yes downvoting should require an explanation and show who downvotes.

    – Nick Res
    Nov 21 '17 at 17:06






  • 2





    To make this answer even more applicable to the OP's question, if your string representation of a hash is called 'strungout' you should be able to do hashit = JSON.parse(strungout.to_json) and then select your items inside hashit via hashit['keyname'] as normal.

    – cixelsyd
    Jan 15 '18 at 20:28



















11














I prefer to abuse ActiveSupport::JSON. Their approach is to convert the hash to yaml and then load it. Unfortunately the conversion to yaml isn't simple and you'd probably want to borrow it from AS if you don't have AS in your project already.



We also have to convert any symbols into regular string-keys as symbols aren't appropriate in JSON.



However, its unable to handle hashes that have a date string in them (our date strings end up not being surrounded by strings, which is where the big issue comes in):



string = '{'last_request_at' : 2011-12-28 23:00:00 UTC }'
ActiveSupport::JSON.decode(string.gsub(/:([a-zA-z])/,'\1').gsub('=>', ' : '))



Would result in an invalid JSON string error when it tries to parse the date value.



Would love any suggestions on how to handle this case






share|improve this answer



















  • 2





    Thanks for the pointer to .decode, it worked great for me. I needed to convert a JSON response to test it. Here's the code I used: ActiveSupport::JSON.decode(response.body, symbolize_keys: true)

    – Andrew Philips
    Dec 3 '13 at 5:01





















8














works in rails 4.1 and support symbols without quotes {:a => 'b'}



just add this to initializers folder:



class String
def to_hash_object
JSON.parse(self.gsub(/:([a-zA-z]+)/,'"\1"').gsub('=>', ': ')).symbolize_keys
end
end





share|improve this answer
























  • Works on the command line, but I get "stack level to deep" when I put this in an intializer...

    – Alex Edelstein
    Apr 3 '15 at 18:06



















2














I built a gem hash_parser that first checks if a hash is safe or not using ruby_parser gem. Only then, it applies the eval.



You can use it as



require 'hash_parser'

# this executes successfully
a = "{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' },
:key_b => { :key_1b => 'value_1b' } }"
p HashParser.new.safe_load(a)

# this throws a HashParser::BadHash exception
a = "{ :key_a => system('ls') }"
p HashParser.new.safe_load(a)


The tests in https://github.com/bibstha/ruby_hash_parser/blob/master/test/test_hash_parser.rb give you more examples of the things I've tested to make sure eval is safe.






share|improve this answer

































    1














    I came to this question after writing a one-liner for this purpose, so I share my code in case it helps somebody. Works for a string with only one level depth and possible empty values (but not nil), like:



    "{ :key_a => 'value_a', :key_b => 'value_b', :key_c => '' }"


    The code is:



    the_string = '...'
    the_hash = Hash.new
    the_string[1..-2].split(/, /).each {|entry| entryMap=entry.split(/=>/); value_str = entryMap[1]; the_hash[entryMap[0].strip[1..-1].to_sym] = value_str.nil? ? "" : value_str.strip[1..-2]}





    share|improve this answer































      0














      Please consider this solution. Library+spec:



      File: lib/ext/hash/from_string.rb:



      require "json"

      module Ext
      module Hash
      module ClassMethods
      # Build a new object from string representation.
      #
      # from_string('{"name"=>"Joe"}')
      #
      # @param s [String]
      # @return [Hash]
      def from_string(s)
      s.gsub!(/(?<!\)"=>nil/, '":null')
      s.gsub!(/(?<!\)"=>/, '":')
      JSON.parse(s)
      end
      end
      end
      end

      class Hash #:nodoc:
      extend Ext::Hash::ClassMethods
      end


      File: spec/lib/ext/hash/from_string_spec.rb:



      require "ext/hash/from_string"

      describe "Hash.from_string" do
      it "generally works" do
      [
      # Basic cases.
      ['{"x"=>"y"}', {"x" => "y"}],
      ['{"is"=>true}', {"is" => true}],
      ['{"is"=>false}', {"is" => false}],
      ['{"is"=>nil}', {"is" => nil}],
      ['{"a"=>{"b"=>"c","ar":[1,2]}}', {"a" => {"b" => "c", "ar" => [1, 2]}}],
      ['{"id"=>34030, "users"=>[14105]}', {"id" => 34030, "users" => [14105]}],

      # Tricky cases.
      ['{"data"=>"{"x"=>"y"}"}', {"data" => "{"x"=>"y"}"}], # Value is a `Hash#inspect` string which must be preserved.
      ].each do |input, expected|
      output = Hash.from_string(input)
      expect([input, output]).to eq [input, expected]
      end
      end # it
      end





      share|improve this answer





















      • 1





        it "generally works" but not necessarily? I would be more verbose in those tests. it "converts strings to object" { expect('...').to eql ... } it "supports nested objects" { expect('...').to eql ... }

        – Lex
        Jun 14 '18 at 1:30













      • Hey @Lex, what method does is described in its RubyDoc comment. The test better not re-state it, it'll create unnecessary details as passive text. Thus, "generally works" is a nice formula to state that stuff, well, generally works. Cheers!

        – Alex Fortuna
        Jun 14 '18 at 12:57











      • Yeah, at the end of the day whatever works. Any tests are better than no tests. Personally I'm a fan of explicit descriptions, but thats just a preference.

        – Lex
        Jun 14 '18 at 22:28











      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f1667630%2fhow-do-i-convert-a-string-object-into-a-hash-object%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      12 Answers
      12






      active

      oldest

      votes








      12 Answers
      12






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      70














      The string created by calling Hash#inspect can be turned back into a hash by calling eval on it. However, this requires the same to be true of all of the objects in the hash.



      If I start with the hash {:a => Object.new}, then its string representation is "{:a=>#<Object:0x7f66b65cf4d0>}", and I can't use eval to turn it back into a hash because #<Object:0x7f66b65cf4d0> isn't valid Ruby syntax.



      However, if all that's in the hash is strings, symbols, numbers, and arrays, it should work, because those have string representations that are valid Ruby syntax.






      share|improve this answer


























      • "if all that's in the hash is strings, symbols, and numbers,". This says a lot. So I can check the validity of a string to be evaluated as a hash by making sure that the above statement is valid for that string.

        – Waseem
        Nov 3 '09 at 14:38






      • 1





        Yes, but in order to do that you either need a full Ruby parser, or you need to know where the string came from in the first place and know that it can only generate strings, symbols, and numbers. (See also Toms Mikoss's answer about trusting the contents of the string.)

        – Ken Bloom
        Nov 3 '09 at 14:43






      • 8





        Be carefule where you use this. Using eval at the wrong place is a huge security hole. Anything inside the string, will be evaluated. So imagine if in an API someone injected rm -fr

        – Pithikos
        Apr 5 '16 at 14:23
















      70














      The string created by calling Hash#inspect can be turned back into a hash by calling eval on it. However, this requires the same to be true of all of the objects in the hash.



      If I start with the hash {:a => Object.new}, then its string representation is "{:a=>#<Object:0x7f66b65cf4d0>}", and I can't use eval to turn it back into a hash because #<Object:0x7f66b65cf4d0> isn't valid Ruby syntax.



      However, if all that's in the hash is strings, symbols, numbers, and arrays, it should work, because those have string representations that are valid Ruby syntax.






      share|improve this answer


























      • "if all that's in the hash is strings, symbols, and numbers,". This says a lot. So I can check the validity of a string to be evaluated as a hash by making sure that the above statement is valid for that string.

        – Waseem
        Nov 3 '09 at 14:38






      • 1





        Yes, but in order to do that you either need a full Ruby parser, or you need to know where the string came from in the first place and know that it can only generate strings, symbols, and numbers. (See also Toms Mikoss's answer about trusting the contents of the string.)

        – Ken Bloom
        Nov 3 '09 at 14:43






      • 8





        Be carefule where you use this. Using eval at the wrong place is a huge security hole. Anything inside the string, will be evaluated. So imagine if in an API someone injected rm -fr

        – Pithikos
        Apr 5 '16 at 14:23














      70












      70








      70







      The string created by calling Hash#inspect can be turned back into a hash by calling eval on it. However, this requires the same to be true of all of the objects in the hash.



      If I start with the hash {:a => Object.new}, then its string representation is "{:a=>#<Object:0x7f66b65cf4d0>}", and I can't use eval to turn it back into a hash because #<Object:0x7f66b65cf4d0> isn't valid Ruby syntax.



      However, if all that's in the hash is strings, symbols, numbers, and arrays, it should work, because those have string representations that are valid Ruby syntax.






      share|improve this answer















      The string created by calling Hash#inspect can be turned back into a hash by calling eval on it. However, this requires the same to be true of all of the objects in the hash.



      If I start with the hash {:a => Object.new}, then its string representation is "{:a=>#<Object:0x7f66b65cf4d0>}", and I can't use eval to turn it back into a hash because #<Object:0x7f66b65cf4d0> isn't valid Ruby syntax.



      However, if all that's in the hash is strings, symbols, numbers, and arrays, it should work, because those have string representations that are valid Ruby syntax.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Nov 3 '09 at 14:44

























      answered Nov 3 '09 at 14:30









      Ken BloomKen Bloom

      43.2k891151




      43.2k891151













      • "if all that's in the hash is strings, symbols, and numbers,". This says a lot. So I can check the validity of a string to be evaluated as a hash by making sure that the above statement is valid for that string.

        – Waseem
        Nov 3 '09 at 14:38






      • 1





        Yes, but in order to do that you either need a full Ruby parser, or you need to know where the string came from in the first place and know that it can only generate strings, symbols, and numbers. (See also Toms Mikoss's answer about trusting the contents of the string.)

        – Ken Bloom
        Nov 3 '09 at 14:43






      • 8





        Be carefule where you use this. Using eval at the wrong place is a huge security hole. Anything inside the string, will be evaluated. So imagine if in an API someone injected rm -fr

        – Pithikos
        Apr 5 '16 at 14:23



















      • "if all that's in the hash is strings, symbols, and numbers,". This says a lot. So I can check the validity of a string to be evaluated as a hash by making sure that the above statement is valid for that string.

        – Waseem
        Nov 3 '09 at 14:38






      • 1





        Yes, but in order to do that you either need a full Ruby parser, or you need to know where the string came from in the first place and know that it can only generate strings, symbols, and numbers. (See also Toms Mikoss's answer about trusting the contents of the string.)

        – Ken Bloom
        Nov 3 '09 at 14:43






      • 8





        Be carefule where you use this. Using eval at the wrong place is a huge security hole. Anything inside the string, will be evaluated. So imagine if in an API someone injected rm -fr

        – Pithikos
        Apr 5 '16 at 14:23

















      "if all that's in the hash is strings, symbols, and numbers,". This says a lot. So I can check the validity of a string to be evaluated as a hash by making sure that the above statement is valid for that string.

      – Waseem
      Nov 3 '09 at 14:38





      "if all that's in the hash is strings, symbols, and numbers,". This says a lot. So I can check the validity of a string to be evaluated as a hash by making sure that the above statement is valid for that string.

      – Waseem
      Nov 3 '09 at 14:38




      1




      1





      Yes, but in order to do that you either need a full Ruby parser, or you need to know where the string came from in the first place and know that it can only generate strings, symbols, and numbers. (See also Toms Mikoss's answer about trusting the contents of the string.)

      – Ken Bloom
      Nov 3 '09 at 14:43





      Yes, but in order to do that you either need a full Ruby parser, or you need to know where the string came from in the first place and know that it can only generate strings, symbols, and numbers. (See also Toms Mikoss's answer about trusting the contents of the string.)

      – Ken Bloom
      Nov 3 '09 at 14:43




      8




      8





      Be carefule where you use this. Using eval at the wrong place is a huge security hole. Anything inside the string, will be evaluated. So imagine if in an API someone injected rm -fr

      – Pithikos
      Apr 5 '16 at 14:23





      Be carefule where you use this. Using eval at the wrong place is a huge security hole. Anything inside the string, will be evaluated. So imagine if in an API someone injected rm -fr

      – Pithikos
      Apr 5 '16 at 14:23













      127














      Quick and dirty method would be



      eval("{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }") 


      But it has severe security implications.

      It executes whatever it is passed, you must be 110% sure (as in, at least no user input anywhere along the way) it would contain only properly formed hashes or unexpected bugs/horrible creatures from outer space might start popping up.






      share|improve this answer





















      • 13





        I have a light saber with me. I can take care of those creatures and bugs. :)

        – Waseem
        Nov 3 '09 at 14:35






      • 11





        USING EVAL can be dangerous here, according to my teacher. Eval takes any ruby code and runs it. The danger here is analogous to SQL injection danger. Gsub is preferable.

        – boulder_ruby
        Jul 20 '12 at 17:37






      • 8





        Example string showing why David's teacher is correct: '{:surprise => "#{system "rm -rf * "}"}'

        – A. Wilson
        Jul 30 '12 at 18:09






      • 13





        I cannot emphasize the DANGER of using EVAL here enough! This is absolutely forbidden if user input can ever wind its way into your string.

        – Dave Collins
        Jan 11 '13 at 13:15











      • good idea. thanks

        – Alireza Rahmani Khalili
        May 28 '17 at 11:26
















      127














      Quick and dirty method would be



      eval("{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }") 


      But it has severe security implications.

      It executes whatever it is passed, you must be 110% sure (as in, at least no user input anywhere along the way) it would contain only properly formed hashes or unexpected bugs/horrible creatures from outer space might start popping up.






      share|improve this answer





















      • 13





        I have a light saber with me. I can take care of those creatures and bugs. :)

        – Waseem
        Nov 3 '09 at 14:35






      • 11





        USING EVAL can be dangerous here, according to my teacher. Eval takes any ruby code and runs it. The danger here is analogous to SQL injection danger. Gsub is preferable.

        – boulder_ruby
        Jul 20 '12 at 17:37






      • 8





        Example string showing why David's teacher is correct: '{:surprise => "#{system "rm -rf * "}"}'

        – A. Wilson
        Jul 30 '12 at 18:09






      • 13





        I cannot emphasize the DANGER of using EVAL here enough! This is absolutely forbidden if user input can ever wind its way into your string.

        – Dave Collins
        Jan 11 '13 at 13:15











      • good idea. thanks

        – Alireza Rahmani Khalili
        May 28 '17 at 11:26














      127












      127








      127







      Quick and dirty method would be



      eval("{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }") 


      But it has severe security implications.

      It executes whatever it is passed, you must be 110% sure (as in, at least no user input anywhere along the way) it would contain only properly formed hashes or unexpected bugs/horrible creatures from outer space might start popping up.






      share|improve this answer















      Quick and dirty method would be



      eval("{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }") 


      But it has severe security implications.

      It executes whatever it is passed, you must be 110% sure (as in, at least no user input anywhere along the way) it would contain only properly formed hashes or unexpected bugs/horrible creatures from outer space might start popping up.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Mar 31 '17 at 9:15









      The Whiz of Oz

      3,77063462




      3,77063462










      answered Nov 3 '09 at 14:29









      Toms MikossToms Mikoss

      4,35592436




      4,35592436








      • 13





        I have a light saber with me. I can take care of those creatures and bugs. :)

        – Waseem
        Nov 3 '09 at 14:35






      • 11





        USING EVAL can be dangerous here, according to my teacher. Eval takes any ruby code and runs it. The danger here is analogous to SQL injection danger. Gsub is preferable.

        – boulder_ruby
        Jul 20 '12 at 17:37






      • 8





        Example string showing why David's teacher is correct: '{:surprise => "#{system "rm -rf * "}"}'

        – A. Wilson
        Jul 30 '12 at 18:09






      • 13





        I cannot emphasize the DANGER of using EVAL here enough! This is absolutely forbidden if user input can ever wind its way into your string.

        – Dave Collins
        Jan 11 '13 at 13:15











      • good idea. thanks

        – Alireza Rahmani Khalili
        May 28 '17 at 11:26














      • 13





        I have a light saber with me. I can take care of those creatures and bugs. :)

        – Waseem
        Nov 3 '09 at 14:35






      • 11





        USING EVAL can be dangerous here, according to my teacher. Eval takes any ruby code and runs it. The danger here is analogous to SQL injection danger. Gsub is preferable.

        – boulder_ruby
        Jul 20 '12 at 17:37






      • 8





        Example string showing why David's teacher is correct: '{:surprise => "#{system "rm -rf * "}"}'

        – A. Wilson
        Jul 30 '12 at 18:09






      • 13





        I cannot emphasize the DANGER of using EVAL here enough! This is absolutely forbidden if user input can ever wind its way into your string.

        – Dave Collins
        Jan 11 '13 at 13:15











      • good idea. thanks

        – Alireza Rahmani Khalili
        May 28 '17 at 11:26








      13




      13





      I have a light saber with me. I can take care of those creatures and bugs. :)

      – Waseem
      Nov 3 '09 at 14:35





      I have a light saber with me. I can take care of those creatures and bugs. :)

      – Waseem
      Nov 3 '09 at 14:35




      11




      11





      USING EVAL can be dangerous here, according to my teacher. Eval takes any ruby code and runs it. The danger here is analogous to SQL injection danger. Gsub is preferable.

      – boulder_ruby
      Jul 20 '12 at 17:37





      USING EVAL can be dangerous here, according to my teacher. Eval takes any ruby code and runs it. The danger here is analogous to SQL injection danger. Gsub is preferable.

      – boulder_ruby
      Jul 20 '12 at 17:37




      8




      8





      Example string showing why David's teacher is correct: '{:surprise => "#{system "rm -rf * "}"}'

      – A. Wilson
      Jul 30 '12 at 18:09





      Example string showing why David's teacher is correct: '{:surprise => "#{system "rm -rf * "}"}'

      – A. Wilson
      Jul 30 '12 at 18:09




      13




      13





      I cannot emphasize the DANGER of using EVAL here enough! This is absolutely forbidden if user input can ever wind its way into your string.

      – Dave Collins
      Jan 11 '13 at 13:15





      I cannot emphasize the DANGER of using EVAL here enough! This is absolutely forbidden if user input can ever wind its way into your string.

      – Dave Collins
      Jan 11 '13 at 13:15













      good idea. thanks

      – Alireza Rahmani Khalili
      May 28 '17 at 11:26





      good idea. thanks

      – Alireza Rahmani Khalili
      May 28 '17 at 11:26











      118














      For different string, you can do it without using dangerous eval method:



      hash_as_string = "{"0"=>{"answer"=>"1", "value"=>"No"}, "1"=>{"answer"=>"2", "value"=>"Yes"}, "2"=>{"answer"=>"3", "value"=>"No"}, "3"=>{"answer"=>"4", "value"=>"1"}, "4"=>{"value"=>"2"}, "5"=>{"value"=>"3"}, "6"=>{"value"=>"4"}}"
      JSON.parse hash_as_string.gsub('=>', ':')





      share|improve this answer



















      • 1





        This answer should be selected for avoiding using eval.

        – Michael_Zhang
        Sep 4 '18 at 21:57











      • you should also replace nils, f.e. JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))

        – Yo Ludke
        Nov 9 '18 at 12:06
















      118














      For different string, you can do it without using dangerous eval method:



      hash_as_string = "{"0"=>{"answer"=>"1", "value"=>"No"}, "1"=>{"answer"=>"2", "value"=>"Yes"}, "2"=>{"answer"=>"3", "value"=>"No"}, "3"=>{"answer"=>"4", "value"=>"1"}, "4"=>{"value"=>"2"}, "5"=>{"value"=>"3"}, "6"=>{"value"=>"4"}}"
      JSON.parse hash_as_string.gsub('=>', ':')





      share|improve this answer



















      • 1





        This answer should be selected for avoiding using eval.

        – Michael_Zhang
        Sep 4 '18 at 21:57











      • you should also replace nils, f.e. JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))

        – Yo Ludke
        Nov 9 '18 at 12:06














      118












      118








      118







      For different string, you can do it without using dangerous eval method:



      hash_as_string = "{"0"=>{"answer"=>"1", "value"=>"No"}, "1"=>{"answer"=>"2", "value"=>"Yes"}, "2"=>{"answer"=>"3", "value"=>"No"}, "3"=>{"answer"=>"4", "value"=>"1"}, "4"=>{"value"=>"2"}, "5"=>{"value"=>"3"}, "6"=>{"value"=>"4"}}"
      JSON.parse hash_as_string.gsub('=>', ':')





      share|improve this answer













      For different string, you can do it without using dangerous eval method:



      hash_as_string = "{"0"=>{"answer"=>"1", "value"=>"No"}, "1"=>{"answer"=>"2", "value"=>"Yes"}, "2"=>{"answer"=>"3", "value"=>"No"}, "3"=>{"answer"=>"4", "value"=>"1"}, "4"=>{"value"=>"2"}, "5"=>{"value"=>"3"}, "6"=>{"value"=>"4"}}"
      JSON.parse hash_as_string.gsub('=>', ':')






      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Apr 2 '14 at 18:49









      zolterzolter

      5,07922548




      5,07922548








      • 1





        This answer should be selected for avoiding using eval.

        – Michael_Zhang
        Sep 4 '18 at 21:57











      • you should also replace nils, f.e. JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))

        – Yo Ludke
        Nov 9 '18 at 12:06














      • 1





        This answer should be selected for avoiding using eval.

        – Michael_Zhang
        Sep 4 '18 at 21:57











      • you should also replace nils, f.e. JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))

        – Yo Ludke
        Nov 9 '18 at 12:06








      1




      1





      This answer should be selected for avoiding using eval.

      – Michael_Zhang
      Sep 4 '18 at 21:57





      This answer should be selected for avoiding using eval.

      – Michael_Zhang
      Sep 4 '18 at 21:57













      you should also replace nils, f.e. JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))

      – Yo Ludke
      Nov 9 '18 at 12:06





      you should also replace nils, f.e. JSON.parse(hash_as_string.gsub("=>", ":").gsub(":nil,", ":null,"))

      – Yo Ludke
      Nov 9 '18 at 12:06











      22














      This short little snippet will do it, but I can't see it working with a nested hash. I think it's pretty cute though



      STRING.gsub(/[{}:]/,'').split(', ').map{|h| h1,h2 = h.split('=>'); {h1 => h2}}.reduce(:merge)


      Steps
      1. I eliminate the '{','}' and the ':'
      2. I split upon the string wherever it finds a ','
      3. I split each of the substrings that were created with the split, whenever it finds a '=>'. Then, I create a hash with the two sides of the hash I just split apart.
      4. I am left with an array of hashes which I then merge together.



      EXAMPLE INPUT: "{:user_id=>11, :blog_id=>2, :comment_id=>1}"
      RESULT OUTPUT: {"user_id"=>"11", "blog_id"=>"2", "comment_id"=>"1"}






      share|improve this answer



















      • 1





        That is one sick oneliner ! :) +1

        – blushrt
        May 23 '13 at 13:02






      • 3





        Won't this also strip away {}: characters from values inside the stringified hash?

        – Vladimir Panteleev
        Aug 7 '14 at 13:58
















      22














      This short little snippet will do it, but I can't see it working with a nested hash. I think it's pretty cute though



      STRING.gsub(/[{}:]/,'').split(', ').map{|h| h1,h2 = h.split('=>'); {h1 => h2}}.reduce(:merge)


      Steps
      1. I eliminate the '{','}' and the ':'
      2. I split upon the string wherever it finds a ','
      3. I split each of the substrings that were created with the split, whenever it finds a '=>'. Then, I create a hash with the two sides of the hash I just split apart.
      4. I am left with an array of hashes which I then merge together.



      EXAMPLE INPUT: "{:user_id=>11, :blog_id=>2, :comment_id=>1}"
      RESULT OUTPUT: {"user_id"=>"11", "blog_id"=>"2", "comment_id"=>"1"}






      share|improve this answer



















      • 1





        That is one sick oneliner ! :) +1

        – blushrt
        May 23 '13 at 13:02






      • 3





        Won't this also strip away {}: characters from values inside the stringified hash?

        – Vladimir Panteleev
        Aug 7 '14 at 13:58














      22












      22








      22







      This short little snippet will do it, but I can't see it working with a nested hash. I think it's pretty cute though



      STRING.gsub(/[{}:]/,'').split(', ').map{|h| h1,h2 = h.split('=>'); {h1 => h2}}.reduce(:merge)


      Steps
      1. I eliminate the '{','}' and the ':'
      2. I split upon the string wherever it finds a ','
      3. I split each of the substrings that were created with the split, whenever it finds a '=>'. Then, I create a hash with the two sides of the hash I just split apart.
      4. I am left with an array of hashes which I then merge together.



      EXAMPLE INPUT: "{:user_id=>11, :blog_id=>2, :comment_id=>1}"
      RESULT OUTPUT: {"user_id"=>"11", "blog_id"=>"2", "comment_id"=>"1"}






      share|improve this answer













      This short little snippet will do it, but I can't see it working with a nested hash. I think it's pretty cute though



      STRING.gsub(/[{}:]/,'').split(', ').map{|h| h1,h2 = h.split('=>'); {h1 => h2}}.reduce(:merge)


      Steps
      1. I eliminate the '{','}' and the ':'
      2. I split upon the string wherever it finds a ','
      3. I split each of the substrings that were created with the split, whenever it finds a '=>'. Then, I create a hash with the two sides of the hash I just split apart.
      4. I am left with an array of hashes which I then merge together.



      EXAMPLE INPUT: "{:user_id=>11, :blog_id=>2, :comment_id=>1}"
      RESULT OUTPUT: {"user_id"=>"11", "blog_id"=>"2", "comment_id"=>"1"}







      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Mar 28 '12 at 15:03









      hrdwdmrblhrdwdmrbl

      2,77712030




      2,77712030








      • 1





        That is one sick oneliner ! :) +1

        – blushrt
        May 23 '13 at 13:02






      • 3





        Won't this also strip away {}: characters from values inside the stringified hash?

        – Vladimir Panteleev
        Aug 7 '14 at 13:58














      • 1





        That is one sick oneliner ! :) +1

        – blushrt
        May 23 '13 at 13:02






      • 3





        Won't this also strip away {}: characters from values inside the stringified hash?

        – Vladimir Panteleev
        Aug 7 '14 at 13:58








      1




      1





      That is one sick oneliner ! :) +1

      – blushrt
      May 23 '13 at 13:02





      That is one sick oneliner ! :) +1

      – blushrt
      May 23 '13 at 13:02




      3




      3





      Won't this also strip away {}: characters from values inside the stringified hash?

      – Vladimir Panteleev
      Aug 7 '14 at 13:58





      Won't this also strip away {}: characters from values inside the stringified hash?

      – Vladimir Panteleev
      Aug 7 '14 at 13:58











      18














      Maybe YAML.load ?






      share|improve this answer
























      • (load method supports strings)

        – silent
        Nov 3 '09 at 14:41






      • 4





        That requires a totally different string representation, but it much, much safer. (And the string representation is just as easy to generate -- just call #to_yaml, rather than #inspect)

        – Ken Bloom
        Nov 3 '09 at 14:46











      • Wow. I had no idea it was so easy to parse strings w/ yaml. It takes my chain of linux bash commands that generate data and intelligently turns it into a ruby Hash w/o any string format massaging.

        – labyrinth
        Aug 29 '17 at 20:56
















      18














      Maybe YAML.load ?






      share|improve this answer
























      • (load method supports strings)

        – silent
        Nov 3 '09 at 14:41






      • 4





        That requires a totally different string representation, but it much, much safer. (And the string representation is just as easy to generate -- just call #to_yaml, rather than #inspect)

        – Ken Bloom
        Nov 3 '09 at 14:46











      • Wow. I had no idea it was so easy to parse strings w/ yaml. It takes my chain of linux bash commands that generate data and intelligently turns it into a ruby Hash w/o any string format massaging.

        – labyrinth
        Aug 29 '17 at 20:56














      18












      18








      18







      Maybe YAML.load ?






      share|improve this answer













      Maybe YAML.load ?







      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Nov 3 '09 at 14:33









      silentsilent

      2,9801729




      2,9801729













      • (load method supports strings)

        – silent
        Nov 3 '09 at 14:41






      • 4





        That requires a totally different string representation, but it much, much safer. (And the string representation is just as easy to generate -- just call #to_yaml, rather than #inspect)

        – Ken Bloom
        Nov 3 '09 at 14:46











      • Wow. I had no idea it was so easy to parse strings w/ yaml. It takes my chain of linux bash commands that generate data and intelligently turns it into a ruby Hash w/o any string format massaging.

        – labyrinth
        Aug 29 '17 at 20:56



















      • (load method supports strings)

        – silent
        Nov 3 '09 at 14:41






      • 4





        That requires a totally different string representation, but it much, much safer. (And the string representation is just as easy to generate -- just call #to_yaml, rather than #inspect)

        – Ken Bloom
        Nov 3 '09 at 14:46











      • Wow. I had no idea it was so easy to parse strings w/ yaml. It takes my chain of linux bash commands that generate data and intelligently turns it into a ruby Hash w/o any string format massaging.

        – labyrinth
        Aug 29 '17 at 20:56

















      (load method supports strings)

      – silent
      Nov 3 '09 at 14:41





      (load method supports strings)

      – silent
      Nov 3 '09 at 14:41




      4




      4





      That requires a totally different string representation, but it much, much safer. (And the string representation is just as easy to generate -- just call #to_yaml, rather than #inspect)

      – Ken Bloom
      Nov 3 '09 at 14:46





      That requires a totally different string representation, but it much, much safer. (And the string representation is just as easy to generate -- just call #to_yaml, rather than #inspect)

      – Ken Bloom
      Nov 3 '09 at 14:46













      Wow. I had no idea it was so easy to parse strings w/ yaml. It takes my chain of linux bash commands that generate data and intelligently turns it into a ruby Hash w/o any string format massaging.

      – labyrinth
      Aug 29 '17 at 20:56





      Wow. I had no idea it was so easy to parse strings w/ yaml. It takes my chain of linux bash commands that generate data and intelligently turns it into a ruby Hash w/o any string format massaging.

      – labyrinth
      Aug 29 '17 at 20:56











      15














      The solutions so far cover some cases but miss some (see below). Here's my attempt at a more thorough (safe) conversion. I know of one corner case which this solution doesn't handle which is single character symbols made up of odd, but allowed characters. For example {:> => :<} is a valid ruby hash.



      I put this code up on github as well. This code starts with a test string to exercise all the conversions



      require 'json'

      # Example ruby hash string which exercises all of the permutations of position and type
      # See http://json.org/
      ruby_hash_text='{"alpha"=>{"first second > third"=>"first second > third", "after comma > foo"=>:symbolvalue, "another after comma > foo"=>10}, "bravo"=>{:symbol=>:symbolvalue, :aftercomma=>10, :anotheraftercomma=>"first second > third"}, "charlie"=>{1=>10, 2=>"first second > third", 3=>:symbolvalue}, "delta"=>["first second > third", "after comma > foo"], "echo"=>[:symbol, :aftercomma], "foxtrot"=>[1, 2]}'

      puts ruby_hash_text

      # Transform object string symbols to quoted strings
      ruby_hash_text.gsub!(/([{,]s*):([^>s]+)s*=>/, '1"2"=>')

      # Transform object string numbers to quoted strings
      ruby_hash_text.gsub!(/([{,]s*)([0-9]+.?[0-9]*)s*=>/, '1"2"=>')

      # Transform object value symbols to quotes strings
      ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>s*:([^,}s]+s*)/, '12=>"3"')

      # Transform array value symbols to quotes strings
      ruby_hash_text.gsub!(/([[,]s*):([^,]s]+)/, '1"2"')

      # Transform object string object value delimiter to colon delimiter
      ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>/, '12:')

      puts ruby_hash_text

      puts JSON.parse(ruby_hash_text)


      Here are some notes on the other solutions here





      • @Ken Bloom and @Toms Mikoss's solutions use eval which is too scary for me (as Toms rightly points out).


      • @zolter's solution works if your hash has no symbols or numeric keys.


      • @jackquack's solution works if there are no quoted strings mixed in with the symbols.


      • @Eugene's solution works if your symbols don't use all the allowed characters (symbol literals have a broader set of allowed characters).


      • @Pablo's solution works as long as you don't have a mix of symbols and quoted strings.






      share|improve this answer


























      • Very cool solution. You could add a gsub of all :nil to :null to handle that particular weirdness.

        – SteveTurczyn
        May 6 '16 at 13:30






      • 1





        This solution also has the bonus of working on multi-level hashes recursively, since it leverages JSON#parse. I had some trouble with nesting on other solutions.

        – Patrick Read
        Dec 13 '16 at 15:50


















      15














      The solutions so far cover some cases but miss some (see below). Here's my attempt at a more thorough (safe) conversion. I know of one corner case which this solution doesn't handle which is single character symbols made up of odd, but allowed characters. For example {:> => :<} is a valid ruby hash.



      I put this code up on github as well. This code starts with a test string to exercise all the conversions



      require 'json'

      # Example ruby hash string which exercises all of the permutations of position and type
      # See http://json.org/
      ruby_hash_text='{"alpha"=>{"first second > third"=>"first second > third", "after comma > foo"=>:symbolvalue, "another after comma > foo"=>10}, "bravo"=>{:symbol=>:symbolvalue, :aftercomma=>10, :anotheraftercomma=>"first second > third"}, "charlie"=>{1=>10, 2=>"first second > third", 3=>:symbolvalue}, "delta"=>["first second > third", "after comma > foo"], "echo"=>[:symbol, :aftercomma], "foxtrot"=>[1, 2]}'

      puts ruby_hash_text

      # Transform object string symbols to quoted strings
      ruby_hash_text.gsub!(/([{,]s*):([^>s]+)s*=>/, '1"2"=>')

      # Transform object string numbers to quoted strings
      ruby_hash_text.gsub!(/([{,]s*)([0-9]+.?[0-9]*)s*=>/, '1"2"=>')

      # Transform object value symbols to quotes strings
      ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>s*:([^,}s]+s*)/, '12=>"3"')

      # Transform array value symbols to quotes strings
      ruby_hash_text.gsub!(/([[,]s*):([^,]s]+)/, '1"2"')

      # Transform object string object value delimiter to colon delimiter
      ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>/, '12:')

      puts ruby_hash_text

      puts JSON.parse(ruby_hash_text)


      Here are some notes on the other solutions here





      • @Ken Bloom and @Toms Mikoss's solutions use eval which is too scary for me (as Toms rightly points out).


      • @zolter's solution works if your hash has no symbols or numeric keys.


      • @jackquack's solution works if there are no quoted strings mixed in with the symbols.


      • @Eugene's solution works if your symbols don't use all the allowed characters (symbol literals have a broader set of allowed characters).


      • @Pablo's solution works as long as you don't have a mix of symbols and quoted strings.






      share|improve this answer


























      • Very cool solution. You could add a gsub of all :nil to :null to handle that particular weirdness.

        – SteveTurczyn
        May 6 '16 at 13:30






      • 1





        This solution also has the bonus of working on multi-level hashes recursively, since it leverages JSON#parse. I had some trouble with nesting on other solutions.

        – Patrick Read
        Dec 13 '16 at 15:50
















      15












      15








      15







      The solutions so far cover some cases but miss some (see below). Here's my attempt at a more thorough (safe) conversion. I know of one corner case which this solution doesn't handle which is single character symbols made up of odd, but allowed characters. For example {:> => :<} is a valid ruby hash.



      I put this code up on github as well. This code starts with a test string to exercise all the conversions



      require 'json'

      # Example ruby hash string which exercises all of the permutations of position and type
      # See http://json.org/
      ruby_hash_text='{"alpha"=>{"first second > third"=>"first second > third", "after comma > foo"=>:symbolvalue, "another after comma > foo"=>10}, "bravo"=>{:symbol=>:symbolvalue, :aftercomma=>10, :anotheraftercomma=>"first second > third"}, "charlie"=>{1=>10, 2=>"first second > third", 3=>:symbolvalue}, "delta"=>["first second > third", "after comma > foo"], "echo"=>[:symbol, :aftercomma], "foxtrot"=>[1, 2]}'

      puts ruby_hash_text

      # Transform object string symbols to quoted strings
      ruby_hash_text.gsub!(/([{,]s*):([^>s]+)s*=>/, '1"2"=>')

      # Transform object string numbers to quoted strings
      ruby_hash_text.gsub!(/([{,]s*)([0-9]+.?[0-9]*)s*=>/, '1"2"=>')

      # Transform object value symbols to quotes strings
      ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>s*:([^,}s]+s*)/, '12=>"3"')

      # Transform array value symbols to quotes strings
      ruby_hash_text.gsub!(/([[,]s*):([^,]s]+)/, '1"2"')

      # Transform object string object value delimiter to colon delimiter
      ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>/, '12:')

      puts ruby_hash_text

      puts JSON.parse(ruby_hash_text)


      Here are some notes on the other solutions here





      • @Ken Bloom and @Toms Mikoss's solutions use eval which is too scary for me (as Toms rightly points out).


      • @zolter's solution works if your hash has no symbols or numeric keys.


      • @jackquack's solution works if there are no quoted strings mixed in with the symbols.


      • @Eugene's solution works if your symbols don't use all the allowed characters (symbol literals have a broader set of allowed characters).


      • @Pablo's solution works as long as you don't have a mix of symbols and quoted strings.






      share|improve this answer















      The solutions so far cover some cases but miss some (see below). Here's my attempt at a more thorough (safe) conversion. I know of one corner case which this solution doesn't handle which is single character symbols made up of odd, but allowed characters. For example {:> => :<} is a valid ruby hash.



      I put this code up on github as well. This code starts with a test string to exercise all the conversions



      require 'json'

      # Example ruby hash string which exercises all of the permutations of position and type
      # See http://json.org/
      ruby_hash_text='{"alpha"=>{"first second > third"=>"first second > third", "after comma > foo"=>:symbolvalue, "another after comma > foo"=>10}, "bravo"=>{:symbol=>:symbolvalue, :aftercomma=>10, :anotheraftercomma=>"first second > third"}, "charlie"=>{1=>10, 2=>"first second > third", 3=>:symbolvalue}, "delta"=>["first second > third", "after comma > foo"], "echo"=>[:symbol, :aftercomma], "foxtrot"=>[1, 2]}'

      puts ruby_hash_text

      # Transform object string symbols to quoted strings
      ruby_hash_text.gsub!(/([{,]s*):([^>s]+)s*=>/, '1"2"=>')

      # Transform object string numbers to quoted strings
      ruby_hash_text.gsub!(/([{,]s*)([0-9]+.?[0-9]*)s*=>/, '1"2"=>')

      # Transform object value symbols to quotes strings
      ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>s*:([^,}s]+s*)/, '12=>"3"')

      # Transform array value symbols to quotes strings
      ruby_hash_text.gsub!(/([[,]s*):([^,]s]+)/, '1"2"')

      # Transform object string object value delimiter to colon delimiter
      ruby_hash_text.gsub!(/([{,]s*)(".+?"|[0-9]+.?[0-9]*)s*=>/, '12:')

      puts ruby_hash_text

      puts JSON.parse(ruby_hash_text)


      Here are some notes on the other solutions here





      • @Ken Bloom and @Toms Mikoss's solutions use eval which is too scary for me (as Toms rightly points out).


      • @zolter's solution works if your hash has no symbols or numeric keys.


      • @jackquack's solution works if there are no quoted strings mixed in with the symbols.


      • @Eugene's solution works if your symbols don't use all the allowed characters (symbol literals have a broader set of allowed characters).


      • @Pablo's solution works as long as you don't have a mix of symbols and quoted strings.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited May 23 '17 at 12:26









      Community

      11




      11










      answered Jun 9 '15 at 6:20









      gene_woodgene_wood

      99311227




      99311227













      • Very cool solution. You could add a gsub of all :nil to :null to handle that particular weirdness.

        – SteveTurczyn
        May 6 '16 at 13:30






      • 1





        This solution also has the bonus of working on multi-level hashes recursively, since it leverages JSON#parse. I had some trouble with nesting on other solutions.

        – Patrick Read
        Dec 13 '16 at 15:50





















      • Very cool solution. You could add a gsub of all :nil to :null to handle that particular weirdness.

        – SteveTurczyn
        May 6 '16 at 13:30






      • 1





        This solution also has the bonus of working on multi-level hashes recursively, since it leverages JSON#parse. I had some trouble with nesting on other solutions.

        – Patrick Read
        Dec 13 '16 at 15:50



















      Very cool solution. You could add a gsub of all :nil to :null to handle that particular weirdness.

      – SteveTurczyn
      May 6 '16 at 13:30





      Very cool solution. You could add a gsub of all :nil to :null to handle that particular weirdness.

      – SteveTurczyn
      May 6 '16 at 13:30




      1




      1





      This solution also has the bonus of working on multi-level hashes recursively, since it leverages JSON#parse. I had some trouble with nesting on other solutions.

      – Patrick Read
      Dec 13 '16 at 15:50







      This solution also has the bonus of working on multi-level hashes recursively, since it leverages JSON#parse. I had some trouble with nesting on other solutions.

      – Patrick Read
      Dec 13 '16 at 15:50













      12














      I had the same problem. I was storing a hash in Redis. When retrieving that hash, it was a string. I didn't want to call eval(str) because of security concerns. My solution was to save the hash as a json string instead of a ruby hash string. If you have the option, using json is easier.



        redis.set(key, ruby_hash.to_json)
      JSON.parse(redis.get(key))


      TL;DR: use to_json and JSON.parse






      share|improve this answer


























      • This is the best answer by far. to_json and JSON.parse

        – ardochhigh
        Sep 2 '17 at 7:23






      • 3





        To whoever downvoted me. Why? I had the same issue, trying to convert a string representation of a ruby hash into an actual hash object. I realized that I was trying to solve the wrong problem. I realized that solving the question asked here was error prone and insecure. I realized that I needed to store my data differently and use a format that is designed to safely serialize and deserialize objects. TL;DR: I had the same question as OP, and realized that the answer was to ask a different question. Also, if you down-vote me, please provide feedback so we can all learn together.

        – Jared Menard
        Sep 22 '17 at 18:52






      • 3





        Downvoting without an explanatory comment is the cancer of Stack Overflow.

        – ardochhigh
        Sep 23 '17 at 6:25








      • 1





        yes downvoting should require an explanation and show who downvotes.

        – Nick Res
        Nov 21 '17 at 17:06






      • 2





        To make this answer even more applicable to the OP's question, if your string representation of a hash is called 'strungout' you should be able to do hashit = JSON.parse(strungout.to_json) and then select your items inside hashit via hashit['keyname'] as normal.

        – cixelsyd
        Jan 15 '18 at 20:28
















      12














      I had the same problem. I was storing a hash in Redis. When retrieving that hash, it was a string. I didn't want to call eval(str) because of security concerns. My solution was to save the hash as a json string instead of a ruby hash string. If you have the option, using json is easier.



        redis.set(key, ruby_hash.to_json)
      JSON.parse(redis.get(key))


      TL;DR: use to_json and JSON.parse






      share|improve this answer


























      • This is the best answer by far. to_json and JSON.parse

        – ardochhigh
        Sep 2 '17 at 7:23






      • 3





        To whoever downvoted me. Why? I had the same issue, trying to convert a string representation of a ruby hash into an actual hash object. I realized that I was trying to solve the wrong problem. I realized that solving the question asked here was error prone and insecure. I realized that I needed to store my data differently and use a format that is designed to safely serialize and deserialize objects. TL;DR: I had the same question as OP, and realized that the answer was to ask a different question. Also, if you down-vote me, please provide feedback so we can all learn together.

        – Jared Menard
        Sep 22 '17 at 18:52






      • 3





        Downvoting without an explanatory comment is the cancer of Stack Overflow.

        – ardochhigh
        Sep 23 '17 at 6:25








      • 1





        yes downvoting should require an explanation and show who downvotes.

        – Nick Res
        Nov 21 '17 at 17:06






      • 2





        To make this answer even more applicable to the OP's question, if your string representation of a hash is called 'strungout' you should be able to do hashit = JSON.parse(strungout.to_json) and then select your items inside hashit via hashit['keyname'] as normal.

        – cixelsyd
        Jan 15 '18 at 20:28














      12












      12








      12







      I had the same problem. I was storing a hash in Redis. When retrieving that hash, it was a string. I didn't want to call eval(str) because of security concerns. My solution was to save the hash as a json string instead of a ruby hash string. If you have the option, using json is easier.



        redis.set(key, ruby_hash.to_json)
      JSON.parse(redis.get(key))


      TL;DR: use to_json and JSON.parse






      share|improve this answer















      I had the same problem. I was storing a hash in Redis. When retrieving that hash, it was a string. I didn't want to call eval(str) because of security concerns. My solution was to save the hash as a json string instead of a ruby hash string. If you have the option, using json is easier.



        redis.set(key, ruby_hash.to_json)
      JSON.parse(redis.get(key))


      TL;DR: use to_json and JSON.parse







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Sep 5 '17 at 13:47

























      answered Nov 15 '16 at 18:35









      Jared MenardJared Menard

      1,5521217




      1,5521217













      • This is the best answer by far. to_json and JSON.parse

        – ardochhigh
        Sep 2 '17 at 7:23






      • 3





        To whoever downvoted me. Why? I had the same issue, trying to convert a string representation of a ruby hash into an actual hash object. I realized that I was trying to solve the wrong problem. I realized that solving the question asked here was error prone and insecure. I realized that I needed to store my data differently and use a format that is designed to safely serialize and deserialize objects. TL;DR: I had the same question as OP, and realized that the answer was to ask a different question. Also, if you down-vote me, please provide feedback so we can all learn together.

        – Jared Menard
        Sep 22 '17 at 18:52






      • 3





        Downvoting without an explanatory comment is the cancer of Stack Overflow.

        – ardochhigh
        Sep 23 '17 at 6:25








      • 1





        yes downvoting should require an explanation and show who downvotes.

        – Nick Res
        Nov 21 '17 at 17:06






      • 2





        To make this answer even more applicable to the OP's question, if your string representation of a hash is called 'strungout' you should be able to do hashit = JSON.parse(strungout.to_json) and then select your items inside hashit via hashit['keyname'] as normal.

        – cixelsyd
        Jan 15 '18 at 20:28



















      • This is the best answer by far. to_json and JSON.parse

        – ardochhigh
        Sep 2 '17 at 7:23






      • 3





        To whoever downvoted me. Why? I had the same issue, trying to convert a string representation of a ruby hash into an actual hash object. I realized that I was trying to solve the wrong problem. I realized that solving the question asked here was error prone and insecure. I realized that I needed to store my data differently and use a format that is designed to safely serialize and deserialize objects. TL;DR: I had the same question as OP, and realized that the answer was to ask a different question. Also, if you down-vote me, please provide feedback so we can all learn together.

        – Jared Menard
        Sep 22 '17 at 18:52






      • 3





        Downvoting without an explanatory comment is the cancer of Stack Overflow.

        – ardochhigh
        Sep 23 '17 at 6:25








      • 1





        yes downvoting should require an explanation and show who downvotes.

        – Nick Res
        Nov 21 '17 at 17:06






      • 2





        To make this answer even more applicable to the OP's question, if your string representation of a hash is called 'strungout' you should be able to do hashit = JSON.parse(strungout.to_json) and then select your items inside hashit via hashit['keyname'] as normal.

        – cixelsyd
        Jan 15 '18 at 20:28

















      This is the best answer by far. to_json and JSON.parse

      – ardochhigh
      Sep 2 '17 at 7:23





      This is the best answer by far. to_json and JSON.parse

      – ardochhigh
      Sep 2 '17 at 7:23




      3




      3





      To whoever downvoted me. Why? I had the same issue, trying to convert a string representation of a ruby hash into an actual hash object. I realized that I was trying to solve the wrong problem. I realized that solving the question asked here was error prone and insecure. I realized that I needed to store my data differently and use a format that is designed to safely serialize and deserialize objects. TL;DR: I had the same question as OP, and realized that the answer was to ask a different question. Also, if you down-vote me, please provide feedback so we can all learn together.

      – Jared Menard
      Sep 22 '17 at 18:52





      To whoever downvoted me. Why? I had the same issue, trying to convert a string representation of a ruby hash into an actual hash object. I realized that I was trying to solve the wrong problem. I realized that solving the question asked here was error prone and insecure. I realized that I needed to store my data differently and use a format that is designed to safely serialize and deserialize objects. TL;DR: I had the same question as OP, and realized that the answer was to ask a different question. Also, if you down-vote me, please provide feedback so we can all learn together.

      – Jared Menard
      Sep 22 '17 at 18:52




      3




      3





      Downvoting without an explanatory comment is the cancer of Stack Overflow.

      – ardochhigh
      Sep 23 '17 at 6:25







      Downvoting without an explanatory comment is the cancer of Stack Overflow.

      – ardochhigh
      Sep 23 '17 at 6:25






      1




      1





      yes downvoting should require an explanation and show who downvotes.

      – Nick Res
      Nov 21 '17 at 17:06





      yes downvoting should require an explanation and show who downvotes.

      – Nick Res
      Nov 21 '17 at 17:06




      2




      2





      To make this answer even more applicable to the OP's question, if your string representation of a hash is called 'strungout' you should be able to do hashit = JSON.parse(strungout.to_json) and then select your items inside hashit via hashit['keyname'] as normal.

      – cixelsyd
      Jan 15 '18 at 20:28





      To make this answer even more applicable to the OP's question, if your string representation of a hash is called 'strungout' you should be able to do hashit = JSON.parse(strungout.to_json) and then select your items inside hashit via hashit['keyname'] as normal.

      – cixelsyd
      Jan 15 '18 at 20:28











      11














      I prefer to abuse ActiveSupport::JSON. Their approach is to convert the hash to yaml and then load it. Unfortunately the conversion to yaml isn't simple and you'd probably want to borrow it from AS if you don't have AS in your project already.



      We also have to convert any symbols into regular string-keys as symbols aren't appropriate in JSON.



      However, its unable to handle hashes that have a date string in them (our date strings end up not being surrounded by strings, which is where the big issue comes in):



      string = '{'last_request_at' : 2011-12-28 23:00:00 UTC }'
      ActiveSupport::JSON.decode(string.gsub(/:([a-zA-z])/,'\1').gsub('=>', ' : '))



      Would result in an invalid JSON string error when it tries to parse the date value.



      Would love any suggestions on how to handle this case






      share|improve this answer



















      • 2





        Thanks for the pointer to .decode, it worked great for me. I needed to convert a JSON response to test it. Here's the code I used: ActiveSupport::JSON.decode(response.body, symbolize_keys: true)

        – Andrew Philips
        Dec 3 '13 at 5:01


















      11














      I prefer to abuse ActiveSupport::JSON. Their approach is to convert the hash to yaml and then load it. Unfortunately the conversion to yaml isn't simple and you'd probably want to borrow it from AS if you don't have AS in your project already.



      We also have to convert any symbols into regular string-keys as symbols aren't appropriate in JSON.



      However, its unable to handle hashes that have a date string in them (our date strings end up not being surrounded by strings, which is where the big issue comes in):



      string = '{'last_request_at' : 2011-12-28 23:00:00 UTC }'
      ActiveSupport::JSON.decode(string.gsub(/:([a-zA-z])/,'\1').gsub('=>', ' : '))



      Would result in an invalid JSON string error when it tries to parse the date value.



      Would love any suggestions on how to handle this case






      share|improve this answer



















      • 2





        Thanks for the pointer to .decode, it worked great for me. I needed to convert a JSON response to test it. Here's the code I used: ActiveSupport::JSON.decode(response.body, symbolize_keys: true)

        – Andrew Philips
        Dec 3 '13 at 5:01
















      11












      11








      11







      I prefer to abuse ActiveSupport::JSON. Their approach is to convert the hash to yaml and then load it. Unfortunately the conversion to yaml isn't simple and you'd probably want to borrow it from AS if you don't have AS in your project already.



      We also have to convert any symbols into regular string-keys as symbols aren't appropriate in JSON.



      However, its unable to handle hashes that have a date string in them (our date strings end up not being surrounded by strings, which is where the big issue comes in):



      string = '{'last_request_at' : 2011-12-28 23:00:00 UTC }'
      ActiveSupport::JSON.decode(string.gsub(/:([a-zA-z])/,'\1').gsub('=>', ' : '))



      Would result in an invalid JSON string error when it tries to parse the date value.



      Would love any suggestions on how to handle this case






      share|improve this answer













      I prefer to abuse ActiveSupport::JSON. Their approach is to convert the hash to yaml and then load it. Unfortunately the conversion to yaml isn't simple and you'd probably want to borrow it from AS if you don't have AS in your project already.



      We also have to convert any symbols into regular string-keys as symbols aren't appropriate in JSON.



      However, its unable to handle hashes that have a date string in them (our date strings end up not being surrounded by strings, which is where the big issue comes in):



      string = '{'last_request_at' : 2011-12-28 23:00:00 UTC }'
      ActiveSupport::JSON.decode(string.gsub(/:([a-zA-z])/,'\1').gsub('=>', ' : '))



      Would result in an invalid JSON string error when it tries to parse the date value.



      Would love any suggestions on how to handle this case







      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Jan 5 '12 at 17:49









      c.apolzonc.apolzon

      36636




      36636








      • 2





        Thanks for the pointer to .decode, it worked great for me. I needed to convert a JSON response to test it. Here's the code I used: ActiveSupport::JSON.decode(response.body, symbolize_keys: true)

        – Andrew Philips
        Dec 3 '13 at 5:01
















      • 2





        Thanks for the pointer to .decode, it worked great for me. I needed to convert a JSON response to test it. Here's the code I used: ActiveSupport::JSON.decode(response.body, symbolize_keys: true)

        – Andrew Philips
        Dec 3 '13 at 5:01










      2




      2





      Thanks for the pointer to .decode, it worked great for me. I needed to convert a JSON response to test it. Here's the code I used: ActiveSupport::JSON.decode(response.body, symbolize_keys: true)

      – Andrew Philips
      Dec 3 '13 at 5:01







      Thanks for the pointer to .decode, it worked great for me. I needed to convert a JSON response to test it. Here's the code I used: ActiveSupport::JSON.decode(response.body, symbolize_keys: true)

      – Andrew Philips
      Dec 3 '13 at 5:01













      8














      works in rails 4.1 and support symbols without quotes {:a => 'b'}



      just add this to initializers folder:



      class String
      def to_hash_object
      JSON.parse(self.gsub(/:([a-zA-z]+)/,'"\1"').gsub('=>', ': ')).symbolize_keys
      end
      end





      share|improve this answer
























      • Works on the command line, but I get "stack level to deep" when I put this in an intializer...

        – Alex Edelstein
        Apr 3 '15 at 18:06
















      8














      works in rails 4.1 and support symbols without quotes {:a => 'b'}



      just add this to initializers folder:



      class String
      def to_hash_object
      JSON.parse(self.gsub(/:([a-zA-z]+)/,'"\1"').gsub('=>', ': ')).symbolize_keys
      end
      end





      share|improve this answer
























      • Works on the command line, but I get "stack level to deep" when I put this in an intializer...

        – Alex Edelstein
        Apr 3 '15 at 18:06














      8












      8








      8







      works in rails 4.1 and support symbols without quotes {:a => 'b'}



      just add this to initializers folder:



      class String
      def to_hash_object
      JSON.parse(self.gsub(/:([a-zA-z]+)/,'"\1"').gsub('=>', ': ')).symbolize_keys
      end
      end





      share|improve this answer













      works in rails 4.1 and support symbols without quotes {:a => 'b'}



      just add this to initializers folder:



      class String
      def to_hash_object
      JSON.parse(self.gsub(/:([a-zA-z]+)/,'"\1"').gsub('=>', ': ')).symbolize_keys
      end
      end






      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Aug 8 '14 at 14:31









      EugeneEugene

      55265




      55265













      • Works on the command line, but I get "stack level to deep" when I put this in an intializer...

        – Alex Edelstein
        Apr 3 '15 at 18:06



















      • Works on the command line, but I get "stack level to deep" when I put this in an intializer...

        – Alex Edelstein
        Apr 3 '15 at 18:06

















      Works on the command line, but I get "stack level to deep" when I put this in an intializer...

      – Alex Edelstein
      Apr 3 '15 at 18:06





      Works on the command line, but I get "stack level to deep" when I put this in an intializer...

      – Alex Edelstein
      Apr 3 '15 at 18:06











      2














      I built a gem hash_parser that first checks if a hash is safe or not using ruby_parser gem. Only then, it applies the eval.



      You can use it as



      require 'hash_parser'

      # this executes successfully
      a = "{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' },
      :key_b => { :key_1b => 'value_1b' } }"
      p HashParser.new.safe_load(a)

      # this throws a HashParser::BadHash exception
      a = "{ :key_a => system('ls') }"
      p HashParser.new.safe_load(a)


      The tests in https://github.com/bibstha/ruby_hash_parser/blob/master/test/test_hash_parser.rb give you more examples of the things I've tested to make sure eval is safe.






      share|improve this answer






























        2














        I built a gem hash_parser that first checks if a hash is safe or not using ruby_parser gem. Only then, it applies the eval.



        You can use it as



        require 'hash_parser'

        # this executes successfully
        a = "{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' },
        :key_b => { :key_1b => 'value_1b' } }"
        p HashParser.new.safe_load(a)

        # this throws a HashParser::BadHash exception
        a = "{ :key_a => system('ls') }"
        p HashParser.new.safe_load(a)


        The tests in https://github.com/bibstha/ruby_hash_parser/blob/master/test/test_hash_parser.rb give you more examples of the things I've tested to make sure eval is safe.






        share|improve this answer




























          2












          2








          2







          I built a gem hash_parser that first checks if a hash is safe or not using ruby_parser gem. Only then, it applies the eval.



          You can use it as



          require 'hash_parser'

          # this executes successfully
          a = "{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' },
          :key_b => { :key_1b => 'value_1b' } }"
          p HashParser.new.safe_load(a)

          # this throws a HashParser::BadHash exception
          a = "{ :key_a => system('ls') }"
          p HashParser.new.safe_load(a)


          The tests in https://github.com/bibstha/ruby_hash_parser/blob/master/test/test_hash_parser.rb give you more examples of the things I've tested to make sure eval is safe.






          share|improve this answer















          I built a gem hash_parser that first checks if a hash is safe or not using ruby_parser gem. Only then, it applies the eval.



          You can use it as



          require 'hash_parser'

          # this executes successfully
          a = "{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' },
          :key_b => { :key_1b => 'value_1b' } }"
          p HashParser.new.safe_load(a)

          # this throws a HashParser::BadHash exception
          a = "{ :key_a => system('ls') }"
          p HashParser.new.safe_load(a)


          The tests in https://github.com/bibstha/ruby_hash_parser/blob/master/test/test_hash_parser.rb give you more examples of the things I've tested to make sure eval is safe.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Mar 30 '17 at 1:35

























          answered Mar 30 '17 at 1:30









          bibsthabibstha

          8,53862430




          8,53862430























              1














              I came to this question after writing a one-liner for this purpose, so I share my code in case it helps somebody. Works for a string with only one level depth and possible empty values (but not nil), like:



              "{ :key_a => 'value_a', :key_b => 'value_b', :key_c => '' }"


              The code is:



              the_string = '...'
              the_hash = Hash.new
              the_string[1..-2].split(/, /).each {|entry| entryMap=entry.split(/=>/); value_str = entryMap[1]; the_hash[entryMap[0].strip[1..-1].to_sym] = value_str.nil? ? "" : value_str.strip[1..-2]}





              share|improve this answer




























                1














                I came to this question after writing a one-liner for this purpose, so I share my code in case it helps somebody. Works for a string with only one level depth and possible empty values (but not nil), like:



                "{ :key_a => 'value_a', :key_b => 'value_b', :key_c => '' }"


                The code is:



                the_string = '...'
                the_hash = Hash.new
                the_string[1..-2].split(/, /).each {|entry| entryMap=entry.split(/=>/); value_str = entryMap[1]; the_hash[entryMap[0].strip[1..-1].to_sym] = value_str.nil? ? "" : value_str.strip[1..-2]}





                share|improve this answer


























                  1












                  1








                  1







                  I came to this question after writing a one-liner for this purpose, so I share my code in case it helps somebody. Works for a string with only one level depth and possible empty values (but not nil), like:



                  "{ :key_a => 'value_a', :key_b => 'value_b', :key_c => '' }"


                  The code is:



                  the_string = '...'
                  the_hash = Hash.new
                  the_string[1..-2].split(/, /).each {|entry| entryMap=entry.split(/=>/); value_str = entryMap[1]; the_hash[entryMap[0].strip[1..-1].to_sym] = value_str.nil? ? "" : value_str.strip[1..-2]}





                  share|improve this answer













                  I came to this question after writing a one-liner for this purpose, so I share my code in case it helps somebody. Works for a string with only one level depth and possible empty values (but not nil), like:



                  "{ :key_a => 'value_a', :key_b => 'value_b', :key_c => '' }"


                  The code is:



                  the_string = '...'
                  the_hash = Hash.new
                  the_string[1..-2].split(/, /).each {|entry| entryMap=entry.split(/=>/); value_str = entryMap[1]; the_hash[entryMap[0].strip[1..-1].to_sym] = value_str.nil? ? "" : value_str.strip[1..-2]}






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 1 '11 at 8:43









                  PabloPablo

                  2,16951844




                  2,16951844























                      0














                      Please consider this solution. Library+spec:



                      File: lib/ext/hash/from_string.rb:



                      require "json"

                      module Ext
                      module Hash
                      module ClassMethods
                      # Build a new object from string representation.
                      #
                      # from_string('{"name"=>"Joe"}')
                      #
                      # @param s [String]
                      # @return [Hash]
                      def from_string(s)
                      s.gsub!(/(?<!\)"=>nil/, '":null')
                      s.gsub!(/(?<!\)"=>/, '":')
                      JSON.parse(s)
                      end
                      end
                      end
                      end

                      class Hash #:nodoc:
                      extend Ext::Hash::ClassMethods
                      end


                      File: spec/lib/ext/hash/from_string_spec.rb:



                      require "ext/hash/from_string"

                      describe "Hash.from_string" do
                      it "generally works" do
                      [
                      # Basic cases.
                      ['{"x"=>"y"}', {"x" => "y"}],
                      ['{"is"=>true}', {"is" => true}],
                      ['{"is"=>false}', {"is" => false}],
                      ['{"is"=>nil}', {"is" => nil}],
                      ['{"a"=>{"b"=>"c","ar":[1,2]}}', {"a" => {"b" => "c", "ar" => [1, 2]}}],
                      ['{"id"=>34030, "users"=>[14105]}', {"id" => 34030, "users" => [14105]}],

                      # Tricky cases.
                      ['{"data"=>"{"x"=>"y"}"}', {"data" => "{"x"=>"y"}"}], # Value is a `Hash#inspect` string which must be preserved.
                      ].each do |input, expected|
                      output = Hash.from_string(input)
                      expect([input, output]).to eq [input, expected]
                      end
                      end # it
                      end





                      share|improve this answer





















                      • 1





                        it "generally works" but not necessarily? I would be more verbose in those tests. it "converts strings to object" { expect('...').to eql ... } it "supports nested objects" { expect('...').to eql ... }

                        – Lex
                        Jun 14 '18 at 1:30













                      • Hey @Lex, what method does is described in its RubyDoc comment. The test better not re-state it, it'll create unnecessary details as passive text. Thus, "generally works" is a nice formula to state that stuff, well, generally works. Cheers!

                        – Alex Fortuna
                        Jun 14 '18 at 12:57











                      • Yeah, at the end of the day whatever works. Any tests are better than no tests. Personally I'm a fan of explicit descriptions, but thats just a preference.

                        – Lex
                        Jun 14 '18 at 22:28
















                      0














                      Please consider this solution. Library+spec:



                      File: lib/ext/hash/from_string.rb:



                      require "json"

                      module Ext
                      module Hash
                      module ClassMethods
                      # Build a new object from string representation.
                      #
                      # from_string('{"name"=>"Joe"}')
                      #
                      # @param s [String]
                      # @return [Hash]
                      def from_string(s)
                      s.gsub!(/(?<!\)"=>nil/, '":null')
                      s.gsub!(/(?<!\)"=>/, '":')
                      JSON.parse(s)
                      end
                      end
                      end
                      end

                      class Hash #:nodoc:
                      extend Ext::Hash::ClassMethods
                      end


                      File: spec/lib/ext/hash/from_string_spec.rb:



                      require "ext/hash/from_string"

                      describe "Hash.from_string" do
                      it "generally works" do
                      [
                      # Basic cases.
                      ['{"x"=>"y"}', {"x" => "y"}],
                      ['{"is"=>true}', {"is" => true}],
                      ['{"is"=>false}', {"is" => false}],
                      ['{"is"=>nil}', {"is" => nil}],
                      ['{"a"=>{"b"=>"c","ar":[1,2]}}', {"a" => {"b" => "c", "ar" => [1, 2]}}],
                      ['{"id"=>34030, "users"=>[14105]}', {"id" => 34030, "users" => [14105]}],

                      # Tricky cases.
                      ['{"data"=>"{"x"=>"y"}"}', {"data" => "{"x"=>"y"}"}], # Value is a `Hash#inspect` string which must be preserved.
                      ].each do |input, expected|
                      output = Hash.from_string(input)
                      expect([input, output]).to eq [input, expected]
                      end
                      end # it
                      end





                      share|improve this answer





















                      • 1





                        it "generally works" but not necessarily? I would be more verbose in those tests. it "converts strings to object" { expect('...').to eql ... } it "supports nested objects" { expect('...').to eql ... }

                        – Lex
                        Jun 14 '18 at 1:30













                      • Hey @Lex, what method does is described in its RubyDoc comment. The test better not re-state it, it'll create unnecessary details as passive text. Thus, "generally works" is a nice formula to state that stuff, well, generally works. Cheers!

                        – Alex Fortuna
                        Jun 14 '18 at 12:57











                      • Yeah, at the end of the day whatever works. Any tests are better than no tests. Personally I'm a fan of explicit descriptions, but thats just a preference.

                        – Lex
                        Jun 14 '18 at 22:28














                      0












                      0








                      0







                      Please consider this solution. Library+spec:



                      File: lib/ext/hash/from_string.rb:



                      require "json"

                      module Ext
                      module Hash
                      module ClassMethods
                      # Build a new object from string representation.
                      #
                      # from_string('{"name"=>"Joe"}')
                      #
                      # @param s [String]
                      # @return [Hash]
                      def from_string(s)
                      s.gsub!(/(?<!\)"=>nil/, '":null')
                      s.gsub!(/(?<!\)"=>/, '":')
                      JSON.parse(s)
                      end
                      end
                      end
                      end

                      class Hash #:nodoc:
                      extend Ext::Hash::ClassMethods
                      end


                      File: spec/lib/ext/hash/from_string_spec.rb:



                      require "ext/hash/from_string"

                      describe "Hash.from_string" do
                      it "generally works" do
                      [
                      # Basic cases.
                      ['{"x"=>"y"}', {"x" => "y"}],
                      ['{"is"=>true}', {"is" => true}],
                      ['{"is"=>false}', {"is" => false}],
                      ['{"is"=>nil}', {"is" => nil}],
                      ['{"a"=>{"b"=>"c","ar":[1,2]}}', {"a" => {"b" => "c", "ar" => [1, 2]}}],
                      ['{"id"=>34030, "users"=>[14105]}', {"id" => 34030, "users" => [14105]}],

                      # Tricky cases.
                      ['{"data"=>"{"x"=>"y"}"}', {"data" => "{"x"=>"y"}"}], # Value is a `Hash#inspect` string which must be preserved.
                      ].each do |input, expected|
                      output = Hash.from_string(input)
                      expect([input, output]).to eq [input, expected]
                      end
                      end # it
                      end





                      share|improve this answer















                      Please consider this solution. Library+spec:



                      File: lib/ext/hash/from_string.rb:



                      require "json"

                      module Ext
                      module Hash
                      module ClassMethods
                      # Build a new object from string representation.
                      #
                      # from_string('{"name"=>"Joe"}')
                      #
                      # @param s [String]
                      # @return [Hash]
                      def from_string(s)
                      s.gsub!(/(?<!\)"=>nil/, '":null')
                      s.gsub!(/(?<!\)"=>/, '":')
                      JSON.parse(s)
                      end
                      end
                      end
                      end

                      class Hash #:nodoc:
                      extend Ext::Hash::ClassMethods
                      end


                      File: spec/lib/ext/hash/from_string_spec.rb:



                      require "ext/hash/from_string"

                      describe "Hash.from_string" do
                      it "generally works" do
                      [
                      # Basic cases.
                      ['{"x"=>"y"}', {"x" => "y"}],
                      ['{"is"=>true}', {"is" => true}],
                      ['{"is"=>false}', {"is" => false}],
                      ['{"is"=>nil}', {"is" => nil}],
                      ['{"a"=>{"b"=>"c","ar":[1,2]}}', {"a" => {"b" => "c", "ar" => [1, 2]}}],
                      ['{"id"=>34030, "users"=>[14105]}', {"id" => 34030, "users" => [14105]}],

                      # Tricky cases.
                      ['{"data"=>"{"x"=>"y"}"}', {"data" => "{"x"=>"y"}"}], # Value is a `Hash#inspect` string which must be preserved.
                      ].each do |input, expected|
                      output = Hash.from_string(input)
                      expect([input, output]).to eq [input, expected]
                      end
                      end # it
                      end






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Jul 12 '18 at 11:58

























                      answered Dec 26 '15 at 22:02









                      Alex FortunaAlex Fortuna

                      1,0841015




                      1,0841015








                      • 1





                        it "generally works" but not necessarily? I would be more verbose in those tests. it "converts strings to object" { expect('...').to eql ... } it "supports nested objects" { expect('...').to eql ... }

                        – Lex
                        Jun 14 '18 at 1:30













                      • Hey @Lex, what method does is described in its RubyDoc comment. The test better not re-state it, it'll create unnecessary details as passive text. Thus, "generally works" is a nice formula to state that stuff, well, generally works. Cheers!

                        – Alex Fortuna
                        Jun 14 '18 at 12:57











                      • Yeah, at the end of the day whatever works. Any tests are better than no tests. Personally I'm a fan of explicit descriptions, but thats just a preference.

                        – Lex
                        Jun 14 '18 at 22:28














                      • 1





                        it "generally works" but not necessarily? I would be more verbose in those tests. it "converts strings to object" { expect('...').to eql ... } it "supports nested objects" { expect('...').to eql ... }

                        – Lex
                        Jun 14 '18 at 1:30













                      • Hey @Lex, what method does is described in its RubyDoc comment. The test better not re-state it, it'll create unnecessary details as passive text. Thus, "generally works" is a nice formula to state that stuff, well, generally works. Cheers!

                        – Alex Fortuna
                        Jun 14 '18 at 12:57











                      • Yeah, at the end of the day whatever works. Any tests are better than no tests. Personally I'm a fan of explicit descriptions, but thats just a preference.

                        – Lex
                        Jun 14 '18 at 22:28








                      1




                      1





                      it "generally works" but not necessarily? I would be more verbose in those tests. it "converts strings to object" { expect('...').to eql ... } it "supports nested objects" { expect('...').to eql ... }

                      – Lex
                      Jun 14 '18 at 1:30







                      it "generally works" but not necessarily? I would be more verbose in those tests. it "converts strings to object" { expect('...').to eql ... } it "supports nested objects" { expect('...').to eql ... }

                      – Lex
                      Jun 14 '18 at 1:30















                      Hey @Lex, what method does is described in its RubyDoc comment. The test better not re-state it, it'll create unnecessary details as passive text. Thus, "generally works" is a nice formula to state that stuff, well, generally works. Cheers!

                      – Alex Fortuna
                      Jun 14 '18 at 12:57





                      Hey @Lex, what method does is described in its RubyDoc comment. The test better not re-state it, it'll create unnecessary details as passive text. Thus, "generally works" is a nice formula to state that stuff, well, generally works. Cheers!

                      – Alex Fortuna
                      Jun 14 '18 at 12:57













                      Yeah, at the end of the day whatever works. Any tests are better than no tests. Personally I'm a fan of explicit descriptions, but thats just a preference.

                      – Lex
                      Jun 14 '18 at 22:28





                      Yeah, at the end of the day whatever works. Any tests are better than no tests. Personally I'm a fan of explicit descriptions, but thats just a preference.

                      – Lex
                      Jun 14 '18 at 22:28


















                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f1667630%2fhow-do-i-convert-a-string-object-into-a-hash-object%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      404 Error Contact Form 7 ajax form submitting

                      How to know if a Active Directory user can login interactively

                      TypeError: fit_transform() missing 1 required positional argument: 'X'