How to dynamically create a local variable?

后端 未结 4 2198
温柔的废话
温柔的废话 2020-11-22 03:46

I have a variable var = \"some_name\" and I would like to create a new object and assign it to some_name. How can I do it? E.g.

var         


        
4条回答
  •  温柔的废话
    2020-11-22 04:35

    Speaking of ruby 2.2.x it is true that you can't create local variables programatically in current context/binding.. but you can set variables in some particular binding you have a handle of.

    b = binding
    b.local_variable_set :gaga, 5
    b.eval "gaga"
    => 5
    

    Interesting here is that calls to binding give you a new binding each time. So you need to get a handle of the binding you are interested in and then eval in it's context once desired variables are set.

    How is this useful? For example I want to evaluate ERB and writing ERB is much nicer if you can use <%= myvar %> instead of <%= opts[:myvar] %> or something like that.

    To create a new binding I'm using a module class method (I'm sure somebody will correct me how to call this properly, in java I'd call it a static method) to get a clean binding with particular variables set:

    module M
      def self.clean_binding
        binding
      end
    
      def self.binding_from_hash(**vars)
        b = self.clean_binding
        vars.each do |k, v|
          b.local_variable_set k.to_sym, v
        end
        return b
      end
    end
    my_nice_binding = M.binding_from_hash(a: 5, **other_opts)
    

    Now you have a binding with only the desired variables. You can use it for nicer controlled evaluation of ERB or other (possibly third party) trusted code (this is not a sandbox of any kind). It's like defining an interface.

    update: A few additional notes about bindings. Place you create them also affects the availability of methods and Constants resolution. In the above example I create a reasonably clean binding. But if I want to make available the instance methods of some object, I could create a binding by a similar method but within the class of that object. e.g.

    module MyRooTModule
      class Work
        def my_instance_method
          ...
        end
        def not_so_clean_binding
          binding
        end
      end
      class SomeOtherClass
      end
    end
    

    Now my my_object.not_so_clean_binding will allow code to call #my_instance_method on my_object object. In the same way, you can call for example SomeOtherClass.new in code using this binding instead of MyRootModule::SomeOtherClass.new. So there is sometimes more consideration needed when creating a binding than just local variables. HTH

提交回复
热议问题