Understanding use case of instance variable and local variable - ruby

Suppose I have a user class as below
class User
def initialize
test
end
def test
name = ['name1','name2', 'name3']
returned_value = test1(name)
lots of if else condition based on returned_value
end
def test1(name)
test2(name)
end
def test2(name)
test3(name)
end
def test3(name)
end
end
And this user class has some methods like test, test1.. and each method do some calculation one single array and then return the array. Now based on the returned value test method add or delete elements from the array. This become very ugly with lot of if else condition because returned value could be blank, one element, two dimensional array and so one.
But if I use an instance variable then I don't have to return any value and so I don't need any if else statement based on the returned value and my code looks clean. For example
class User
def initialize
#name = ['name1','name2', 'name3']
test
end
def test
test1
end
def test1
test2
end
def test2
test3
end
def test3
end
end
My question is, should I use instance variable or not in this case? An explanation would be nice.
Update:
In short it would be, I want to manipulate one single array in different methods of a Class. Now, I can create the array inside test method and then pass it to other methods (first case in my above example) or I can create the array in initialize method and then I don't have to pass the array every time(second case in my example above). So my questions is
Is my first/second approach is bad/okay? Or both approach is okay to use?

If you have data that needs to be accessible to many methods in a class, then instance variables is a good way to manage that.
I generally use instance variables in PORO classes for two reasons
To store information, usually at initialization, that many of the
class methods need access to. This is what you're asking about
above.
To memoize resource intensive methods.
For example to avoid doing an api call every time I access customer_data I would replace
def customer_data
HTTParty.get... (some api call)
end
with
def customer_data
#customer_data ||= HTTParty.get... (some api call)
end
#customer_data is only used within that method, but if I call the method multiple times only one api call is needed. This assumes (of course) that for a given class object there is only one associated customer.

Related

Is it possible to override value in a block

New to Ruby so apologies in advance if this is a dumb question. I have a need to supply a value to a block but would like not to update everywhere called.
Let's say I have the following block:
{ base.call_my_test }
It get's passed to a function where I'd like to wrap it in another block but supply that other blocks value to it such as:
def test(&block)
MyTest.with_base_object do |base|
#neither of these work
block.instance_variable_set(:#base, base) # Doesn't work
block.define_singleton_method(:hi) do
return base
end
block.call <---- Is it possible to define base here?
end
end
In the above example, is it possible to define base on the block without passing as an argument? I tried instance_variable_set as well as define_singleton_method but I can't seem to get anything to be defined as it always says base is undefined.
Not sure if this is even possible but figured I'd ask.
First, blocks in Ruby are non-rigid Proc objects. That means that you can pass extra arguments, and anyone who doesn't expect arguments will silently ignore them.
def test(&block)
base = Object.new
block.call(base)
end
test { |x| puts "Works with an object #{x}." }
test { puts "Works without an object as well!" }
So if you control the block where you need base to be defined, then you can simply add the argument. Any other uses of the test function will simply ignore the extra argument, even if they're not declared to take one.
But this is assuming you control any of the blocks at all. It sounds like you have some blocks somewhere out there that you can't change, and you automagically want to inject the name base into their scope. You can change the class instance that a block is being invoked for by passing the block to instance_eval.
Buyer beware: This will completely change self. If the block in question tries to view self or call any other methods on the object (it thinks) it's enclosed in, it will fail.
class HasBase
attr_reader :base
def initialize(base)
#base = base
end
end
def test(&block)
base = Object.new
HasBase.new(base).instance_eval(&block)
end
test { puts "I can see my #{base} from here!" }
Depending on your specific needs, you can start augmenting this to work with whatever your callers need. For instance, you can write method_missing to fall back to the proc's original binding. But that's getting into some deep magic, and you probably don't want to play with that footgun in production for very long.

Return containing object instance in ruby

I'm trying to implement a funky version of method chaining. Returning the instance of the class after each function call is easy, you just do
def chainable_method
some_code()
self
end
My idea is that the methods you can call depend on the previous method call. I'm trying to achieve this by returning an object belonging to the containing object. The contained object will have a few special methods, and then implement method_missing to return the containing object's instance.
Edit: The child object has some state associated with it that should be in itself, and not the parent. It might not have been clear previously as to why I need a whole instance for just method calls.
super is irrelevant in this case because the contained object doesn't inherit from the containing object, and I wouldn't want to call the containing object's methods on the contained object anyway - I want to call the containing object's methods on the containing object itself. I want the containing object, not the containing object class.
Not sure if this is possible.
Edit: reworded everything to use "containing/contained object" instead of the completely incorrect parent/child object.
Also, I'm using 1.9.3, if that matters. Version isn't important, I can change if needed.
My explanation was probably unclear. Here's the code:
class AliasableString
def initialize(string)
#string = string
end
def as(aka)
#aka = aka
end
def has_aka?
!#aka.nil?
end
# alias is a reserved word
def aka
#aka
end
def to_s
#string + (self.has_aka? ? (" as " + #aka) : "")
end
end
class Query
def initialize
#select_statements = Array.new
end
def select(statement)
select_statement = AliasableString.new(statement)
#select_statements.push(select_statement)
select_statement
end
def print
if #select_statements.size != 0
puts "select"
#select_statements.each_with_index {| select, i|
puts select
}
end
end
end
# Example usage
q0 = Query.new
q0.select("This is a select statement")
.select("Here's another one")
.as("But this one has an alias")
.select("This should be passed on to the parent!")
q0.print
I haven't yet fully implemented print. AliasableString needs to have #string and #aka separate so I can pull them apart later.
First of all, it doesn't matter what class of object is contained within a Query instance. All of the syntax shown on your 'example usage' section is appropriately defined in Query. The only requirement of the objects contained within a query instance is that they respond to as (or some similar method). What you have here is something like a state machine, but the only state that really matters is that some object occupies the last position in the select_statements array. Here's how I would build this (again, based mostly on your example at the end, I'm afraid I can't quite follow your initial explanation):
class Query
# ... initialize, etc.
def select(statement, statement_class = AliasableString)
select_statements << statement_class.new(statement)
self
end
def as(aka)
# this will only ever be used on the most recent statement added
statement_to_alias = select_statements.last
# throw an error if select_statements is empty (i.e., :last returns nil)
raise 'You must add a statement first' unless statement_to_alias
# forward the message on to the statement
statement_to_alias.as(aka)
# return the query object again to permit further chaining
self
end
end
AliasableString doesn't need to know a thing about Query; all it needs to do is respond appropriately to as.

How and why does this dynamic method definition work?

How does following code works and, more importantly, why does it work that way?
class Example
def one
def one
#value = 99
end
puts "Expensive Call"
#value = 99 # assume its expensive call
end
end
ex = Example.new
puts ex.one # => "Expensive Call"; 99
puts ex.one # => 99
Here, on first call to method one, Ruby executes the outer one method, but on successive calls, it executes only the inner one method, bypassing the outer one method totally.
I want to know how does it happen and why does it happen so.
How It Works
Ruby allows you to redefine classes at run-time, because class and def are actually executable code. In your example, the code does the following:
Defines an Example#one method that will (re)define the Example#one method when the instance method is called.
For practical purposes, the inner def will not be executed until the outer instance method is called. (Hair-splitters may legitimately argue this definition, but that gets into details of the parser/interpreter that just don't matter for the purposes of this discussion.)
You define an instance of Example named "ex."
You invoke the instance method on ex, which defines a new method with the same name.
When you call the instance method again, the new method is used instead of the old one.
Why It Works
Basically, the last definition of a method replaces any earlier definitions in that namespace, but the methods are actually new objects. You can see this in action as follows:
def my_method
puts 'Old Method'
puts self.method(:my_method).object_id
def my_method
puts 'New Method'
puts self.method(:my_method).object_id
end
end
If you run this in an irb or pry session, you can see the method redefined at run-time:
> my_method; puts; my_method
Old Method
8998420
New Method
8998360
As you can see by the different object IDs, even though the methods have the same name and are attached to the same object (generally main at the console), they are actually different method objects. However, since the methods were defined with the same name, only the most recent definition is found when the instance does a method lookup.
When you execute it the first time, it redefines itself in the class and then finishes. The second time, the method one has been overriden by itself to just #value = 99, so nothing is printed.
It's important to realize first that there is no such thing as inner or outer methods in Ruby.
You're defining a new method within a method—in this case, since the method being defined has the same name as an existing one, the new definition completely overwrites the original one.
What you have is equivalent to the (perhaps) more obvious:
class Example
def one
self.class.send(:define_method, :one) do
#value = 99
end
puts "Expensive Call"
#value = 99 # assume its expensive call
end
end
Here it's clearer that you're defining a method within the context of the class.

Copy all methods from one class to another on the fly

I have two classes and I want to copy all of the methods from one class to another. Some methods will have no arguments, some will have arguments, and some will have hashes as arguments. And I never know in advance which ones will. So I created this code, until I figured out that it didn't take into account arguments. Is there any way to get a list of methods from a Class, and then clone them exactly to another class?
def partial(cls)
cls.instance_methods(false).each do |method_name|
define_method(method_name) do
cls.new.method(method_name.to_sym).call
end
end
end
The methods are created on the fly using define_method in the first class, so I can't just use an include. The code above has cls being passed in, then it finds all of the instance methods that are actually written in that Class, not ones it inherits, and then creates a new method with the same name. When that method is called, it actually calls the other Class with its method of the same name. This works wonderfully, unless I have args. I had condition check to see if it had arguments, and then had it call a method with arguments, but it did not handle hashes very well. It made the hash as an array for an argument, which is not what I wanted.
I was wondering if there was a simple way to literally say "Hey you know this method, whatever it is, literally make the same thing for this other Class."
you could also try DelegateClass:
class NamedArray < DelegateClass(Array)
def initialize n
#name = n
super(Array.new)
end
def sayName
"My name is #{#name}"
end
end
You could try SimpleDelegator: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/delegate/rdoc/SimpleDelegator.html
If all the methods are identical, why not just define them in a common module which you include in both classes? You mention not using include because the methods are dynamically defined, but that doesn't mean they won't be found when you mixin the module:
module Foo
def self.make_an_example_method(name)
define_method(name) do |*args|
puts "I am #{name} called with (#{args.inspect})"
end
end
end
class A
include Foo
end
class B
include Foo
end
Foo.make_an_example_method(:example)
Foo.make_an_example_method(:dynamic)
A.new.example # => I am example called with ([])
B.new.dynamic(1,2,3) # => I am dynamic called with ([1, 2, 3])

Is it possible to compare private attributes in Ruby?

I'm thinking in:
class X
def new()
#a = 1
end
def m( other )
#a == other.#a
end
end
x = X.new()
y = X.new()
x.m( y )
But it doesn't works.
The error message is:
syntax error, unexpected tIVAR
How can I compare two private attributes from the same class then?
There have already been several good answers to your immediate problem, but I have noticed some other pieces of your code that warrant a comment. (Most of them trivial, though.)
Here's four trivial ones, all of them related to coding style:
Indentation: you are mixing 4 spaces for indentation and 5 spaces. It is generally better to stick to just one style of indentation, and in Ruby that is generally 2 spaces.
If a method doesn't take any parameters, it is customary to leave off the parantheses in the method definition.
Likewise, if you send a message without arguments, the parantheses are left off.
No whitespace after an opening paranthesis and before a closing one, except in blocks.
Anyway, that's just the small stuff. The big stuff is this:
def new
#a = 1
end
This does not do what you think it does! This defines an instance method called X#new and not a class method called X.new!
What you are calling here:
x = X.new
is a class method called new, which you have inherited from the Class class. So, you never call your new method, which means #a = 1 never gets executed, which means #a is always undefined, which means it will always evaluate to nil which means the #a of self and the #a of other will always be the same which means m will always be true!
What you probably want to do is provide a constructor, except Ruby doesn't have constructors. Ruby only uses factory methods.
The method you really wanted to override is the instance method initialize. Now you are probably asking yourself: "why do I have to override an instance method called initialize when I'm actually calling a class method called new?"
Well, object construction in Ruby works like this: object construction is split into two phases, allocation and initialization. Allocation is done by a public class method called allocate, which is defined as an instance method of class Class and is generally never overriden. It just allocates the memory space for the object and sets up a few pointers, however, the object is not really usable at this point.
That's where the initializer comes in: it is an instance method called initialize, which sets up the object's internal state and brings it into a consistent, fully defined state which can be used by other objects.
So, in order to fully create a new object, what you need to do is this:
x = X.allocate
x.initialize
[Note: Objective-C programmers may recognize this.]
However, because it is too easy to forget to call initialize and as a general rule an object should be fully valid after construction, there is a convenience factory method called Class#new, which does all that work for you and looks something like this:
class Class
def new(*args, &block)
obj = alloc
obj.initialize(*args, &block)
return obj
end
end
[Note: actually, initialize is private, so reflection has to be used to circumvent the access restrictions like this: obj.send(:initialize, *args, &block)]
Lastly, let me explain what's going wrong in your m method. (The others have already explained how to solve it.)
In Ruby, there is no way (note: in Ruby, "there is no way" actually translates to "there is always a way involving reflection") to access an instance variable from outside the instance. That's why it's called an instance variable after all, because it belongs to the instance. This is a legacy from Smalltalk: in Smalltalk there are no visibility restrictions, all methods are public. Thus, instance variables are the only way to do encapsulation in Smalltalk, and, after all, encapsulation is one of the pillars of OO. In Ruby, there are visibility restrictions (as we have seen above, for example), so it is not strictly necessary to hide instance variables for that reason. There is another reason, however: the Uniform Access Principle.
The UAP states that how to use a feature should be independent from how the feature is implemented. So, accessing a feature should always be the same, i.e. uniform. The reason for this is that the author of the feature is free to change how the feature works internally, without breaking the users of the feature. In other words, it's basic modularity.
This means for example that getting the size of a collection should always be the same, regardless of whether the size is stored in a variable, computed dynamically every time, lazily computed the first time and then stored in a variable, memoized or whatever. Sounds obvious, but e.g. Java gets this wrong:
obj.size # stored in a field
vs.
obj.getSize() # computed
Ruby takes the easy way out. In Ruby, there is only one way to use a feature: sending a message. Since there is only one way, access is trivially uniform.
So, to make a long story short: you simply can't access another instance's instance variable. you can only interact with that instance via message sending. Which means that the other object has to either provide you with a method (in this case at least of protected visibility) to access its instance variable, or you have to violate that object's encapsulation (and thus lose Uniform Access, increase coupling and risk future breakage) by using reflection (in this case instance_variable_get).
Here it is, in all its glory:
#!/usr/bin/env ruby
class X
def initialize(a=1)
#a = a
end
def m(other)
#a == other.a
end
protected
attr_reader :a
end
require 'test/unit'
class TestX < Test::Unit::TestCase
def test_that_m_evaluates_to_true_when_passed_two_empty_xs
x, y = X.new, X.new
assert x.m(y)
end
def test_that_m_evaluates_to_true_when_passed_two_xs_with_equal_attributes
assert X.new('foo').m(X.new('foo'))
end
end
Or alternatively:
class X
def m(other)
#a == other.instance_variable_get(:#a)
end
end
Which one of those two you chose is a matter of personly taste, I would say. The Set class in the standard library uses the reflection version, although it uses instance_eval instead:
class X
def m(other)
#a == other.instance_eval { #a }
end
end
(I have no idea why. Maybe instance_variable_get simply didn't exist when Set was written. Ruby is going to be 17 years old in February, some of the stuff in the stdlib is from the very early days.)
There are several methods
Getter:
class X
attr_reader :a
def m( other )
a == other.a
end
end
instance_eval:
class X
def m( other )
#a == other.instance_eval { #a }
end
end
instance_variable_get:
class X
def m( other )
#a == other.instance_variable_get :#a
end
end
I don't think ruby has a concept of "friend" or "protected" access, and even "private" is easily hacked around. Using a getter creates a read-only property, and instance_eval means you have to know the name of the instance variable, so the connotation is similar.
If you don't use the instance_eval option (as #jleedev posted), and choose to use a getter method, you can still keep it protected
If you want a protected method in Ruby, just do the following to create a getter that can only be read from objects of the same class:
class X
def new()
#a = 1
end
def m( other )
#a == other.a
end
protected
def a
#a
end
end
x = X.new()
y = X.new()
x.m( y ) # Returns true
x.a # Throws error
Not sure, but this might help:
Outside of the class, it's a little bit harder:
# Doesn't work:
irb -> a.#foo
SyntaxError: compile error
(irb):9: syntax error, unexpected tIVAR
from (irb):9
# But you can access it this way:
irb -> a.instance_variable_get(:#foo)
=> []
http://whynotwiki.com/Ruby_/_Variables_and_constants#Variable_scope.2Faccessibility

Resources