Last week, I posted part one of my Ruby Tips & Tricks for people new to Ruby. In part two, we've got a whole new set of fantastic things you may find useful:
Working with Arrays
As you probably know, Arrays are essentially lists of objects. Once you've got an array containing items, you often need to perform actions on those items.
Firstly a simple but powerful one, we'll take a look at the uniq
method. This allows you to return an array which only contains items which only exist once.
array = [1,2,2,2,3,4,5,5,6]
array.uniq => [1,2,3,4,5,6]
Next, the flatten
method. This is used to turn an array of arrays into a single flat array containing all items of all nested arrays. Quite the mouthful!
array = [1, [2,3,[4,5,6], 7, 8], 9]
array.flatten #=> [1,2,3,4,5,6,7,8,9]
Finally, compact
is a method which allows you to remove nils from an array. This may not sound terribly useful but it comes in handy every now and then and is worth having in your repertoire.
array = [1,2,nil,3,nil,nil,nil]
array.compact #=> [1,2,3]
Operator Methods on Classes
If you're making your own classes, you may be interested to learn how easy to create your own operator methods for your instances.
ten = Money.new(10.00)
twenty = Money.new(20.00)
ten + twenty #=> Money(30.00)
twenty - ten #=> Money(10.00)
twenty / ten #=> Money(2.00)
ten * twenty #=> Money(200.00)
It's really simple to do this, you simply define methods using the name of the operator you want to use.
class Money
attr_accessor :decimal
def initialize(decimal)
@decimal = decimal
end
def +(other)
Money.new(@decimal + other.decimal)
end
def -(other)
Money.new(@decimal - other.decimal)
end
end
Before we move on, there's also a []
method which can be useful in certain circumstances. In this example, we're demonstrating it in its most basic form:
class Config
def initialize(config = {})
@config = config
end
def [](value)
@config[value]
end
end
config = Config.new(:host => 'potato.com')
config[:host] #=> 'potato.com'
Mapping / Collecting
Using map
allows you to manipulate items in an Enumerable object (for example, an array or hash) and return a new array containing your new objects.
# In this example, we've multiplied each number by two
array = [1,2,3,4,5]
array.map { |i| i * 2} #=> [2,4,6,8,10]
# Next, we'll work with some strings and add some text
array = ["Adam", "Jim", "Bob"]
hellos = array.map do |name|
"Hello #{name}"
end
hellos #=> ["Hello Adam", "Hello Jim", "Hello Bob"]
Reducing / Injecting
In this example, we're going to use inject
to add together all the items in an array. The basic premise for inject is that it will loop over all the items, run your code and set the resulting value to a variable which is provided to each future iteration.
prettyprint lang-ruby
numbers = [1,2,3,4,5,6]
total = numbers.inject(0) do |total, number|
total + number
end
The value we pass to the inject method is the starting point for the total
variable in our block. You can see here, we simply return the total plus the current number. Finally, when all items have been evaluated, it will return the total
(in this case, 21).
Inject can also be used with a hash if you wish to manipulate the contents of a hash and return a new Hash. In this code, we're going to change the keys of the hash to be symbols rather than strings.
hash = {'name' => 'Adam', 'age' => 28, 'country' => 'UK'}
hash.inject(Hash.new) do |new_hash, (old_key, old_value)|
new_hash[old_key.to_sym] = old_value
new_hash
end
Just remember to return new_hash
when you've set the value. As before, whatever you return from your block will be used as new_hash
in the future iterations. If you don't return new_hash
, it will simply return the value of old_value
.
Extracting data from a string
Using regular expressions, we can easily extract certain bits of information from a string. We just need to create a regular expression with a capturing group around the item(s) we want to extract.
Our string is Name: Adam
and we want to extract the person's name from it.
if match = string.match(/\w+\: (\w+)/)
match[1] #=> 'Adam'
# Return the values of all items which were captured.
match.captures #=> ["Adam"]
# Return the beginning & end position of any capturing groups in the regexp.
match.begin(1) #=> 6
match.end(1) #=> 10
end
That's about it.
... and that's about it for my Ruby Tips & Tricks. I'm planning to write a post next week about my favourite gems, how they work and why I love them.
If there's anything else you'd like me to cover, do feel free to drop me a message on Twitter and I'll happily include it.