Ruby Variables & Objects, as a Python Dev
Tags: ruby, codenewbie, python
Published: 2020-12-26 22:54:43

*This is a continuation of Picking up Ruby Fast, as a Python Dev. Again, expect examples with minimal math*

---

Everything is an object and there are so many different kinds of variables! Every day I look at Ruby I learn new things. I'm really enjoying it.


## Objectification

### Data Types == Instances of Classes

Each data type was created by a class. I guess this is probably the same in Python and other languages, but it's definitely not something I've thought about. So, somewhere there is a class that says what an `int` is. This feels very existential. It reminds me of this question I got from a student last month:

> How did we program an editor to write programs if we didn't have a program to program programs?


Anyway, we can use the `.class` method to find out what each item is. 

```ruby
irb(main):189:0> 1.class
=> Integer
irb(main):190:0> 34.6.class
=> Float
irb(main):191:0> "Mouse".class
=> String
```

The same works for variables.
```ruby
irb(main):192:0> cat = 78
=> 78
irb(main):193:0> cat.class
=> Integer

irb(main):194:0> dog = "Wiley"
=> "Wiley"
irb(main):195:0> dog.class
=> String
```

---
## Variable Types

Turns out, Ruby has 4 types of variables. Who knew? Okay, I'm sure lots of people did, but I didn't.

### local
These are variables that are likely to be used quickly. If created outside of a class, method, or block they cannot be pulled into a method or anywhere else for that matter. Most of the examples I've had were using local variables. 

The iterator variables used in blocks are also local variables as they can't be used after the `end` of the block.

### global

Global variables start with `$`. These variables can be created outside of a method, in a class, or anywhere and then it can be used anywhere.

Here's global variable that we are going to send to the method `greet`:
```ruby
$language = "Ruby"  # hey look, a global var

def greet
  puts "we're learning " + $language
end

# running & output
irb(main):218:0> greet
we're learning Ruby
```

### class
Class variables start with `@@`. These variables can be used inside the class and by all instances of the class. These are for classes to save info about themselves. It seems these aren't used very often. Class variables are limited in usefulness because all instances of the class share that one variable.

```ruby
class Player
    @@moves = 9

    def initialize(name, letter='x')
        @name = name
        @letter = letter
    end

    def mark_spot letter
        if @@moves > 0
            @@moves -= 1
            puts "drew an #{letter}! Moves left: #{@@moves}"
        else
            puts 'no more spells'
        end
    end
end

# running & output
irb(main):231:0> wiley = Player.new("Wiley", "x")
=> #<Player:0x00007fcee80dd838 @name="Wiley", @letter="x">
irb(main):232:0> cheeto = Player.new("Cheeto", "o")
=> #<Player:0x00007fcee8101cd8 @name="Cheeto", @letter="o">
irb(main):235:0> wiley.mark_spot "x"
drew an x! Moves left: 8
=> nil
irb(main):236:0> cheeto.mark_spot "o"
drew an o! Moves left: 7
=> nil
```
The problem here is that both players are sharing the `@@moves`. It may work in this example, but it often won't. 

### instance
Instance variables start with `@`. Instance variables are seen inside the class and by all instances of the class. However, each instance of a class gets its very own copy of the variable. Each instance doesn't have to share with other instances.

In the class variable, I gave a total number of moves, but in reality, most games allow each person to take the same amount of move. So, player1 would have 5 moves and player2 would have 5 moves. Then, we'd go until the game ends. We wouldn't typically share a pool of movies. 

```ruby
class Player

    def initialize(name, letter='x')
        @name = name
        @letter = letter
        @moves = 5
    end

    def mark_spot letter
        if @moves > 0
            @moves -= 1
            puts "drew an #{letter}! Moves left: #{@moves}"
        else
            puts 'no more spells'
        end
    end
end

# running & output
irb(main):239:0> remmy = Player.new "Remmy", 'x'
=> #<Player:0x00007fcee40f9780 @name="Remmy", @letter="x", @moves=5>
irb(main):240:0> puppy = Player.new "Puppy", 'o'
=> #<Player:0x00007fcee4100058 @name="Puppy", @letter="o", @moves=5>
irb(main):241:0> puppy.mark_spot 'o'
drew an o! Moves left: 4
=> nil
irb(main):242:0> remmy.mark_spot 'x'
drew an x! Moves left: 4
=> nil
irb(main):243:0> puppy.mark_spot 'o'
drew an o! Moves left: 3
=> nil
```

This works much better because now each player has their own set of moves.

---
If you missed the first post in this series, I've heard it's a good read and there's cats.
{% post https://dev.to/vickilanger/python-to-ruby-1hc2 %}