Run command line scripts from within Rake tasks

My usual approach when writing Rake tasks is to import a library and then use its API:

require_relative '../slides'

namspace :slides do
  desc 'Create an empty slideshow'
  task :new do
    Slides.new.write_to_disk
  end
end

Sometimes that is impractical: the API is not public, or you need to invoke a standalone script which only has a command line interface.

I found out Rake implements a ruby method which lets you invoke the ruby program directly:

task :new do
  ruby 'create_slideshow.rb'
  puts 'Created a new slideshow.'
end

There is also a sh method, which allows you to run system commands. Make sure to use the multiple argument version and avoid passing it unfiltered user input.

2019-09-11 by Dimiter Petrov

Install mysql gem on Mac OS X

According to this Gist.

brew install mysql
brew install openssl
gem install mysql2 -v '0.5.2' -- --with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include
2019-09-05 by Andy Pfister

Step through migrations in Rails

tl;dr db:forward is the opposite of db:rollback

bin/rails db:migrate

runs all pending migrations.

If you want to migrate to a specific DB version, you can use

bin/rails db:migrate VERSION=20190730123456

which is rather cumbersome, especially if you only want to run one migration. Therefore you can use

bin/rails db:forward

You can combine it with variable STEP to execute multiple migrations.

bin/rails db:forward STEP=5
2019-08-02 by Mario Schüttel

rubocop-rails

rubocop 0.72.0 removes all Rails cops, since they “[…] want RuboCop to be focused just on Ruby […]” (and I agree with them), see PR #5976.

In order to use the Rails cops after rubocop 0.72.0, we need to add rubocop-rails gem and require it as a dependency in .rubocop.yml:

require:
  - rubocop-rails
2019-07-29 by Mario Schüttel

Enumerable#grep

Ruby enumerables respond to grep. You can use it to quickly filter a collection with a regular expression.

['Marta', 'Mario', 'Bill'].grep(/Ma/)
# => ['Marta', 'Mario']
2019-07-12 by Dimiter Petrov

Update nested maps in Elixir

Being a functional programming language, Elixir is a bit different from other languages when it comes to update a nested data structure.

For example, in javascript we could do:

data = {
  inner: {
    one: {
      a: 1
    },
    two: {
      b: 45
    }
  }
}

data.inner.one.a = 2

In Elixir you have to build a new map with the updated information, for example:

data = %{
  inner: %{
    one: %{
      a: 1
    },
    two: %{
      b: 45
    }
  }
}

new_one = %{data.inner.one | a: 2}
new_inner = %{data.inner | one: new_one}
new_data = %{data | inner: new_inner}

which is not very handy.

In other functional languages like Haskell, there are libraries like Lenses that aims to solve the problem. In Elixir the kernel have an put_in function that acts in a similar way:

data = put_in(data, [:inner, :one, :a], 2)

You can find other similar functions in the Kernel documentation

2019-06-13 by Tiziano Puppi

The query function in Ecto Repo (Elixir)

There is a hidden function in Ecto which is the function query in the Repo module.

This is a wrapper around the Ecto.Adapters.SQL.query and it is injected in the Repo module of your application. It can be called in this way:

MyApp.Repo.query("SELECT * FROM mytable")

This function can also take an array of query parameters like:

MyApp.Repo.query("""                                           
SELECT * FROM mytable
WHERE id = $1
""", [42])

This is quite handy when you need to debug in production, and there is no database client available.

2019-06-07 by Tiziano Puppi

Union, Difference and Intersect with Ruby Arrays

Union

> [:a, :b, :c].union([:b, :c, :d])
 => [:a, :b, :c, :d]

Difference

> [:a, :b, :c].difference([:b, :c, :d])
 => [:a]

Intersect

> [:a, :b, :c] & [:b, :c, :d]
 => [:b, :c]
2019-06-07 by Mario Schüttel

The sample output HTML element

There is an HTML element called <samp> meant for representing computer program output. The specification document has this humorous example:

<p>The computer said <samp>Too much cheese in tray
two</samp> but I didn't know what that meant.</p>