calling a nonstatic function in ruby - ruby

I am confused how to call a function defined in a class inside another function defined in that same class. Here is what I have done:
class Test
def TestFunc(obj)
puts obj
end
def Test.StatFun(obj)
puts obj
TestFunc(obj)
end
end
Test.StatFun([[5,2], [4,3]])
When I run this in cmd.exe, I get the following error:
ruby LawtonTest.rb 5 2 4 3 LawtonTest.rb:10:in StatFun': undefined
methodTestFunc' for Test:Class (NoMet hodError)
from LawtonTest.rb:14:in `'
I can't figure it out. Any help would be greatly appreciated.

You have to call it on the object. I think you need a good reference of oop in Ruby, take a look at http://zetcode.com/lang/rubytutorial/oop/. But anyway, the thing is, methods (which is what you declare with def) have to be called on an object, not like a global function. So if you want to use TestFunc, try this:
def Test.StatFun(obj)
puts obj
Test.new.TestFunc(obj)
end
The Test.new part is used to create an object, on which you can use the TestFunc method.

I can't see a definition for TestFunc anywhere. Have you defined it?
Also, the general Ruby convention is to use lowercase names for methods (eg test_func)
edit should really read the question before answering...
The problem here is that TestFunc is only defined for instances of the class Test, whereas when you call Test.StatFun, the object executing the code is the actual class Test. This means that it doesn't know what TestFunc is. One way to get around this is to create a new instance (because that is one thing classes do know how to do):
def Test.StatFun(obj)
puts obj
new.TestFunc(obj)
end

Related

What is the scope of variables and methods included via ruby modules?

Suppose I have the following:
module MyModule
module SubModule
Var = 'this is a constant'
var = 'this is not a constant'
def hello_world
return 'hello world!'
end
end
end
In the same file, I can only seem to access MyModule::SubModule::Var, but not any the constant or the method. If I now create a class and include these modules in different ways, I get additional strange behavior:
class MyClass
include MyModule
def initialize()
puts SubModule::Var
end
def self.cool_method
puts SubModule::Var
end
end
In this case, I can again only access Var, but not the other two. SubModule::var and SubModule::hello_world do not work. Finally:
class MyClass
include MyModule::SubModule
def initialize()
puts Var
puts hello_world
end
def self.cool_method
puts Var
puts hello_world
end
end
In this case, I can now access both Var and the method hello_world but not var, and, the weirdest thing, is that hello_world appears to have become an instance method! That is, the call to hello_world in initialize works, but the one in self.cool_method doesn't. This is pretty strange, considering that Var seems to have been included as a class variable, since outside the class, I must access them like so:
MyClass::Var
x = MyClass.new
x.hello_world
So, I have a few major questions.
What is going on behind the scenes with regards to Var vs var? It appears that capitalizing a variable name is more than just a convention after all.
When includeing a module, what kinds of things are passed to the including class, and at what scope?
Is there a way to do the opposite? That is, use include to include an instance variable or a class method?
What is going on behind the scenes with regards to Var vs var? It appears that capitalizing a variable name is more than just a convention after all.
Yes, of course, it's not a convention. Variables which start with an uppercase letter are constants, variables which start with a lowercase letter are local variables. The two are completely different.
When includeing a module, what kinds of things are passed to the including class, and at what scope?
Nothing gets passed anywhere. includeing a mixin simply makes that mixin the superclass of the class you are includeing it into. That's all. Everything else then works exactly as with classes.
Is there a way to do the opposite? That is, use include to include an instance variable or a class method?
I don't understand this question. Instance variables have nothing to do with mixins or classes. They belong to instances, that's why they are called "instance" variables.
There are no such things as "class methods" in Ruby. Ruby only knows one kind of methods: instance methods. When Rubyists talk to each other, they will sometimes use the term "class method" to mean "singleton method of an object that happens to be a class", but they do that knowing full well that class methods don't actually exist, it's just a shorthand in conversation. (And, of course, singleton methods don't exist either, they are just a convenient way of saying "instance method of the singleton class".)

How to check calls to a method called from constructor in rspec?

If I have a class where the constructor calls another function, how do I check that it was called and the right number of times?
class MyClass
def initialize(count)
count.times{self.do_something}
end
def do_something
# whatever
end
end
I want to say something like
n = 4
MyClass.new(n).should_receive(:do_something).exactly(n).times
n = 2
MyClass.new(n).should_receive(:do_something).exactly(n).times
but that fails because the call to do_something happens before should_receive gets attached to it (at least I think that's why).
expected: 4 times with any arguments
received: 0 times with any arguments
Or is it just wrong to call stuff like this from the constructor and I should refactor?
Also, this question is very similar to this one:
rspec: How to stub an instance method called by constructor?
but I'm hoping in the last 5 years the answer has gotten better than setting up manual implementations of a stubbed new call.
The new syntax for doing this is as follows:
allow_any_instance_of(ExampleClass).to receive(:example_method).and_return("Example")
expect_any_instance_of(ExampleClass).to receive(:example_method).and_return("Example")
See the docs
Expectations are meant to be placed before the code that will be expected to meet them.
MyClass.any_instance.should_receive(:do_something).exactly(1).time
MyClass.new
That should work.
Another answer is to use rspec spies. The issue here is that you have to create a mock for the methods you want to make requirements on after the fact. Turns out it's not hard, but you still have to enumerate them. The and_call_original is the magic that makes the implementation not change.
MyClass.any_instance.stub(:method_name).and_call_original
Then you can just say:
MyClass.new(4).should have_received(:method_name).exactly(4).times
I'd still love to find a way that doesn't require you to enumerate the methods, though.
Here's the best I came up with, but I don't like it:
Create a new method in Class that runs a block on the allocated, but not yet initialize'd object. I put this in the before block in my spec file, but there's probably a better place for it:
class Class
def rspec_new(*params, &block)
o = allocate
yield(o) if block
o.__send__(:initialize, *params)
return o
end
end
Then call it like this:
MyClass.rspec_new(n){|obj| obj.should_receive(:do_something).exactly(n).times}
it seems to work, but you can't pass a block to your constructor. At least not the way you normally do. That's why I didn't override the regular new method.

How do I define an instance method in Ruby? [duplicate]

This question already has answers here:
What does a Java static method look like in Ruby?
(2 answers)
Closed 8 years ago.
I'm trying to define a method called function. It works when I do this:
a = A.new
def a.function
puts 100
end
But I want the method to work for any instance variable, not just a. For example, when I call function on an instance of A other than a, nothing happens. So I used A::f to define the function rather than a.function.
class A
attr_accessor :function
attr_accessor :var
end
def A::function
self.var = 0x123
end
a = A.new
a.function
puts a.var
This compiles fine but when I try to call the function I get an error. Why is it not working and how can I do what I'm attempting?
You're really tangled up here. I suggest you check out _why's poignant guide to ruby and get a handle on what is going on here.
As an attempt to steer you right, though…
a isn't an instance variable. It's a local variable that you're using to reference an instance of A.
def a.foo defines a method on the eigenclass of a.
attr_accessor :function already defined A#function (that is, an instance method on A called function) that essentially looks like this: def function; #function; end
def A::function defines a class method on A that you could access via A.function (not an instance of A as in a.function.
MRI doesn't really compile ruby like you might anticipate. It runs it, dynamically interpreting statements in realtime.
You probably want to stick with defining standard instance methods in the traditional manner, and avoid using “function” as a placeholder name since it is a reserved word and has special meaning in other languages. I'll use “foo” here:
class A
def foo
'Awww foo.'
end
end
That's it, you can now create an instance of A (a = A.new) and call foo on it (a.foo) and you'll get back 'Aww foo.'.
class A
def function
puts 100
end
end
a = A.new
a.function #=> "100"
That's a classic instance method. Is that what you're looking for or am I missing something?
If you're trying to define methods dynamically, you could use Class#define_method. Otherwise, if you are just wanting to define the method for the class, defining it in the scope of class A will suffice.
Anyway, could you be more specific on what are you trying to accomplish and what kind of error you're having, please?

Which method to define on a Ruby class to provide dup / clone for its instances?

I have a Pointer class with a single attribute :contents, that points to an object of class MyObject.
class MyObject
def hello; "hello" end
end
class Pointer
attr_reader :contents
def initialize( cont ); #contents = cont end
# perhaps define some more state
end
I want my Pointer to be able to make copies of itself. I know that #dup method is defined by default, while #clone method is expected to be overriden to be able to make deep copies. But here, the copies don't have to be too deep. So, the first dilemma that I have is, should I override #dup method, because I don't really want to copy the additional state of my Pointer, just make a new one pointing to the same MyObject instance? Or should I refrain from overridine #dup, because I am not "supposed to" and override #clone with a method making shallow copies?
I would welcome comments on the above, but let's say that I will choose to override #dup. I could do just this:
class Pointer
def dup; self.class.new( contents ) end
end
But online, I read something like "the dup method will call the initialize copy method". Also, this guy writes about #initialize_clone, #initialize_dup and #initialize_copy in Ruby. That leaves me wondering, is the best practice perhaps like this?
class Pointer
def initialize_copy
# do I don't know what
end
end
Or like this?
class Pointer
def initialize_dup
# do I don't know what
end
end
Or should I just forget about online rants written to confuse beginners and go for overriding #dup without concerns?
Also, I do understand that I can just call #dup without defining any custom #dup, but what if I want to define #dup with different behavior?
Also, the same question apply to #clone - should I try to define #initialize_clone or just #clone?
From my experience, overloading #initialize_copy works just fine (never heard about initialize_dup and initialize_clone).
The original initialize_copy (which initializes every instance variable with the values from the original object) is available through super, so I usually do:
class MyClass
def initialize_copy(orig)
super
# Do custom initialization for self
end
end

Saving Dynamic Ruby Classes

I have a curiosity question. If I have a ruby class and then I dynamically add class methods, class variables, etc. to it during execution is there anyway for me to save the altered class definition so that next time I start my application I can use it again?
There is no built-in way to do this. Marshal can't save methods. If these methods and variables are generated in some systematic way, you could save the data necessary for the class to recreate them. For example, if you have a make_special_method(purpose, value) method that defines these methods, create an array of the arguments you need to pass to these methods and read it in when you want to reconstitute the state of the class.
Depending on what exactly you mean, there are a couple of ways to go about this.
The simplest case is the one where you've added variables or methods to an already-existing class, as in this example:
class String
def rot13
return self.tr('a-z', 'n-za-m')
end
end
Here we've added the rot13 method to class String. As soon as this code is run, every String everywhere in your program will be able to #rot13. Thus, if you have some code that needs rot13-capable strings, you just ensure that the code above is run before the code in question, e.g. by putting the rot13 code in a file someplace and require()ing it. Very easy!
But maybe you've added a class variable to a class, and you want to preserve not just its existence but its value, as in:
class String
##number_of_tr_calls_made = 0
# Fix up #tr so that it increments ##number_of_tr_calls_made
end
Now if you want to save the value of ##number_of_tr_calls_made, you can do so in the same way you would with any other serializable Ruby value: via the Marshal library. Also easy!
But something in the way you phrased your question makes me suspect that you're doing something like this:
greeting = "Hello"
class <<greeting
def rot13
return self.tr('a-z', 'n-za-m')
end
end
encrypted_greeting = greeting.rot13
This is very different from what we did in the first example. That piece of code gave every String in your program the power to rot13 itself. This code grants that power to only the object referred to by the name 'greeting'. Internally, Ruby does this by creating an anonymous Singleton subclass of String, adding the rot13 method to it, and changing greeting's class to that anonymous subclass.
The problem here is that Singletons can't be Marshal'd (to see why, try to figure out how to maintain the Singleton invariant when any call to Marshal.load can generate copies of extant Singleton objects). Now greeting has a Singleton in its inheritance hierarchy, so if you want to save and load it you are hosed. Make a subclass instead:
class HighlySecurableString < String
def rot13
return self.tr('a-z', 'n-za-m')
end
end
greeting = HighlySecurableString.new("hello")
Simply marshalling the object (as others have said) wont work. Lets look at an example. Consider this class:
class Extras
attr_accessor :contents
def test
puts "This instance of Extras is OK. Contents is: " + #contents.to_s
end
def add_method( name )
self.class.send :define_method, name.to_sym do
puts "Called " + name.to_s
end
end
end
Now lets write a program which creates an instance, adds a method to it and saves it to disk:
require 'extras'
fresh = Extras.new
fresh.contents = 314
fresh.test # outputs "This instance of Extras is OK. Contents is: 314"
fresh.add_method( :foo )
fresh.foo # outputs "Called foo"
serial = Marshal.dump( fresh )
file = File.new "dumpedExample", 'w'
file.write serial
So we can call the normal method 'test' and the dynamic method 'foo'. Lets look at what happens if we write a program which loads the instance of Example which was saved to disk:
require 'extras'
file = File.new 'dumpedExample', 'r'
serial = file.read
reheated = Marshal.load( serial )
reheated.test # outputs "This instance of Extras is OK. Contents is 314"
reheated.foo # throws a NoMethodError exception
So we can see that while the instance (including the values of member variables) was saved the dynamic method was not.
From a design point of view it's probably better to put all your added code into a module and load that into the class again when you next run the program. We'd need a good example of how you might want to use it though to really know this.
If you need extra information to recreate the methods then have the module save these as member variables. Implement included in the module and have it look for these member variables when it is included into the class.
http://ruby-doc.org/core/classes/Marshal.html
You're editing the class on the fly, and you want to save that? You could try using the Marshal module, it'll allow you to save objects to a file, and read them back in memory dynamically.

Resources