Hardscrabble šŸ«

By Maxwell Jacobson

See also: the archives and an RSS feed

integrating vim with the mac clipboard

July 30, 2016

Using terminal text editors has a lot of advantages, but for a while the biggest disadvantage I’ve felt as a vim user is that it’s kind of hard to interact with the system clipboard. I’m aware that there’s a concept called ā€œregistersā€ which are something like multiple clipboards that you can copy and paste from, and one of them is the system clipboard, and the others are all virtual, or something like this, but I haven’t taken the time to really learn how those work yet.

If I want to copy a helpful code snippet from Stack Overflow into vim and I copy it to the mac clipboard, and then press ā€œcommand + vā€ to paste it into vim, the indentation gets totally screwed up. This is becuse vim is trying to help. It doesn’t know that I just pasted, it thinks that I was suddenly just typing super super fast and each newline character I ā€œtypedā€ caused it to helpfully auto-indent the appropriate amount. When I actually am typing, this is helpful. But when I’m pasting, it’s kind of annoying.

Pasting into vim doesn't work well

(You can see in this example that not only is the indentation screwed up, but also there is an extra end which vim-endwise helpfully tried to auto-insert)

The workaround I’ve used for a while is to always run :set paste before I paste, and then :set nopaste afterward. This mode doesn’t auto-indent. It also breaks a number of my other vim configurations, such as jk being an alias for the escape key.

Pretty annoying.

Copying text out of vim is even more difficult. I can use my mouse to highlight the text I want to copy and then press ā€œcommand + cā€ to copy it, but this is pretty awful, too, because it’s very easy to accidentally copy things like line numbers (which are just text in the terminal, and your mouse doesn’t know to avoid it) or to even copy text from multiple files which you happen to have open side by side in split buffers, such that the code is totally broken when you paste it out again.

Copying from vim split buffer doesn't work well

My workaround for this is even worse! I generally close my splits, turn off line numbers (:set nonumber) and sometimes make my font smaller so I can fit the whole lines on my screen and select the text and copy it. When I do this, I generally pick up a bunch of trailing whitespace that wasn’t there in the source code. It totally stinks.

Sometimes I will just open the file in Atom so I can copy text in a sane way.

Other times I will run :! cat % | pbcopy to ā€œshell outā€ to a bash command and copy the entire contents of the file to the clipboard.1

OK. So obviously that sucks, right? That’s just some context for how I’ve been doing things. I meant to look into a better technique and never got to it.

The other day at work I saw my coworker Will very seamlessly copy some text out of vim and paste it into Slack.

Scandalized, I asked him how he had done that. He told me he’s using neovim and it’s probably something neovim does.

I made a note to look into it. I’m open to the idea of using neovim instead of regular vim – I think it’s cool that you can run a terminal inside vim, which makes me wonder if I even need tmux…

One of the first things I found in my research was a neovim issue from April 2014 about how some vim configuration was working in vim but not neovim

… the follwing works perfectly fine with mainline vim, ā€œyā€ and ā€œpā€ work with X clipboard:

set clipboard=unnamedplus

but not for neovim.

I’ve tried setting it to:

set clipboard=unnamed

still works in vim, but not neovim.

Hm. Wait. Does this mean vim already supports clipboard integration this whole time and no one told me!?

Indeed, yes, and this is why I’m writing this blog post to tell you. I feel like there’s a good chance you already knew.

So yep, I added that second config option to my .vimrc and now it works great:

  • I can yank text from vim and then ā€œcommand + vā€ it into other apps.
  • I can copy text from Stack Overflow and then ā€œpā€ it into vim – no weird indentation behavior or anything

I may yet switch to neovim2 or learn about registers, but for now I don’t yet need to, and for that I celebrate.

  1. The ! means to run a bash command; the % will expand to refer to the file name; pbcopy is a mac thing for piping data to your clipboard.Ā 

  2. Note that neovim did fix that issue and it does work now.Ā 

the first useful thing I wrote in Rust

June 9, 2016

I’ve been interested in the Rust programming language for a while, but it wasn’t until this week that I wrote something in it which I found useful.

Let’s rewind. I like to have a random, nice emoji in my shell prompt. It’s just to add a little flair to the proceedings, some color. The emoji don’t mean anything, they’re just for fun.

My shell prompt is set like this:

PROMPT="%F{grey}%C%f \$(random_nice_emoji) \$(git_prompt) "

random_nice_emoji is a command line program on my PATH. git_prompt is a shell function. The \$(...) syntax means that the program or function should be called each time the prompt is drawn, not just once when you first open your terminal.

I could have written random_nice_emoji as a shell function if I could figure out how to use shell arays, but I could not.

Instead I wrote it as a simple ruby script:

#!/usr/bin/env ruby

print %w(
  šŸ–
  šŸ˜…
  🌸
  šŸ™
  šŸŽ‘
  šŸ–Œ
  ā˜•
  šŸ“Š
  šŸ‹
  🌈
  ✨
).sample

And my prompt looks like this:

my prompt, where each line includes a random fun emoji

But over time I noticed that it was kind of….. slow. And I started to wonder if maybe my fun affectation was worth it. Some benchmarking suggests that this program takes about a tenth of a second to run. That’s not a lot, really. But we can do better.

Maybe the shell function would be much faster, but yea, still don’t know how to use shell arrays.

So let’s try writing this little script as a Rust program – Rust is supposed to be fast!

To make a new command line program in Rust, you can use Cargo to scaffold the project:

cargo new random_nice_emoji --bin

The --bin part means that it will be a command line program. Without it, I think the idea is that you’re making a package which will be used in an application.

That command crates a directory called random_nice_emoji, and within that there is a file src/main.rs which is where you put your code which should run when the command line program is invoked.

Here’s what I came up with (I’m really new to Rust so this isn’t necessarily good code):

extern crate rand;
use rand::distributions::{IndependentSample, Range};

fn main() {
    // cool, friendly emoji that look fine against a black terminal background
    let list = vec!["šŸ–", "šŸ˜…", "🌸", "šŸ™", "šŸŽ‘", "šŸ–Œ", "ā˜•", "šŸ“Š", "šŸ‹", "🌈",
                    "✨"];
    let between = Range::new(0, list.len());
    let mut rng = rand::thread_rng();
    let index = between.ind_sample(&mut rng);
    let emoji = list[index];
    print!("{}", emoji);
}

I couldn’t find a super-simple sample method, so I did my best to adapt the example from the docs for the rand crate to achieve that behavior.

You can install it yourself with cargo install random_nice_emoji. Maybe I shouldn’t have released it because it’s not generally useful – but it’s very convenient for me so I can install it on multiple computers, for example.

And this one usually finishes in 0.006 seconds – 16 times faster. And it was maybe 5 times harder to write? I’m hopeful that if I get better at Rust, that will go down.

If you’re into Ruby and intrigured by Rust, I recommend checking out this Helix project which makes it easy to embed Rust code in Ruby projects to ease performance hot spots. I haven’t used Helix yet, but that talk does a really great job of explaining the idea and was really inspiring to me.

Fun method names in Ruby

June 8, 2016

One thing I like about Ruby is that you can use a little punctuation in your method names, which can help you write expressions that read like nice sentences:

delete_user user unless user.special?

Kind of fun.

I knew a guy who liked to use these question mark methods in conjunction with the ternary operator to write code that reads like a panicked friend:

user.special?? protect(user) : delete(user)

The double question mark always makes me smile, which makes me wonder… Can I just define a method with double question marks right in the method signature? Like this:

class User
  def special??
    name == 'Max'
  end
end

Turns out: nope. That’s a syntax error. Not valid Ruby code.

Well… OK. But this is Ruby, so there’s not just one way to do a thing. There’s another way to define a method… Let’s try this:

class User
  def initialize(name)
    @name = name
  end

  define_method("special??") do
    @name == 'Max'
  end

  define_method("multi
                line
                method
                name??") do
    puts "sure, why not?"
  end

  define_method("!?") do
    "‼"
  end
end

user = User.new("Max")
user.public_send("special??") #=> true
user.public_send("!?") #=> "‼"
user.public_methods(false) #=> [:"special??", :"multi\n                line\n                method\n                name??", :"!?"]

Haha that works!

OK it’s not as satisfying calling the methods with public_send, but as far as I know, it’s the only syntactically-correct way to call these methods.

Articulating my Vegetarianism

April 5, 2016

note: this is going to be sort of personal and self-indulgent and I’m mostly writing it for myself to work out some ideas and make some decisions

I’m writing this from vacation, in Mumbai. Last year, I googled ā€œbest vegetarian citiesā€ and Mumbai was near the top. New York City, where I live, was also near the top. It’s not a shock – New York has many specialty restaurants that focus on vegetarians and vegans, and almost any restaurant has something for me. But after spending a few days in Mumbai, I think it’s truer here.

In software, we sometimes talk about ā€œsensible defaultsā€. If you’re going to provide options to your user to change the behavior of your app, the default behavior should probably make sense for the majority of users. I don’t think the majority of Mumbaikers are vegetarian, actually, but the nomenclature suggests it. It manifests like this:

  • FourSquare tips like ā€œbest place for non-veg in the cityā€.
  • Restaurant servers asking ā€œveg or non-veg?ā€
  • Restaurant signs indicating that a place is ā€œpure vegā€ (which I think means it’s suited for Jain vegetarians)

I like that the ā€œnonā€ is attached to ā€œvegā€ and not ā€œmeatā€.


If you become a vegetarian, people will want to know why. I’ve been a vegetarian for a little over three years, and I often struggle to come up with a good answer. This dissatisfies people, myself included.

The truthful answer is that I’m a vegetarian today because I was a vegetarian yesterday and for no other conscious reason. This of course raises a few questions:

  1. why did I start eating vegetarian?
  2. what do I like about eating vegetarian?
  3. what do I do next?

1. Why did I start eating vegetarian?

In February 2013 my toe hurt. I thought maybe it was broken. I had a vague memory of stubbing it badly while walking in the snow. There were drinks involved.

The doctor x-rayed me and said it looked fine. No broken toe or anything.

ā€œYou probably have goutā€ (I paraphrase).

Gout, as I understood it, is a form of arthritis. If your diet is too purine-rich, uric acid causes crystallization in your joints, which can be painful or uncomfortable. (This is probably not a fully accurate definition of gout – I’m writing without WiFi currently and going from memory from a conversation 3 years ago) He took some blood to assess the levels of uric acid and gave me a cheat sheet of foods to avoid.

He didn’t tell me to become vegetarian. He told me to moderate my levels of purine by limiting my consumption of specific foods to lower levels. The list was kind of surprising to me: I recall spinach and oatmeal being on the no-fly list. There were specific amounts of red meat I was recommended to eat in a week, limited to a few ounces. Similarly for other meat, maybe a little more generous.

I’ve never been a very conscientious eater. I still don’t feel like I understand the basics of nutrition. I wasn’t excited to memorize a list of foods to eat or to buy a kitchen scale. I decided to try eating vegetarian for a few weeks and see if the toe pain went away.

It did.

Curiously, the blood test showed normal levels of uric acid. I might’ve had it, anyway although I may never know.

I think in the first few weeks I was just superstitious and didn’t want the toe pain to return. It was very inconvenient! I could barely walk.

And then it became a habit and I forgot about stopping.


In the interim, I’ve bought a few books about veg* eating, but I think I’ve only finished one: Eat & Run. It’s a very inspiring memoir about a vegan ultra-marathoner. This dude runs 100+ miles at a time powered by smoothies, salads, and black bean burritos. He makes a very persuasive case for veganism as an ideal diet for some kinds of athletic pursuits. I’m not an athlete, but I do encounter people who insist that they ā€œcould never be vegetarianā€ because their gym regimen requires amounts of protein which would be impossible, inconvenient, impractical, or unaffordable to attain through a plant-based diet. They’re probably right, I don’t know their life. One takeaway from the book I took away is that most Americans are consuming too much protein. I like to share that when people worry about my protein.

People worry about my protein all the time. ā€œBut how do you get your protein?ā€ People need to know. I’ll tell ya: I don’t worry about it. I’m still not a very conscientious eater, and I feel pretty much fine. I think I feel a little better than before, but I don’t really remember.

(This post continues not to be medical advice.)

2. What do I like about eating vegetarian?

There are a few benefits I’ve picked up on, which I’ll enumerate now, as they occur to me.

Easier decision making

Some people talk about clothing this way: I wear the same thing every day so I have one fewer decision to make each day. I haven’t heard people talk about food in the same way, but I think it’s similar. I have the personality where I feel compelled to read the whole menu before I make a decision, lest I make the mistake of overlooking something I might like. Have you ever been to a diner? These menus are an astonishment. I can get thru a menu much quicker when I can skip all of the non-veg items. No more ā€œplease, come to me lastā€; I know what I’m ordering.

No more storing and cooking meat

I used to try to cook meat. I was real bad at it. I couldn’t make a burger without setting off the smoke alarm or undercooking it. I couldn’t defrost a chicken breast without accidentally cooking it a bit, which I found kind of gross at the time but pushed down. I didn’t really enjoy handling raw meat – it’s kind of slimy and sticky, right? I don’t really remember, and maybe it’s grown more ghoulish with distance.

No more gristle, no more veins, no more bones

It’s been a long time since I’ve taken a bite and felt a surprising popping resistance in my mouth. I used to secret unpleasant, gristly bites into napkins. I used to worry I wasn’t effective at extracting as much meat as I could from a bone. I used to avoid eating veins. No more!

Physical comfort

Meat sits like a lump in your stomach in a way that vegetables don’t. Restaurants sometimes serve these giant sandwiches, burgers, steaks… And I would eat the whole thing, and it would just sit there. Look, I don’t want to go into too much detail about gastro-intestinal scenarios. But let’s just say it’s harder to cause problems when you skip all that stuff.

Moral correctness

This is a touchy one. When a meat eater asks me why I’m vegetarian, what they really seem to mean is: do you think I’m an asshole? I don’t think you’re an asshole. But I do think it’s morally correct to avoid eating meat.

I don’t think it’s majorly evil. But I think it’s kind of wrong.

I don’t feel strongly enough to try and convince others to give up meat. But I do take a small amount of pleasure in feeling like I’m doing the right thing, the same feeling I get when I recycle. That’s the moral level I put it at. It’s a nice thing to do.

I ate meat for 24 years and didn’t eat meat for 3 years. I think of it like I’m offsetting some damage, paying off some debt. If I take that thought to its conclusion, I should remain vegetarian for another 21 years, after which point I would be in the black and could start eating meat again guilt free.

That’s not necessarily the plan, by the way.

Having a label for my diet

There are many diets. I’ll list a few (summarized crudely):

  1. Omnivore – I’ll eat anything
  2. Kosher/Halal – I’ll eat anything except a few specific things
  3. Vegetarian – I’ll eat anything except an animal
  4. Pescaterian – Vegetarian, except I’ll eat seafood
  5. [?????] – I’ll eat anything except red meat
  6. Vegan – I’ll eat anything unless an animal was involved
  7. Jain vegetarianism – I’ll eat anything except animals, eggs, and vegetables which grow in the ground

Before I stopped eating meat I didn’t belong in any of these categories and I was kind of embarrassed about it. Not a deep burning shame or anything, but I had a hard time explaining it, and I was put into some uncomfortable situations. My diet was something like: ā€œInverse Pescatarian – I’ll eat anything except seafood… or mushrooms… or green olives… or solid tomatoes… or a few other thingsā€. Not great! I’m very proud and happy that I fit into a group now, called vegetarian. People understand it and people have been mostly happy to accommodate what they can understand.

And, happily, I’ve expanded to fill the space I entered and have come to appreciate many or most of the vegetables I used to discriminate against.

If I were to start eating meat again, I think I would need to eat seafood as well, or I wouldn’t belong to a group anymore.

3. What do I do next?

I’m writing this out because recently I’ve been tempted to eat meat again and I wanted to explore the idea.

Here are my temptations, as they occur to me:

  • Shake Shack burger
  • McDonald’s burger
  • Wendy’s burger
  • Most other burgers
  • sliced pastrami – specifically in a pastrami reuben from a specific deli in Vermont near where I lived senior year of college
  • boneless spare ribs at literally any takeout Chinese restaurant
  • pork belly bao at Baohaus
  • Chicken Parmesan at an Italian restaurant near where I grew up
  • Lamb … in some context? I forget when I ate lamb. Maybe it was goat? Something kind of tough and rich.

My mouth is watering as I think about these. But it passes pretty quickly.

I fear if I started eating meat again, even slowly and carefully, I would shortly be subsumed by it.

And I really have no desire to start eating seafood.

And no real reason.

Well, it ain’t broke.

how to run shell commands from ruby if you care about their output or if they failed

January 31, 2016

Recently I made a new gem called shell whisperer which you might find useful for when your ruby programs need to run shell commands.

Let’s say you want to write a script which prints a summary of the current directory. The desired output is:

There are 213 files in this git repo.
Last commit: fixed a typo

There are two questions we need to ask the shell in order to print this output.

First question: how many files are there in this git repo?

First answer: we can ask git to list the files in the repo, and pipe the list to the word counting command to get the answer:

git ls-files | wc -l

Second question: what is the last commit?

Second answer: we can ask git for the log, limited to the most recent commit, and formatted to include just the first line:

git log -1 --pretty="%s"

So far so good, but how do we run these commands from Ruby?

The language provides two ways that I’m aware of:

# backtick style
`git ls-files | wc -l`

Or:

# system style
system 'git ls-files | wc -l'

What is the difference? I don’t want to go into all of the nuances (see this SO post for that and more) but I’ll share how I think of the difference:

  1. if you use the backtick (`) style, the return value is whatever was output by the command – but only STDOUT, not STDERR, so you’ll miss error messages
  2. if you use the system style, the output from the command will go to STDOUT, as if you had run puts and output some text, and the return value will signify whether the command failed or not

So our program might look something like this:

count = `git ls-files`.each_line.count
message = `git log -1 --pretty="%s"`.chomp
puts "There are #{count} files in this git repo."
puts "Last commit: #{message}"

And this is okay.

The issue becomes: well, what do you if you care that the command might fail? The system style allowed for checking the return value to see whether it succeeded or failed, but there’s a reason we’re not using the system style: we care about capturing the output of the command. So with the backtick style, we can capture the output, but (seemingly) we can’t capture the successfulness.

Well, we can, it’s just a little awkward:

count = `git ls-files`.each_line.count
raise 'list failed somehow' unless $?.success?
message = `git log -1 --pretty="%s"`.chomp
raise 'message failed somehow' unless $?.success?
puts "There are #{count} files in this git repo."
puts "Last commit: #{message}"

Which, OK, kind of cool, but what if we want to know why it failed?

This is possible:

count_or_failure_reason = `git ls-files 2>&1`.each_line.count
raise count_or_failure_reason unless $?.success?
message_or_failure_reason = `git log -1 --pretty="%s" 2>&1`.chomp
raise message_or_failure_reason unless $?.success?
puts "There are #{count_or_failure_reason} files in this git repo."
puts "Last commit: #{message_or_failure_reason}"

Let me attempt to explain this. The 2>&1 part means that we want the STDERR stream to be directed to the STDOUT stream, so that we’ll capture either one (or both). This gives us access to the reason the command failed, if it failed, but still gives us access to the output if it succeeds.

I found myself doing this in multiple places, so I decided to wrap this pattern up in a tiny gem, which allows you to instead write your program like this:

require 'shell_whisperer'
count = ShellWhisperer.run('git ls-files').each_line.count
message = ShellWhisperer.run('git log -1 --pretty="%s"').chomp
puts "There are #{count} files in this git repo."
puts "Last commit: #{message}"

If any of the commands fail, that error message will be re-raised as a ShellWhisperer::CommandFailed exception, so you can handle that as you please.

The node.js community seems to be all about tiny modules, and I think that idea is very cool, and I’m hoping to find more opportunities to do that with Ruby.

how to re-draw the line you just printed in Ruby, like to make a progress bar

December 14, 2015

Here’s something I learned recently. Let’s say you have a program that is going to take a long time, and you want to mark the progress over time. You can print out some information like this:

tasks = Array.new(1000)
tasks.each.with_index do |task, index|
  sleep rand(0..0.1) # (something slow)
  percentage = (index + 1) / tasks.count.to_f
  puts "#{(percentage * 100).round(1)}%"
end

Which looks kinda like this:

progress bar before picture

Which is, let’s say, serviceable, but not, let’s say, beautiful. It stinks that it printed out all those lines when it didn’t really need to. I would rather it had sort of animated while it went. But how is this done?

This is one of those questions that’s itched at the back of my mind for a while and which, when I finally googled it, was a bit disappointing. It’s just another unix escape character, like \n (which prints a new line). It’s \r, which I now think of as ā€œthe backspace to the beginning of the lineā€ magic character.

Armed with this knowledge and some clunky math we can write something like this:

begin
  tasks = Array.new(1000)
  tasks.each.with_index do |task, i|
    width = `tput cols`.to_i
    sleep rand(0..0.1) # (something slow)
    percentage = (i + 1) / tasks.count.to_f
    summary = "#{(percentage * 100).round(1)}% ".rjust("100.0% ".length)
    remaining_chars_for_progress_bar = width - summary.length - 2
    chunks = (percentage * remaining_chars_for_progress_bar).ceil
    spaces = remaining_chars_for_progress_bar - chunks
    bar = "\r#{summary}[#{ '#' * chunks }#{' ' * spaces}]"
    print bar
  end
rescue Interrupt
  system "say 'I was almost done, jeez'" if RUBY_PLATFORM.include?("darwin")
end

progress bar after gif

Probably you shouldn’t use this – there’s a very nice gem called ruby-progressbar which will work across platforms and lets you customize some things. But it’s nice information to have, because now you can do things like this:

barnyard

I’ll leave it as an exercise to the reader how to write this one.

how to tell ruby how to compare numbers to your object with coerce

November 9, 2015

Let’s say you have some object that represents some numeric idea:

class CupsOfCoffeePerDay
  include Comparable

  MY_LIMIT = 3

  def initialize(num)
    @num = num
  end

  def <=>(other)
    num <=> other
  end

  def risky?(threshold: MY_LIMIT)
    self > threshold
  end
end

CupsOfCoffeePerDay.new(4).risky? #=> true
CupsOfCoffeePerDay.new(4) > 5 #=> false

This object takes in a number and wraps it, and then extends it with some domain-specific logic. Specifically, it represents the idea that there is a threshold to how many cups of coffee an individual can have per day before it becomes risky.

It’s neat that we’re able to compare our custom ruby object to a plain number. All we had to do was include Comparable and then implement the <=> method (also known as ā€œthe spaceship operatorā€) to define how we’d like our object to compare to numbers. We’d like to expose the internal num value, and use that when comparing.

The neat thing is that we get all the comparing methods for free.

We’re not quite done yet, though. Watch what happens when we try to do this:

CupsOfCoffeePerDay.new(4) > CupsOfCoffeePerDay.new(5)

I get this error when I run the program:

app.rb:27:in `>': comparison of CupsOfCoffeePerDay with CupsOfCoffeePerDay failed (ArgumentError)
        from app.rb:27:in `<main>'

What’s happening here?

  1. we create two objects
  2. we ask one object if it’s greater than the second object
  3. our implementation refers to the wrapped number value (num, which is just a Fixnum) and asks it if it’s greater than this second object
  4. the fixnum complains that it doesn’t know how to compare itself to some ranom object

And, fair enough. From the point of view of the number, it has no idea what cups of coffee per day even means.

We could change our implementation to accomodate this use-case:

class CupsOfCoffeePerDay
  include Comparable

  MY_LIMIT = 3

  def initialize(num)
    @num = num
  end

  def <=>(other)
    if other.is_a?(CupsOfCoffeePerDay)
      num <=> other.num
    else
      num <=> other
    end
  end

  def risky?(threshold: MY_LIMIT)
    self > threshold
  end

  protected

  attr_reader :num
end

Note that we had to add those last few lines to make it easier to access the num from outside an instance of CupsOfCoffeePerDay.

This is not bad.

That attribute is marked as protected because so far we can only imagine it being necessary to be used by other instances of CupsOfCoffeePerDay, for the sake of comparison.

(I remember having a long and horrified conversation with a coworker when neither of us could come up with a scenario where you would use protected over private, but it turns out that this is precisely the situation where you would.)

But look what happens when you try this:

4 > CupsOfCoffeePerDay.new(5)

Or this:

[
  CupsOfCoffeePerDay.new(4),
  3,
  CupsOfCoffeePerDay.new(1)
].sort

When I try these, I get errors like this:

app.rb:32:in `>': comparison of Fixnum with CupsOfCoffeePerDay failed (ArgumentError)
        from app.rb:32:in `<main>'

Is there anything we can do to avoid these errors? I think one, strong argument is that we shouldn’t try to. Rather, we should audit our system and make sure that we never mix-and-match our types. If we can do that, that’s probably for the best.

Except… this is Ruby, and Ruby always has another trick up its sleeve.

Check it:

class CupsOfCoffeePerDay
  include Comparable

  MY_LIMIT = 3

  def initialize(num)
    @num = num
  end

  def <=>(other)
    if other.is_a?(CupsOfCoffeePerDay)
      num <=> other.num
    else
      num <=> other
    end
  end

  def risky?(threshold: MY_LIMIT)
    self > threshold
  end

  def coerce(other)
    [CupsOfCoffeePerDay.new(other), self]
  end

  protected

  attr_reader :num
end

There’s not a ton of documentation about this. I only found it by luck. I was looking to understand how Ruby numbers does its comparisons, and I opened up pry (with pry-doc installed), and started exploring:

$ gem install pry pry-doc
$ pry
> 4.pry
(4)> show-source >
From: numeric.c (C Method):
Owner: Fixnum
Visibility: public
Number of lines: 17

static VALUE
fix_gt(VALUE x, VALUE y)
{
    if (FIXNUM_P(y)) {
        if (FIX2LONG(x) > FIX2LONG(y)) return Qtrue;
        return Qfalse;
    }
    else if (RB_TYPE_P(y, T_BIGNUM)) {
        return FIX2INT(rb_big_cmp(rb_int2big(FIX2LONG(x)), y)) > 0 ? Qtrue : Qfalse;
    }
    else if (RB_TYPE_P(y, T_FLOAT)) {
        return rb_integer_float_cmp(x, y) == INT2FIX(1) ? Qtrue : Qfalse;
    }
    else {
        return rb_num_coerce_relop(x, y, '>');
    }
}

At this point, I thought oh no! C!

But like, this is so cool: this is the implementation of the greater than method in numbers in Ruby, and it’s totally discoverable if you open pry and ask it to show-source.

I don’t really know C, but if I squint, I can tell that this is doing something kind of reasonable. It seems to be checking the type of the second value (the one you’re comparing the current value to) and doing something different based on the type. The final branch of logic is when the type is unknown. Bingo. Our CupsOfCoffeePerDay type is definitely unknown. In that case, it calls rb_num_coerce_relop. Unfortunately, when I asked pry to show-source rb_num_coerce_relop it didn’t know how.

Thankfully, it printed the filename this source code can be found in, so I went to the ruby source code and searched for a file called numeric.c. Within that, I searched for the rb_num_coerce_relop function. It takes in the two objects (the CupsOfCoffeePerDay and the number) and the operator (>). Its source looks like this:

VALUE
rb_num_coerce_relop(VALUE x, VALUE y, ID func)
{
    VALUE c, x0 = x, y0 = y;

    if (!do_coerce(&x, &y, FALSE) ||
	NIL_P(c = rb_funcall(x, func, 1, y))) {
	rb_cmperr(x0, y0);
	return Qnil;		/* not reached */
    }
    return c;
}

What does that do? It looks like it coerces the two types to be the same type, and then calls the > function on the first one, passing the second one. (Again: squinting).

So do_coerce is where the interesting part happens. I’ll just link to it because it’s pretty long. But the cool thing in it is that it checks if the first object implements a coerce method, and if it does, it does something different. So then it becomes a game of figuring out how to write a coerce method and finding out, via stack overflow (of course), that you can add this magic coerce method, and it will take in the second object, and it’s expected to return an array of compatible types, with the second object’s value first, and the first object’s value second.

So. Now that we know about coerce, our objects can be really simple, but they can still be compared bidirectionally.

begin rescue else

October 20, 2015

Quick ruby tip kinda post.

Today I learned, this is a valid Ruby program:

begin
  raise if [true, false].sample
rescue
  puts "failed"
else
  puts "did not fail"
end

I’m used to using else after an if, but not after a rescue. This is like saying ā€œdo this thing. if it fails, do this other thing. if it doesn’t fail, do this other, other thing.

Huh!

(Via rails)

how to log all input in your pry rails console

October 14, 2015

Many Rubyists use and love the pry gem for adding breakpoints to their programs and inspecting objects. Super useful. Some others use the pry-rails gem to use the pry REPL in place of irb for the rails console.

Let’s say you want to log all of the activity that occurs in your rails console. This could be a nice security thing. Maybe you’re just nostalgic for old times.

Pry has something called an ā€œinput objectā€, which you can override in your configuration. The object’s responsibility is to feed ruby code to Pry, line by line. By default, it uses the Readline module. I don’t know a ton about readline, but I gather that it’s wrapping some standard unix program, which means it sort of feels natural. For example, you can input Control+l and it will clear the screen; gets.chomp doesn’t do that kind of thing.

So, Readline is great. We want to use it. We just kind of want to wrap it. SO let’s see what that looks like.

First: where do we actually put our configuration?

You can put a .pryrc file in the root of your project. You can even put Ruby code in that file. I think that’s the official way to do it. But I don’t know… it doesn’t get syntax highlighting because it doesn’t have a .rb file extension… I put my configuration in a Rails initializer named config/initializers/pry.rb, and that works fine too.

class LoggingReadline
  delegate :completion_proc, :completion_proc=, to: Readline

  def readline(prompt)
    Readline.readline(prompt).tap do |user_input|
      logger.info(user_input)
    end
  end

  private

  def logger
    @logger ||= Logger.new('log/console.log')
  end
end

Pry.config.input = LoggingReadline.new

The important thing for custom input objects is that they implement the readline method. The method takes in a string that holds the current user prompt, and it is expected to return a string that holds the next line of Ruby code for Pry to evaluate.

If pry is a REPL (read evaluate print loop), the custom input object assumes the responsibility of the first letter, and thats’ it.

It doesn’t strictly need to ask the user for input. It could just return some nonsense.

But, this one does. We can summarize what it does as: ask the dev for a line of input, but first log it to a file before returning it to pry for EPL-ing.

There’s one line that’s kind of strange:

delegate :completion_proc, :completion_proc=, to: Readline

What’s that about?

Well, I’ve learned, it’s just kind of a necessary thing to make sure your custom input object seamlessly behaves like the default pry input behavior. Let me explain.

Readline, by default, has some strategy for tab completing when you start to write something, and then press tab. That strategy is a proc object. The default one has something to do with irb I guess?

$ irb
>> Readline.completion_proc
=> #<Proc:0xb9964ce0@/home/max/.rubies/2.2.3/lib/ruby/2.2.0/irb/completion.rb:37>

But! When starting pry, it has a different completion proc!

$ pry
[1] pry(main)> Readline.completion_proc
=> #<Proc:0xb8a0c25c@/home/max/.gem/ruby/2.2.3/gems/pry-0.10.2/lib/pry/repl.rb:177>

But when you provide a custom input object, pry doesn’t replace the completion proc on readline because you seem not to even be using it, so why bother? But in this case we totally are using it, we’re just wrapping it.

At first, I thought this was a bug with Pry, and I opened an issue to complain about it, but while writing this blog post I realized that it’s kind of not a bug, and this delegation approach is probably fine.

fake tools

October 11, 2015

Last week, Flatiron School launched a new online learning program called ā€œLearn Verifiedā€. The launch was accompanied by a letter from the founders, Avi and Adam. This section jumped out to me:

Real Tools

You can’t learn real skills with fake tools. As much as you can learn in a simulation, you can’t become a competent surgeon without picking up a scalpel or pilot without stepping into an airplane. Yet, online learning platforms today teach people using in-browser, simulated coding tools (often referred to as REPLs) and multiple choice quizzes which, while helpful, can never bring a student to the level of competency required of a professional software engineer.

Learn requires students to use the same tools and workflows that professional software engineers use on the job. From the start, students work in their terminals using git-based workflows. They’re taught to master the craft using the tools of the trade.

On the most recent episode of metaphor loop, we talked about the different styles of learning. One of them was kinesthetic learning, which we can say is like ā€œhands onā€ learning. I hadn’t heard the term until Vaidehi told me about it and I realized I identified with it. I think kinesthetic learners are the same ones who will identify with Learn Verified’s emphasis on using ā€œreal toolsā€, because they’ll get to get their hands on the material they’re learning in a more direct, free-to-explore way. That market of learners has been underserved by the existing solutions, and I wonder if Flatiron will be able to pull off an online learning environment just for them.

I do kind of chafe at the idea that ā€œyou can’t learn real skills with fake toolsā€, though. It feels like a pretty inflammatory position to take. I’m reminded of Lost’s great ā€œDon’t tell me what I can’t do!ā€ catchphrase. Aren’t some people different from other people? And not to be all metaphysical here, but aren’t all tools kind of fake tools? Where do you draw the line? idk.