# Practical usage of identity function

If you are learning functional programming then you can’t go far without running into “identity function”.

An identity function is a very basic function that

• takes one argument
• returns the argument
``````f(x) = x;
``````

This seems like the most useless function in the world. We never needed any function like this while building any application. Then what’s the big deal about this identity function.

In this blog we will see how this identity concept is used in the real world.

For the implementation we will be using Ramda.js. We previously wrote about how we, at BigBinary, write JavaScript code using Ramda.js.

Again please note that in the following code `R` stands for `Ramda` and not for programming language R.

### Example 1

Here is JavaScript code.

``````if (x) return x;
return [];
``````

Here is same code using Ramda.js.

``````R.ifElse(
R.isNil,
() => [],
R.identity
);
``````

try it

### Example 2

Here we will use identity as the return value in the default case.

``````R.cond([
[R.equals(0), R.always("0")],
[R.equals(10), R.always("10")],
[R.T, R.identity]
]);
``````

try it

### Example 3

Get the unique items from the list.

``````R.uniqBy(R.identity, [1,1,2])
``````

try it

### Example 4

Count occurrences of items in the list.

``````R.countBy(R.identity, ["a","a","b","c","c","c"]);
``````

try it

### Example 5

Begin value from zero all the way to n-1.

``````R.times(R.identity, 5)
``````

try it

# Ruby 2.5 adds Exception#full_message method

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

Before Ruby 2.5, if we want to log a caught exception, we would need to format it ourselves.

``````class AverageService

def initialize(numbers)
@numbers = numbers
@coerced_numbers = coerce_numbers
end

def average
sum / count
end

private

def coerce_numbers
numbers.map do |number|
begin
Float(number)
rescue Exception => exception
puts "#{exception.message} (#{exception.class})\n\t#{exception.backtrace.join("\n\t")}"
puts "Coercing '#{number}' as 0.0\n\n"

0.0
end
end
end

def sum
coerced_numbers.map(&:to_f).sum
end

def count
coerced_numbers.size.to_f
end
end

average = AverageService.new(ARGV).average
puts "Average is: #{average}"
``````
``````\$ RBENV_VERSION=2.4.0 ruby average_service.rb 5 4f 7 1s0
invalid value for Float(): "4f" (ArgumentError)
average_service.rb:18:in `Float'
average_service.rb:18:in `block in coerce_numbers'
average_service.rb:16:in `map'
average_service.rb:16:in `coerce_numbers'
average_service.rb:6:in `initialize'
average_service.rb:37:in `new'
average_service.rb:37:in `<main>'

Coercing '4f' as 0.0

invalid value for Float(): "1s0" (ArgumentError)
average_service.rb:18:in `Float'
average_service.rb:18:in `block in coerce_numbers'
average_service.rb:16:in `map'
average_service.rb:16:in `coerce_numbers'
average_service.rb:6:in `initialize'
average_service.rb:37:in `new'
average_service.rb:37:in `<main>'

Coercing '1s0' as 0.0

Average of [5.0, 0.0, 7.0, 0.0] is: 3.0
``````

It was proposed that there should be a simple method to print the caught exception using the same format that ruby uses while printing an uncaught exception.

Some of the proposed method names were `display`, `formatted`, `to_formatted_s`, `long_message`, and `full_message`.

Matz approved the `Exception#full_message` method name.

In Ruby 2.5, we can re-write above example as follows.

``````class AverageService

def initialize(numbers)
@numbers = numbers
@coerced_numbers = coerce_numbers
end

def average
sum / count
end

private

def coerce_numbers
numbers.map do |number|
begin
Float(number)
rescue Exception => exception
puts exception.full_message
puts "Coercing '#{number}' as 0.0\n\n"

0.0
end
end
end

def sum
coerced_numbers.map(&:to_f).sum
end

def count
coerced_numbers.size.to_f
end
end

average = AverageService.new(ARGV).average
puts "Average is: #{average}"
``````
``````\$ RBENV_VERSION=2.5.0 ruby average_service.rb 5 4f 7 1s0
Traceback (most recent call last):
6: from average_service.rb:37:in `<main>'
5: from average_service.rb:37:in `new'
4: from average_service.rb:6:in `initialize'
3: from average_service.rb:16:in `coerce_numbers'
2: from average_service.rb:16:in `map'
1: from average_service.rb:18:in `block in coerce_numbers'
average_service.rb:18:in `Float': invalid value for Float(): "4f" (ArgumentError)

Coercing '4f' as 0.0

Traceback (most recent call last):
6: from average_service.rb:37:in `<main>'
5: from average_service.rb:37:in `new'
4: from average_service.rb:6:in `initialize'
3: from average_service.rb:16:in `coerce_numbers'
2: from average_service.rb:16:in `map'
1: from average_service.rb:18:in `block in coerce_numbers'
average_service.rb:18:in `Float': invalid value for Float(): "1s0" (ArgumentError)

Coercing '1s0' as 0.0

Average of [5.0, 0.0, 7.0, 0.0] is: 3.0
``````

Note that, Ruby 2.5 prints exception backtrace in reverse order if STDERR is unchanged and is a TTY as discussed in our previous blog post.

# Ruby 2.5 prints backtrace and error message in reverse order

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

Stack trace or backtrace is a sequential representation of the stack of method calls in a program which gets printed when an exception is raised. It is often used to find out the exact location in a program from where the exception was raised.

## Before Ruby 2.5

Before Ruby 2.5, the printed backtrace contained the exception class and the error message at the top. Next line contained where in the program the exception was raised. Next we got more lines which contained cascaded method calls.

Consider a simple Ruby program.

``````class DivisionService

def initialize(a, b)
@a, @b = a.to_i, b.to_i
end

def divide
puts a / b
end
end

DivisionService.new(ARGV[0], ARGV[1]).divide
``````

Let’s execute it using Ruby 2.4.

``````\$ RBENV_VERSION=2.4.0 ruby division_service.rb 5 0

division_service.rb:9:in `/': divided by 0 (ZeroDivisionError)
from division_service.rb:9:in `divide'
from division_service.rb:13:in `<main>'
``````

In the printed backtrace above, the first line shows the location, error message and the exception class name; whereas the subsequent lines shows the caller method names and their locations. Each line in the backtrace above is often considered as a stack frame placed on the call stack.

Most of the times, a backtrace has so many lines that it makes it very difficult to fit the whole backtrace in the visible viewport of the terminal.

Since the backtrace is printed in top to bottom order the meaningful information like error message, exception class and the exact location where the exception was raised is displayed at top of the backtrace. It means developers often need to scroll to the top in the terminal window to find out what went wrong.

## After Ruby 2.5

Over 4 years ago an issue was created to make printing of backtrace in reverse order configurable.

After much discussion Nobuyoshi Nakada made the commit to print backtrace and error message in reverse order only when the error output device (`STDERR`) is a TTY (i.e. a terminal). Message will not be printed in reverse order if the original `STDERR` is attached to something like a `File` object.

Look at the code here where the check happens if `STDERR` is a TTY and is unchanged.

Let’s execute the same program using Ruby 2.5.

``````\$ RBENV_VERSION=2.5.0 ruby division_service.rb 5 0

Traceback (most recent call last):
2: from division_service.rb:13:in `<main>'
1: from division_service.rb:9:in `divide'
division_service.rb:9:in `/': divided by 0 (ZeroDivisionError)

\$
``````

We can notice two new changes in the above backtrace.

1. The error message and exception class is printed last (i.e. at the bottom).
2. The stack also adds frame number when printing in reverse order.

This feature makes the debugging convenient when the backtrace size is a quite big and cannot fit in the terminal window. We can easily see the error message without scrolling up now.

Note that, the `Exception#backtrace` attribute still holds an array of stack frames like before in the top to bottom order.

So if we rescue the caught exception and print the backtrace manually

``````class DivisionService

def initialize(a, b)
@a, @b = a.to_i, b.to_i
end

def divide
puts a / b
end
end

begin
DivisionService.new(ARGV[0], ARGV[1]).divide
rescue Exception => e
puts "#{e.class}: #{e.message}"
puts e.backtrace.join("\n")
end
``````

we will get the old behavior.

``````\$ RBENV_VERSION=2.5.0 ruby division_service.rb 5 0

ZeroDivisionError: divided by 0
division_service.rb:9:in `/'
division_service.rb:9:in `divide'
division_service.rb:16:in `<main>'

\$
``````

Also, note that if we assign `STDERR` with a `File` object, thus making it a non-TTY

``````puts "STDERR is a TTY? [before]: #{\$stderr.tty?}"
\$stderr = File.new("stderr.log", "w")
\$stderr.sync = true
puts "STDERR is a TTY? [after]: #{\$stderr.tty?}"

class DivisionService

def initialize(a, b)
@a, @b = a.to_i, b.to_i
end

def divide
puts a / b
end
end

DivisionService.new(ARGV[0], ARGV[1]).divide
``````

we can get the old behavior but the backtrace would be written to the specified file and not to `STDERR`.

``````\$ RBENV_VERSION=2.5.0 ruby division_service.rb 5 0

STDERR is a TTY? [before]: true
STDERR is a TTY? [after]: false

\$ cat stderr.log

division_service.rb:14:in `/': divided by 0 (ZeroDivisionError)
from division_service.rb:14:in `divide'
from division_service.rb:18:in `<main>'

\$
``````

This feature has been tagged as experimental feature. What it means is that Ruby team is gathering feedback on this feature.

# Deploying Ruby on Rails application using HAProxy Ingress with unicorn/puma and websockets

After months of testing we recently moved a Ruby on Rails application to production that is using Kubernetes cluster.

In this article we will discuss how to setup path based routing for a Ruby on Rails application in kubernetes using HAProxy ingress.

This post assumes that you have basic understanding of Kubernetes terms like pods, deployments, services, configmap and ingress.

Typically our Rails app has services like unicorn/puma, sidekiq/delayed-job/resque, Websockets and some dedicated API services. We had one web service exposed to the world using load balancer and it was working well. But as the traffic increased it became necessary to route traffic based on URLs/path.

However Kubernetes does not supports this type of load balancing out of the box. There is work in progress for alb-ingress-controller to support this but we could not rely on it for production usage as it is still in alpha.

The best way to achieve path based routing was to use ingress controller.

We researched and found that there are different types of ingress available in k8s world.

We experimented with nginx-ingress and HAProxy and decided to go with HAProxy. HAProxy has better support for Rails websockets which we needed in the project.

We will walk you through step by step on how to use haproxy ingress in a Rails app.

### Configuring Rails app with HAProxy ingress controller

Here is what we are going to do.

• Create a Rails app with different services and deployments.
• Create tls secret for SSL.
• Create HAProxy ingress configmap.
• Create HAProxy ingress controller.
• Expose ingress with service type LoadBalancer
• Setup app DNS with ingress service.
• Create different ingress rules specifying path based routing.
• Test the path based routing.

Now let’s build Rails application deployment manifest for services like web(unicorn),background(sidekiq), Websocket(ruby thin),API(dedicated unicorn).

Here is our web app deployment and service template.

Here is background app deployment and service template.

Here is websocket app deployment and service template.

Here is API app deployment and service info.

Let’s launch this manifest using `kubectl apply`.

Once our app is deployed and running we should create HAProxy ingress. Before that let’s create a tls secret with our SSL key and certificate.

This is also used to enable HTTPS for app URL and to terminate it on L7.

Here `server.key` is our SSL key and `server.pem` is our SSL certificate in pem format.

Now let’s Create HAProxy controller resources.

### HAProxy configmap

For all the available configuration parameters from HAProxy refer here.

### HAProxy Ingress controller deployment

Deployment template for the Ingress controller with at-least 2 replicas to manage rolling deploys.

Notable fields in above manifest are arguments passed to controller.

` --default-backend-service` is the service when No rule is matched your request will be served by this app.

In our case it is `test-production-web` service, But it can be custom 404 page or whatever better you think.

`--default-ssl-certificate` is the SSL secret we just created above this will terminate SSL on L7 and our app is served on HTTPS to outside world.

### HAProxy Ingress service

This is the `LoadBalancer` type service to allow client traffic to reach our Ingress Controller.

LoadBalancer has access to both public network and internal Kubernetes network while retaining the L7 routing of the Ingress Controller.

Now let’s apply all the manifests of HAProxy.

Once all the resources are running get the LoadBalancer endpoint using.

### DNS mapping with application URL

Once we have ELB endpoint of ingress service, map the DNS with URL like `test-rails-app.com`.

### Ingress Implementation

Now after doing all the hard work it is time to configure ingress and path based rules.

In our case we want to have following rules.

https://test-rails-app.com requests to be served by `test-production-web`.

https://test-rails-app.com/websocket requests to be served by `test-production-websocket`.

https://test-rails-app.com/api requests to be served by `test-production-api`.

Let’s create a ingress manifest defining all the rules.

Moreover there are Ingress Annotations for adjusting configuration changes.

As expected,now our default traffic on `/` is routed to `test-production-web` service.

`/api` is routed to `test-production-api` service.

`/websocket` is routed to `test-production-websocket` service.

Thus ingress implementation solves our purpose of path based routing and terminating SSL on L7 on Kubernetes.

# Rails 5.2 adds default option to module and class attribute accessors

This blog is part of our Rails 5.2 series.

When DHH introduced support for specifying a default value for class_attribute, Genadi Samokovarov brought to notice that the module and class attribute accessor macros also support specifying a default value but using a block and not with a `default` option.

To have consistent and symmetrical behaviour across all the attribute extensions, it was decided to support specifying a default value using `default` option for all the module and class attribute macros as well.

`mattr_accessor`, `mattr_reader` and `mattr_writer` macros generate getter and setter methods at the module level.

Similarly, `cattr_accessor`, `cattr_reader`, and `cattr_writer` macros generate getter and setter methods at the class level.

## Before Rails 5.2

Before Rails 5.2, this is how we would set the default values for the module and class attribute accessor macros.

``````module ActivityLoggerHelper
mattr_accessor :colorize_logs
mattr_writer :log_ip { false }

self.colorize_logs = true
end

class ActivityLogger
include ActivityLoggerHelper

cattr_writer :logger { Logger.new(STDOUT) }
cattr_accessor :level
cattr_accessor :settings

@@level = Logger::DEBUG
self.settings = {}
end
``````

## After Rails 5.2

We can still set a default value of a module or class attribute accessor by providing a block. In this pull request, support for specifying a default value using a new `default` option has been introduced.

``````cattr_writer :logger { Logger.new(STDOUT) }
``````

or

``````cattr_writer :logger
self.logger = Logger.new(STDOUT)
``````

or

``````cattr_writer :logger
@@logger = Logger.new(STDOUT)
``````

we can now easily write

``````cattr_writer :logger, default: Logger.new(STDOUT)
``````

Same applies to the other attribute accessor macros like `mattr_accessor`, `mattr_reader`, `mattr_writer`, `cattr_accessor`, and `cattr_reader`.

Note that, the old way of specifying a default value using the block syntax will work but will not be documented anywhere.

Also, note that if we try to set the default value by both ways i.e. by providing a block as well as by specifying a `default` option; the value provided by `default` option will always take the precedence.

``````mattr_accessor(:colorize_logs, default: true) { false }
``````

Here, `@@colorize_logs` would be set with `true` as per the above precedence rule.

Here is a test which verifies this behavior.

Finally, here is simplified version using the new `default` option.

``````module ActivityLoggerHelper
mattr_accessor :colorize_logs, default: true
mattr_writer :log_ip, default: false
end

class ActivityLogger
include ActivityLoggerHelper

cattr_writer :logger, default: Logger.new(STDOUT)
cattr_accessor :level, default: Logger::DEBUG
cattr_accessor :settings, default: {}
end
``````

# Rails 5.2 supports specifying default value for a class_attribute

This blog is part of our Rails 5.2 series.

It is very common to set a default value for a `class_attribute`.

Before Rails 5.2, to specify a default value for a `class_attribute`, we needed to write like this.

``````class ActivityLogger
class_attribute :logger
class_attribute :settings

self.logger = Logger.new(STDOUT)
self.settings = {}
end
``````

As we can see above, it requires additional keystrokes to set a default value for each `class_attribute`.

Rails 5.2 has added support for specifying a default value for a `class_attribute` using `default` option.

``````class ActivityLogger
class_attribute :logger, default: Logger.new(STDOUT)
class_attribute :settings, default: {}
end
``````

This enhancement was introduced in this pull request.

# Ruby 2.5 added Hash#slice method

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

#### Ruby 2.4

Let’s say that we have a hash `{ id: 1, name: 'Ruby 2.5', description: 'BigBinary Blog' }` and we want to select key value pairs having keys `name` and `description`.

We can use Hash#select method.

``````irb> blog = { id: 1, name: 'Ruby 2.5', description: 'BigBinary Blog' }
=> {:id=>1, :name=>"Ruby 2.5", :description=>"BigBinary Blog"}

irb> blog.select { |key, value| [:name, :description].include?(key) }
=> {:name=>"Ruby 2.5", :description=>"BigBinary Blog"}
``````

Matzbara Masanao proposed a simple method to take care of this.

Some of the names proposed were `choice` and `pick`.

Matz suggested the name `slice` since this method is ActiveSupport compatible.

#### Ruby 2.5.0

``````irb> blog = { id: 1, name: 'Ruby 2.5', description: 'BigBinary Blog' }
=> {:id=>1, :name=>"Ruby 2.5", :description=>"BigBinary Blog"}

irb> blog.slice(:name, :description)
=> {:name=>"Ruby 2.5", :description=>"BigBinary Blog"}
``````

As we can see, now we can use a simple method `slice` to select key value pairs from a hash with specified keys.

Here is relevant commit and discussion.

# Ruby 2.5 allows creating structs with keyword arguments

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

In Ruby, structs can be created using positional arguments.

``````Customer = Struct.new(:name, :email)
Customer.new("John", "john@example.com")
``````

This approach works when the arguments list is short. When arguments list increases then it gets harder to track which position maps to which value.

Here if we pass keyword argument then we won’t get any error. But the values are not what we wanted.

``````Customer.new(name: "John", email: "john@example.com")
=> #<struct Customer name={:name=>"John", :email=>"john@example.com"}, email=nil>
``````

Ruby 2.5 introduced creating structs using keyword arguments. Relevant pull request is here.

However this introduces a problem. How do we indicate to `Struct` if we want to pass arguments using position or keywords.

Takashi Kokubun suggested to use `keyword_argument` as an identifier.

``````Customer = Struct.new(:name, :email, keyword_argument: true)
Customer.create(name: "John", email: "john@example.com")
``````

Matz suggested to change the name to `keyword_init`.

So in Ruby 2.5 we can create structs using keywords as long as we are passing `keyword_init`.

``````Customer = Struct.new(:name, :email, keyword_init: true)

Customer.new(name: "John", email: "john@example.com")
=> #<struct Customer name="John", email="john@example.com">
``````

# Rails 5.2 allows mailers to use custom Active Job class

This blog is part of our Rails 5.2 series.

Rails allows sending emails asynchronously via Active Job.

``````Notifier.welcome(User.first).deliver_later
``````

It uses `ActionMailer::DeliveryJob` as the default job class to send emails. This class is defined internally by Rails.

The `DeliveryJob` defines `handle_exception_with_mailer_class` method to handle exception and to do some housekeeping work.

``````def handle_exception_with_mailer_class(exception)
if klass = mailer_class
klass.handle_exception exception
else
raise exception
end
end
``````

One might need more control on the job class to retry the job under certain conditions or add more logging around exceptions.

Before Rails 5.2, it was not possible to use a custom job class for this purpose.

Rails 5.2 has added a feature to configure the job class per mailer.

``````class CustomNotifier < ApplicationMailer
self.delivery_job = CustomNotifierDeliveryJob
end
``````

By default, Rails will use the internal `DeliveryJob` class if the `delivery_job` configuration is not present in the mailer class.

Now, Rails will use `CustomNotifierDeliveryJob` for sending emails for CustomNotifier mailer.

``````CustomNotifier.welcome(User.first).deliver_later
``````

As mentioned above `CustomNotifierDeliveryJob` can be further configured for logging, exception handling and reporting.

By default, `deliver_later` will pass following arguments to the `perform` method of the `CustomNotifierDeliveryJob`.

• mailer class name
• mailer method name
• mail delivery method
• original arguments with which the mail is to be sent
``````class CustomNotifierDeliveryJob < ApplicationJob

rescue_from StandardError, with: :handle_exception_with_mailer_class

retry_on CustomNotifierException

def perform(mailer, mail_method, delivery_method, *args)
logger.log "Mail delivery started"
klass = mailer.constantize
klass.public_send(mail_method, *args).send(delivery_method)
logger.log "Mail delivery completed"
end

def handle_exception_with_mailer_class(exception)
if klass = mailer_class
klass.handle_exception exception
else
raise exception
end
end
end
``````

We can also simply inherit from the `ActionMailer::DeliveryJob` and override the retry logic.

``````class CustomNotifierDeliveryJob < ActionMailer::DeliveryJob
retry_on CustomNotifierException
end
``````

# Rails 5.2 supports descending indexes for MySQL

This blog is part of our Rails 5.2 series.

An index is used to speed up the performance of queries on a database.

Rails allows us to create index on a database column by means of a migration. By default, the sort order for the index is ascending.

But consider the case where we are fetching reports from the database. And while querying the database, we always want to get the latest report. In this case, it is efficient to specify the sort order for the index to be descending.

We can specify the sort order by adding an index to the required column by adding a migration .

``````add_index :reports, [:user_id, :name], order: { user_id: :asc, name: :desc }
``````

## PostgreSQL

If our Rails application is using postgres database, after running the above migration we can verify that the sort order was added in schema.rb

``````create_table "reports", force: :cascade do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id", "name"], name: "index_reports_on_user_id_and_name", order: { name: :desc }
end
``````

Here, the index for `name` has sort order in descending. Since the default is ascending, the sort order for `user_id` is not specified in schema.rb.

## MySQL < 8.0.1

For MySQL < 8.0.1, running the above migration, would generate the following schema.rb

``````create_table "reports", force: :cascade do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id", "name"], name: "index_reports_on_user_id_and_name"
end
``````

As we can see, although the migration runs successfully, it ignores the sort order and the default ascending order is added.

## Rails 5.2 and MySQL > 8.0.1

MySQL 8.0.1 added support for descending indices.

Rails community was quick to integrate it as well. So now in Rails 5.2, we can add descending indexes for MySQL databases.

Running the above migration would lead to the same output in schema.rb file as that of the postgres one.

``````create_table "reports", force: :cascade do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id", "name"], name: "index_reports_on_user_id_and_name", order: { name: :desc }
end
``````

# Ruby 2.5 adds Hash#transform_keys method

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

Ruby 2.4 added Hash#transform_values method to transform values of the hash.

In Ruby 2.5, a similar method Hash#transform_keys is added for transforming keys of the hash.

``````>> h = { name: "John", email: "john@example.com" }
=> {:name=>"John", :email=>"john@example.com"}

>> h.transform_keys { |k| k.to_s }
=> {"name"=>"John", "email"=>"john@example.com"}

``````

The bang sibling of this method, `Hash#transform_keys!` is also added which changes the hash in place.

These two methods are already present in Active Support from Rails and are natively supported in Ruby now.

Rails master is already supporting using the native methods if supported by the Ruby version.

# Rails 5.2 allows passing request params to Action Mailer previews

This blog is part of our Rails 5.2 series.

Rails has inbuilt feature to preview the emails using Action Mailer previews.

A preview mailer can be setup as shown here.

``````class NotificationMailer < ApplicationMailer
def notify(email: email, body: body)
user = User.find_by(email: email)
mail(to: user.email, body: body)
end
end

def notify
end
end
``````

This will work as expected. But our email template is displayed differently based on user’s role. To test this, we need to update the notify method and then check the updated preview.

What if we could just pass the email in the preview URL.

``````http://localhost:3000/rails/mailers/notification/notify?email=superadmin@example.com
``````

In Rails 5.2, we can pass the params directly in the URL and params will be available to the preview mailers.

Our code can be changed as follows to use the params.

``````class NotificationMailerPreview < ActionMailer::Preview
def notify
email =  params[:email] || User.first.email
end
end
``````

This allows us to test our mailers with dynamic input as per requirements.

# Ruby 2.5 enumerable predicates accept pattern argument

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

Ruby 2.5.0 was recently released.

Ruby has sequence predicates such as `all?`, `none?`, `one?` and `any?` which take a block and evaluate that by passing every element of the sequence to it.

Ruby 2.5 allows using a shorthand for this by passing a pattern argument. Internally `case equality operator(===)` is used against every element of the sequence and the pattern argument.

This allows us to write concise and shorthand expressions where block is only used for comparisons. This feature is applicable to `all?`, `none?`, `one?` and `any?` methods.

### Similarities with Enumerable#grep

This feature is based on how `Enumerable#grep` works. `grep` returns an array of every element in the sequence for which the `case equality operator(===)` returns true by applying the pattern. In this case, the `all?` and friends return true or false.

There is a proposal to add it for `select` and `reject` as well.

# Rails 5.2 adds bootsnap to the app to speed up boot time

This blog is part of our Rails 5.2 series.

Rails 5.2 beta 1 was recently released.

If we generate a new Rails app using Rails 5.2, we will see bootsnap gem in the Gemfile. bootsnap helps in reducing the boot time of the app by caching expensive computations.

In a new Rails 5.2 app, `boot.rb` will contain following content:

``````ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)

require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.

if %w[s server c console].any? { |a| ARGV.include?(a) }
puts "=> Booting Rails"
end
``````

This sets up bootsnap to start in all environments. We can toggle it per environment as required.

This works out of the box and we don’t have do to anything for the new app.

If we are upgrading an older app which already has bootsnap, then we need to make sure that we are using bootsnap >= 1.1.0 because new Rails apps ship with that version constraint.

If the app doesn’t contain the bootsnap gem already then we will need to add it manually since `rails app:update` task adds the `bootsnap/setup` line to `boot.rb` regardless of its presence in the Gemfile.

# Ruby 2.5 requires pp by default

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

Ruby 2.5.0-preview1 was recently released.

Ruby allows pretty printing of objects using pp method.

Before Ruby 2.5, we had to require PP explicitly before using it. Even the official documentation states that “All examples assume you have loaded the PP class with require ‘pp’”.

``````>> months = %w(January February March)
=> ["January", "February", "March"]

>> pp months
NoMethodError: undefined method `pp' for main:Object
Did you mean?  p
from (irb):5
from /Users/prathamesh/.rbenv/versions/2.4.1/bin/irb:11:

>> require 'pp'
=> true

>> pp months
["January",
"February",
"March"]
=> ["January", "February", "March"]
``````

In Ruby 2.5, we don’t need to require pp. It gets required by default. We can use it directly.

``````>> months = %w(January February March)
=> ["January", "February", "March"]

>> pp months
["January",
"February",
"March"]
=> ["January", "February", "March"]
``````

This feature was added after Ruby 2.5.0 preview 1 was released, so it’s not present in the preview. It’s present in Ruby trunk.

# Array#prepend and Array#append in Ruby 2.5

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

Ruby has `Array#unshift` to prepend an element to the start of an array and `Array#push` to append an element to the end of an array.

The names of these methods are not very intuitive. Active Support from Rails already has aliases for the unshift and push methods , namely `prepend` and `append`.

In Ruby 2.5, these methods are added in the Ruby language itself.

They are implemented as aliases to the original `unshift` and `push` methods so there is no change in the behavior.

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

Ruby 2.5 added a new method named yield_self. It yields the receiver to the given block and returns output of the last statement in the block.

``````irb> "Hello".yield_self { |str| str + " World" }
=> "Hello World"
``````

#### How is it different from `try` in Rails ?

Without a method argument try behaves similar to `yield_self`. It would yield to the given block unless the receiver is nil and returns the output of the last statement in the block.

``````irb> "Hello".try { |str| str + " World" }
=> "Hello World"
``````

Couple of differences to note are, `try` is not part of `Ruby` but `Rails`. Also `try`’s main purpose is protection against `nil` hence it doesn’t execute the block if receiver is `nil`.

``````irb> nil.yield_self { |obj| "Hello World" }
=> "Hello World"

irb> nil.try { |obj| "Hello World" }
=> nil
``````

#### What about `tap`?

`tap` also is similar to `yield_self`. It’s part of Ruby itself. The only difference is the value that is returned. `tap` returns the receiver itself while `yield_self` returns the output of the block.

``````irb> "Hello".yield_self { |str| str + " World" }
=> "Hello World"

irb> "Hello".tap { |str| str + " World" }
=> "Hello"
``````

Overall, `yield_self` improves readability of the code by promoting chaining over nested function calls. Here is an example of both the styles.

``````irb> add_greeting = -> (str) { "HELLO " + str }
irb> to_upper = -> (str) { str.upcase }

# with new `yield_self`
irb> "world".yield_self(&to_upper)
=> "HELLO WORLD"

# nested function calls
=> "HELLO WORLD"

``````

`yield_self` is part of `Kernel` and hence it’s available to all the objects.

# Rails 5.2 implements fetch_values for HashWithIndifferentAccess

This blog is part of our Rails 5.2 series.

Ruby 2.3 added fetch_values method to hash.

By using `fetch_values` we are able to get values for multiple keys in a hash.

``````capitals = { usa: "Washington DC",
china: "Beijing",
india: "New Delhi",
australia: "Canberra" }

capitals.fetch_values(:usa, :india)
#=> ["Washington DC", "New Delhi"]

capitals.fetch_values(:usa, :spain) { |country| "N/A" }
#=> ["Washington DC", "N/A"]

``````

Rails 5.2 introduces method `fetch_values` on HashWithIndifferentAccess. We’ll hence be able to fetch values of multiple keys on any instance of HashWithIndifferentAccess class.

``````capitals = HashWithIndifferentAccess.new
capitals[:usa] = "Washington DC"
capitals[:china] = "Beijing"

capitals.fetch_values("usa", "china")
#=> ["Washington DC", "Beijing"]

capitals.fetch_values("usa", "spain") { |country| "N/A" }
#=> ["Washington DC", "N/A"]

``````

# Ruby 2.5 added delete_prefix and delete_suffix methods

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

#### Ruby 2.4

Let’s say that we have a string `Projects::CategoriesController` and we want to remove `Controller`. We can use chomp method.

``````irb> "Projects::CategoriesController".chomp("Controller")
=> "Projects::Categories"
``````

However if we want to remove `Projects::` from the string then there is no corresponding method of `chomp`. We need to resort to sub.

``````irb> "Projects::CategoriesController".sub(/Projects::/, '')
=> "CategoriesController"
``````

Naotoshi Seo did not like using regular expression for such a simple task. He proposed that Ruby should have a method for taking care of such tasks.

Some of the names proposed were `remove_prefix`, `deprefix`, `lchomp`, `remove_prefix` and `head_chomp`.

Matz suggested the name `delete_prefix` and this method was born.

#### Ruby 2.5.0-preview1

Now in order to delete prefix we can use `delete_prefix` and to delete suffix we could use `chomp`. This did not feel right. So for symmetry `delete_suffix` was added.

# Ruby 2.5 introduces Dir.children and Dir.each_child

This blog is part of our Ruby 2.5 series. Ruby 2.5 was recently released.

Dir.entries is a method present in Ruby 2.4. It returns the output of shell command `ls -a` in an array.

`````` > Dir.entries("/Users/john/Desktop/test")
=> [".", "..", ".config", "program.rb", "group.txt"]
``````

We also have method Dir.foreach which iterates and yields each value from the output of `ls -a` command to the block.

``````> Dir.foreach("/Users/john/Desktop/test") { |child| puts child }
.
..
.config
program.rb
group.txt
test2

``````

We can see that the output includes the directives for current directory and parent directory which are `"."` and `".."`.

When we want to have access only to the children files and directories, we do not need the `[".", ".."]` subarray.

This is a very common use case and we’ll probably have to do something like `Dir.entries(path) - [".", ".."]` to achieve the desired output.

To overcome such issues, Ruby 2.5 introduced Dir.children. It returns the output of `ls -a` command without the directives for current and parent directories.

``````
> Dir.children("/Users/mohitnatoo/Desktop/test")
=> [".config", "program.rb", "group.txt"]

``````

Additionally, we can use `Dir.each_child` method to avoid yielding current and parent directory directives while iterating,

``````> Dir.each_child("/Users/mohitnatoo/Desktop/test") { |child| puts child }
.config
program.rb
group.txt
test2
``````

As noted in the discussion the names were chosen to match with existing methods Pathname#children and Pathname#each_child.

These additions seem like simple features. Well the issue was posted more than two years ago.