Array not accessible from method - ruby

I have code:
class Blah
#hello = ["a", "b", "c"]
puts #hello[0]
def something()
puts "abc"
#puts #hello[0]
end
end
z = Blah.new()
z.something()
puts #hello[0]
It results in the output:
a
abc
If I uncomment
#puts #hello[0]
and try to output the first result of the array #hello, which is a, I get this error:
array_2.rb:13:in `something': undefined method `[]' for nil:NilClass (NoMethodError)
Why can I not get the result:
a
abc
a
Why doesn't my code work? An array such as #example should be accessible not just in the the class, but also in the something method. Why can't I access #hello[0] within methods? Why is #hello[0] only accessible within the class, and not the method? Need someone to fix my code so that I can access #array within the method.

You need to initialize instance variable in instance methods, but you are doing this in the scope of the class body, which isn't going to work.
If you set #hello from the initialize method, it should work like you expect.
class Blah
def initialize
#hello = ["a","b","c"]
end
def something()
puts #hello[0]
end
end
Blah.new.something #=> 'a'
It works this way so that you can pass arguments when instantiating a class, and each instance may have different data stored in its instance variables.

Related

Calling a class method with local variable as parameter

I want to pass a string in a variable from a method to another class. I have this code:
class A
def method_a
variable = "some string"
B.method_b(variable)
end
end
class B
def self.method_b(parameter)
puts parameter
end
end
This code generates the following error:
Undefined local variable or method `variable`
What am I doing wrong?
What you've defined here is an instance method, one that can only operate on an instance of B:
class B
def self.class_only(v)
puts "Class: #{v}"
end
def instance_only(v)
puts "Instance: #{v}"
end
end
The class_only method does not require an instance:
B.class_only(variable)
The instance_only method must operate on an instance:
b = B.new
b.instance_only(variable)
Now anything the B method is given via arguments is valid, and any local or instance variables on the A side are things you can supply to the call. There's no scope issues here because you're explicitly passing them over.
For example:
class A
def test
variable = SecureRandom.hex(6)
B.class_only(variable)
end
end
A.new.test

Ruby. Class vs instance variable methods

I have a class:
class MyClass
def self.create_array
variable = ['one', 'two', 'three']
# I had:
# variable.each {|v| v.upcase}
# but want to do:
second_method(variable)
# or like this:
variable.second_method
# of course without parameter 'var' in second option
end
def second_method (var)
var.map {|v| v.upcase}
end
end
puts MyClass.create_array
# of course:
=> undefined method `second_method' for MyClass:Class (NoMethodError)
So I am just wondering how to incorporate second_method into first one.
It only worked when I did:
class MyClass
def self.create_array
variable = ['one', 'two', 'three']
MyClass.second_method(variable)
end
def self.second_method (var)
var.map {|v| v.upcase}
end
end
puts MyClass.create_array
Why it works only when I call it on class? I would like to just call it on my variable. Please, enlighten me!
Edit
Would it make any sense to create method in:
class Array
def second_method
#content
end
end
You've defined second_method as an instance method on MyClass, which means it can only be called on an instance of MyClass - not on the class itself (that's why the second version works, where you define both methods as class methods using the self. operator.
To get your existing code to work, you could call MyClass.new.second_method(variable) inside self.create_array.
In Ruby only class methods can be called from an class method. when you are calling create_array in first snippet, you can not call a instance methds from inside it.
Like the others pointed out, class methods can only be called directly on the class itself.
Is it this you want to achieve ?
class MyClass
attr_accessor :variable
def initialize
#variable = ['one', 'two', 'three']
second_method #variable
end
def second_method var
#variable = var.map {|v| v.upcase}
end
end
MyClass.new
#<MyClass:0x292fda0 #variable=["ONE", "TWO", "THREE"]>
Or you can give the array as a parameters when instantiating the class like this
class MyClass
attr_accessor :variable
def initialize variable
#variable = variable
second_method #variable
end
def second_method var
#variable = var.map {|v| v.upcase}
end
end
MyClass.new ['one', 'two', 'three']
#<MyClass:0x292fda0 #variable=["ONE", "TWO", "THREE"]>

Ruby invoking attr method with array of attributes

Please explain me why i should define attr_list before attr? I can not understand why i should do that?
class Question
def self.attr_list
[:id, :name]
end
attr *self.attr_list
end
class Question
attr *self.attr_list
def self.attr_list
[:id, :name]
end
end
NoMethodError: undefined method `attr_list' for Question:Class
Unlike a def, a class is executed line by line immediately after you hit return to run your program:
class Dog
x = 10
puts x
end
--output:--
10
...
class Dog
puts x
x=10
end
--output:--
1.rb:2:in `<class:Dog>': undefined local variable or method `x'
In this line:
...
class Dog
def self.greet
puts 'hello'
end
greet
end
--output:--
hello
...
class Dog
greet
def self.greet
puts 'hello'
end
end
--output:--
1.rb:2:in `<class:Dog>': undefined local variable or method `greet'
Similarly, in this line:
attr *self.attr_list
you call self.attr_list(), yet the def comes after that line, so the method doesn't exist yet.
With a def, you can write this:
def do_math()
10/0
end
and you won't get an error until you call the method.
But by the time you create an instance of a class, all the code inside the class has already executed, creating the methods and constants that are defined inside the class.
By the way, you don't ever need to use attr because ruby 1.8.7+ has attr_accessor(reader and writer), attr_reader, and attr_writer.

Ruby map method with instance_variables

Say I have a class SomeClass with instance variables a and b.
def SomeClass
def initialize a, b
#a = a
#b = b
end
end
When I type into pry the following lines
someclass = SomeClass.new "one", "two"
someclass.instance_variables
As expected it prints an array with symbols
[:#a, :#b]
now, when I use
a.instance_variables.map do |var|
puts var
end
I expect it to print
:#a
:#b
but what I am getting is
#a
#b
Can someone please explain this behaviour ?
puts transparently calls to_s on arguments. Symbol#to_s returns symbol’s name (strings w/out preceding colon.) On the other hand, Array#to_s calls inspect on nested elements, that’s why you see colons while putting array’s instance.
Look:
▶ :a.to_s
#=> "a"
▶ [:a,:b,:c].to_s
#=> "[:a, :b, :c]"
This is exactly what you yield calling puts.
If you just want to print the symbols as
:#a
:#b
use 'p var', as p calls inspect on its argument unlike puts which calls to_s

Why this assignment fails in Ruby?

I was experimenting with making a DSL and ran across something that confuses me. In my call method I wanted to set an initial value for #mymethod before evaulating the block. It works if I assign to the variable directly:
class Test
class << self
attr_accessor :mymethod
end
def self.call(&block)
#mymethod="foo"
class_eval &block
end
end
Test.call do
puts "mymethod returned: #{mymethod}"
mymethod = "bar"
puts "mymethod is now: #{mymethod}"
end
Which returns:
[1] pry(main)> load 'test.rb'
mymethod returned: foo
mymethod is now: bar
=> true
But I feel like this should work and it doesn't. The only thing that has changed is the # has been removed from the assignment to mymethod so I think it should be using the mymethod= method created by attr_accessor:
class Test
class << self
attr_accessor :mymethod
end
def self.call(&block)
mymethod="foo"
class_eval &block
end
end
Test.call do
puts "mymethod returned: #{mymethod}"
mymethod = "bar"
puts "mymethod is now: #{mymethod}"
end
However the assignment to mymethod from within call fails while the same assignment inside the block succeeds:
[1] pry(main)> load 'test.rb'
mymethod returned:
mymethod is now: bar
=> true
What's going on here? Can someone explain to my why the assignment would fail inside the call method?
in your case, mymethod="foo" will define mymethod local variable
rather than call mymethod= method.
use self.mymethod="foo" instead

Resources