Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Command-line Ruby

jeg2
February 22, 2013

Command-line Ruby

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

jeg2

February 22, 2013
Tweet

More Decks by jeg2

Other Decks in Technology

Transcript

  1. Now For Something Completely Different
    Command-line Ruby
    Or “How You Can Learn Ruby Faster”

    View full-size slide

  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

    View full-size slide

  3. Ruby is Beautiful

    View full-size slide

  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

    View full-size slide

  5. That’s All True,
    and Usually Very Important

    View full-size slide

  6. But Not Today!

    View full-size slide

  7. This Is For Your Own Good!
    Ugly Ruby
    Strap In Folks, This Could Get Weird

    View full-size slide

  8. “Why would you do this???”

    View full-size slide

  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?

    View full-size slide

  10. Stay Mindful of
    the Reasons We Write Code

    View full-size slide

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

    View full-size slide

  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.

    View full-size slide

  13. Use Ruby to Do More

    View full-size slide

  14. Command-line Ruby Basics

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  28. 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.

    View full-size slide

  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.

    View full-size slide

  30. 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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  34. 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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  39. 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.

    View full-size slide

  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.

    View full-size slide

  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.

    View full-size slide

  42. 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.

    View full-size slide

  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.

    View full-size slide

  44. 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

    View full-size slide

  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

    View full-size slide

  46. 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

    View full-size slide

  47. 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

    View full-size slide

  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

    View full-size slide

  49. 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

    View full-size slide

  50. 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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  53. 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"]

    View full-size slide

  54. 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"]

    View full-size slide

  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"]

    View full-size slide

  56. 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"]

    View full-size slide

  57. 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"]

    View full-size slide

  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"]

    View full-size slide

  59. 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"]

    View full-size slide

  60. 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"]

    View full-size slide

  61. Getting Back to Normal

    View full-size slide

  62. 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

    View full-size slide

  63. 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

    View full-size slide

  64. 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

    View full-size slide