Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

WELCOME! WELCOME! 2 . 1

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

SINATRA 0.6 SINATRA 0.6 sudo gem install sinatra 4 . 3

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

ruby myapp.rb 4 . 5

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

A LITTLE RUBY HISTORY A LITTLE RUBY HISTORY 5 . 1

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

EXAMPLE EXAMPLE 12 . 4

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

SUMMARY SUMMARY 14 . 1

Slide 72

Slide 72 text

RUBY IS FUN! RUBY IS FUN! 14 . 2

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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