Category Archives: English

puma

Puma vs. Unicorn

TL; DR – You should start using Puma.

Rails has switched the default server from Webrick to Puma in Rails 5!

It also supports Action Cable (one of the new features from Rails 5) and Basecamp said they’re using Puma in production.

I was wondering if Puma has been in fact better than Unicorn so I’ve read some blog posts about it:

Basically, the answer is yes – it is a bit better, but don’t wait for a huge improvement. I’d say it might be a good idea if you’re:

  • about to start a new project;
  • about to migrate your current project to Rails 5;
  • unhappy with your Rails 3 / 4 app server performance.
database

Rake task to import a production DB dump

Every now and then I need to write a script (rake task) to import a production database dump.

This is code I usually use:

require 'yaml'

namespace :db do
  desc 'Downloads and imports a production DB dump'
  task :import_production_dump do
    puts '➙ Generating production DB dump...'

    execute_on_server %(
      PGPASSWORD="`cat /var/www/project/current/config/database.yml | \
        grep password | awk '{ print $2 }'`" \
        pg_dump database_name -h custom_url.rds.amazonaws.com -U user_name \
        --column-inserts --no-owner --no-privileges > backup.sql
    )

    puts '➙ Downloading production DB dump...'
    system "scp #{server_user_and_host}:#{backup_file_name} ."

    puts '➙ Deleting production DB dump...'
    execute_on_server 'rm backup.sql'

    puts '➙ Cleaning your local DB...'
    %w(drop create).each { |task| Rake::Task["db:#{task}"].invoke }

    puts '➙ Importing production DB dump...'
    system "bin/rails db development < #{backup_file_name} > /dev/null"

    puts '➙ Removing local dump...'
    system "rm #{backup_file_name}"

    puts '➙ Done!'
  end

  def execute_on_server(commands)
    system %(ssh -T #{server_user_and_host} << 'SSH'
      #{commands}
    SSH).split("\n").map(&:strip).join("\n")
  end

  def server_user_and_host
    'username@example.com'
  end

  def backup_file_name
    'backup.sql'
  end
end

Let me know in the comments if you have a better solution! Perhaps a tiny gem? ツ

Why I regenerated my SSH key and maybe you should too

security

I think we all agree it’s a good practice to regenerate your SSH key from time to time. Not sure about you, but the first thing that comes to my mind when I think about that is: it’d take forever to replace my key in all servers I need to access, all online services that use my key, etc.

Overcoming my laziness, I decided at least to list every place I’d have to update it. Interesting fact: it turned out that it was pretty much a small list:

  • Servers
  • Github
  • BitBucket
    • Although now it looks more reasonable, I was still lazy to do it. Then, a few days ago, I noticed that Github recommends the use of HTTPS instead of SSH for Git repositories syncs:

      Github - HTTPS vs SSH

      What does one thing have to do with another? Well, by using HTTPS, you don’t need to upload your SSH key to Github (check this out: mine isn’t longer at Github). BitBucket also supports it, which means I’d be able to regenerate my SSH key without having to upload it again to these services.

      Servers

      What’s left? Servers! From now on, every time I realise it’s time to regenerate my SSH key, all I need to update are the servers. I ended up making a list of servers that I’d need to update and found out in the end it wasn’t a big list and it’d be way easier than I thought it would.

      Let’s face the truth: I had been using the same SSH key in the last 5 years or so and it’d be totally worth it to ensure my security as well as the security of the projects from the company I work for.

      Becoming safer

      There’s more! This is the interesting part of this post: I’ve changed other things that made everything even safer:

      1. My new SSH key uses 4096 bitsrecommended by Github – instead of the default (2048 bits).
      2. As I mentioned before, I’ve changed all my local repositories to use HTTPS instead of SSH (see how in the end of this post).
      3. I’m now using a personal access token rather than my Github password (you can create it here), along with two-factor authentication, which I was already using.
      4. Cool, but would I need to type this token every time? Nope. There’s a nifty tool called ssh-agent that can save your token. If you’re using OS X, it’s even easier: Keychain can save and encrypt your token for you.
      5. My SSH key now has a passphrase, also saved encrypted in OS X’s Keychain, which means I don’t need to type it every time either.

      HTTPS is faster!

      According to some tests I made here, HTTPS is faster than SSH:

      # SSH
      $ time git clone git@github.com:rails/rails.git
      # 24.28s user 9.56s system 49% cpu 1:08.20 total
      
      # HTTPS
      $ time git clone https://github.com/rails/rails.git
      # 13.52s user 6.41s system 39% cpu 50.730 total
      

      In order to use HTTPS in my Git repos, do I need to re-clone every project?

      Nope. Just edit the file .git/config (within your project folder) and replace:

      url = git@github.com:username/repo.git

      with:

      url = https://github.com/username/repo.git

      Conclusion

      Regenerating your SSH key every now and then isn’t painful as you think it is. I’d recommend doing it every 3 years or even less if you’re paranoid or you work on something critic.

What is “frozen_string_literal” in Ruby?

ruby3

Freezing Strings feature improves apps performance by freezing Strings. So, Matz – Ruby’s creator – decided to make all String literals frozen (immutable) by default in Ruby 3.0.

In order to have a transition path to this coming big change, it was decided to have a magic comment at the beginning of files, so you can use in Ruby 2.3.

To do so, just add this comment in the first line of your files:

# frozen_string_literal: true

class YourClass
  # ...
end

Trying adding it to your spec_helper file and let me know in the comments if you performance improved!

More info: Ruby issue #8976.

If you really need to create a monkey patch, do it properly

Ruby

Sometimes we need to create a monkey patch for a gem or external lib.
In these cases, it’s good to force it to fail if the gem has been bumped up:

if Paperclip::VERSION != '1.2.3'
  # If you see this message, please test removing this file
  # If it's still required, please bump up the version above
  fail 'Please remove me, Paperclip version has changed'
end

If the gem doesn’t provide you the version through a method, you can solve it with:

if Bundler.load.specs.find { |gem| gem.name == 'paperclip' }.version.to_s != '1.2.3'
  # If you see this message, please test removing this file
  # If it's still required, please bump up the version above
  fail 'Please remove me, Paperclip version has changed'
end

Or even when you’re waiting for a new Rails version, e.g.:

fail 'Remove this file' if Rails::VERSION::MAJOR >= 5

Ps.: Paperclip gem was just an example :-)

Measuring and improving your Rails app quality

I’ve just written a blog post on the NetEngine’s blog:

http://netengine.com.au/blog/measuring-and-improving-your-rails-app-quality/

I hope you enjoy it.

CampJS 2014 – the best nerd event I ever attended

A few days ago I was in CampJS, the best nerd event I ever attended.

campjs

This is the official website (which is pretty nice by the way): http://campjs.com/.

Why it was the best in my opinion:

  • It happened in an amazing place – to be near of the nature, changing the usual environment is renewable. I definitely recommend to try it.
  • I had the chance to talk to a lot of other Javascript developers
  • Awesome talks and workshops
  • Good food and beers
  • A live podcast was recorded in there

A friend of mine (@erikEcoologic) have written an awesome blog post about the event, so go check it out! ;)

A special thanks to @brucestronge and to NetEngine for the tickets!

Video & some pictures

IMG_0

IMG_1067

IMG_1099

IMG_1199

IMG_1202

IMG_1206

IMG_1267

How to use command line on Mac OS X

A friend of mine (who came from Windows world) have bought a Mac recently and he asked me how to use command line on Mac OS X:

My answer was:

1) 99% of commands are identical in Linux. This is good news as there are a lot of material about it available on the Internet;

2) Terminal.app from OS X is cool, but it’s not perfect. I (and 90% of developers I know) use iTerm2 (http://iterm2.com/). It’s light (3mb), free, open-source, has a better interface than the native one and it rocks! Best terminal I’ve ever used.

3) This is the most useful topic in my answer: an awesome cheat-sheet with command line commands made by the Git-tower team;

4) To finish: I’ve recorded a screencast showing up how to create scripts in OS X and Linux (similar to BAT file in Windows). Unfortunately this is only available in portuguese:

What do I have in the OS X’s menu bar?

menubar

Application Description Type
Caffeine Prevent your Mac from automatically going to sleep, dimming the screen or starting screen savers Free
ColorSnapper Color picker Paid
1Password Password manager Paid
Dropbox File hosting service Free / Paid
CrashPlan Online data backup in real time Paid
Spectacle Window control Free / Open source
Evernote I love Evernote, but I don’t use this icon for anything.
When I close it, it returns automatically ¯\_(ツ)_/¯
Free / Paid
Chrome notifications I never really use it, but I guess there’s no way to remove it though Free
Text Expander Custom keyboard shortcuts into frequently-used texts Paid
AirPlay Play content on your TV via Apple TV Free
Time Machine Built-in backup feature of OS X that works with an external HD or Time Capsule Free

An awesome Wiki built with Ruby and Rails!

I’ve been worked on a small (but awesome) open-source project.

I’m talking about ruby_wiki – a simple wiki built with Ruby on Rails:
https://github.com/lucascaton/ruby_wiki

As I said before – it’s quite simple, although it works fine.
Anyway, would be nice to have more features in this project, so, if you’re a developer and have any interest in that, feel free to fork the project and contribute.

Some screenshots:


1


2


3


4


5


6

Have a Rails 2 app? You can run it on the newest Ruby!

old_rails_with_new_ruby

Do you have a legacy Rails application which is still running on Rails 2?

There are several reasons to migrate your application to new Rails versions, like to improve the security, to be able to use a better syntax, to take advantage of new features and also because most of current gems will only work on Rails 3 or higher. However, sometimes it’s hard to do that, especially for big projects. And certainly today there’re many project still running on Rails 2.

But there’s one good thing you can (and should) do! I’m talking about to use the newest Ruby version. Yes, I’m serious. When I wrote this post, the current Ruby version was 2.1.1 – and it’s not so hard to get it working fine with Rails 2.

Obviously, would be better if you have a good test coverage.

That said, let’s do it in a few steps:

Replacements

1. Gemfile

Rails 2 apps don’t use Bundler by default, so if you don’t have Bundler managing your gems yet, you should check here how to do that.

# There's no way to ensure that next Ruby versions will work,
# but so far the current one works fine:
ruby '2.1.1'

# The same for rake:
rake '10.1.1'

# You might need the iconv gem:
gem 'iconv'

2. Rakefile

# Replace:
# require 'rake/rdoctask'

# with:
require 'rake/task'

3. config.ru

# Replace:
# require 'config/environment'

# with:
require File.dirname(__FILE__) + '/config/environment'

4. FasterCSV => CSV

Replace all FasterCSV constant with CSV. Also, include require 'csv' to relevant files (or include this require to config/environment.rb).

Inclusions

5. config/environment.rb

# Include this before the `Rails::Initializer.run` line:
if RUBY_VERSION >= '2.0.0'
  module Gem
    def self.source_index
      sources
    end

    def self.cache
      sources
    end

    SourceIndex = Specification

    class SourceList
      # If you want vendor gems, this is where to start writing code.
      def search(*args); []; end
      def each(&block); end
      include Enumerable
    end
  end
end

6. config/initializers/paperclip.rb

# The patches below are needed when using an old version of PaperClip + Ruby 2.x
# https://github.com/thoughtbot/paperclip/issues/262
# https://github.com/thoughtbot/paperclip/commit/1bcfc14388d0651c5fc70ab9ca3511144c698903

module Paperclip
  class Tempfile < ::Tempfile
    def make_tmpname(basename, n)
      extension = File.extname(basename)
      sprintf('%s,%d,%d%s', File.basename(basename, extension), $$, n.to_i, extension)
    end
  end
end

module IOStream
  def to_tempfile
    name = respond_to?(:original_filename) ? original_filename : (respond_to?(:path) ? path : 'stream')
    tempfile = Tempfile.new(['stream', File.extname(name)])
    tempfile.binmode
    self.stream_to(tempfile)
  end
end

New files

7. config/initializers/ruby2.rb

# This is a very important monkey patch to make Rails 2.3.18 to work with Ruby 2+
# If you're thinking to remove it, really, don't, unless you know what you're doing.

if Rails::VERSION::MAJOR == 2 && RUBY_VERSION >= '2.0.0'
  module ActiveRecord
    module Associations
      class AssociationProxy
        def send(method, *args)
          if proxy_respond_to?(method, true)
            super
          else
            load_target
            @target.send(method, *args)
          end
        end
      end
    end
  end
end

8. config/initializers/rails_generators.rb

It’ll prevent Rails migration generator from stop working, otherwise you’ll receive the following error message:

undefined local variable or method `vars' for #<Rails::Generator::Commands::Create

(Thanks Mr. S and jnwheeler44 for helping me to fix this one)

# This is a very important monkey patch to make Rails 2.3.18 to work with Ruby 2+
# If you're thinking to remove it, really, don't, unless you know what you're doing.

if Rails::VERSION::MAJOR == 2 && RUBY_VERSION >= '2.0.0'
  require 'rails_generator'
  require 'rails_generator/scripts/generate'

  Rails::Generator::Commands::Create.class_eval do
    def template(relative_source, relative_destination, template_options = {})
      file(relative_source, relative_destination, template_options) do |file|
        # Evaluate any assignments in a temporary, throwaway binding
        vars = template_options[:assigns] || {}
        b = template_options[:binding] || binding
        # this no longer works, eval throws "undefined local variable or method `vars'"
        # vars.each { |k, v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
        vars.each { |k, v| b.local_variable_set(:"#{k}", v) }

        # Render the source file with the temporary binding
        ERB.new(file.read, nil, '-').result(b)
      end
    end
  end
end

RSpec

9. Make sure you’re using the last compatible version with Rails 2.3.18:

gem 'rspec', '1.3.2'
gem 'rspec-rails', '1.3.4'

10. Remove the file script/spec.

11. lib/tasks/rspec.rake

Remove all the following lines:

gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9
rspec_gem_dir = nil

Dir["#{Rails.root}/vendor/gems/*"].each do |subdir|
  rspec_gem_dir = subdir if subdir.gsub("#{Rails.root}/vendor/gems/","") =~ /^(\w+-)?rspec-(\d+)/ && File.exist?("#{subdir}/lib/spec/rake/spectask.rb")
end

rspec_plugin_dir = File.expand_path(File.dirname(__FILE__) + '/../../vendor/plugins/rspec')

if rspec_gem_dir && (test ?d, rspec_plugin_dir)
  raise "\n#{'*'*50}\nYou have rspec installed in both vendor/gems and vendor/plugins\nPlease pick one and dispose of the other.\n#{'*'*50}\n\n"
end

if rspec_gem_dir
  $LOAD_PATH.unshift("#{rspec_gem_dir}/lib")
elsif File.exist?(rspec_plugin_dir)
  $LOAD_PATH.unshift("#{rspec_plugin_dir}/lib")
end

Ruby syntax

12. Some details has been changed in Ruby syntax, especially from 1.8.x to 1.9.x.

Example 1:

# Replace:
when 'foo': bar

# with:
when 'foo' then bar

Example 2:

The behaviour for protected methods in new Ruby versions is a little bit different. See more in this post.

# In some cases, you might need to replace:
respond_to?(:foobar)

# with:
respond_to?(:foobar, true)

Example 3 (Yaml files):

# Replace:
order: [ :day, :month, :year ]

# with:
order:
  - :year
  - :month
  - :day

Ruby changes

13. The default encoding for Ruby 2.0 (or higher) is UTF-8. So, remove all the code similar to:

# encoding: utf-8

Or:

$KCODE = 'UTF-8'

Important note (included on July 27, 2014)

Check below the comments of this post — Gabriel Sobrinho, Kyle Ries and Greg made some very interesting and useful comments.

Conclusion

Each project could have different issues.
But I hope this little guide helps you to use new Ruby versions in legacy Rails applications!

How to improve your software development team’s communication

I’ve just written another post on the NetEngine’s blog:

http://netengine.com.au/blog/how-to-improve-your-software-development-team-s-communication/

I hope you enjoy it.

Agile methodologies for software development

Yesterday, I wrote my first blog post on the NetEngine blog:

http://netengine.com.au/blog/agile_methodologies_for_software_development/

I hope you enjoy it.

Interesting script written in Ruby: “The Globe”

Minutes ago I received this link from some friends. It’s very interesting (and crazy).

Create an empty ruby file, paste this content and save as a.rb.

v=0000;eval$s=%q~d=%!^Lcf<LK8,                  _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC       "%.#%  :::##"       97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B     "##%      ::##########"     O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y?    "##:         ###############"    g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W    "#            #.   .####:#######"    lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<.   "              ##### # :############"   R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5   "              #######################"   00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ   "              ############:####  %#####"   EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q   "              .#############:##%   .##  ."   /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!;  " %%            .################.     #.   "  ;s="v=%04o;ev"%
(;v=(v-($*+[45,  ":####:          :##############%       :   "  ])[n=0].to_i;)%
360)+"al$s=%q#{  "%######.              #########            "  ;;"%c"%126+$s<<
126}";d.gsub!(/  "##########.           #######%             "  |\s|".*"/,"");;
require"zlib"||  "###########           :######.             "  ;d=d.unpack"C*"
d.map{|c|n=(n||  ":#########:           .######: .           "  )*90+(c-2)%91};
e=["%x"%n].pack   " :#######%           :###### #:          "   &&"H*";e=Zlib::
Inflate.inflate(   "  ######%           .####% ::          "   &&e).unpack("b*"
)[0];22.times{|y|   "  ####%             %###             "   ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(;   " .###:             .#%             "   ;2))*23).floor;(w*
2-1).times{|x|u=(e+    " %##                           "    )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[(    " #.                        "    ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count((     " .                   "     ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ (       "#  :#######"       ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe                  Copyright(C).Yusuke Endoh, 2010

After that, just run this script using:

while true; do clear; ruby a.rb | tee b.rb; sleep 0.2; mv -f b.rb a.rb; done

Hellо, I am a compiler

robot

I copied this little text from a comment on the Stackoverflow website. I really enjoyed it ;)

Hellо, I am a compiler.
I just scanned thousands of lines of code while you were reading this sentence. I browsed through millions of possibilities of optimizing a single line of yours using hundreds of different optimization techniques based on a vast amount of academic research that you would spend years getting at. I won’t feel any embarrassment, not even a slight ick, when I convert a three-line loop to thousands of instructions just to make it faster. I have no shame to go to great lengths of optimization or to do the dirtiest tricks. And if you don’t want me to, maybe for a day or two, I’ll behave and do it the way you like. I can transform the methods I’m using whenever you want, without even changing a single line of your code. I can even show you how your code would look in assembly, on different processor architectures and different operating systems and in different assembly conventions if you’d like. Yes, all in seconds. Because, you know, I can; and you know, you can’t.

P.S. Oh, by the way you weren’t using half of the code you wrote. I did you a favor and threw it away.

Getting root permissions on a file inside of Vim

Sometimes you open a file that you need root permissions to save it.
When it happen, you can close and reopen the Vim (with sudo) or you also can do:

:w !sudo tee %

Thanks to @dlisboa for the tip.

A simple way to deploy your Rails applications

Sometimes I prefer to use a simpler way to deploy my Rails applications instead of install and configure some complex tool (eg.: capistrano).

A very simple way to do this is creating a shell script within the /script directory, which will access the server via SHH:

#! /bin/bash
# script/deploy.sh

TAG=deployed_at_$(date +"%F_%H-%M")
git tag -m '' -a $TAG
git push --tags

ssh user@your_domain.com << 'SSH'
  cd /var/rails_apps/my_app
  rm -rf public/assets
  git pull
  bundle install --without development test
  bundle exec rake db:migrate db:seed assets:clean assets:precompile
  touch tmp/restart.txt
  git describe > public/version
SSH

After that, a tag will be created in the git repository. Now, you know exactly the date and time when it was deployed.

And you can find out which version (tag from git) is in production accessing the URL your_domain.com/version.

your_domain

Update on March 8, 2013:

I’ve created another script which accepts the -q param (quick).
https://gist.github.com/lucascaton/5118852

An easy way to split windows in Vim

There are several ways to split windows in Vim. This one is what I prefer:

cell-division

How to test ElasticSearch in a Rails application

Since I started using ElasticSearch in my Rails applications, I had a problem to create separate indexes for the automated tests.

The problem is: there is no way to create more than one database in ElasticSearch. You can create different indexes, but no different databases. But creating indexes with different names doesn’t solve the problem: it’s necessary to configure our Rails models in order to work with a different index name when the tests is running.

I’m using the tire and RSpec gems and in this post, I’ll explain how to separate indexes for development and test environments.

First of all, I’ve included the code below in file config/initializers/tire.rb:

if Rails.env.test?
  prefix = "#{Rails.application.class.parent_name.downcase}_#{Rails.env.to_s.downcase}_"
  Tire::Model::Search.index_prefix(prefix)
end

And I set manually the index name in the model (assuming that there is a Movie model):

index_name "#{Tire::Model::Search.index_prefix}movies"

Done! After that, when your application is running in development environment, the name of indexes will be “movies”. But if it’s in the test environment, the name of indexes will be “appname_test_movies” and then the tire gem and your models can perform the search with different indexes!

Deleting test indexes

In order to delete the test indexes after the suite has finished running, just add the following code to file spec/integration_helper.rb (or similar):

RSpec.configure do |config|
  config.after(:all, type: :request) { delete_movie_index }
end

And create a custom macro, which will delete the indexes:

def delete_movie_index
  Movie.index.delete
end

Demo app

I created a small application to demonstrate the technique explained in this post:
https://github.com/lucascaton/elasticsearch_app_example

I hope this has been helpful!

Pair programming with tmux

Server:

tmux -2 -S /tmp/pair new-session -s PairProgramming
chmod 777 /tmp/pair

Client:

tmux -2 -S /tmp/pair attach-session -t PairProgramming

Replacing “Selenium” with “Poltergeist”

Poltergeist

My friend @pellegrino give me an awesome tip: to replace “Selenium” with “Poltergeist”. For those who don’t know, Poltergeist is a PhantomJS driver for Capybara. I’ve done it in some projects and it works so well!

So, let’s do it:

Include the gem to your Gemfile:

gem 'poltergeist'

Update Capybara configuration:

Capybara.configure do |config|
  # config.javascript_driver = :selenium
  config.javascript_driver = :poltergeist
end

Run the specs!

If you are testing some confirm() javascript method and you have a code similar to page.driver.browser.switch_to.alert.accept, you’ll got this error:

undefined method `switch_to'

While I was trying to fix it, I find out that Poltergeist always returns true from window.confirm. There’s no way (at the moment) to make it return false, but it should not prevent your test from running.

So, I just removed that line and it worked fine!

This is the improvement from the first project I’ve done it:

Before:
Finished in 1 minute 35.45 seconds

After:
Finished in 41.03 seconds

Hope that can be useful for you!

RSpec profiling

In order to find out the slowest specs, just add to .rspec file:

--profile

RSpec will show the top 10 slowest examples!

My dotfiles

Finally I created a repository with my dotfiles.

Dotfiles are configurations files, usually with their names beginning with a dot (hidden files) and located in your home directory (~/).

The repository is: https://github.com/lucascaton/dotfiles

Check the instructions in the link above, in order to get the dotfiles.

The dotfiles are focused on the Ruby language, but there’s also Git and PostgreSQL configuration files. I’ve included files as .bash_profile, .gitconfig, .irbrc (using pry), .pryrc, .psqlrc and .rvmrc. There is also a list of ruby gems (file “default.gems”).

My vimfiles can be found at: https://github.com/lucascaton/vimfiles

I have tested it only in OSX 10.7, but it should work in any *nix without problems.

Regex to match Youtube URLs (using Ruby)

I created a regular expression in order to match Youtube URLs.

Currently, the most common URLs from Youtube are http://youtube.com and http://youtu.be:

/^(?:https?:\/\/)?(?:www\.)?youtu(?:\.be|be\.com)\/(?:watch\?v=)?([\w-]{10,})/

This regex will match:

  • http://youtube.com/watch?v=1234567890
  • https://youtube.com/watch?v=1234567890
  • http://www.youtube.com/watch?v=1234567890
  • http://www.youtube.com/watch?v=12345-67890
  • https://www.youtube.com/watch?v=1234567890
  • http://youtu.be/1234567890
  • https://youtu.be/1234567890
  • http://www.youtu.be/1234567890
  • https://www.youtu.be/1234567890
  • http://www.youtube.com/watch?v=1234567890&feature=context&context=G2de15aaFAAAAAAAAAAA
  • www.youtube.com/watch?v=1234567890
  • youtube.com/watch?v=1234567890
  • youtu.be/1234567890

And won’t match:

  • youtube.com
  • youtube.com/
  • youtube.com/watch
  • youtube.com/watch/
  • youtu.be
  • youtu.be/