did_you_know.ruby?
ivo anjo
ruby ninja @ talkdesk

follow along @

https://tinyurl.com/i-cant-read-from-here

Let's talk function arguments
get_contacts(10, true)



...?
deleted?
active?
with_phone?
page?
limit?
Documentation!!!
get_contacts(
  start_from: 10,
  has_address: true,
)
get_contacts(10, true)



Less derping/bugs!!!
get_contacts(true, 10)



?????

Extensibility!!!
get_contacts(10, true,
  nil, nil, :married)

??????????

When to use
...my rules of 👍
• Hey! A bullet point
• Face it: you **were**
  beginning to miss them
Now srsly
Methods from other classes •
Whenever **helpful** in •
private methods  
How to code 'em
def get_contacts(options = {})
  start_from = 
    options.fetch(:start_from)
  has_address = 
    options.fetch(:has_address)
Ruby >= 2.1

 

 
Kudos to the ones already updated, you rock guys!
def get_contacts(
  start_from:, has_address: true)
required
optional
Variable Args?
def get_contacts(
  start_from:, has_address: true,
  **options)
get_contacts(start_from: 10,
  foo: 'yes')
not allowed without **
Yes, you can (still) do this!
def get_contacts(**options)
  start_from = 
    options.fetch(:start_from)
avoid unless you really need to
And it has a name!
**double splat**
You can combine with positional stuff
def print_hello(name, language:)
  # ...
end

print_hello('Joe',
  language: 'en_US')
The most complex method signature you will ever see
def foo(a, *b, c = true, d:,
  e: true, **f, &block)
a ➡️ required positional
b ➡️ vararg positional
c ➡️ optional positional
The most complex method signature you will ever see
def foo(a, *b, c = true, d:,
  e: true, **f, &block)
d ➡️ required keyword
e ➡️ optional keyword
f ➡️ vararg keyword
The most complex method signature you will ever see
def foo(a, *b, c = true, d:,
  e: true, **f, &block)
block ➡️ duh
def foo(a, *b, c = true, d:,
  e: true, **f, &block)
foo('a', 'b1', 'b2', 'b3', false,
  d: 'd', e: false, f1: 'f1',
  f2: 'f2') do puts 'Hello!' end
a ➡️ 'a'
b ➡️ ['b1', 
    'b2', 'b3']
c ➡️ false
d ➡️ 'd'
e ➡️ false
f ➡️ {f1: 'f1', 
     f2: 'f2'}
These rules (mostly) apply to blocks too
def foo
  yield a:1
end

foo do |a:, b: 2|
  puts a + b
end
But wait, there's more!
class Foo
  def self.print(options = {})
    name = options.fetch(:name)
    puts name
  end
  def self.print_joe
    print(user: 'Joe')
  end
end
RSpec.describe Foo do
  describe '#print_joe' do
    it 'calls print' do
      expect(Foo).to \
        receive(:print).with(user:'Joe')
      Foo.print_joe
    end
  end
end
Yay, my spec passes!
Nevermind the code actually being broken
class Foo
  def self.print(options = {})
    name = options.fetch(:name)
    puts name
  end

  def self.print_joe
    print(user: 'Joe')
  end
end
Rspec knows kung-fu
...and keyword args
def self.print(name:)
  puts name
end
That brings me to rspec doubles
d = double('Foo', print: nil)

d.print(user: 'Joe')
...verifying doubles!
d = class_double('Foo',
      print: nil)

d.print(user: 'Joe')
Keyword args are just an example
Verifying doubles check number of positional args and if the method exists too. 
https://relishapp.com/rspec/rspec-mocks/v/3-4/docs/verifying-doubles
• instance_double
• class_double
• o hai, more bullets!?
IF YOU REMEMBER ANYTHING
(e.g. if you dozed off around the "Hello I'm Ivo" part)
Keyword arguments
&
Verifying doubles
Oh and I almost forgot to tell you can use splat like this
rgb = [:red,  :green,   :blue]
cmy = [:cyan, :magenta, :yellow]

colors =
  [:white, :black, *rgb, *cmy]

# colors is now 
[:white, :black, :red, :green,
 :blue, :cyan, :magenta, :yellow]
And you can use it on method calls too
def do_stuff(a, b, c)
  # ...
end

some_args = ['b', 'c']

do_stuff('a', *some_args)
You can do the same with the double splat
def do_stuff(a:, b:, c:)
  # ...
end

some_args =
  {b: "not_the_b's", c: 'c'}

do_stuff(a: 'a', **some_args)
Merging hashes like a sir
def build_event(data, meta)
  {**data, **meta}
end
But wait, there's more!
Pry is your friend!
To really confuse you, I'm going back to rspec again
class Bar
  def self.hello
    message = 
      ENV['MESSAGE'] || 'hello'
    puts message
  end
end
describe '#hello' do
  it 'prints hello' do
    expect(Bar).to \
     receive(:puts).with('hello')
    Bar.hello
  end
  it "when ENV['MESSAGE'] is set
    prints the mssage" do
    ENV['MESSAGE'] = 'hello world'
    expect(Bar).to \
      receive(:puts)
        .with('hello world')
    Bar.hello
  end
Nice! Time to open that PR
DAT TYPO
:(
Well I fixed it and re-ran the specs
Random spec ordering! ... :| ?


Well, how do I debug this???
Ask me for help :)
Let's try this again: Ask **rspec** for help
$ bundle exec rspec --bisect
Bisect started
Running suite to find failures... (0.16527
seconds)
Starting bisect with 1 failing example and 
1 non-failing example.
Checking that failure(s) are order-dependent
... failure appears to be order-dependent

Bisect complete! Reduced necessary non-fail
ing examples from 1 to 1 in 0.15835 seconds.

The minimal reproduction command is:
  rspec ./bar_spec.rb[1:1:1,1:1:2]
Especially useful when issue is cross-spec 
interference
AKA I know this example was a bit trivial.
I don't care :D
Pry is your friend
irb is dead to me
You can use it to debug too
require 'pry'; binding.pry
Inspect, interact, call, ...
ls -- list methods and variables
show-source: where does this come from, and what is it?
It has tab completion!
Such tabbing!
break/step/next/finish/continue/frame/...
...using pry-byebug
gem 'pry'

# <-- just add this to gemfile
gem 'pry-byebug'
rubular.com for all your regexp stuffies
Shiny stuff you can do with Ruby 2.3
foo = {a: {b: {c: {d: :foo}}}}

foo.dig(:a, :b, :c, :d) # ➡️ :foo
foo.dig(:erm, :oops, :derp)
  # ➡️ nil
# You can simplify this

foo && foo.bar && foo.bar.baz
# Using the safe navigation
# operator

foo&.bar&.baz
Ruby & Threads
• mri runs one thread at a time
• but you can still cause mayhem

Ruby & Threads
• be careful with threads and threaded webservers (puma)
• common mistake: require is *NOT* thread-safe -- don't use it in the middle of a method!!!!
• in concurrent-ruby we trust:
https://github.com/ruby-concurrency/concurrent-ruby
Oh and FYI on Rubies
• mri
• jruby
• jruby+truffle
• rubyomr
• rubinious
My bet's
on this one
Tired yet?
Friendly reminder:

Ruby 2.3.1 is out

Ruby < 2.1 is EOL 
UPGRADE YOUR RUBY
Get Elixir today
NEXT EPISODE
git
Thanks!
You guys r awesome



learned lots from y'all
Made with Slides.com