0

I'm currently working on a feature for CocoaPods, a Ruby gem. There's an existing command that accepts a number of options. I'd like to add an extra option that enables the user to enter a custom message by opening the default text editor and, when the user saves and quits the editor, the message is fed to the command that was executed.

What I want to replicate is how you can add -m to the git commit command to have you enter a commit message. I have little experience with creating command line tools so any help is much appreciated.

The goal is to execute a specific command command --message, open the editor, have the user enter a custom message, and execute the command with the custom message being one of the arguments stored in argv.

1
  • The interactive_editor gem seems related to what you try to achieve. I did not check the source, but there might be ideas to pick there. Commented Nov 21, 2015 at 2:40

1 Answer 1

2

The common workflow is:

  • the caller application creates a temporary file;
  • determines the default editor (for Debian-based it would be /usr/bin/editor, for other linuces — the content of shell variable $EDITOR, etc);
  • runs a shell command in a subshell with Kernel#system (not with backticks!);
  • waits for it to exit;
  • determines the exit code, and skips following if it is not 0;
  • reads the content of temporary file, created in step 1 and removes this file.

In ruby that would be like:

▶ f = Tempfile.new 'cocoapods'
#⇒ #<File:/tmp/am/cocoapods20151120-6901-u2lubx>
-rw------- 1 am am 0 nov 20 15:03 /tmp/am/cocoapods20151120-6901-u2lubx
▶ path = f.path
#⇒ "/tmp/am/cocoapods20151120-6901-u2lubx"
▶ f.puts 'This content is already presented in file'
#⇒ nil
▶ f.close # HERE MUST BE ENSURE BLOCK, BUT FOR THE SAKE OF AN EXAMPLE...
#⇒ nil
▶ system "editor #{path}"
#⇒ Vim: Warning: Output is not to a terminal

If you are testing this in console, just type anything, followed by Esc:wq. In real life there will be normal vim (or what the default editor is) opened.

▶ File.read path
#⇒ "GGGGGGGGGThis content is already presented in file\n"

All together:

#!/usr/bin/env ruby

require 'tempfile'

f = Tempfile.new 'cocoapods'
path = f.path
f.puts 'This content is already presented in file'
f.close # HERE MUST BE ENSURE BLOCK, BUT FOR THE SAKE OF AN EXAMPLE...
system "editor #{path}"
puts File.read path
Sign up to request clarification or add additional context in comments.

2 Comments

That's a great start. The problem I'm running into is getting the contents of the file before the Ruby script exits. The Ruby script exits when the editor is opened. I was hoping/expecting that it would continue its execution the moment the editor is closed. You write File.read path. Where do you read the contents of the temporary file?
Oh, sorry, I messed things up: to invoke an editor in the same context (in a subshell,) one should use Kernel#system rather that backticks. I updated an answer with the code of the whole script for your convenience.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.