1

Turn json object to local and global variables, below is the code

require 'json'
hash = '{"$a":5,"b":10}'
hash1 = JSON.parse(hash)
hash1.each do |k,v|
   singleton_class.send(:attr_accessor,k)
   send(eval("#{k}=",v))
end
puts $a

Expected output:

5
6
  • 1
    You can't dynamically set local variables. Eval runs in the scope of a block so any local variables will immediately go out of scope. You can only ever actually dynamically resassign existing local variables as they exist outside of the scope of the eval. Whatever the real world problem you're attempting to solve the is a most likely another answer. Commented Sep 4, 2021 at 20:52
  • @max It seems that you can set the context manually by passing in a binding to the parent scope, see apidock.com/ruby/Kernel/eval and my answer. Commented Sep 4, 2021 at 20:56
  • @max Pinging you here since you might not get a notification on my new comment on my answer since you deleted your comment there. Commented Sep 4, 2021 at 21:14
  • I stand corrected. Commented Sep 4, 2021 at 21:17
  • Why do you want to want to do that? When you assign a variable dynamically how do you want to use it later in your program (when do not know its name)? Additionally using eval makes me think if is there is a better way to do that and if this leads to a security vulnerability. Perhaps working directly with the hash would be a better idea? Commented Sep 5, 2021 at 5:42

2 Answers 2

1

Take this answer with a grain of salt because I'm no expert on Ruby's eval, but this worked for me:

require 'json'

hash = '{"$a":5,"b":10}'
hash1 = JSON.parse(hash)
bind = binding
hash1.each do |k,v|
  # Dunno what this is for and things work fine without it.
  # singleton_class.send(:attr_accessor,k)

  # You don't want to call `send` here, just call `eval` directly.
  eval("#{k}=#{v}", bind)
end

puts $a
# => 5

puts b
# => 10

Note that I'm passing in a binding from the parent scope to eval since you'll want to access local variables such as b in the parent scope after you exit the loop.

Lastly, v needed to be part of the string passed to eval, not the second parameter passed to eval, which, if anything, needs to be a binding. If you pass an integer it will raise an exception.

However, I should warn you that global variables should be used with restraint, and that using eval can be dangerous, especially if you get this JSON from someone else.

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

2 Comments

@max I've stated that it works for me. I've run it. Both variables can be accessed and evaluate to the correct values for me.
@max Not sure why you deleted your comment, maybe there was something to it: when I run your example eval('foo="Bar"'); foo it indeed raises an exception. No surprise there. But the solution I used in my answer – passing in a binding to the parent context – should have worked. It doesn't with your example. Which makes me wonder why my answer works at all (which is another reason OP should take it with a grain of salt).
0

Here is the another method which will work out for local and global variables. where global variable can be evaluated if the key starts with "$" ,else attribute accessor can take care of local variables.

require 'json'

hash = '{"$a":5,"b":10}'
hash1 = JSON.parse(hash)
bind = binding
hash1.each do |k,v|
    if k.start_with?"$"
      eval("#{k}=#{v}")
    else 
       singleton_class.send(:attr_accessor,k)
       send("#{k}=",v)
    end
end
puts "#{$a} \n#{b}"

Output:

5
10

3 Comments

You took the line ‘bind = binding’ and the eval line from my answer without credit. In your last line, you can get the same result by just doing ‘puts a, b’.
Edited. Without binding also it looks fine. Thanks for reminding to update @weltschmerz
You edited the wrong part. Read my comment again, carefully.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.