Comparing plain old Ruby objects

Try Google-ing for <=> it not very helpful. It’s the spaceship method, I can never remember that. So in my case I had a custom classes representing a remote resource and I needed to compare if these objects were similar based on their id. If you compare object == other_object, they won’t be the same because they are different objects in memory. You could write…

class Tentacle
  def ==(other)
    self.id == other.id
  end
end

..but what about >, >=, <, <=, !=, etc. Comparable covers all of this.

class Tentacle
  include Comparable
  def <=>(other)
    self.id <=> other.id
  end
end

…but what if the object you’re comparing against is an instance of another class?

class Tentacle
  def <=>(other)
    return nil unless other.is_a?(self.class)
    self.id <=> other.id
  end
end

And that was the day that was.

Test expiry of a PEM Certificate

Want to test the expiry of PEM Certificate?

Robs-iMac:something roblacey$ openssl x509 -enddate -noout -in config/certificates/ios/production.pem
notAfter=Apr 21 16:55:18 2017 GMT

Nice.

RangeError (2918996727 is out of range for ActiveModel::Type::Integer with limit 4):

If you’re attempting to store an IP as an Integer in MySQL, you’ll find that an Integer just isn’t enough. I hadn’t noticed for a few days and came home to a log file full of

RangeError (2918996727 is out of range for ActiveModel::Type::Integer with limit 4):

Easily fixed.

Database changed
MariaDB [robl]> ALTER TABLE fossa_logs MODIFY ip bigint(20) NULL;
Query OK, 209 rows affected (0.03 sec)             
Records: 209  Duplicates: 0  Warnings: 0

Encoding::CompatibilityError: incompatible character encodings: UTF-8 and ASCII-8BIT

Comparison of a UTF-8 string and an ASCII-8BIT string fails.

2.2.2 :031 > "∞".force_encoding('UTF-8').include?("∞".force_encoding('ASCII-8BIT'))
Encoding::CompatibilityError: incompatible character encodings: UTF-8 and ASCII-8BIT
	from (irb):31:in `include?'
	from (irb):31
	from /Users/roblacey/.rvm/gems/ruby-2.2.2@upgrade-ruby2/gems/railties-3.2.22/lib/rails/commands/console.rb:47:in `start'
	from /Users/roblacey/.rvm/gems/ruby-2.2.2@upgrade-ruby2/gems/railties-3.2.22/lib/rails/commands/console.rb:8:in `start'
	from /Users/roblacey/.rvm/gems/ruby-2.2.2@upgrade-ruby2/gems/railties-3.2.22/lib/rails/commands.rb:41:in `<top (required)>'
	from script/rails:6:in `require'
	from script/rails:6:in `<main>'

Docker innit...

##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
           \______ o           __/
             \    \         __/
              \____\_______/


docker is configured to use the default machine with IP 192.168.99.100
For help getting started, check out the docs at https://docs.docker.com

Robs-MBP:pledge_core rl$ docker run hello-world
Unable to find image 'hello-world:latest' locally
Pulling repository docker.io/library/hello-world

03f4658f8b78: Pull complete 
a3ed95caeb02: Pull complete 
Digest: sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
Status: Downloaded newer image for hello-world:latest

Hello from Docker.
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
 https://hub.docker.com

For more examples and ideas, visit:
 https://docs.docker.com/userguide/

Just testing what’s now running.

Robs-MBP:pledge_core rl$ docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER    ERRORS
default   *        virtualbox   Running   tcp://192.168.99.100:2376           v1.10.1 

upgrading Rails 3 to Rails 4 and try

In a Rails project I am using the ZendeskAPI gem to integrate with Zendesk. It’s a simple integration with Hash-like objects representing the remote data.

e.g. ZendeskAPI::User #- is a kind of Hash with magic methods

Subtle differences between Rails 3 and 4 make Jack a dull boy.

Rails 3

# just calls send on source if it is not nil
user.try(:id)
def try(*a, &b)
  if a.empty? && block_given?
    yield self
  else
    __send__(*a, &b)
  end
end

Rails 4

# just calls send on source if it isn’t nil and responds to ‘id'
user.try(:id)
def try(*a, &b)
  try!(*a, &b) if a.empty? || respond_to?(a.first)
end

user can potentially be nil at any point we when we call try on it, it will always return nil because the ZendeskAPI::User does not respond to the those methods. So in cases where you might be overriding method_missing try most certainly won’t work.

However, ‘try’ takes a block…so I discovered quite by accident that I can do this instead

source.try(&:id)

This works because if the first argument is empty it simply instance_evals the block I gave it, which calls ‘id’. And relax.

The Mad Katter - Boardgame Cafes Interactive Map

A really nice little project http://www.themadkatter.co.uk/cafes not to mention give us a clue on where to go on holiday next.

Calling rake task within other rake tasks

and blocking non-test environments for safety…

namespace :db do
  desc 'Rebuild test database and load seeds'
  task rebuild: [:environment] do
    fail ArgumentError, 'Test Environment required' unless Rails.env.test?
    Rake::Task['db:drop'].invoke
    Rake::Task['db:create'].invoke
    Rake::Task['db:schema:load'].invoke
    Rake::Task['db:migrate'].invoke
    Rake::Task['db:seed'].invoke
  end
end

Can't install Ruby 2.3.0 because of CURL

deployer@www:~$ rvm reinstall ruby-2.3.0
ruby-2.3.0 - #removing src/ruby-2.3.0..
ruby-2.3.0 - #removing rubies/ruby-2.3.0..
Searching for binary rubies, this might take some time.
Found remote file https://rubies.travis-ci.org/ubuntu/14.04/x86_64/ruby-2.3.0.tar.bz2
Checking requirements for ubuntu.
Requirements installation successful.
ruby-2.3.0 - #configure
ruby-2.3.0 - #download
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
curl: (60) SSL certificate problem: self signed certificate in certificate chain
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.
/home/deployer/.rvm/scripts/fetch: line 105: log: command not found
Checking fallback: ftp://rubies.travis-ci.org/ubuntu/14.04/x86_64/ruby-2.3.0.tar.bz2?rvm=1.26.11
Checking fallback: http://www.mirrorservice.org/sites/rubies.travis-ci.org/ubuntu/14.04/x86_64/ruby-2.3.0.tar.bz2?rvm=1.26.11
No fallback URL could be found, try increasing timeout with:

    echo "export rvm_max_time_flag=20" >> ~/.rvmrc

Downloading https://rubies.travis-ci.org/ubuntu/14.04/x86_64/ruby-2.3.0.tar.bz2 failed.
Mounting remote ruby failed with status 2, trying to compile.
Checking requirements for ubuntu.
Requirements installation successful.
Installing Ruby from source to: /home/deployer/.rvm/rubies/ruby-2.3.0, this may take a while depending on your cpu(s)...
ruby-2.3.0 - #downloading ruby-2.3.0, this may take a while depending on your connection...
ruby-2.3.0 - #extracting ruby-2.3.0 to /home/deployer/.rvm/src/ruby-2.3.0....
ruby-2.3.0 - #configuring..........................................................
ruby-2.3.0 - #post-configuration..
ruby-2.3.0 - #compiling.................................................................................
ruby-2.3.0 - #installing...........................
ruby-2.3.0 - #making binaries executable..
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.
There was an error while trying to resolve rubygems version for 'latest'. 
Halting the installation.

I am pretty sure the last this happened I had to apt-get install ca-certificates.

Ah, just skipping secure check finally did it.

echo insecure >> ~/.curlrc

Benchmarking String Matching in Ruby

I am very prone to writing string matching as ‘string’.match(/ing/), which is very readable, however it is not always necessary to capture the matching part of the string. Having seen alternative syntax from a colleague I’ve used the following benchmark to test what is the most efficient syntax/method.

Robs-iMac:benchmarks$ irb
2.2.2 :001 > require 'benchmark'
 => true 
2.2.2 :002 > 
2.2.2 :003 >   "cloudfront.net" =~ /cloudfront/
 => 0 
2.2.2 :004 > 
2.2.2 :005 >   Benchmark.measure{ 1000000.times { "cloudfront.net" =~ /cloudfront/ } }
 => #<Benchmark::Tms:0x007fdea2288ee8 @label="", @real=0.30020256410352886, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.30000000000000004, @total=0.30000000000000004> 
2.2.2 :006 > 
2.2.2 :007 >   "cloudfront.net"[/cloudfront/]
 => "cloudfront" 
2.2.2 :008 > 
2.2.2 :009 >   Benchmark.measure{ 1000000.times { "cloudfront.net"[/cloudfront/] } }
 => #<Benchmark::Tms:0x007fdea24785a0 @label="", @real=0.36411550105549395, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.36, @total=0.36> 
2.2.2 :010 > 
2.2.2 :011 >   "cloudfront.net".match(/cloudfront/)
 => #<MatchData "cloudfront"> 
2.2.2 :012 > Benchmark.measure{ 1000000.times { "cloudfront.net".match(/cloudfront/) } }
 => #<Benchmark::Tms:0x007fdea2350920 @label="", @real=0.967038004193455, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.9600000000000001, @total=0.9600000000000001>

I would appear that =~ is the outright winner, being at least three times faster. Keeping an eye out for unnecessary overuse of .match from now on. Referencing Stack Overflow http://stackoverflow.com/questions/11887145/fastest-way-to-check-if-a-string-matches-or-not-a-regexp-in-ruby