Common ruby ​​idioms

One thing I love about ruby ​​is that it is basically a very readable language (which is great for self-documenting code)

However, inspired by this question: the Ruby Code explained and the description of how ||= works in ruby, I thought about ruby ​​idioms that I don’t use, since, to be honest, I do not fully understand them.

So, my question is similar to the example from the mentioned question, what common, but not obvious, ruby ​​idioms do I need to know in order to be a really experienced ruby ​​programmer?

By the way, from the mentioned question

 a ||= b 

equivalently

 if a == nil || a == false a = b end 

(Thanks to Ian Terrell for the correction)

Edit: It turns out this point is not absolutely certain. Actually the correct extension

 (a || (a = (b))) 

Check out these links for why:

Thanks to Jörg W Mittag for pointing this out.

+62
idioms ruby
Mar 05 '09 at 8:35
source share
15 answers

A magic if clause that allows you to use the same file as a library or script:

 if __FILE__ == $0 # this library may be run as a standalone script end 

Packing and unpacking arrays:

 # put the first two words in a and b and the rest in arr a,b,*arr = *%w{a dog was following me, but then he decided to chase bob} # this holds for method definitions to def catall(first, *rest) rest.map { |word| first + word } end catall( 'franken', 'stein', 'berry', 'sense' ) #=> [ 'frankenstein', 'frankenberry', 'frankensense' ] 

Syntactic sugar for hashes as method arguments

 this(:is => :the, :same => :as) this({:is => :the, :same => :as}) 

Hash Initializers:

 # this animals = Hash.new { [] } animals[:dogs] << :Scooby animals[:dogs] << :Scrappy animals[:dogs] << :DynoMutt animals[:squirrels] << :Rocket animals[:squirrels] << :Secret animals #=> {} # is not the same as this animals = Hash.new { |_animals, type| _animals[type] = [] } animals[:dogs] << :Scooby animals[:dogs] << :Scrappy animals[:dogs] << :DynoMutt animals[:squirrels] << :Rocket animals[:squirrels] << :Secret animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]} 
Metaclass Syntax

 x = Array.new y = Array.new class << x # this acts like a class definition, but only applies to x def custom_method :pow end end x.custom_method #=> :pow y.custom_method # raises NoMethodError 

class instance variables

 class Ticket @remaining = 3 def self.new if @remaining > 0 @remaining -= 1 super else "IOU" end end end Ticket.new #=> Ticket Ticket.new #=> Ticket Ticket.new #=> Ticket Ticket.new #=> "IOU" 

Blocks, procs and lambdas. Live and breathe them.

  # know how to pack them into an object block = lambda { |e| puts e } # unpack them for a method %w{ and then what? }.each(&block) # create them as needed %w{ I saw a ghost! }.each { |w| puts w.upcase } # and from the method side, how to call them def ok yield :ok end # or pack them into a block to give to someone else def ok_dokey_ok(&block) ok(&block) block[:dokey] # same as block.call(:dokey) ok(&block) end # know where the parentheses go when a method takes arguments and a block. %w{ a bunch of words }.inject(0) { |size,w| size + 1 } #=> 4 pusher = lambda { |array, word| array.unshift(word) } %w{ eat more fish }.inject([], &pusher) #=> ['fish', 'more', 'eat' ] 
+50
Mar 05 '09 at 9:27
source share

This one is completely completed in the basic Ruby idioms, as in:

  • Change two values:

    x, y = y, x

  • Parameters that, if not specified, default

    def somemethod(x, y=nil)

  • Unload extraneous parameters into an array

    def substitute(re, str, *rest)

And so on...

+10
Mar 05 '09 at 9:22
source share

A few more idioms:

Using the %w , %r and %(

 %w{ An array of strings %} %r{ ^http:// } %{ I don't care if the string has 'single' or "double" strings } 

Type Comparison for Operators

 def something(x) case x when Array # Do something with array when String # Do something with string else # You should really teach your objects how to 'quack', don't you? end end 

... and general abuse of the === method in case statements

 case x when 'something concrete' then ... when SomeClass then ... when /matches this/ then ... when (10...20) then ... when some_condition >= some_value then ... else ... end 

Something that should look natural for rubists, but maybe not so for people coming from other languages: using each in favor of for .. in

 some_iterable_object.each{|item| ... } 

In Ruby 1.9+, Rails, or by fixing the symbol method # to_proc this becomes an increasingly popular idiom:

 strings.map(&:upcase) 

Conditional Method / Constant Definition

 SOME_CONSTANT = "value" unless defined?(SOME_CONSTANT) 

Request methods and destructive methods (bang)

 def is_awesome? # Return some state of the object, usually a boolean end def make_awesome! # Modify the state of the object end 

Implicit display options

 [[1, 2], [3, 4], [5, 6]].each{ |first, second| puts "(#{first}, #{second})" } 
+8
Jul 04 '10 at 21:47
source share

I like it:

 str = "Something evil this way comes!" regexp = /(\w[aeiou])/ str[regexp, 1] # <- This 

Which is (roughly) equivalent:

 str_match = str.match(regexp) str_match[1] unless str_match.nil? 

Or at least what I used to replace such blocks.

+7
Mar 05 '09 at 9:08
source share

I would suggest reading the code of popular and well-designed plugins or gems from people you admire and respect.

Some examples I came across:

 if params[:controller] == 'discussions' or params[:controller] == 'account' # do something here end 

appropriate

 if ['account', 'discussions'].include? params[:controller] # do something here end 

which will later be reorganized into

 if ALLOWED_CONTROLLERS.include? params[:controller] # do something here end 
+7
Mar 05 '09 at 9:27
source share

Here are a few, taken from different sources:

use "except" and "until" instead of "if not" and "while not". Try not to use if if the else condition exists.

Remember that you can assign several variables at once:

 a,b,c = 1,2,3 

and even a swap variable without temp:

 a,b = b,a 

Use appropriate conventions, e.g.

 do_something_interesting unless want_to_be_bored? 

Remember the commonly used, but not immediately obvious (at least to me) way of defining class methods:

 class Animal class<<self def class_method puts "call me using Animal.class_method" end end end 

Some links:

+5
Mar 05 '09 at 9:47
source share

By the way, from the link question

 a ||= b 

equivalently

 if a == nil a = b end 

This is subtlely flawed and is a source of errors for beginners in Ruby applications.

Since both (and only) nil and false are evaluated as logical false, a ||= b actually (almost *) equivalent to:

 if a == nil || a == false a = b end 

Or, to rewrite it with another Ruby idiom:

 a = b unless a 

(* Since each operator matters, this is not technically equivalent to a ||= b . But if you do not rely on the value of the instruction, you will not see the difference.)

+5
Mar 05 '09 at 15:23
source share

I maintain a wiki page that covers some Ruby idioms and formatting:

https://github.com/tokland/tokland/wiki/RubyIdioms

+4
Sep 27 2018-11-21T00:
source share

You can easily copy the Marshaling object. - taken from the Ruby programming language

 def deepcopy(o) Marshal.load(Marshal.dump(o)) end 

Note that files and I / O streams, as well as method and binding objects, are too dynamic to marshal; there would not be a reliable way to restore their condition.

+1
Jul 04 2018-10-21T00:
source share
 a = (b && b.attribute) || "default" 

about:

 if ( ! b.nil? && ! b == false) && ( ! b.attribute.nil? && ! b.attribute.false) a = b else a = "default" 

I use this when b is a record that may or may not be found, and I need to get one of its attributes.

+1
Mar 09 '11 at 20:13
source share

I always forget the exact syntax of this shorthand if the else statement (and the name of the operator. Is someone commenting?) I think it is widely used outside of ruby, but in case someone wants the syntax here:

 refactor < 3 ? puts("No need to refactor YET") : puts("You need to refactor this into a method") 

expands to

 if refactor < 3 puts("No need to refactor YET") else puts("You need to refactor this into a method") end 

Update

called the ternary operator:

return myvar? myvar.size: 0

+1
Oct 25 '11 at 17:53
source share

I like how if-then-elses or case-when can be shortened because they return a value:

 if test>0 result = "positive" elsif test==0 result = "zero" else result = "negative" end 

can be overwritten

 result = if test>0 "positive" elsif test==0 "zero" else "negative" end 

The same can be applied to case-when:

 result = case test when test>0 ; "positive" when test==0 ; "zero" else "negative" end 
+1
Feb 09 2018-12-12T00:
source share

Array.pack and String.unpack for working with binary files:

 # extracts four binary sint32s to four Integers in an Array data.unpack("iiii") 
0
Mar 28
source share

not enough magic

 class Dummy def method_missing(m, *args, &block) "You just called method with name #{m} and arguments- #{args}" end end Dummy.new.anything(10, 20) => "You just called method with name anything and arguments- [10, 20]" 

if you call methods that do not exist in ruby ​​objects, the ruby ​​interpreter will call a method called method_missing, if defined, you can use this for some tricks, for example, to write api wrappers or dsl, where you do not know all the names methods and parameters

0
Jun 20 '14 at 10:13
source share

Good question!

In my opinion, the more intuitive and fast the code, the better the software was built. I will show you how I express my thoughts with Ruby in small pieces of code. More here

Map

We can use the display method in different ways:

 user_ids = users.map { |user| user.id } 

Or:

 user_ids = users.map(&:id) 

Example

We can use the rand method:

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

In random order:

 [1, 2, 3].shuffle.first 

And the idiomatic, simple and easy way ... sample!

 [1, 2, 3].sample 

Double pipes / demounting

As you said in the description, we can use memoization:

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

Static Method / Class Method

I like to use class methods, I believe that this is really an idiomatic way to create and use classes:

 GetSearchResult.call(params) 

Simple Nice. Intuitively. 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 

For more information to write the idiomatic Ruby code, read here.

0
Apr 22 '17 at 0:30
source share



All Articles