Today I Learned

A Hashrocket project

10 posts by nickpalaniuk @nikkypx

How Sinatra avoids polluting inheritance chain

When you open a new file:

[13] pry(main)> self
=> main
[14] pry(main)> self.class
=> Object

main is an instance of Object

An example: the Sinatra DSL

require 'sinatra'

get '/' do
  'Hello world!'
end

#get is put in main’s singleton class

[1] pry(main)> require 'sinatra'
=> true
[2] pry(main)> method(:get).source_location
=> .../sinatra-1.4.6/lib/sinatra/base.rb", 1987]
pry(main)> Object.new.get
NoMethodError: undefined method `get' for #<Object:0x007fc423d9ec18>

This is achieved by extending the singleton class of main.

from Sinatra:

extend Sinatra::Delegator

A simple example:

class Foo
  module DSL
    def foo
      'bar'
    end
  end
end

extend ::Foo::DSL

Ruby objects from YAML

For certain objects if the ISO8601 standard is followed, Ruby will create an instance instead of a string when parsing the value.

“A date can be represented by its year, month and day in ISO8601 order.”

For example:

post.txt

title: Updated
date: 2011-09-25
pry(main)> p = YAML.load(File.new('post.txt'))
=> {"title"=>"Updated", "date"=>#<Date: 2011-09-25 ((2455830j,0s,0n),+0s,2299161j)>}
pry(main)> p['date'].class
=> Date

http://yaml.org/YAML_for_ruby.html#date

Proc.new inside a method

Typically, you see blocks passed with yield:

def foo
  yield
end
foo { 1 + 1 }
=> 2

or with the explicit to proc (&block ) at the end of your method arguments:

def foo(&block)
  block.call
end
foo { 1 + 1 }
=> 2

Proc.new can be called without a block within a method and it will capture an attached block

def foo
  Proc.new.call
end

foo { 1 + 1 }
=> 2

Redefine #respond_to_missing with #method_missing

Initial attempt:

class User
  def method_missing(name, *args, &block)
    if "#{name}" =~ /foo/
      'exists'
    else
      super
    end
  end
end
> u = User.new
=> #<User:0x007fdf3b152c60>
> u.foo
=> exists
> u.method(:foo)
=> NameError: undefined method `foo' for class `User'
User.class_eval do
  def respond_to_missing?(name, include_private = false)
    "#{name}" =~ /foo/ || super
  end
end
> u = User.new
=> #<User:0x007ffcda847f90>
> u.method(:foo)
=> #<Method: User#foo>

ruby operators <, >, === etc.

ruby -v 2.2.2

Different implementations of some of these operators can be used to do some cool things.

The #< implementation on Module for example.

> Module < BasicObject
=> true

> Object < Class
=> false

#== and #=== are implemented the same on Fixnum or BigDecimal, but on Module

> a === b

evaluates to true if b is an instance of a or a’s descendants

> (1..10) === 5
=> true

> 5 === (1..10)
=> false

> 'str' === String
=> false

> String === 'str'
=> true

This is the case-equality operator and this behavior can be overridden to customize case statements. An example of overriding.

class Range
  def ===(o)
    puts 'nope sucka'
  end
end

case 5
when(1..10)
'This would normally work'
else
end
=> nope sucka

Quick .vimrc editing and sourcing

Vim will set the MYVIMRC environment variable to the path of your vimrc on startup. You can verify this by running

:! env | grep VIM

This gives us the ability to do quick vimrc editing after adding something like this in your vimrc.

nnoremap <leader>ev :vs $MYVIMRC<cr>
nnoremap <leader>sv :source $MYVIMRC<cr>

You could change the to horizontal split if want with :sp, but you get the idea. Don’t forget to source!