Ruby idiomatique: écrire du beau code

Ruby est un magnifique langage de programmation.

Selon la page Web officielle de Ruby, Ruby est:

« Langage de programmation dynamique et open source axé sur la simplicité et la productivité. Il possède une syntaxe élégante, naturelle à lire et facile à écrire. »

Ruby a été créé par Yukihiro Matsumoto, un ingénieur logiciel japonais. Depuis 2011, il est le designer en chef et ingénieur logiciel pour Ruby chez Heroku.

Matsumoto a souvent dit qu'il essayait de rendre Ruby naturel, pas simple , d'une manière qui reflète la vie.

«Le rubis est simple en apparence, mais il est très complexe à l'intérieur, tout comme notre corps humain» - Yukihiro Matsumoto

Je ressens la même chose à propos de Ruby. C'est un langage de programmation complexe mais très naturel, avec une belle syntaxe intuitive.

Avec un code plus intuitif et plus rapide, nous sommes en mesure de créer de meilleurs logiciels. Dans cet article, je vais vous montrer comment j'exprime mes pensées (aka code) avec Ruby, en utilisant des extraits de code.

Exprimer mes pensées avec des méthodes de tableau

Carte

Utilisez la méthode map pour simplifier votre code et obtenir ce que vous voulez.

La méthode map renvoie un nouveau tableau avec les résultats de l'exécution d'un bloc une fois pour chaque élément de enum.

Essayons:

an_array.map  element * element 

Aussi simple que cela.

Mais lorsque vous commencez à coder avec Ruby, il est facile de toujours utiliser chaque itérateur.

La chaque itérateur comme indiqué ci - dessous

user_ids = [] users.each user

Peut être simplifié avec la carte en une seule belle ligne de code:

user_ids = users.map  user.id 

Ou encore mieux (et plus rapide):

user_ids = users.map(&:id)

Sélectionner

Et lorsque vous avez l'habitude de coder avec map , votre code peut parfois être comme ceci:

even_numbers = [1, 2, 3, 4, 5].map element # [ni, 2, nil, 4, nil] even_numbers = even_numbers.compact # [2, 4]

En utilisant la carte pour sélectionner uniquement les nombres pairs, leobjet nul également. Utilisez la méthode compacte pour supprimer tous les objets nil .

Et ta-da, vous avez sélectionné tous les nombres pairs.

Mission accomplie.

Allez, on peut faire mieux que ça! Avez-vous entendu parler de la méthode de sélection du module énumérable?

[1, 2, 3, 4, 5].select  

Juste une ligne. Code simple. Facile à comprendre.

Prime

[1, 2, 3, 4, 5].select(&:even?)

Échantillon

Imaginez que vous ayez besoin d'obtenir un élément aléatoire d'un tableau. Vous venez de commencer à apprendre Ruby, donc votre première pensée sera: «Utilisons la méthode aléatoire », et c'est ce qui se passe:

[1, 2, 3][rand(3)]

Eh bien, nous pouvons comprendre le code, mais je ne suis pas sûr qu'il soit assez bon. Et si nous utilisons la méthode aléatoire ?

[1, 2, 3].shuffle.first

Hmm. En fait, je préfère utiliser shuffle sur rand . Mais quand j'ai découvert la méthode d' exemple , cela avait tellement plus de sens:

[1, 2, 3].sample

Vraiment, vraiment simple.

Assez naturel et intuitif. Nous demandons un échantillon d'un tableau et la méthode le renvoie. Maintenant je suis content.

Et vous?

Exprimer mes pensées avec la syntaxe Ruby

Comme je l'ai déjà mentionné, j'aime la façon dont Ruby me permet de coder. C'est vraiment naturel pour moi. Je vais montrer des parties de la belle syntaxe Ruby.

Retour implicite

Toute instruction dans Ruby renvoie la valeur de la dernière expression évaluée. Un exemple simple est la méthode getter . Nous appelons une méthode et attendons une certaine valeur en retour.

Voyons voir:

def get_user_ids(users) return users.map(&:id) end

Mais comme nous le savons, Ruby renvoie toujours la dernière expression évaluée. Pourquoi utiliser l' instruction return ?

Après avoir utilisé Ruby pendant 3 ans, je me sens bien en utilisant presque toutes les méthodes sans l' instruction return .

def get_user_ids(users) users.map(&:id) end

Affectations multiples

Ruby me permet d'attribuer plusieurs variables en même temps. Lorsque vous commencez, vous codez peut-être comme ceci:

def values [1, 2, 3] end one = values[0] two = values[1] three = values[2]

Mais pourquoi ne pas attribuer plusieurs variables en même temps?

def values [1, 2, 3] end one, two, three = values

Plutôt génial.

Méthodes qui posent des questions (également appelées prédicats)

One feature that caught my attention when I was learning Ruby was the question mark (?) method, also called the predicates methods. It was weird to see at first, but now it makes so much sense. You can write code like this:

movie.awesome # => true

Ok… nothing wrong with that. But let’s use the question mark:

movie.awesome? # => true

This code is much more expressive, and I expect the method’s answer to return either a true or false value.

A method that I commonly use is any? It’s like asking an array if it has anything inside it.

[].any? # => false [1, 2, 3].any? # => true

Interpolation

For me string interpolation is more intuitive than string concatenation. Period. Let’s see it in action.

An example of a string concatenation:

programming_language = "Ruby" programming_language + " is a beautiful programming_language" # => "Ruby is a beautiful programming_language"

An example of a string interpolation:

programming_language = "Ruby" "#{programming_language} is a beautiful programming_language" # => "Ruby is a beautiful programming_language"

I prefer string interpolation.

What do you think?

The if statement

I like to use the if statement:

def hey_ho? true end puts "let’s go" if hey_ho?

Pretty nice to code like that.

Feels really natural.

The try method (with Rails mode on)

The try method invokes the method identified by the symbol, passing it any arguments and/or the block specified. This is similar to Ruby’s Object#send. Unlike that method, nil will be returned if the receiving object is a nil object or NilClass.

Using if and unless condition statement:

user.id unless user.nil?

Using the try method:

user.try(:id)

Since Ruby 2.3, we can use Ruby’s safe navigation operator (&.) instead of Rails try method.

user&.id

Double pipe equals (||=) / memoization

This feature is so C-O-O-L. It’s like caching a value in a variable.

some_variable ||= 10 puts some_variable # => 10 some_variable ||= 99 puts some_variable # => 10

You don’t need to use the if statement ever. Just use double pipe equals (||=) and it’s done.

Simple and easy.

Class static method

One way I like to write Ruby classes is to define a static method (class method).

GetSearchResult.call(params)

Simple. Beautiful. Intuitive.

What happens in the background?

class GetSearchResult def self.call(params) new(params).call end def initialize(params) @params = params end def call # ... your code here ... end end

The self.call method initializes an instance, and this object calls the call method. Interactor design pattern uses it.

Getters and setters

For the same GetSearchResult class, if we want to use the params, we can use the @params

class GetSearchResult def self.call(params) new(params).call end def initialize(params) @params = params end def call # ... your code here ... @params # do something with @params end end

We define a setter and getter:

class GetSearchResult def self.call(params) new(params).call end def initialize(params) @params = params end def call # ... your code here ... params # do something with params method here end private def params @params end def params=(parameters) @params = parameters end end

Or we can define attr_reader, attr_writer, or attr_accessor

class GetSearchResult attr_reader :param def self.call(params) new(params).call end def initialize(params) @params = params end def call # ... your code here ... params # do something with params method here end end

Nice.

We don’t need to define the getter and setter methods. The code just became simpler, just what we want.

Tap

Imagine you want to define a create_user method. This method will instantiate, set the parameters, and save and return the user.

Let’s do it.

def create_user(params) user = User.new user.id = params[:id] user.name = params[:name] user.email = params[:email] # ... user.save user end

Simple. Nothing wrong here.

So now let’s implement it with the tap method

def create_user(params) User.new.tap do |user| user.id = params[:id] user.name = params[:name] user.email = params[:email] # ... user.save end end

You just need to worry about the user parameters, and the tap method will return the user object for you.

That’s it

We learned I write idiomatic Ruby by coding with

  • array methods
  • syntax

We also learned how Ruby is beautiful and intuitive, and runs even faster.

And that’s it, guys! I will be updating and including more details to my blog. The idea is to share great content, and the community helps to improve this post! ☺

I hope you guys appreciate the content and learned how to program beautiful code (and better software).

If you want a complete Ruby course, learn real-world coding skills and build projects, try One Month Ruby Bootcamp. See you there ☺

This post appeared first here on my Renaissance Developer publication.

Have fun, keep learning, and always keep coding!

My Twitter & Github. ☺