Ruby and Javascript both have a method called slice
. They looks similar but they work differently. Let’s look at some examples.
Guess what the following Ruby code returns.
And it returns…
[1,2]
It’s a new array containing the first 2
values of the calling array starting from index 0
.
What about this Javascript?
[1,2]
Javascript returns an array with the values starting from index 0
up to, but not including index 2
.
I know. It looks the same. But don’t fall for it. Here’s another example that actually shows this difference.
Ruby
[3, 4, 5]
Javascript
[3]
In Ruby the method is slice(start, length)
where start
is the starting index, length
is the number of values to take up to.
In Javascript the method is slice(begin, end)
where begin
is, again, the starting index, but end
is the index to take up to, non-inclusive.
slice
also has a single argument format
Ruby
3
Javascript
[3, 4, 5]
Here, Ruby’s slice(index)
simply returns the value at index
.
And Javascript’s slice(begin)
returns a new array starting from the value at the index begin
all the way through to end of the array.
Ruby and Javascript both also have String.slice
that work the same as their respective array-based counterparts, but on characters in the string.
Ruby
"hello".slice(2)
"hello".slice(2,3)
Javascript
"hello".slice(2);
"hello".slice(2,3);
Javascript also has a splice
method. It’s just like slice
but it removes the selected values from the original array. It’s like Ruby’s slice!
method.
Ruby
arr = [1,2,3,4,5]
arr.slice!(1,1) # returns [2]
arr # contains [1,3,4,5]
Javascript
arr = [1,2,3,4,5];
arr.splice(1,1); // returns [2]
arr; // contains [1,3,4,5]
Okay last example.
Ruby
str = "hello"
str.slice!(1,1) # returns "e"
str # contains "hllo"
Javascript
str = "hello";
str.splice(1,1);
TypeError: str.splice is not a function
Whoops! There’s no built-in String.splice method in Javascript. Arrays only!
If you have to switch between Ruby and Javascript a lot, be careful out there and always keep your methods straight.
And there are more differences than what I mentioned here. Ruby’s slice
methods can take a range value as a parameter. Javascripts splice
can be used to insert values. And more! Check out the docs for details.
References
Play Now
This is a game about what it’s like to be a dragon doing your taxes.
When I decided to participate in Ludum Dare I didn’t expect to be spending most of my time dealing with stupid CSS issues. But I think it worked out in the end.
This is my first Ludum Dare.
Pen & paper and/or calculator recommended.
Play Now
(Originally posted here)
I finally put this kit together tonight. Another amazing bleep-maker from Bleep Labs.
Class methods are methods that apply to a particular class in Ruby. Rather than acting on a particular instance of a class, they act on the class blueprint itself, i.e. the instance of the Class object.
Class methods can’t access instance variables. But instance methods can access class variables.
The most common way to create a class method in Ruby is to use the self
keyword. This refers back to the class object itself.
class IceCream
@@total_scoops = 0
def self.increment_scoops
@@total_scoops +=1
end
def self.scoops_served
@@total_scoops
end
end
In this example, we use the class variable @@scoops
to keep track of total ice cream scoops served. If you aren’t careful, class variables can cause you problems in Ruby. Consider the following example.
class FrozenYogurt < IceCream
@@total_scoops = 0
end
What would you expect the output to be when you ran the following code?
puts "Serving ice cream."
IceCream.increment_scoops
puts "#{IceCream.scoops_served} scoops of ice cream served."
puts "Serving froyo."
FrozenYogurt.increment_scoops
puts "#{FrozenYogurt.scoops_served} scoops of froyo served."
The answer is…
Serving ice cream.
1 scoops of ice cream served.
Serving froyo.
2 scoops of froyo served.
In Ruby, classes share class variables with their ancestors. Both of these classes are operating on the same @@scoops variable
. This is often not the desired behavior. When you don’t want this, you should use what are sometimes called “class instance variables”. These are really just instance variables, but they’re applied to the instance of the Class
class, the blueprint object. You create one by defining an instance variable right in the class body. You can only refer to these variable within class methods. Let’s try it.
class IceCream
@total_scoops = 0
def self.increment_scoops
@total_scoops +=1
end
def self.scoops_served
@total_scoops
end
end
class FrozenYogurt < IceCream
@total_scoops = 0
end
puts "Serving ice cream."
IceCream.increment_scoops
puts "#{IceCream.scoops_served} scoops of ice cream served."
puts "Serving froyo."
FrozenYogurt.increment_scoops
puts "#{FrozenYogurt.scoops_served} scoops of froyo served."
This code outputs:
Serving ice cream.
1 scoops of ice cream served.
Serving froyo.
1 scoops of froyo served.
Now both of our class instances, IceCream
and Froyo
, each have their own @scoops
variable. Remember, classes in Ruby are objects too, specifically instances of the Class
class. It’s a little confusing but all we are doing here is adding instance variables to our class instance. This avoids the issue with class variables being inherited by child classes.
In Ruby, pretty much everything is an object. The number 5
is an object. The string “boo!” is an object. When we want to be able to create a lot of similar objects, we use classes. Classes are objects too.
A class is like a blueprint for something we call instances. Each object you create using a class is called an instance. Ruby has a lot of built-in classes. Let’s take a quick look at the String
class. To create a new instance of any class, we call the new
method. So to create instances of the String
class we could type:
greeting = String.new("Hi!")
#=>"Hi!"
formal_greeting = String.new("Hello!")
#=>"Hello!"
These String
instances are each their own objects but they also share a lot of methods that they get from the String
class.
greeting.size
#=>3
formal_greeting.size
#=>6
The built-in classes are great and all, but let’s try making our own. Let’s make a class for spooky monsters.
class Monster
def initialize(spookiness, spooky_grabber)
@spookiness = spookiness
@spooky_grabber = spooky_grabber
end
end
A lot of stuff is actually going on here so let’s break it down a bit.
The class
keyword declares the beginning of a class. Our class can be referenced later by its class name, Monster
.
``ruby
def initialize(spookiness, spooky_grabber)
Here we declare the `initialize` method. `initialize` is a special method. Whenever a new instance is of a class created, that class's `initialize` method is automatically called on that instance. It also receives all the arguments that were passed to the new method. This is the place to set up your object.
```ruby
@spookiness = spookiness
@spooky_grabber = spooky_grabber
Just assigning the parameters to some variables. But what are those @ signs? Those @ signs indicate that these are instance variables. Each instance keeps track of it’s own instance variables. Each monster will have it’s own individual spookiness and spooky grabber.
Now we can create some instances!
ghost = Monster.new(1, "a chilling presence")
skeleton = Monster.new(2, "a bony claw")
fishman = Monster.new(2, "a damp webbed hand")
cthulu = Monster.new(3, "several eldritch tentacles")
The good news is we have our instances. The bad news is, they don’t really do much yet. Let’s add some methods to our class so we can at least inspect the values we set up.
class Monster
def initialize(spookiness, spooky_grabber)
@spookiness = spookiness
@spooky_grabber = spooky_grabber
end
def spookiness
@spookiness
end
def spooky_grabber
@spooky_grabber
end
end
We can use these methods to see the values of our instance variables.
That seems like a lot of code to write just to read each variable. I know what you’re thinking. This is Ruby. There’s gotta be a shorter way. That’s where the attr_reader
keyword come into play.
class Monster
attr_reader "spookiness"
end
is the same as
class Monster
def spookiness
@spookiness
end
end
Great let’s add it to our code.
class Monster
attr_reader "spookiness", "spooky_grabber"
And let’s add some methods to print spooky text to the console.
class Monster
attr_reader "spookiness", "spooky_grabber"
def initialize(spookiness, spooky_grabber)
@spookiness = spookiness
@spooky_grabber = spooky_grabber
end
def spook
print "You suddenly feel #{@spooky_grabber} brush your shoulder"
puts "." * spookiness
end
def scare
print "You suddenly feel #{@spooky_grabber} wrap around your neck"
puts "!" * spookiness
end
end
The spook
and scare
methods are called ‘instance methods’. That’s because each instance can use them. And when you call an instance method it has access to its caller’s instance variables.
ghost.spook
# You suddenly feel a chilling presence brush your shoulder.
#=>nil
skeleton.scare
# You suddenly feel a bony claw wrap around your neck!!
#=>nil
Sometimes you have a method that’s related to a class, but doesn’t really apply to individual instances. You can create ‘class methods’ by using the self
keyword. Here’s an example. Pay attention to how self
is used.
class Monster
def self.merge (monster_a, monster_b)
spookiness = monster_a.spookiness + monster_b.spookiness
grabber = monster_a.spooky_grabber + " and " + monster_b.spooky_grabber
Monster.new(spookiness, grabber)
end
end
You call class methods like this:
spook_team = Monster.merge(fishman, cthulu)
This method combines the properties of two objects then creates and returns a new instance. The created instance also has all the same methods as the other instances.
spook_team.scare
# You suddenly feel a damp webbed hand and several eldritch tentacles wrap around your neck!!!!!
#=>nil
Great, nice and spooky!
And here’s the full code for our class.
class Monster
attr_reader "spookiness", "spooky_grabber"
def initialize(spookiness, spooky_grabber)
@spookiness = spookiness
@spooky_grabber = spooky_grabber
end
def spook
print "You suddenly feel #{@spooky_grabber} brush your shoulder"
puts "." * spookiness
end
def scare
print "You suddenly feel #{@spooky_grabber} wrap around your neck"
puts "!" * spookiness
end
def self.merge (monster_a, monster_b)
spookiness = monster_a.spookiness + monster_b.spookiness
grabber = monster_a.spooky_grabber + " and " + monster_b.spooky_grabber
Monster.new(spookiness, grabber)
end
end