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

Single File Ruby Programs

Single File Ruby Programs

A loose collection of Ruby fun facts and examples to organize your code in a single file.

Let’s have some fun with Ruby!

Source: https://github.com/fabrik42/single-file-ruby-programs/

Christian Bäuerlein

March 26, 2020
Tweet

More Decks by Christian Bäuerlein

Other Decks in Programming

Transcript

  1. SINGLE FILE RUBY
    SINGLE FILE RUBY
    PROGRAMS
    PROGRAMS
    CHRISTIAN BÄUERLEIN
    CHRISTIAN BÄUERLEIN
    Created: 2020-03-26 Thu 18:58
    1

    View Slide

  2. WELCOME!
    WELCOME!
    2 . 1

    View Slide

  3. THE LOST ART OF SINGLE FILE RUBY PROGRAMS
    THE LOST ART OF SINGLE FILE RUBY PROGRAMS
    A loose collec on of Ruby fun facts and examples to
    organize your code in a single file.
    Let's have some fun with Ruby!
    2 . 2

    View Slide

  4. CODE & TESTS IN ONE FILE
    CODE & TESTS IN ONE FILE
    3 . 1

    View Slide

  5. RUBY MAGIC CONSTANTS
    RUBY MAGIC CONSTANTS
    There is ~$0.
    Source:
    Contains the name of the file containing
    the Ruby script being executed.
    Pre-defined variables and constants
    Pre-defined variables and constants
    3 . 2

    View Slide

  6. THE SOURCE FILE
    THE SOURCE FILE
    def greet(name)
    "Hello #{name}!"
    end
    # this will only run if the script was the main
    # not load'd or require'd
    if __FILE__ == $0
    require "test/unit/assertions"
    include Test::Unit::Assertions
    assert_equal 'Hello Ruby', greet('Ruby'), "greet function shoul
    end
    3 . 3

    View Slide

  7. WHEN CALLED DIRECTLY
    WHEN CALLED DIRECTLY
    $ ruby code_and_test.rb
    greet function should return 'Hello Ruby!'. (Test::Unit::Asserti
    <"Hello Ruby"> expected but was
    <"Hello Ruby!">.
    diff:
    - Hello Ruby
    + Hello Ruby!
    ?
    3 . 4

    View Slide

  8. WHEN REQUIRED
    WHEN REQUIRED
    require './code_and_test.rb'
    puts greet "Christian"
    $ ruby code_and_test_usage.rb
    Hello Christian!
    3 . 5

    View Slide

  9. YOU MAY KNOW THIS FROM PYTHON
    YOU MAY KNOW THIS FROM PYTHON
    Source:
    def hello():
    print("Hello world, this script was called!")
    if __name__ == '__main__':
    hello()
    Python Define Unit Test Classes Together with Code
    Python Define Unit Test Classes Together with Code
    3 . 6

    View Slide

  10. A WEBSERVER IN ONE FILE?
    A WEBSERVER IN ONE FILE?
    4 . 1

    View Slide

  11. MY LIFE BEFORE RUBY
    MY LIFE BEFORE RUBY
    Before Ruby, my favorite web framework was
    .
    Security first: One index.html file in EVERY folder.
    CodeIgniter
    CodeIgniter
    4 . 2

    View Slide

  12. SINATRA 0.6
    SINATRA 0.6
    sudo gem install sinatra
    4 . 3

    View Slide

  13. Awesome!!!
    require "rubygems"
    require "sinatra"
    get '/' do
    "Hello World"
    end
    4 . 4

    View Slide

  14. ruby myapp.rb
    4 . 5

    View Slide

  15. TEMPLATES: UNCOOL WAY
    TEMPLATES: UNCOOL WAY
    "You can do this too but it's not as cool" - Sinatra
    Readme
    template :index do
    '%div.title Hello World!'
    end
    4 . 6

    View Slide

  16. TEMPLATES
    TEMPLATES
    As documented in the this was the cool
    way to do it.
    README.rdoc
    README.rdoc
    get '/' do
    haml :index
    end
    use_in_file_templates!
    __END__
    @@ layout
    X
    = yield
    X
    @@ index
    %div.title Hello world!!!!!
    4 . 7

    View Slide

  17. A LITTLE RUBY HISTORY
    A LITTLE RUBY HISTORY
    5 . 1

    View Slide

  18. RUBY IS A BETTER PERL
    RUBY IS A BETTER PERL
    Why the name 'Ruby'?
    Source:
    Influenced by Perl, Matz wanted to use a
    jewel name for his new language, so he
    named Ruby a er a colleague's
    birthstone.
    The Ruby Language FAQ
    The Ruby Language FAQ
    5 . 2

    View Slide

  19. PERL'S LEGACY
    PERL'S LEGACY
    Ruby took a lot of things from Pearl.
    Today we will learn about:
    Keywords
    Command line flags
    5 . 3

    View Slide

  20. LET'S START WITH PERLDATA
    LET'S START WITH PERLDATA
    Perl has two special literals:
    __END__ - Indicates the logical end of the script
    before the actual end of file. Any following text is
    ignored.
    __DATA__ - A filehandle that points to everything
    that comes a er __END__.
    Source: perldata - perldoc.perl.org
    perldata - perldoc.perl.org
    5 . 4

    View Slide

  21. THE
    THE __END__
    __END__ AND
    AND DATA
    DATA
    KEYWORDS
    KEYWORDS
    Denotes the end of the regular source
    code sec on of a program file. Lines
    below __END__ will not be executed.
    6 . 1

    View Slide

  22. Source:
    Those lines will be available via the
    special filehandle DATA
    Class: Object
    Class: Object
    6 . 2

    View Slide

  23. SIMPLE EXAMPLE
    SIMPLE EXAMPLE
    DATA.each_line do |line|
    puts line
    end
    __END__
    Doom
    Quake
    Diablo
    6 . 3

    View Slide

  24. ERB TEMPLATE AND CODE IN ONE FILE
    ERB TEMPLATE AND CODE IN ONE FILE
    require 'erb'
    time = Time.now
    renderer = ERB.new(DATA.read)
    puts renderer.result()
    __END__
    The current time is <%= time %>.
    6 . 4

    View Slide

  25. EXPLAINED: SINATRA STYLE MULTIPLE TEMPLATES IN FILE
    EXPLAINED: SINATRA STYLE MULTIPLE TEMPLATES IN FILE
    get '/' do
    haml :index
    end
    use_in_file_templates!
    __END__
    @@ layout
    X
    = yield
    X
    @@ index
    %div.title Hello world!!!!!
    6 . 5

    View Slide

  26. Source:
    File.read(caller.first.split(":").first).split("__END__", 2).last
    Mixing code and data in Ruby
    Mixing code and data in Ruby
    6 . 6

    View Slide

  27. PSA: PHP CAN DO IT AS WELL
    PSA: PHP CAN DO IT AS WELL
    Source: Example:
    // open self
    $fp = fopen(__FILE__, 'rb');
    // seek file pointer to data
    //__COMPILER_HALT_OFFSET__ will return
    //the point after __halt_compiler();
    fseek($fp, __COMPILER_HALT_OFFSET__);
    // and output it
    $unpacked = gzinflate(stream_get_contents($fp));
    __halt_compiler();
    //now here... all the binary gzdeflate already items!!!
    PHP: __halt_compiler - Manual
    PHP: __halt_compiler - Manual
    __halt_compiler(), make install files for PHP smaller
    __halt_compiler(), make install files for PHP smaller
    6 . 7

    View Slide

  28. BUNDLER INLINE
    BUNDLER INLINE
    Fun fact: You don't need a Gemfile to use bundler!
    Useful for scripts in your /utils folder that you only
    use once a year.
    Source: How to use Bundler in a single-file Ruby script
    How to use Bundler in a single-file Ruby script
    7 . 1

    View Slide

  29. INLINE HTTPARTY
    INLINE HTTPARTY
    require 'bundler/inline'
    gemfile do
    gem 'httparty'
    end
    puts HTTParty.get('https://www.boredapi.com/api/activity')
    7 . 2

    View Slide

  30. INLINE MINITEST
    INLINE MINITEST
    require 'bundler/inline'
    gemfile do
    gem 'minitest', require: false
    end
    require 'minitest/autorun'
    class MyTest < Minitest::Test
    def test_should_be_true
    assert_equal true, true
    end
    end
    7 . 3

    View Slide

  31. ADVANCED EXAMPLE: DOWNLOAD ICAL TO
    ADVANCED EXAMPLE: DOWNLOAD ICAL TO
    ORG
    ORG
    Source: ical_to_org.rb
    ical_to_org.rb
    8 . 1

    View Slide

  32. ADVANCED EXAMPLE: DOWNLOAD ICAL TO
    ADVANCED EXAMPLE: DOWNLOAD ICAL TO
    ORG
    ORG
    Install Dependencies
    Source: ical_to_org.rb
    ical_to_org.rb
    8 . 1

    View Slide

  33. ADVANCED EXAMPLE: DOWNLOAD ICAL TO
    ADVANCED EXAMPLE: DOWNLOAD ICAL TO
    ORG
    ORG
    Install Dependencies
    Do stuff (download calendar events)
    Source: ical_to_org.rb
    ical_to_org.rb
    8 . 1

    View Slide

  34. ADVANCED EXAMPLE: DOWNLOAD ICAL TO
    ADVANCED EXAMPLE: DOWNLOAD ICAL TO
    ORG
    ORG
    Install Dependencies
    Do stuff (download calendar events)
    Render to ERb template
    Source: ical_to_org.rb
    ical_to_org.rb
    8 . 1

    View Slide

  35. BEGIN
    BEGIN AND
    AND END
    END KEYWORDS
    KEYWORDS
    Yes, this is taken from Perl as well.
    9 . 1

    View Slide

  36. DEFINITION
    DEFINITION
    Source:
    BEGIN defines a block that is run before
    any other code in the current file. It is
    typically used in one-liners with ruby -e.
    Similarly END defines a block that is run
    a er any other code.
    Documenta on for Ruby 2.2.0
    Documenta on for Ruby 2.2.0
    9 . 2

    View Slide

  37. EXAMPLE
    EXAMPLE
    END { puts 3 }
    BEGIN { puts 1 }
    puts 2
    ruby begin.rb
    1
    2
    3
    9 . 3

    View Slide

  38. INTRODUCING LRUBY
    INTRODUCING LRUBY
    Logging Ruby - The Ruby alias for the forge ul scripter
    Logging Ruby!
    Only Feature: No more scrolling through your
    terminal… Logs the output of a script to the script
    itself!
    10 . 1

    View Slide

  39. LET'S TRY THIS OUT
    LET'S TRY THIS OUT
    cat log_results/hello_world.rb
    ruby log_results/hello_world.rb
    10 . 2

    View Slide

  40. INTRODUCING: LRUBY
    INTRODUCING: LRUBY
    lruby log_results/hello_world.rb
    cat log_results/hello_world.rb
    10 . 3

    View Slide

  41. HOW DOES IT WORK?
    HOW DOES IT WORK?
    Let's check out the source of
    which lruby
    LRuby log_results.rb
    LRuby log_results.rb
    10 . 4

    View Slide

  42. THE GARBAGE FLAG
    THE GARBAGE FLAG
    Aaaaand back to Perl!
    11 . 1

    View Slide

  43. PERLRUN
    PERLRUN
    Source:
    perl -x
    Leading garbage will be discarded un l
    the first line that starts with #! and
    contains the string "perl".
    perlrun - perldoc.perl.org
    perlrun - perldoc.perl.org
    11 . 2

    View Slide

  44. BUT… WHY?
    BUT… WHY?
    Tells Perl that the program is embedded
    in a larger chunk of unrelated text, such
    as in a mail message.
    11 . 3

    View Slide

  45. AND IN RUBY..
    AND IN RUBY..
    Source:
    ruby -x
    Tells Ruby that the script is embedded in
    a message. Leading garbage will be
    discarded un l the first that starts with
    "#!" and contains string "ruby".
    Ruby Docs Command line Op ons
    Ruby Docs Command line Op ons
    11 . 4

    View Slide

  46. EXAMPLE
    EXAMPLE
    Hello dear friend,
    this is a mail message. Please execute it with your ruby interpre
    Thanks,
    a random stranger
    #! hahaha this is ruby now
    puts "Hello World"
    ruby -x email.eml
    11 . 5

    View Slide

  47. A SELF-ANIMATING GIF
    A SELF-ANIMATING GIF
    This is not an animated gif, but a gif that animates
    itself.
    12 . 1

    View Slide

  48. LET'S TALK ABOUT GIFS
    LET'S TALK ABOUT GIFS
    12 . 2

    View Slide

  49. A GIF FILE CONSISTS OF BLOCKS
    A GIF FILE CONSISTS OF BLOCKS
    12 . 3

    View Slide

  50. EXAMPLE
    EXAMPLE
    12 . 4

    View Slide

  51. TERMINATOR BYTE
    TERMINATOR BYTE
    The trailer block indicates when you've reached the
    end of the file. It is always a byte with a value of 3B.
    Source: What's In A GIF
    What's In A GIF
    12 . 5

    View Slide

  52. SOOOO NOW WE KNOW THAT..
    SOOOO NOW WE KNOW THAT..
    12 . 6

    View Slide

  53. SOOOO NOW WE KNOW THAT..
    SOOOO NOW WE KNOW THAT..
    GIFs are nice
    12 . 6

    View Slide

  54. SOOOO NOW WE KNOW THAT..
    SOOOO NOW WE KNOW THAT..
    GIFs are nice
    GIFs always end with the same terminator byte
    12 . 6

    View Slide

  55. SOOOO NOW WE KNOW THAT..
    SOOOO NOW WE KNOW THAT..
    GIFs are nice
    GIFs always end with the same terminator byte
    Ruby is nice
    12 . 6

    View Slide

  56. SOOOO NOW WE KNOW THAT..
    SOOOO NOW WE KNOW THAT..
    GIFs are nice
    GIFs always end with the same terminator byte
    Ruby is nice
    Ruby can start with a defined start line
    12 . 6

    View Slide

  57. SOOOO NOW WE KNOW THAT..
    SOOOO NOW WE KNOW THAT..
    GIFs are nice
    GIFs always end with the same terminator byte
    Ruby is nice
    Ruby can start with a defined start line
    Nice.
    12 . 6

    View Slide

  58. A SELF-ANIMATING GIF
    A SELF-ANIMATING GIF
    This is not an animated gif, but a gif that animates
    itself.
    12 . 7

    View Slide

  59. A SELF-ANIMATING GIF
    A SELF-ANIMATING GIF
    This is not an animated gif, but a gif that animates
    itself.
    One file
    12 . 7

    View Slide

  60. A SELF-ANIMATING GIF
    A SELF-ANIMATING GIF
    This is not an animated gif, but a gif that animates
    itself.
    One file
    Upper half is a GIF
    12 . 7

    View Slide

  61. A SELF-ANIMATING GIF
    A SELF-ANIMATING GIF
    This is not an animated gif, but a gif that animates
    itself.
    One file
    Upper half is a GIF
    Lower half is Ruby code
    12 . 7

    View Slide

  62. A SELF-ANIMATING GIF
    A SELF-ANIMATING GIF
    This is not an animated gif, but a gif that animates
    itself.
    One file
    Upper half is a GIF
    Lower half is Ruby code
    File rewrites itself!
    12 . 7

    View Slide

  63. A SELF-ANIMATING GIF
    A SELF-ANIMATING GIF
    This is not an animated gif, but a gif that animates
    itself.
    One file
    Upper half is a GIF
    Lower half is Ruby code
    File rewrites itself!
    Profit!
    12 . 7

    View Slide

  64. SOURCE CODE
    SOURCE CODE
    Let's check out the together!
    rbgif.gif source code
    rbgif.gif source code
    12 . 8

    View Slide

  65. LIVE DEMO!
    LIVE DEMO!
    while 1; do cd ~/Dropbox/slides/single-file-ruby-programs/rbgif;
    12 . 9

    View Slide

  66. ONE MORE THING…
    ONE MORE THING…
    Source:
    #!/bin/sh
    echo This is bash
    i=12
    echo $i
    perl - $i <<'__HERE__'
    my $i = shift;
    print "This is perl\n";
    print ++$i . "\n";
    __HERE__
    echo This is bash again
    echo $i
    perl script inside a shell script
    perl script inside a shell script
    13 . 1

    View Slide

  67. PERLMONKS.ORG 2000 TESTIMONIALS
    PERLMONKS.ORG 2000 TESTIMONIALS
    13 . 2

    View Slide

  68. PERLMONKS.ORG 2000 TESTIMONIALS
    PERLMONKS.ORG 2000 TESTIMONIALS
    "Ain't that fun?" - dchetlin
    13 . 2

    View Slide

  69. PERLMONKS.ORG 2000 TESTIMONIALS
    PERLMONKS.ORG 2000 TESTIMONIALS
    "Ain't that fun?" - dchetlin
    "It's strange and terrible and I'm not sure how to
    get something out of the perl part, but this sort of
    works" - eg
    13 . 2

    View Slide

  70. PERLMONKS.ORG 2000 TESTIMONIALS
    PERLMONKS.ORG 2000 TESTIMONIALS
    "Ain't that fun?" - dchetlin
    "It's strange and terrible and I'm not sure how to
    get something out of the perl part, but this sort of
    works" - eg
    "This, on the other hand is just … just .. well, I
    don't know. Not right. Not even wrong. It just is." -
    Blue
    13 . 2

    View Slide

  71. SUMMARY
    SUMMARY
    14 . 1

    View Slide

  72. RUBY IS FUN!
    RUBY IS FUN!
    14 . 2

    View Slide

  73. SINGLE FILE RUBY PROGRAMS
    SINGLE FILE RUBY PROGRAMS
    Code & Tests
    Dependencies & Code
    Data & Code
    Code & Data
    Code & Output
    Try it out for fun and profit!
    14 . 3

    View Slide

  74. THANKS!
    THANKS!
    Ques ons?
    Chris an Bäuerlein @fabrik42
    @fabrik42
    15 . 1

    View Slide