Why does the following code result in the error 'undefined local variable or method `foo_client' for Foo::People:Class'
class Foo::People
class << self
def get_account_balance(account_num)
foo_client.request :get_account_balance, :body => {"AccountNum" => account_num}
end
end
def foo_client
##client ||= Savon::Client.new do|wsdl, http|
wsdl.document = PEOPLE_SERVICE_ENDPOINT[:uri] + "?WSDL"
wsdl.endpoint = PEOPLE_SERVICE_ENDPOINT[:uri]
end
end
end
def get_account_balance is inside the class << self block, so it's a class method. def foo_client is not, so it's an instance method. So you can't call foo_client from get_account_balance because you're not calling it on an instance of People.
Related
I would like to understand why in this scenario, subclasses of A won't heritate from sequence_name.
class A < ApplicationRecord
self.abstract_class = true
self.sequence_name = "my_seq"
end
And why when defined as follow they will.
class A < ApplicationRecord
self.abstract_class = true
class << self
def sequence_name
"my_seq"
end
end
end
I thought that self.method was equivalent to:
class << self
def method; end
end
I thought that self.method was equivalent to:
class << self
def method; end
end
Not quite.
You can create a class method by defining an instance method in the class' singleton class: (that's what class methods really are)
class A
class << self
def method; end
end
end
Or by using the def self. syntax: (equivalent to the above)
class A
def self.method; end
end
To call the method from within the class, you'd use:
class A
method
end
And if your method is a setter, you have to add an explicit receiver, e.g.:
class A
self.method = 123
end
That looks a bit like the def self. syntax for defining a class method, but note that there's no def in here.
You can rewrite your working code as:
class A < ApplicationRecord
self.abstract_class = true
def self.sequence_name
"my_seq"
end
end
So I have two files, one called a.rb and one called b.rb. Here's the contents in both:
# a.rb
class A
def initialize
#variable = ""
#module_b = B.new(self)
end
def pass_to_b(self)
#module_b.do_something(#variable)
end
def set_variable(var)
# var = empty
#variable = var
end
end
and
# b.rb
class B
def initialize(module_a)
#module_a = module_a
end
def set_variable_in_a(data)
#module_a.set_variable(data)
end
def do_something(variable)
# variable = empty
set_variable_in_a("hello world")
end
end
This is just an example of what I'm dealing with. If I'm trying to start a function in Class A, which is supposed to do something in ClassB and then change an instance variable in Class A, I'm not sure how to do this properly. This is what I've tried, however:
a = A.new
a.pass_to_b
Class B cannot see the instance variable #variable, and if it tries to set_variable_in_a, that doesn't work either. It's like the do_something function in Class A successfully calls the do_something function in Class B, but the instance variable information is not available. I thought by passing self to Class B, we'd be able to at least call the function
My MRI throws exeption about
def pass_to_b(self)
because you can't pass self to method as argument.
You need delete 'self' how argument
Run code below and you will see that #variable of instance of Class A has '123hello world' string
class A
def initialize
#variable = "123"
#module_b = B.new(self)
end
def pass_to_b
#module_b.do_something(#variable)
end
def set_variable(var)
# var = empty
#variable = var
end
end
# b.rb
class B
def initialize(module_a)
#module_a = module_a
end
def set_variable_in_a(data)
#module_a.set_variable(data)
end
def do_something(variable)
set_variable_in_a(variable + "hello world")
end
end
a = A.new
a.pass_to_b
display variable 'a' and you will see something like this
#<A:0x00007fdaba0f3c90 #variable="123hello world", #module_b=#<B:0x00007fdaba0f3c40 #module_a=#<A:0x00007fdaba0f3c90 ...>>>
I have simple class with class's and private's methods
class XmlConnection
def self.guitarmania
request = HTTParty.get(site_url)
handle_errors(request)
end
private
def handle_errors(request)
if request.code == 200
request
else
raise 'Connection error'
end
end
end
when i call XmlConnection.guitarmania i get
NoMethodError: undefined method 'handle_errors' for
XmlConnection:Class
How i can fix it?
When you're using a self. for a class method, all private methods also need to use self to be accessed from within it. The following will work:
class XmlConnection
def self.guitarmania
request = HTTParty.get(site_url)
handle_errors(request)
end
private
def self.handle_errors(request)
if request.code == 200
request
else
raise 'Connection error'
end
end
end
If all your methods will be class methods, you could wrap them all in a self to make it a bit more readable. This works exactly as above:
class XmlConnection
class << self
def guitarmania
request = HTTParty.get(site_url)
handle_errors(request)
end
private
def handle_errors(request)
if request.code == 200
request
else
raise 'Connection error'
end
end
end
end
You have to define handle_errors on the class as well:
def self.handle_errors(request)
If I have a class like
class MyClass
def initialize(&block)
#myBlock = block
end
def process
#...
#myBlock.call
#..
end
and I want to test a DifferentClass which needs to use MyClass and thus receive a block in the new.
How can I stub that block? What can I do in this situation?
describe DifferentClass do
it 'zomfg' do
allow(MyClass).to receive(:new) do |&block|
expect(block).to receive(:call)
my_object = double
allow(my_object).to receive(:process) { block.call }
my_object
end
foo = MyClass.new {}
# Here you should be passing the foo object to
# whatever method DifferentClass uses it in
foo.process
end
end
I am trying to access variable in ruby after initialize, but i didn't get that variable , anything wrong in that?
class Test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
def self.method1(params)
Test.new(params)
#can i get that two instance variable
end
end
You should probably set up attribute accessors, then use them this way:
class Test
attr_accessor :has_test
attr_accessor :limit_test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
def self.method1(params)
t = Test.new(params)
// can i get that two instance variable
// Yes:
// use t.has_test and t.limit_test
end
end
You are mixing an instance and a class method in your example.
If this is really what you want, then you have to define an accessor with attr_reader:
class Test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
attr_reader :has_test
attr_reader :limit_test
def self.method1(params)
obj = Test.new(params)
p obj.has_test
p obj.limit_test
end
end
Test.method1(has_test: 1, limit_test: 3)
It the instance/class-method is a mistake, then this example may help you:
class Test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
def method1()
p #has_test
p #limit_test
end
end
obj = Test.new(has_test: 1, limit_test: 3)
obj.method1
If you define also the accessors like in the first code, then you have again access from outside the class.
Just in case you don't want a reader, see also Access instance variable from outside the class