Skip to content

Instantly share code, notes, and snippets.

@jfeldstein
Created October 20, 2011 00:31
Show Gist options
  • Save jfeldstein/1300087 to your computer and use it in GitHub Desktop.
Save jfeldstein/1300087 to your computer and use it in GitHub Desktop.
Ruby is Just Like PHP, Except for a Few Things
###Ruby is Just Like PHP, Except for a Few Things###
After a few attempts and failures to learn Ruby, it finally clicked when I accepted that Ruby was just different than PHP. After that, learning was easy. 
If you're trying to learn Ruby as well, I'll do my best to compare Ruby to PHP (and sometimes javascript) which I found confusing, unexpected or tricky. When I can, I’ll try to explain why these "peculiarities" exist. 
- Syntax differences in Ruby
- Classes, Objects and Scope
## Ruby Syntax##
#EVERYTHING is an Object#
Like Javascript, everything in Ruby is an object, complete with methods and properties.
*Javascript*
“Hello”.length // returns 5
*Ruby*
"Hello”.length // also 5
Even Ruby’s concept of `null` (normally meaning that there isn’t any data here) is actually an ordinary object called `nil`.
Somewhat Strict Typing
In PHP, the string value ‘0’ can be a string, an integer or the boolean false. Ruby does not allow this type of dynamic typing.
PHP
5 + ‘0‘ // integer 5
“Total: “ . ‘0’ // String “Total: 0”
if(‘0’) // Boolean false
In Ruby, a value is whatever it is, and you need to convert it yourself if you want to use it as something else.
Ruby
5 + ‘0’.to_i // converts string ‘0’ to integer 0, then ads
Ruby also has no concept of ‘loose evaluation’. All condition are type-strict. (“Triple equals” in PHP)
PHP
‘5’ == 5 // true
‘5’ === 5 // false
Ruby
‘5’ == 5 #false
‘5’ == ‘5’ # true
#‘5’ === 5 Oops... There is no triple-equals in Ruby
Dynamic Strings
Like PHP, Ruby lets you put variables inside strings as you define them.
Ruby
name = “Bob”
str = “Hello, #{name}.” # Hello, Bob
str = ‘Hello, #{name}.’ # Hello, #{name}
PHP
$name = “Bob”;
$str = “Hello, $bob.”; // Hello, Bob
$str = ‘Hello, $bob.’; // Hello, $name
Like PHP, this only works in double quoted strings.
But, unlike PHP, Ruby does more than simply substitute the value of a variable into the string. The #{...} is a full execution block. You can put function calls in there, and the returned content will be substituted.
Ruby
str = “The file contains: ‘#{read_from_file(‘/path/to/file.txt’)}’”
Suffix Conditionals
PHP
if( condition ) {
return false
}
Ruby
return false if condition
Ruby also has an ‘unless’ conditional.
return true unless condition
Can be handy. Can also be very confusing. Adhere to some basic sanity rules when using Ruby’s flexible and friendly conditional system.
Blocks
Ruby has an execution block structure that, to me, feels like Javascript’s vanilla functions.
jQuery
$(‘.special-buttons’).each(function() {
... passing in some instructions ...
}
Ruby
99.downto(1) do |num|
puts “#{num} bottles of beer on the wall.”
end
The `do` in this example is what tells the Ruby interpreter that we’re about to give it an executable block of code.
The `yield` keyword has some interesting properties when used in callback, or from inside methods which were given callbacks. I don’t quite understand it yet.
Implied Return
You can break execution and return a value at any time, using `return` as you normally would, but Ruby functions also assume that they should return the value of their last statement.
Ruby
def form_bottle_statement(num, contents)
return false unless contents == ‘beer’
“#{num} bottles of #{contents}”
end
puts form_bottle_statement(3, ‘beer’) #prints “3 bottles of beer”
Symbols instead of Constants
Ruby has a syntax called “Symbols” which are like constants in PHP. A symbol is a colon followed by a lower-case string. Symbols don’t have corresponding string values, they just _are_. They’re also not defined in advance, but simply created as you type them.
I’ve mainly seen symbols used in string-indexed arrays or to indicate the keys of a hash.
PHP
$beers = array(
‘lager’ => ‘Sam Adams’,
‘ipa’ => ‘Blue Moon’
);
$beers[‘ipa’]; // ‘Blue Moon’
Ruby
beers = [ #ruby defines arrays with [...], instead of array(...)
:lager => ‘Sam Adams’,
:ipa => ‘Blue Moon’
]
beers[:ipa] # ‘Blue Moon’
Lots of Shortcuts Relating to Functions and Their Arguments
Technically, Ruby has almost identical syntax to PHP when it comes to defining and calling functions.
PHP
function test( $val = null ) {
var_dump($val)
}
test(‘value’);
Ruby
def test( val = nil ) {
puts val.inspect
}
test(‘value’)
But Ruby allows for some shortcuts that make your code simpler to write and cleaner to read.
1. Curly brackets and parenthesis are optional.
Ruby
def test val, otherval
“You specified #{val} and #{otherval}”
end
test ‘this’, ‘the other’ # “You specified this and the other”
Don’t forget your `end` keyword when writing this way.
2. Easily Pass Hashes as Arguments
It’s very common syntax for functions to accept an array or hash of parameters, rather than each requiring each parameter be a separate argument that must be passed in order.
It’s also very common that a function accepts only a hash or parameters as its one and only argument.
PHP
function performAction( $action, $params ) {
...
}
performAction(‘speak’, array(
‘speed’ => ‘fast’,
‘tone’ => ‘angry’
));
Ruby
def performAction action, params = {}
...
end
performAction ‘speak’, {:use_gestures => true, :speed => ‘fast’, :tone => happy}
Ruby, expecting this pattern, lets you omit the curly braces when calling any function whose last argument is a hash. It assumes that the last group of symbols you’re writing in whatever order, are actually key/value pairs meant for the hash argument.
This is especially nice with functions with only a single, hash-type argument.
Ruby
def speak params
performAction ‘speak’, params
end
speak :speed => ‘slow’, :enunciate => true
performAction ‘speak’, :enunciate => true, :speed => ‘slow’ # same thing
The first time I tried to learn Rails, not knowing how to interpret this ambiguous syntax was a major source of frustration for me. I wasn’t aware of many of the shortcuts Rails lets developers use while writing code, and wound up tangled in confusion.
Classes, Objects and Scope
Ruby has an incredibly powerful object/class system.
Classes, Subclasses and Modules are ways of organizing code into nice packages, and controlling the scope that’s available to each block of code.
Ruby Doesn’t Care About Type
When you pass an object into a function, there doesn’t seem to be any way to enforce that the object is of a certain type. I’m not even sure you can `get_class()` or `instanceOf` the way you can in PHP.
Instead, every object in Ruby (so... everything.) has a `respond_to?(method_name)` method which returns true if the object has a method by that name, and you use this to make sure that the object you have is something that knows how to behave in the way you’re asking it to.
Ruby
class Duck
def swim
...
end
end
class Fish
def swim
...
end
end
Now, you’re out in the ocean with a variable called `animal`.
Do you care what type of creature animal is, or just that it can swim?
Ruby
def drown
puts “dag, yo.”
die
end
drown unless animal.respond_to? ‘swim’
Classes Can be Modified at Run Time
Ruby has a novel behavior that’s absent in PHP, but is very similar to Javascript’s `.prototype.` structure.
Javascript
var str = “Hello!”
String.prototype.shout_to_the_heavens = function() {...}
str.shout_to_the_heavens() // They heard your prayers.
Ruby
class String
def shout_to_the_heavens
puts “Your prayers are heard.”
end
end
Even though String is defined somewhere deep within Ruby, we can re-open the class declaration and add, or even overwrite, anything we want.
This can be done with any class.
All Data Members are ‘private’ Scoped
All instance variables are private, accessible only to the methods defined on the class itself. This means you need getters and setters for everything you want accessible outside the object.
Ruby
class Person
def age
@age
end
def age= age # with omitted parenthesis, we’re saying: def age= (age) { ... }
@age = age
end
end
Operations are Just Ordinary Methods
You can define operational methods, like adding or subtracting, for your own classes.
Ruby
class Person
def += companion
Person.new(“#{@name[0..2]}#{companion.name[-3..]}”)
end
end
# Adding two Persons now returns a new person with a composite name
jake_and_sally = jake + sally
jake_and_sally.name # Pretty sure this returns “Jally”
Classes can Implement and/or Include Any Other Class
Ruby
class Trex
implements Carnivore
...
end
Trex now needs its own definitions for all methods in Carnivore, such as `eat` and `rawr`
Ruby
class Trex
include Carnivore
...
end
Trex now has all the Carnivore methods defined, as if you’d re-typed the contents of Carnivore as part of Trex’s definition.
Modules Are Bundles of Classes
A module is just a scoping mechanism, like a class which can’t be instantiated on it’s own, but which bundles other subclasses together neatly.
Ruby
module XML
class Document
...
end
end
module PDF
class Document
...
end
end
paper = XML::Document.new
Modules can also be included from any scope, which brings their contents into the current scope.
Ruby
include XML
doc = Document.new # Document class is defined as XML::Document
Conclusion
I tried a few times to “learn Rails” with no success. In hindsight, I think this was because I was trying to learn Ruby and Ruby on Rails at the same time, without understanding where one stopped and the other began.
After learning Symfony, the “Rails for PHP,” I found Ruby and RoR much easier to pick up. I think learning MVC in a familiar environment (PHP) and then translating that knowledge onto a new language made things click.
My hope is that this guide will help you use your PHP and Javascript knowledge to make sense of Ruby, which is why this article is all about teaching Ruby as a language, and has nothing to do with Rails or MVC.
That being said, I’m looking for a good “Intro to MVC and Rails” guide that I can link to from here, that would pick up where this guide leaves off.
Cheers.
Questions or Corrections? @jfeldstein on twitter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment