Create a binding whose only variables are hash keys

I know that I can create a binding from hashing using ostruct, for example:

require 'ostruct'

not_in_locals = "we don't want this"
locals = {a: 1, b: 2}
my_binding = OpenStruct.new(locals).instance_eval { binding }
p my_binding
p eval("a", my_binding) #good, we want this
p eval("b", my_binding) #good, we want this
p eval("not_in_locals", my_binding) #bad, don't want it to access this, but it can

Here you can see the output that confirms the comments in the code: https://eval.in/132925

As you can see, the problem is that Binding also binds variables in the local context that are not in the Hash. I need a method to create anchor objects from Hash that are not related to anything other than the keys to this Hash.

+4
source share
2 answers

- . eval() . (), ( ) ().

, , , .

class HashBinding
  def initialize(hash)
    @hash = hash
  end

  def evaluate(str)
    binding_code = @hash.to_a.map do |k,v|
      "#{k} = #{v.inspect};"
    end.join(" ")
    eval "#{binding_code}; #{str}"
  end
end

not_in_hash = 'I am not in the hash'
hash = { :foo => 'foo value', :baz => 42}
hash_binding = HashBinding.new(hash)

hash_binding.evaluate('puts "foo = #{foo}"')
hash_binding.evaluate('puts "baz = #{baz}"')
hash_binding.evaluate('puts "not_in_hash = #{not_in_hash}"')

:

ruby binding_of_hash.rb
foo = foo value
baz = 42
binding_of_hash.rb:10:in `eval': undefined local variable or method `not_in_hash' for #<HashBinding:0x007fcc0b9ec1e8> (NameError)
    from binding_of_hash.rb:10:in `eval'
    from binding_of_hash.rb:10:in `evaluate'
    from binding_of_hash.rb:20:in `<main>'
+1

"" , "" .

require 'json'

class HashBinding
  attr_accessor :hash
  def initialize(hash)
    # Require symbol keys
    @hash = Hash[hash.map {|k,v| [k.to_sym, v]}]
  end

  def evaluate(str)
    binding_code = @hash.to_a.map do |k,v|
      "#{k} = @hash[:#{k}];"
    end.join(" ")
    eval "#{binding_code}; #{str}"
  end
end

not_in_hash = 'I am not in the hash'
hash = { :foo => 'foo value', :baz => 42, 'str' => "a string value"}
hash_binding = HashBinding.new(hash)

hash_binding.evaluate('puts "foo = #{foo}"')
hash_binding.evaluate('puts "baz = #{baz}"')
hash_binding.evaluate('puts "str = #{str}"')
hash_binding.evaluate('puts "not_in_hash = #{not_in_hash}"')
0

Source: https://habr.com/ru/post/1535277/


All Articles