Store and retrieve variables from objects - ruby

I want to store and retrieve some variables from object. For example in a
a = "a"
So far I found two possible ways to do it.
Using instance_variable_set and instance_variable_get
a.instance_variable_set(:#x, 10)
a.instance_variable_get(:#x) # => 10
or just using instance_eval
a.instance_eval { #y = 5 }
a.instance_eval { #y } # => 5
The second approach looks shorter and simpler for me, is there anything wrong with my code if I prefer this one?

Speed isn't everything, but... the instance_variable_set method is faster than using instance_eval. Here's a benchmark if you're interested: https://gist.github.com/1268188
Here's another post that gives another good reason for avoiding instance_eval when possible: Alex Kliuchnikau on instance_eval

If there is no good reason (e.g. metaprogramming), you'd better avoid using instance_variable_get(set), coz it will break encapsulation. You can refer to ruby-doc: thereby frustrating the efforts of the class’s author to attempt to provide proper encapsulation.
And the best practice of using instance_eval is to compose DSL style:
assume you have a Engineer class with instance method: program, play and sleep. So,
sb = Engineer.new
sb.program
sb.play
sb.sleep
# is equivalent to
sb.instance_eval do
program
play
sleep
end
In this case, it's shorter :)

Related

Is it possible to access "main:Object" in Ruby?

I really don't know how else to entitle this one. Anyway, I am doing some metaprogramming in Ruby, and while I was debugging I came across a reference to "main:Object".
This got me thinking, if Ruby classes are never fully closed and I can reopen them later for any reason, is it possible to access this "main:Object"? if this is really an Object is should be possible just like any other class/object? If it is not, then why not? Is this a truly protected space? Either way, I want to know if I can access it from anywhere in Ruby. And if so how? And if not why not?
Other than the interpreter complaining about something not being in there, I haven't really many any references or info about this. I mean other than this is the top level scope. But this is not really what I want to know.
There really isn't much out there, these posts below talk about what it is.
Is there a “main” method in Ruby like in C?
What is “main” in Ruby?
I know this doesn't give you action items work with but I do hope that some of the experts the like share their knowledge here in StackOverflow might share it and we (I) can all learn something new.
Anyway, thanks in advance. And if this is not the correct forum please let me know which one is.
It is an instance introduced by irb/pry REPLs or Ruby interpreter on the top level, outside of any other declaration. You might check how does it do:
self
#⇒ main
self.class
#⇒ Object
self.__id__
#⇒ 47421128700280
When you type def foo; 42; end you actually extend this object.
TOPLEVEL_BINDING (definition) is your friend:
def m1
class << TOPLEVEL_BINDING.receiver
def m2
puts 'm2'
end
end
# or
# main = TOPLEVEL_BINDING.receiver
# def main.m2
# puts 'm2'
# end
end
m1
m2 # => m2
Alternatively, you can use TOPLEVEL_BINGING.eval('self') in place of TOPLEVEL_BINGING.receiver.

Specify Ruby method namespace for readability

This is a bit of a weird question, but I'm not quite sure how to look it up. In our project, we already have an existing concept of a "shift". There's a section of code that reads:
foo.shift
In this scenario, it's easy to read this as trying to access the shift variable of object foo. But it could also be Array#shift. Is there a way to specify which class we expect the method to belong to? I've tried variations such as:
foo.send(Array.shift)
Array.shift(foo)
to make it more obvious which method was being called, but I can't get it to work. Is there a way to be more explicit about which class the method you're trying to call belongs to to help in code readability?
On a fundamental level you shouldn't be concerned about this sort of thing and you absolutely can't tell the Array shift method to operate on anything but an Array object. Many of the core Ruby classes are implemented in C and have optimizations that often depend on specific internals being present. There's safety measures in place to prevent you from trying to do something too crazy, like rebinding and applying methods of that sort arbitrarily.
Here's an example of two "shifty" objects to help illustrate a real-world situation and how that applies:
class CharacterArray < Array
def initialize(*args)
super(args.flat_map(&:chars))
end
def inspect
join('').inspect
end
end
class CharacterList < String
def shift
slice!(0, 1)
end
end
You can smash Array#shift on to the first and it will work by pure chance because you're dealing with an Array. It won't work with the second one because that's not an Array, it's missing significant methods that the shift method likely depends on.
In practice it doesn't matter what you're using, they're both the same:
list_a = CharacterArray.new("test")
list_a.shift
# => "t"
list_a.shift
# => "e"
list_a << "y"
# => "sty"
list_b = CharacterList.new("test")
list_b.shift
# => "t"
list_b.shift
# => "e"
list_b << "y"
# => "sty"
These both implement the same interfaces, they both produce the same results, and as far as you're concerned, as the caller, that's good enough. This is the foundation of Duck Typing which is the philosophy Ruby has deeply embraced.
If you try the rebind trick on the CharacterList you're going to end up in trouble, it won't work, yet that class delivers on all your expectations as far as interface goes.
Edit: As Sergio points out, you can't use the rebind technique, Ruby abruptly explodes:
Array.instance_method(:shift).bind(list_b).call
# => Error: bind argument must be an instance of Array (TypeError)
If readability is the goal then that has 35 more characters than list_b.shift which is usually going dramatically in the wrong direction.
After some discussion in the comments, one solution is:
Array.instance_method(:shift).bind(foo).call
Super ugly, but gets across the idea that I wanted which was to completely specify which instance method was actually being called. Alternatives would be to rename the variable to something like foo_array or to call it as foo.to_a.shift.
The reason this is difficult is that Ruby is not strongly-typed, and this question is all about trying to bring stronger typing to it. That's why the solution is gross! Thanks to everybody for their input!

"The simplest" way to use a method as a proc in Ruby

Obviously, method(:method_name).to_proc works but I'm looking for a more concise way to do it - or I will not be doing it even when it's technically the right thing to do.
I'm contemplating a mix-in defining to_proc (just proc would be nicer but some genius made it a private method in Kernel)
module ProcifiedMethods
def to_proc(sym)
method(sym).to_proc
end
end
and then call
to_proc(:method_name)[*args]
but one would think something like that already exists in Ruby core?
My general motivation is to use functional programming concepts interchangeably with OOP. Got a method in some mixin that has no side-effects? Well... use it as a proc! Curry it, compose it, all the other good stuff.
That's the general idea, anyway :)
QUESTION: is there a simpler, battle tested, ideally within-ruby-core way to convert methods to procs? (i.e. a more shorthand alias of method(:method_name).to_proc).
If you're using this proc as method argument, you could use & unary operator, like foo(&method(:method_name))
If method is defined on object, this works too: foo(&obj.method(:method_name))
Firstly, proc does something different from to_proc. to_proc gives you a proc representation of a method. proc creates a proc given a block (or using the block with which the method was invoked if no block is given).
Secondly, method(:name).to_proc is fairly simple. You can define a method that simplifies it a bit, but for what it does - I would say it is very straight forward.
So for the direct question - No, there is no such way.
An argument to be made as for why it has to be slightly more explicit is that unlike with purely functional languages, here the method (and hence the proc) is tied to the instance.
class Foo
attr_accessor :bar
def calculate(baz)
baz * bar
end
end
foo = Foo.new
pro = foo.method(:calculate).to_proc
foo.bar = 7
pro.call(6) # => 42
foo.bar = 9
pro.call(6) # => 54
Stefan gave a good response, a Method behaves like / answers to the same methods as a Proc, so the answer is that the simplest way of using a Method as a Proc is simply using the Method which answers to #call, #[], #curry and all other funny stuff that a Proc has.
This makes a Method useful for standard FP shennanigans. An example:
3.method(:+).curry[3] == 6
If anyone is interested, this is the use case

Procs and Lambdas for what when we have methods

My doubt is pretty much a matter of misunderstanding...
From what I read, a block is a group of code enclosed by {} or do and end.
From my understanding, what a Proc or Lambda does is:
Get this block
Assign the block to a variable
Which means; we don't need to repeat the whole block all the time.
But, what is the difference among a Proc, Lambda and a standard Method? From my understanding, they all work the same way.
There is one crucial difference between Procs (and lambdas) and methods. Procs are objects, methods aren't. And since Ruby is an object-oriented language, where you can only do things with and to objects, that is very important.
So, if you want to pass a piece of code to a method, you need to have an object, and that's what Procs provide.
You can get a proxy object that represents a method via the Object#method method, which will return an instance of the Method class (which duck-types Proc).
Everything in ruby is considered an object. Proc and lambda are fundamentally similar constructs. This topic is highly opinionated as far as usage goes.
The key advantages is that they can be easily passed around into other blocks and the syntax is short and sweet. Consider the following very simple examples:
multiply = Proc.new {|x,y| x*y}
subtract = lambda {|x,y| x-y}
add = ->(x,y) {x+y}
def do_math (opr, *b)
opr.each do |bloc|
puts bloc.call(b[0],b[1])
end
end
do_math([multiply, subtract, add], 10, 5)
# => 50
# => 5
# => 15
puts multiply.call(5,5)
# => 25
puts subtract.call(5,5)
# => 0
puts add.call(5,5)
# => 10
To get a better grasp of what they are, watch this video: An Introduction to Procs, Lambdas and Closures in Ruby
Additionally the documentation has more examples here: http://www.ruby-doc.org/core-2.0.0/Proc.html
I found that this Codecademy section helps with the distinction.

DSL block without argument in ruby

I'm writing a simple dsl in ruby. Few weeks ago I stumbled upon some blog post, which show how to transform code like:
some_method argument do |book|
book.some_method_on_book
book.some_other_method_on_book :with => argument
end
into cleaner code:
some_method argument do
some_method_on_book
some_other_method_on_book :with => argument
end
I can't remember how to do this and I'm not sure about downsides but cleaner syntax is tempting. Does anyone have a clue about this transformation?
def some_method argument, &blk
#...
book.instance_eval &blk
#...
end
UPDATE: However, that omits book but don't let you use the argument. To use it transparently you must transport it someway. I suggest to do it on book itself:
class Book
attr_accessor :argument
end
def some_method argument, &blk
#...
book.argument = argument
book.instance_eval &blk
#...
end
some_method 'argument' do
some_method_on_book
some_other_method_on_book argument
end
Take a look at this article http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation — there is an overview of the method (specifically stated in the context of its downsides and possible solution to them), plus there're several useful links for further reading.
Basically, it's about using instance_eval to execute the block in the desirable context.
Speaking about downside of this technique:
So what's the problem with it? Well, the problem is that blocks are
generally closures. And you expect them to actually be full closures.
And it's not obvious from the point where you write the block that
that block might not be a full closure. That's what happens when you
use instance_eval: you reset the self of that block into something
else - this means that the block is still a closure over all local
variables outside the block, but NOT for method calls. I don't even
know if constant lookup is changed or not.
Using instance_eval changes the rules for the language in a way that
is not obvious when reading a block. You need to think an extra step
to figure out exactly why a method call that you can lexically see
around the block can actually not be called from inside of the block.
Check out the docile gem. It takes care of all the sharp edges, making this very easy for you.

Resources