I hack a fair bit of Ruby, usually in a pretty plain way to solve a text-based problem; I can write scripts to do what I need, because my problems aren’t too large, but what I write isn’t elegant. Just recently I started using Rubocop in Emacs, and wow, what a great tool! It’s making the code better and me a better coder.
Rubocop is written by Bozhidar Batsov, who also made rubocop-emacs to integrate it into Emacs. I’ve had that running for a while and found it useful for pointing out unused variables and things like that, but otherwise it didn’t seem to do a lot. That’s because I had it turned on but wasn’t actually using it.
Here’s a short Ruby script:
What it looks like in my Emacs with rubocop-mode on:
The lines in red are highlighted because there’s a problem: in this case, the variables aren’t reused so, as the script stands, they could be removed without affecting anything.
Now, if I run rubocop on this script at the command line, it tells me helpful things about making the script better. If I run M-x rubocop-check-current-file in Emacs it tells me the same helpful things. But if I run M-x rubocop-autocorrect-current-file it fixes the problems.
Here’s the output:
-*- mode: compilation; default-directory: "~/" -*-
Compilation started at Thu Oct 13 20:28:30
rubocop -a --format emacs /home/wtd/rubocop.rb
/home/wtd/rubocop.rb:3:6: C: [Corrected] Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
/home/wtd/rubocop.rb:5:1: W: Useless assignment to variable - `x`.
/home/wtd/rubocop.rb:7:1: W: Useless assignment to variable - `y`.
/home/wtd/rubocop.rb:7:5: C: [Corrected] Use `%w` or `%W` for an array of words.
/home/wtd/rubocop.rb:9:1: C: [Corrected] Favor modifier `if` usage when having a single-line body. Another good alternative is the usage of control flow `&&`/`||`.
/home/wtd/rubocop.rb:11:1: C: [Corrected] Redundant `else`-clause.
Compilation exited abnormally with code 1 at Thu Oct 13 20:28:30
(I can hit Enter on any of those lines and jump to that line in the code.)
All of the corrections are corrected and the warnings are left alone. The code is changed to this:
Magic! It’s up to me to decide what to do with x and y, but all the style problems are fixed. That’s just a tiny example. Rubocop does a lot more, and I’ve been going through scripts changing CGI::parse to CGI.parse or foo["bar"] to foo[:bar] and all sorts of other small things that make them more readable and consistent.
The one thing I didn’t like about Rubocop was its preference for ‘single’ quotes over “double” quotes, so I put this in a new ~/.rubocop.yml file to tell it how I like things:
“The hardest bug I ever debugged in my life was a concurrency bug; the second hardest wasn’t even close (and thankfully, I didn’t try to solve it at the same time).” — John Wiegley, Emacs maintainer, on Emacs Lisp’s future, 09 October 2016
I noticed it when I happened to check my cookies. I expect to recognize all the domains where I allow them, but the list was endless and was full of junk I didn’t know. What the hell? Firefox 44:”Ask me every time” cookie option removed explained it: “While it is likely that the majority of users are not affected by the removal of the feature as it was deeply hidden in the options of the browser, those who have made use of it are.” Damn straight.
Cookie Monster, which I used to use, does me no good any more. To do things the way I want I installed Self-Destructing Cookies, which looks like it works well: it accept cookies from sites but then removes them when I close the tab, unless I whitelist the site. Blocking all cookies from a site often breaks the whole thing, but with this, I can look at a site without trouble and when I close the tab the cookies are deleted so if I go back to the site it doesn’t know I was there before. Nice.
I had to go into the cookie settings and remove pretty much everything, because hundreds of sites were whitelisted thanks to Firefox’s incorrect behaviour. Self-Destructing Cookies started deleting cookies, and I restarted the browser to help force a reset of everything. I had to log in to a few sites (and whitelist them) but after a little bit of use it seems OK so far.
Update (2016-10-06): Works a treat on mobile devices, too.
I made a schoolboy error last week: I narrowed down a problem I was having with a program to one line and one setting … but then I didn’t read the documentation. It was Org mode in Emacs, and the variable was org-export-babel-evaluate. I set it to nil, and what happened wasn’t what I thought should happen, so I thought it was a bug, when actually it’s all set out in the docs. Lesson re-learned: RTFM.
Here’s what happened. At work I did a long report analyzing some aspects of the library’s presence in the university’s course management system. We made a box in Moodle that generates customized recommendations to students based on the course code: students see links to relevant research guides (for example poli sci students see a link to the poli sci research guide), to the course’s specific guide and/or reserves if they exist, and to the profile of the librarian who handles that subject. Turns out the links in the box don’t get many clickthroughs, but that’s something I’ll write up some other time.
The thing is, doing the full analysis means looking at millions of lines of data from log files, then processing things in R and Ruby, generating charts, tables of numbers, the whole schmear. The way I have it set up, the Org file, which is full of source code blocks, can be fully reproducible research: when I export to PDF, every data file is read in and analyzed fresh, every table and chart are regenerated. That’s wonderful, and it’s one of the reasons I love Org—but it’s intensive, and it takes about five minutes to run on my personal machine, and usually crashes my slower work machine. (I asked for a new one.) And when I’m rewriting and editing and want to see how the changes look, I don’t need to regenerate all the data, I just want to turn what’s there into a PDF as is.
Because I didn’t want any of the code blocks evaluated, I set this in a file variable (it’s the first line in the Org file):
# -*- org-export-babel-evaluate: nil -*-
But when I exported the file to PDF, all of a sudden not only were the results of the code blocks in the PDF (as desired) but also the code that generated them. Instead of showing the results of a bit of Ruby, the Ruby was there too. Instead of just showing a chart, the R that made it was there too. Not what I wanted!
I spent about an hour narrowing this down and reported it as a possible bug to the Org mailing list. Very quickly Charles Berryreplied and gently corrected me, pointing me to the documentation (which I now notice contains a typo, which I’ll submit a real bug report for):
Switch controlling code evaluation during export.
When set to nil no code will be evaluated as part of the export
process and no header argumentss will be obeyed. When set to
‘inline-only’, only inline code blocks will be executed. Users
who wish to avoid evaluating code on export should use the header
argument ‘:eval never-export’.
It’s the “no header arguments will be obeyed” that was causing my trouble. I needed that “:eval never-export” thing, which isn’t managed like the org-export-babel-evaluate variable, but is a header argument, which I’d never used before (and had to search GitHub to find examples of). I put this near the start of the file and hit C-c C-c on the line to make Emacs know about it:
#+PROPERTY: header-args :eval never-export
Now when I export the file to PDF (C-c C-e l o) it just blasts the document as is into LaTeX and turns it into a PDF, no calculating done. For minor tweaks and copy editing, that’s just what I need. When I need to rerun some data analysis, I can remove the line to rerun everything fully and completely.
This is all a bit arcane, so I document this in the hopes it will save someone, perhaps just future me, a moment of trouble in some month or year to come.
Interviewer: So when you were working in the studio, in the fifties and sixties, did you ever think about representation? I mean, I understand what you were saying in terms of that previous generation of artists having to work through it, but for you, was that even a thing that you considered?
Stella: No, I mean, it’s ludicrous, why would I—you know, the only time it ever came up is when you were meeting young ladies or something like that, and most, you know, nine out of ten of them really wanted to pose for you. But you know, it would have been a waste of time with me.
Interviewer: So you never did that?
Stella: No, I never got anyone to visit my garret—on that pretext.
I work at a university library, and when I analyse data I like to arrange things by academic year (September to August) so I often need to find the academic year for a given date. Here are Ruby and R functions I made to do that. Both are pretty simple—they could be better, I’m sure, but they’re good enough for now. They use the same method: subtract eight months and then find the year you’re in.
The Ruby is the shortest, and uses the Date class. First, subtract eight months, with <<.
d « n: Returns a date object pointing n months before self. The n should be a numeric value.
Rather cryptic. Then we find the year with .year, which is pretty clear. This is the function:
The function is very short because Ruby nicely handles leap years and months of varying lengths. What is 30 October 2015 - eight months?
The floor_date function gets called twice, the first time to drop back to the start of the month, which avoids R’s problems dealing with leap years:
> as.Date("2016-10-30") - months(8)
But you can always subtract 8 months from the first of a month. Then the function goes to 01 January of that year, pulls out just the year (“%Y”) and returns it as an integer. I’m sure it could be faster.
And once the academic year is identified, when making charts it’s nice to have September–August on the x axis. I often do something like this, with a data frame called data that has a date column:
Finding the academic year of a date could be a code golf thing, but Stack Overflow has too many rules.