Ruby code order - ruby

Why can the following part # def games # #games = games # end come at the very end (bottom) of the code and still work? I thought Ruby reads the code from top to bottom. If I do not define games at the top, shouldn't it give an error?
class Library
# def games
# #games
# end
def initialize(games)
#games = games
end
def add_game(game)
games << game
end
# The following lines should come at the top of this code.
def games
#games
end
end
games = ['WoW','SC2','D3']
lib = Library.new(games)
lib.games #=> WoW,SC2,D3
lib.add_game('Titan')
lib.games #=> WoW,SC2,D3,Titan

When the method is defined, ruby is not running it. It's just available for the instance to use after you've invoked the class.
I generally put my methods in alphabetical order to make it easier to navigate my code as it grows. This is a personal preference.
Ruby allows you to structure and organize your classes/modules however is logical/beneficial to you.
To clarify, Ruby classes are executed when they're defined, but methods are not.
example.rb
class Example
puts "hello"
def my_method
puts "world"
end
end
Run it
$ ruby example.rb
hello
Because Ruby executes classes, that's how things like macros work in Ruby classes.
class Example2
attr_accessor :foo
end
attr_accessor is a method that gets called when the class is executed. In this case attr_acessor will setup get and set functions for the #foo instance variable.
If Ruby didn't execute your classes, this code would have to be called manually in some sort of initializer.
All you need to do is learn to differentiate between calling a method and defining a method. Defined methods will not be automatically executed.

The reason it is so is because of the way a class is built by Ruby: Every instance method definition inside a Ruby class gets defined first, during the top-down parsing. Then when you invoke each method it just matters whether its defined or not and not how its ordered.
Having said that order is important if you are redefining a method below. Then precedence will be given to lower definition.

Related

Listing parts of a class

I am trying to make a code with a cat, where you are able to buy certain toys and use them. However, whenever I try to list the toys in the "shop," it gives me an error every time. I'm not sure what I'm doing wrong, but it is definitely somewhere in how I'm executing the command.
class Toy
attr_reader :name
def initialize(name)
#name = name
end
def shop
puts "#{#Toy}"
end
end
toy.shop
I am not sure how to properly run this command, but I'm fairly certain the problem is in the "toy.shop" line.
A Working Rewrite and Simplification
There are a number of issues with your current code. Since there's always more than one way to do almost anything in Ruby, you can do this in other ways, too. However, here are some key issues:
You're not really leveraging #initialize.
You don't instantiate a new Toy object with Toy#new.
You don't assign Toy#new to a local toy variable.
Because toy is not defined, it doesn't have access to any of Toy's instance methods like #shop.
The non-existent toy variable is the receiver for the #shop method, so it will raise NameError if toy is undefined, or NoMethodError if toy is defined but not an instance of the Toy class or another class that can respond to the #shop method.
Based on your limited example, I'd rewrite and simplify the code as follows:
class Toy
attr_accessor :name
def shop
p "You bought a #{#name}."
end
end
toy = Toy.new
toy.name = "mouse"
toy.shop
#=> "You bought a mouse."
Why Kernel#p Instead of Kernel#puts
Note that Kernel#p will not only print your output to STDOUT, but will also return a value, which is extremely useful in a REPL or when debugging code. Kernel#puts, on the other hand, always returns nil so I generally prefer #p unless the output from #inspect is undesirable for some reason. Your mileage in that regard may vary.
See Also
The defined? keyword.
Variable assignment.
Ruby syntax.
Ruby exceptions.
First of all, this is a class, you should initialize and then call the method like this: Toy.new('some_toy').shop
And there is an error in your shop method, #Toy doesn't exists.
It should be:
def shop
puts "#{#name}"
end

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?

How do I bypass a call to super method in test

I have a basic structure like this
class Automobile
def some_method
# this code sets up structure for child classes... I want to test this
end
end
class Car < Automobile
def some_method
super
# code specific to Car... it's tested elsewhere so I don't want to test this now
end
end
class CompactCar < Car
def some_method
super
# code specific to CompactCar... I want to test this
end
end
What is the recommended way to test CompactCar and Automobile without running the code from Car? Automobile#some_method provides the structure that is required by child classes, so I want to always test that, but Car's functionality is tested elsewhere and I don't want to duplicate efforts.
One solution is to use class_eval to overwrite Car#some_method, but this isn't ideal because the overwritten method stays in place for the duration of my testing (unless I re-load the original library file with setup/teardown methods... kind of an ugly solution). Also, simply stubbing the call to Car#some_method does not seem to work.
Is there a cleaner/more generally accepted way of doing this?
Just put the specific code into a separate method. You don't appear to be using anything from super. Unless you are?
class CompactCar < Car
def some_method
super
compact_car_specific_code
end
# Test this method in isolation.
def compact_car_specific_code
# code specific to CompactCar... I want to test this
end
end

In how many ways can methods be added to a ruby object?

When it comes to run time introspection and dynamic code generation I don't think ruby has any rivals except possibly for some lisp dialects. The other day I was doing some code exercise to explore ruby's dynamic facilities and I started to wonder about ways of adding methods to existing objects. Here are 3 ways I could think of:
obj = Object.new
# add a method directly
def obj.new_method
...
end
# add a method indirectly with the singleton class
class << obj
def new_method
...
end
end
# add a method by opening up the class
obj.class.class_eval do
def new_method
...
end
end
This is just the tip of the iceberg because I still haven't explored various combinations of instance_eval, module_eval and define_method. Is there an online/offline resource where I can find out more about such dynamic tricks?
Ruby Metaprogramming seems to be a good resource. (And, linked from there, The Book of Ruby.)
If obj has a superclass, you can add methods to obj from the superclass using define_method (API) as you mentioned. If you ever look at the Rails source code, you'll notice that they do this quite a bit.
Also while this isn't exactly what you're asking for, you can easily give the impression of creating an almost infinite number of methods dynamically by using method_missing:
def method_missing(name, *args)
string_name = name.to_s
return super unless string_name =~ /^expected_\w+/
# otherwise do something as if you have a method called expected_name
end
Adding that to your class will allow it to respond to any method call which looks like
#instance.expected_something
I like the book Metaprogramming Ruby which is published by the publishers of the pickaxe book.

Scoping of Open classes in Ruby versus MOP in Groovy

What I'm trying to find out is whether there is some sort of equivalence to what I see in Groovy as ExpandoMetaClasses. I've been reading about Open Classes but I can't quite see what level of scoping Ruby allows of the class modifications.
Borrowing an example from the blog above, in Groovy, I could modify Java's String class and add a method to it like so:
String.metaClass.shout = {->
return delegate.toUpperCase()
}
println "Hello MetaProgramming".shout()
// output
// HELLO METAPROGRAMMING
And I think that Ruby would have you redefine the class and possibly alias it (please help clarify my misunderstandings at this point):
class String
def foo
"foo"
end
end
puts "".foo # prints "foo"
In Groovy, there are ways to scope the redefinition of core Java library methods to single instances or to a group of instances using Categories, which feel similar to what I would define as mixins in Ruby.
What are the ways to scope open classes to specific instances or to subsets of modules?
If I were to install a gem that had redefined some core class, would only that module be affected, or would any .rb file I include that gem with be affected with it?
Apologies in advance for making some possible assumptions on both Ruby and Groovy, I'm new to both but have been trying to find equivalence between the two.
Ruby's classes are never "closed". So when you say:
class String
def omg!
self.replace "OMG"
end
end
You are defining the omg! method on the String class. Unlike in Groovy, which requires the usage of a special metaclass concept, Ruby classes are always open, period.
If you wanted to modify a particular set of Strings, you could do this:
module Magic
def presto
puts "OMG A HAT!"
end
end
class Array
include Magic
end
x = "Hello".extend(Magic)
puts x #=> Hello
x.presto #=> OMG A HAT!
[].presto #=> OMG A HAT!
def x.really?
true
end
x.really? #=> true
Effectively, a module is a collection of methods that can be added to a class or specific instances.
So you can either open a class directly or add new methods to a class using a module. You can also open an instance directly or add new methods to an instance using a module. That's because a class is just an instance of Class ;) Pretty nifty!
In addition to what Yehuda said, instances in Ruby also have metaclasses (technically called "singleton classes"), accessed with class <<whatever. For example, to redo Yehuda's Magic example with a singleton class:
x = "Hello"
class <<x
include Magic
def magical?
true
end
end
x.presto #=> OMG A HAT!
x.magical? #=> true
"Something else".magical? #=> NoMethodError
There's no scoping on modifications to classes. As soon as a class is modified, the modified class is accessible to all later requires and following code.

Resources