Replace the variable value via symbol? - ruby

var is a variable that has some value stored in it. How to replace the value of var in :var (symbol) to nil?
Any ideas?

If it's one or more local variables, call Kernel#eval on the implicit local Binding using a String containing the assignment you want to make. Note that interpolation implicitly converts the Symbol to a String, so you don't need to explicitly call #to_s on the Symbol objects you're iterating over. For example:
local_vars = [:foo, :bar]
local_vars.map { eval "#{_1} = nil" }
If it's an instance or class variable, then you have access to Object and Class methods that don't require an explicit call to #eval. Instead, you can call Object#instance_variable_set or Module#class_variable_set on the instance or class object you want to modify rather than on the binding. For example:
obj = Object.new
instance_vars = [:#foo, :#bar]
instance_vars.map { obj.instance_variable_set _1, nil }

Related

In Ruby, what is are the specific methods to retrieve the return value of Class.new (an instance)?

Given the following code below:
class Animal
end
dog = Animal.new # --> return value of Animal.new
What are the specific methods to retrieve the return value for Animal.new? I understand that a new instance is created from the class Animal and assigned to the variable dog. But what are the methods to retrieve the return value of Animal.new?
According to docs here:
new(args, ...) → obj
Calls allocate to create a new object of class’s class, then invokes
that object’s initialize method, passing it args. This is the method
that ends up getting called whenever an object is constructed using
.new.
You can test this yourself in irb. It returns an instance of that object.
# Instantiating a new instance of a class
irb(main):001:0> Class.new
=> #<Class:0x007fe24193c918>
# Assigning a new instance of a class to a variable
irb(main):005:0> some_var = Class.new
=> #<Class:0x007fe2410e68b8>
irb(main):006:0> some_var
=> #<Class:0x007fe2410e68b8>
class A
end
Calling a = A.new return the new object of class A, the string appear as eg #<A:0x00000002d8eb98> is the string containing human readable representation of the object from the default implementation of inspect method which is called each time new object is created.
The default inspect shows the object’s class name, an encoding of the object id and a list of the instance variables and their values User custom classes eg A should/adviced to override this method to provide better representation of their objects eg
class A
def inspect
"I am what i am"
end
end
b = A.new
prints -> I am what i amnot the hexadecimal value

Ruby's class expression---how is it different from `Class.new`? [duplicate]

What is difference between class and Class.new & module and Module.new?
I know that:
Class.new/Module.new create an anonymous class/module. When we assign it to constant for the first time it becomes name of that class/module. class/module do this automatically.
When we want to inherit, we can pass an argument: Class.new(ancestor). When we don't specify an ancestor, it is set to the Object. class use this syntax: class A < Ancestor
Class.new returns an object. class A returns nil. Same goes for modules.
Did I miss something?
The interesting point that you missed between class keyword and Class::new is - Class::new accepts block. So when you will be creating a class object using Class::new you can also access to the surrounding variables. Because block is closure. But this is not possible, when you will be creating a class using the keyword class. Because class creates a brand new scope which has no knowledge about the outside world. Let me give you some examples.
Here I am creating a class using keyword class :
count = 2
class Foo
puts count
end
# undefined local variable or method `count' for Foo:Class (NameError)
Here one using Class.new :
count = 2
Foo = Class.new do |c|
puts count
end
# >> 2
The same difference goes with keyword module and Module::new.
Class.new returns an object. class A returns nil. Same goes for modules.
That's wrong. A class/module definition returns the value of the last expression evaluated inside of the class/module body:
class Foo
42
end
# => 42
Typically, the last expression evaluated inside of a class/module body will be a method definition expression, which in current versions of Ruby returns a Symbol denoting the name of the method:
class Foo
def bar; end
end
# => :bar
In older versions of Ruby, the return value of a method definition expression was implementation-defined. Rubinius returned a CompiledMethod object for the method in question, whereas YARV and most others simply returned nil.

ruby access instance variable in instance_eval

I am trying some ruby metaprogramming and got some confusion with instance_eval().
see below examples
#instance_var = 'instance_var'
local_var = 'local_var'
obj = Object.new
obj.instance_eval { p #instance_var; p local_var }
obj.instance_eval { #instance_var = 'instance_var_in_obj'; local_var = 'local_var_in_obj' }
p #instance_var; p local_var
I expect both of #instance_var and local_var can be pass/modify in block but i got
nil
"local_var"
"instance_var"
"local_var_in_obj"
as result we can share(pass/modify) local vars in instance_val but instance vars are belong to self CAN NOT share.
and about instance_exec:
obj.instance_exec(#instance_var) {|instance_var| p instance_var; instance_var = #instance_var }
=> "instance_var"
#instance_var
=> "instance_var"
now i can pass my outer instance var and still CAN NOT modify it.
#instance_arr = []
obj.instance_exec(#instance_arr) {|instance_arr| instance_arr << 'in_block' }
#instance_arr
=> ["in_block"]
obj.instance_exec(#instance_arr) {|instance_arr| instance_arr = [] }
#instance_arr
=> ["in_block"]
with a instance var of array i can modify my instance var but ONLY within current array object
in summary play instance_eval or instance_exec with local vars not instance vars?
is there some concepts i missed?
After some search and advices from my friend i think i figured out the problem.
In ruby there is two Context when your code running self and binding, when you work with local vars or method without set self.xxx first thing will be checking is it in your binding object as a local var if not Ruby will think it's a method then search on your self object to find its definition and invoke it.
Think this:
class A
def test
4
end
def use_variable
test = 5
test
end
def use_method
test = 5
self.test
end
end
a = A.new
a.use_variable # returns 5
a.use_method # returns 4
That's explained WHY of instance_eval as its document said instance_eval just changed self in the given block and NOT touch binding so methods will be search on new self, local vals still in same binding object.
About instance_exec i'm not very sure about this but seems like instance vars(with at prefix vars) it will be search on self directly skip on binding, so out of instance_exec your #instance_arr belongs to old self and in instance_exec block you got it as a new local var in the new binding of block(block has own scope) but the value of it actually is the reference of #instance_arr so invoke method on the new local var such like push it will change both of them because they share same Array instance, but when you assign a new Array instance to the new local var they are no longer refer same Array instance that's the second WHY.
In order to evaluate the local variable, you would need to pass in the string `"local_var" and it will return the value of the local variable. If you pass in a block, then an argument can not be passed in, according to my interpretation of the documentation.
The behavior of instance eval in the block form is to access as a closure the instance variables and private methods of the object where that call is.
The behavior of instance eval with an argument allows you to evaluate a string in the scope of that call.

Ruby: access to attr_accessor's method from internal method

I have a code:
class A
attr_accessor :somevar
def a
somevar = 'something'
puts #somevar
end
def b
send :somevar=, 'something'
puts #somevar
end
end
A.new.a #=> nil
A.new.b #=> 'something'
Why is there a difference? Why can't I just assign an instance variable through a writer? But why local variable has been created instead of method (setter) has been called?
attr_accessor :somevar references the instance variable #somevar. Instance variables must be preceded by the # sign. All other variables like 'somevar' without an # sign in a method are just local variables to that method or scope, not instance variables for the object.
Thus, changing the first line in method "a" to
#somevar = 'something'
will result in the answer you expect.
Related note: you don't have to declare instance variables in Ruby, you just create them with #somevar type notation. The attr_accessor method creates setters and getters for that instance variable.
Methods in Ruby are attached to objects, so in order for class A to invoke its own somevar setter method, you would need to write self.somevar = 'something', otherwise the Ruby parser thinks you are just creating a local variable.
This could be confusing because you could invoke method a from b, by just doing:
def b
send :somevar=,'something'
puts #somevar
a # would invoke its own method 'a'
end
But the setter method somevar= is ambiguous with creating a local variable with the same notation:
somevar='something' # Ruby assumes you want to create a local variable
So to call the somevar setter method you need to explicitly say that you are calling the method on self with:
self.somevar = 'something'
When you called send :somevar=,'something' you were invoking the somevar instance method also.
It's because method a is creating a local variable called somevar. It's just one of Ruby's little quirks. You can get around this by doing self.somevar = 'something' or #somevar = 'something'.

Why is klass used in conjunction with const_get here?

def self.get(server)
return unless server
server = server.to_s
if klass = #handlers[server]
obj = Object
klass.split("::").each { |x| obj = obj.const_get(x) }
obj
else
try_require('rack/handler', server)
const_get(server)
end
end
In the code above, const_get is being used to retrieve some kind of named constant on this line:
klass.split("::").each { |x| obj = obj.const_get(x) }
If so, why is 'klass' particularly being used here? I've read that klass is used to avoid namespace collisions with the "class" keyword. But in this example I don't see where the possible conflict could come from.
The variable is called klass instead of class because both if class = #handlers[server] and class.split("::") would cause a syntax error because, as you said, class is a keyword in ruby.
As a rule local variables can't be named like keywords (methods are fine, but they may only be called with an explicit receiver, which is why you can't write e.g. class.name instead of self.class.name).
Everytime the parser sees the token class at the beginning of an expression, it interprets it as the keyword.
Edit: To clarify: The problem is not that the usage of class here would be ambiguous, it's that you simply can't use keywords as local variable names. The parser won't recognize them as such.
Edit in response to second comment: klass is used here as a local variable holding the value of #handlers[server]. The code could also be written without the variable (assuming that the value of #handlers[server] can't change between the two calls):
if #handlers[server]
obj = Object
#handlers[server].split("::").each { |x| obj = obj.const_get(x) }
I assume that the author of the code stored the value of #handles[server] in a variable to a) not have to type #handlers[server] twice instead of once, b) make clear to the reader that that value is a class, and/or c) to avoid having to call #handlers[] twice.
YAEdit: To hopefully remove the last bit of confusion the following code is also equivalent:
if foo = #handlers[server]
obj = Object
foo.split("::").each { |x| obj = obj.const_get(x) }
Or:
foo = #handlers[server]
if foo
obj = Object
foo.split("::").each { |x| obj = obj.const_get(x) }
However klass is a more descriptive variable name than foo, so that's (presumably) why the author chose to name the variable klass.

Resources