Pro Yearly is on sale from $80 to $50! »

Command-line Ruby

259f23c3b129f07b0c496b9f0495f07e?s=47 jeg2
February 22, 2013

Command-line Ruby

A discussion about ways to learn Ruby faster and one possible avenue for doing that.

259f23c3b129f07b0c496b9f0495f07e?s=128

jeg2

February 22, 2013
Tweet

Transcript

  1. Now For Something Completely Different Command-line Ruby Or “How You

    Can Learn Ruby Faster”
  2. James Edward Gray II ✤ I am a regular panelist

    on The Ruby Rogues podcast ✤ I was a Rubyist before Rails shipped and made us popular ✤ I have written a lot of code and documentation for Ruby, including the standard CSV library
  3. Ruby is Beautiful

  4. I Suspect You’ve Been Learning… ✤ How clean code helps

    you manage complexity ✤ How well written code eases communication with others ✤ How to identify and improve problem spots in your code
  5. That’s All True, and Usually Very Important

  6. But Not Today!

  7. This Is For Your Own Good! Ugly Ruby Strap In

    Folks, This Could Get Weird
  8. “Why would you do this???”

  9. What If… ✤ Our goal isn’t to write the best

    code possible? ✤ Our goal is to do a big chunk of work quickly? ✤ Our goal is to learn Ruby faster?
  10. Stay Mindful of the Reasons We Write Code

  11. “I can learn Ruby faster???”

  12. The Wheel of Time ✤ A fantasy series from my

    childhood ✤ The female magic users have a strict training process built up over 100’s of years of magic use ✤ The male magic users, brand new to magic, try to catch up by using it for everything: cooking, chores, etc.
  13. Use Ruby to Do More

  14. Command-line Ruby Basics

  15. The -e (execute) Switch $ ruby -e 'p 21 *

    2' 42 $ ruby -e 'p "some data"' "some data" $ ruby -e 'var = 42; p var' 42 ✤ Run some Ruby without a script ✤ Hints: ✤ Use ‘…’ for shell quoting and “…” for Ruby quoting (to minimize escaping) ✤ Use ;’s to get multiple lines
  16. The -e (execute) Switch $ ruby -e 'p 21 *

    2' 42 $ ruby -e 'p "some data"' "some data" $ ruby -e 'var = 42; p var' 42 ✤ Run some Ruby without a script ✤ Hints: ✤ Use ‘…’ for shell quoting and “…” for Ruby quoting (to minimize escaping) ✤ Use ;’s to get multiple lines
  17. The -e (execute) Switch $ ruby -e 'p 21 *

    2' 42 $ ruby -e 'p "some data"' "some data" $ ruby -e 'var = 42; p var' 42 ✤ Run some Ruby without a script ✤ Hints: ✤ Use ‘…’ for shell quoting and “…” for Ruby quoting (to minimize escaping) ✤ Use ;’s to get multiple lines
  18. The -e (execute) Switch $ ruby -e 'p 21 *

    2' 42 $ ruby -e 'p "some data"' "some data" $ ruby -e 'var = 42; p var' 42 ✤ Run some Ruby without a script ✤ Hints: ✤ Use ‘…’ for shell quoting and “…” for Ruby quoting (to minimize escaping) ✤ Use ;’s to get multiple lines
  19. The “Unix Filter” Pattern ✤ Accepts a file name on

    the command-line ✤ Or multiple names at once ✤ Or reads from STDIN ✤ Writes to STDOUT $ echo 'A line from file_1.' > file_1.txt $ echo 'A line from file_2.' > file_2.txt $ cat file_1.txt A line from file_1. $ cat file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | cat A line from $stdin.
  20. The “Unix Filter” Pattern ✤ Accepts a file name on

    the command-line ✤ Or multiple names at once ✤ Or reads from STDIN ✤ Writes to STDOUT $ echo 'A line from file_1.' > file_1.txt $ echo 'A line from file_2.' > file_2.txt $ cat file_1.txt A line from file_1. $ cat file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | cat A line from $stdin.
  21. The “Unix Filter” Pattern ✤ Accepts a file name on

    the command-line ✤ Or multiple names at once ✤ Or reads from STDIN ✤ Writes to STDOUT $ echo 'A line from file_1.' > file_1.txt $ echo 'A line from file_2.' > file_2.txt $ cat file_1.txt A line from file_1. $ cat file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | cat A line from $stdin.
  22. The “Unix Filter” Pattern ✤ Accepts a file name on

    the command-line ✤ Or multiple names at once ✤ Or reads from STDIN ✤ Writes to STDOUT $ echo 'A line from file_1.' > file_1.txt $ echo 'A line from file_2.' > file_2.txt $ cat file_1.txt A line from file_1. $ cat file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | cat A line from $stdin.
  23. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  24. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  25. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  26. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  27. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  28. Shortcuts

  29. Kernel#gets ✤ Ruby’s default “get a line of input” method

    ✤ Available everywhere ✤ It reads from ARGF ✤ You get a Unix Filter for free $ ruby -e 'puts gets' file_1.txt A line from file_1. $ ruby -e '2.times do puts gets end' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts gets' A line from $stdin.
  30. Kernel#gets ✤ Ruby’s default “get a line of input” method

    ✤ Available everywhere ✤ It reads from ARGF ✤ You get a Unix Filter for free $ ruby -e 'puts gets' file_1.txt A line from file_1. $ ruby -e '2.times do puts gets end' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts gets' A line from $stdin.
  31. The Current Line Variable: $_ ✤ Ruby has a special

    variable for “the current line:” $_ ✤ Note how it looks like a line ✤ Kernel#gets assigns to $_ ✤ Kernel#print prints $_ if no arguments are given $ ruby -e 'gets; print' file_1.txt A line from file_1. $ ruby -e 'gets; $_.tr! " ", "+"; print' file_1.txt A+line+from+file_1.
  32. The Current Line Variable: $_ ✤ Ruby has a special

    variable for “the current line:” $_ ✤ Note how it looks like a line ✤ Kernel#gets assigns to $_ ✤ Kernel#print prints $_ if no arguments are given $ ruby -e 'gets; print' file_1.txt A line from file_1. $ ruby -e 'gets; $_.tr! " ", "+"; print' file_1.txt A+line+from+file_1.
  33. The Current Line Variable: $_ ✤ Ruby has a special

    variable for “the current line:” $_ ✤ Note how it looks like a line ✤ Kernel#gets assigns to $_ ✤ Kernel#print prints $_ if no arguments are given $ ruby -e 'gets; print' file_1.txt A line from file_1. $ ruby -e 'gets; $_.tr! " ", "+"; print' file_1.txt A+line+from+file_1.
  34. The Current Line Variable: $_ ✤ Ruby has a special

    variable for “the current line:” $_ ✤ Note how it looks like a line ✤ Kernel#gets assigns to $_ ✤ Kernel#print prints $_ if no arguments are given $ ruby -e 'gets; print' file_1.txt A line from file_1. $ ruby -e 'gets; $_.tr! " ", "+"; print' file_1.txt A+line+from+file_1.
  35. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  36. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  37. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  38. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  39. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  40. The -n (non-print loop) Switch ✤ Same as -p, but

    it doesn’t print ✤ This allows you to decide when to print $ ruby -ne 'print if $_ =~ /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  41. The -n (non-print loop) Switch ✤ Same as -p, but

    it doesn’t print ✤ This allows you to decide when to print $ ruby -ne 'print if $_ =~ /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  42. The -n (non-print loop) Switch ✤ Same as -p, but

    it doesn’t print ✤ This allows you to decide when to print $ ruby -ne 'print if $_ =~ /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  43. A Bare Regexp Conditional ✤ My last example can be

    shortened ✤ A bare Regexp conditional is assumed to be a test against $_ $ ruby -ne 'print if /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  44. A Bare Regexp Conditional ✤ My last example can be

    shortened ✤ A bare Regexp conditional is assumed to be a test against $_ $ ruby -ne 'print if /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  45. The “Flip-flop” Operator ✤ A conditional can also be a

    Range of two Regexp objects ✤ It “turns on” when the first matches and will stay true until the second matches $ ruby -e 'puts %w[one two three four five six]' > numbers.txt $ ruby -ne 'print if /\A[os]/../ee\Z/' numbers.txt one two three six
  46. The “Flip-flop” Operator ✤ A conditional can also be a

    Range of two Regexp objects ✤ It “turns on” when the first matches and will stay true until the second matches $ ruby -e 'puts %w[one two three four five six]' > numbers.txt $ ruby -ne 'print if /\A[os]/../ee\Z/' numbers.txt one two three six
  47. More Twists

  48. The -i (in place edit) Switch ✤ Passing -i turns

    causes your filter to replace the input itself ✤ This is done with a buffer, so it feels like you are reading from and writing to the same place $ cat numbers.txt one two three four five six $ ruby -pi \ > -e '$_.tr! "aeiou", "X"' \ > numbers.txt $ cat numbers.txt XnX twX thrXX fXXr fXvX sXx
  49. The -i (in place edit) Switch ✤ Passing -i turns

    causes your filter to replace the input itself ✤ This is done with a buffer, so it feels like you are reading from and writing to the same place $ cat numbers.txt one two three four five six $ ruby -pi \ > -e '$_.tr! "aeiou", "X"' \ > numbers.txt $ cat numbers.txt XnX twX thrXX fXXr fXvX sXx
  50. The -i (in place edit) Switch ✤ Passing -i turns

    causes your filter to replace the input itself ✤ This is done with a buffer, so it feels like you are reading from and writing to the same place $ cat numbers.txt one two three four five six $ ruby -pi \ > -e '$_.tr! "aeiou", "X"' \ > numbers.txt $ cat numbers.txt XnX twX thrXX fXXr fXvX sXx
  51. Now With Backups ✤ -i can also accept a backup

    argument ✤ The original content is moved into a file with the backup suffix appended ✤ This can really protect you when you try to make sweeping changes with some gnarly Regexp! $ ruby -pi.bak \ > -e '$_.delete! "X"' \ > numbers.txt $ cat numbers.txt n tw thr fr fv sx $ cat numbers.txt.bak XnX twX thrXX fXXr fXvX sXx
  52. Now With Backups ✤ -i can also accept a backup

    argument ✤ The original content is moved into a file with the backup suffix appended ✤ This can really protect you when you try to make sweeping changes with some gnarly Regexp! $ ruby -pi.bak \ > -e '$_.delete! "X"' \ > numbers.txt $ cat numbers.txt n tw thr fr fv sx $ cat numbers.txt.bak XnX twX thrXX fXXr fXvX sXx
  53. Now With Backups ✤ -i can also accept a backup

    argument ✤ The original content is moved into a file with the backup suffix appended ✤ This can really protect you when you try to make sweeping changes with some gnarly Regexp! $ ruby -pi.bak \ > -e '$_.delete! "X"' \ > numbers.txt $ cat numbers.txt n tw thr fr fv sx $ cat numbers.txt.bak XnX twX thrXX fXXr fXvX sXx
  54. Now With Backups ✤ -i can also accept a backup

    argument ✤ The original content is moved into a file with the backup suffix appended ✤ This can really protect you when you try to make sweeping changes with some gnarly Regexp! $ ruby -pi.bak \ > -e '$_.delete! "X"' \ > numbers.txt $ cat numbers.txt n tw thr fr fv sx $ cat numbers.txt.bak XnX twX thrXX fXXr fXvX sXx
  55. The -a (autosplit) Switch ✤ -a will cause $_ to

    be split() into $F (fields) with each read ✤ By default, split() uses a pattern like: /\s+/ $ ruby -e 'puts "some spaced\tfields"' | \ > ruby -nae 'p $F' ["some", "spaced", "fields"]
  56. The -a (autosplit) Switch ✤ -a will cause $_ to

    be split() into $F (fields) with each read ✤ By default, split() uses a pattern like: /\s+/ $ ruby -e 'puts "some spaced\tfields"' | \ > ruby -nae 'p $F' ["some", "spaced", "fields"]
  57. The -a (autosplit) Switch ✤ -a will cause $_ to

    be split() into $F (fields) with each read ✤ By default, split() uses a pattern like: /\s+/ $ ruby -e 'puts "some spaced\tfields"' | \ > ruby -nae 'p $F' ["some", "spaced", "fields"]
  58. The -F (field separator) Switch ✤ Used with -a, -F

    will let you change the split() pattern ✤ WARNING: this is a weird old switch that doesn’t allow a space before the pattern starts! $ echo "1,2, 3" | \ > ruby -naF',\s*' -e 'p $F' ["1", "2", "3\n"]
  59. The -F (field separator) Switch ✤ Used with -a, -F

    will let you change the split() pattern ✤ WARNING: this is a weird old switch that doesn’t allow a space before the pattern starts! $ echo "1,2, 3" | \ > ruby -naF',\s*' -e 'p $F' ["1", "2", "3\n"]
  60. The -F (field separator) Switch ✤ Used with -a, -F

    will let you change the split() pattern ✤ WARNING: this is a weird old switch that doesn’t allow a space before the pattern starts! $ echo "1,2, 3" | \ > ruby -naF',\s*' -e 'p $F' ["1", "2", "3\n"]
  61. The -l (line ending) Switch ✤ -l trims the line

    ending off of read input ✤ The record separator (Ruby’s idea of a line ending) can be changed by passing an octal character code to -0 (not shown) $ echo "1,2, 3" | \ > ruby -nalF',\s*' -e 'p $F' ["1", "2", "3"]
  62. The -l (line ending) Switch ✤ -l trims the line

    ending off of read input ✤ The record separator (Ruby’s idea of a line ending) can be changed by passing an octal character code to -0 (not shown) $ echo "1,2, 3" | \ > ruby -nalF',\s*' -e 'p $F' ["1", "2", "3"]
  63. Getting Back to Normal

  64. The Choice is Yours ✤ You could take the blue

    pill and pretend Ruby is always beautiful, without any of these ugly features ✤ You could take the red pill, go further down the rabbit hole, and learn yourself some command-line Ruby wizardry
  65. For Those Who Like Red Pills ✤ Learn some regular

    expression ✤ Look into the standard “find” library ✤ When you’re ready for the really crazy stuff, look up Ruby’s BEGIN { … } and END { … } blocks
  66. One Last Warning ✤ Remember, I didn’t say these are

    the best ways to do things ✤ There are definitely shell commands that do some of these things better ✤ You can move on to learning those later ✤ Or you may already know them! ✤ That’s not the point ✤ The point: get new ideas and learn new things
  67. Thanks!