Slide 1

Slide 1 text

RUBY BATTERIES INCLUDED Ruby Can Standard Library, And So Can You!

Slide 2

Slide 2 text

HOW MANY GEMS DOES IT TAKE TO BUILD AN APP?

Slide 3

Slide 3 text

HOW MANY GEMS DOES IT TAKE TO BUILD AN APP? $ grep gem Gemfile -c

Slide 4

Slide 4 text

HOW MANY GEMS DOES IT TAKE TO BUILD AN APP? $ grep gem Gemfile -c 135

Slide 5

Slide 5 text

THE STANDARD LIBRARY http://ruby-doc.org/

Slide 6

Slide 6 text

CORE VS STD-LIB

Slide 7

Slide 7 text

find `ruby -e 'puts $:.join(" ")'` -iname '*.rb' -exec grep -E '^\w*class ' {} \; | sort | uniq | wc -l

Slide 8

Slide 8 text

find `ruby -e 'puts $:.join(" ")'` -iname '*.rb' -exec grep -E '^\w*class ' {} \; | sort | uniq | wc -l

Slide 9

Slide 9 text

OKAY, NOT ALL OF THEM •Bed Basics •Bath Performance •Beyond Beyond

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

http://www.flickr.com/photos/austinevan/3368444745/

Slide 12

Slide 12 text

Set

Slide 13

Slide 13 text

Set require 'set'

Slide 14

Slide 14 text

Set require 'set' s = Set.new([1, 2, 3, 1, 1, 1]) puts s.inspect # => #

Slide 15

Slide 15 text

Enumerable

Slide 16

Slide 16 text

Enumerable class MyFileChanger include Enumerable File = Struct.new(:name, :content) def initialize @files = [] end def <<(filename) content = ::File.read(filename) @files << File.new(filename, content) self end def each @files.each do |file| yield([file.name, file.content]) end end end

Slide 17

Slide 17 text

Enumerable class MyFileChanger include Enumerable File = Struct.new(:name, :content) def initialize @files = [] end def <<(filename) content = ::File.read(filename) @files << File.new(filename, content) self end def each @files.each do |file| yield([file.name, file.content]) end end end files = MyFileChanger.new files << '/etc/profile' << '/etc/bashrc' files.each_with_index do |(name, content), index| puts "#{index}. #{name} is #{content.bytesize} bytes" end names = files.map do |(name, content)| name end puts names.inspect size = files.reduce(0) do |sum, (name, content)| sum + content.bytesize end puts size

Slide 18

Slide 18 text

Enumerable class MyFileChanger include Enumerable File = Struct.new(:name, :content) def initialize @files = [] end def <<(filename) content = ::File.read(filename) @files << File.new(filename, content) self end def each @files.each do |file| yield([file.name, file.content]) end end end files = MyFileChanger.new files << '/etc/profile' << '/etc/bashrc' files.each_with_index do |(name, content), index| puts "#{index}. #{name} is #{content.bytesize} bytes" end names = files.map do |(name, content)| name end puts names.inspect size = files.reduce(0) do |sum, (name, content)| sum + content.bytesize end puts size 0. /etc/profile is 189 bytes 1. /etc/bashrc is 745 bytes ["/etc/profile", "/etc/bashrc"] 934

Slide 19

Slide 19 text

Enumerator

Slide 20

Slide 20 text

Enumerator a = [1, 2, 3] a.each { |n| puts n } Enumerator.new(a).each { |n| puts n }

Slide 21

Slide 21 text

Enumerator a = [1, 2, 3] a.each { |n| puts n } Enumerator.new(a).each { |n| puts n } naturals = Enumerator.new do |y| n = 1 loop do y << n n += 1 end end odds = Enumerator.new do |y| naturals.each do |n| y << n if n % 2 != 0 end end

Slide 22

Slide 22 text

Enumerator a = [1, 2, 3] a.each { |n| puts n } Enumerator.new(a).each { |n| puts n } naturals = Enumerator.new do |y| n = 1 loop do y << n n += 1 end end odds = Enumerator.new do |y| naturals.each do |n| y << n if n % 2 != 0 end end class Integer def prime? return false if self < 2 max = Math.sqrt(self).floor (2..max).none? { |n| self % n == 0 } end end primes = Enumerator.new do |y| y << 2 odds.each do |n| y << n if n.prime? end end

Slide 23

Slide 23 text

Enumerator a = [1, 2, 3] a.each { |n| puts n } Enumerator.new(a).each { |n| puts n } naturals = Enumerator.new do |y| n = 1 loop do y << n n += 1 end end odds = Enumerator.new do |y| naturals.each do |n| y << n if n % 2 != 0 end end class Integer def prime? return false if self < 2 max = Math.sqrt(self).floor (2..max).none? { |n| self % n == 0 } end end primes = Enumerator.new do |y| y << 2 odds.each do |n| y << n if n.prime? end end puts primes.take(10).inspect # => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Slide 24

Slide 24 text

SimpleDelegator

Slide 25

Slide 25 text

SimpleDelegator require 'delegate'

Slide 26

Slide 26 text

SimpleDelegator require 'delegate' class FancyString < SimpleDelegator def fancy? self == 'fancy' end end

Slide 27

Slide 27 text

SimpleDelegator require 'delegate' class FancyString < SimpleDelegator def fancy? self == 'fancy' end end s = FancyString.new('fancy') puts s.fancy? # => true

Slide 28

Slide 28 text

SimpleDelegator require 'delegate' class FancyString < SimpleDelegator def fancy? self == 'fancy' end end s = FancyString.new('fancy') puts s.fancy? # => true puts s.length # => 5

Slide 29

Slide 29 text

Forwardable

Slide 30

Slide 30 text

Forwardable require 'forwardable'

Slide 31

Slide 31 text

Forwardable require 'forwardable' FancyString = Struct.new(:str) do extend Forwardable # Single delegation def_delegator :str, :length, :fancy_length # Multiple delegations def_delegators :str, :include?, :match end

Slide 32

Slide 32 text

Forwardable require 'forwardable' FancyString = Struct.new(:str) do extend Forwardable # Single delegation def_delegator :str, :length, :fancy_length # Multiple delegations def_delegators :str, :include?, :match end s = FancyString.new('Hello!')

Slide 33

Slide 33 text

Forwardable require 'forwardable' FancyString = Struct.new(:str) do extend Forwardable # Single delegation def_delegator :str, :length, :fancy_length # Multiple delegations def_delegators :str, :include?, :match end s = FancyString.new('Hello!') puts s.fancy_length # => 6 puts s.include?('!') # => true

Slide 34

Slide 34 text

Forwardable require 'forwardable' FancyString = Struct.new(:str) do extend Forwardable # Single delegation def_delegator :str, :length, :fancy_length # Multiple delegations def_delegators :str, :include?, :match end s = FancyString.new('Hello!') puts s.fancy_length # => 6 puts s.include?('!') # => true puts s.bytesize # => NoMethodError

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

Benchmark

Slide 37

Slide 37 text

Benchmark require 'benchmark' results = Benchmark.measure do 1_000_000.times { |i| i.to_s } GC.start end puts results # => 0.480000 0.010000 0.490000 ( 0.487643)

Slide 38

Slide 38 text

Benchmark require 'benchmark' results = Benchmark.measure do 1_000_000.times { |i| i.to_s } GC.start end puts results # => 0.480000 0.010000 0.490000 ( 0.487643) n = 5000000 # Simple benchmark Benchmark.bm do |x| x.report { for i in 1..n; a = "1"; end } x.report { n.times do ; a = "1"; end } x.report { 1.upto(n) do ; a = "1"; end } end

Slide 39

Slide 39 text

Benchmark

Slide 40

Slide 40 text

Benchmark # Nice reporting labels Benchmark.bm(10) do |x| x.report('for:') { for i in 1..n; a = "1"; end } x.report('times:') { n.times do ; a = "1"; end } x.report('upto:') { 1.upto(n) do ; a = "1"; end } end # Warmup Benchmark.bmbm(10) do |x| x.report('for:') { for i in 1..n; a = "1"; end } x.report('times:') { n.times do ; a = "1"; end } x.report('upto:') { 1.upto(n) do ; a = "1"; end } end

Slide 41

Slide 41 text

RubyVM http://timelessrepo.com/tailin-ruby

Slide 42

Slide 42 text

RubyVM def acc(i, n, result) if i == -1 result else acc(i - 1, n + result, n) end end def fib(i) acc(i, 1, 0) end puts fib(10000) # => stack level too deep (SystemStackError) http://timelessrepo.com/tailin-ruby

Slide 43

Slide 43 text

RubyVM::InstructionSequence

Slide 44

Slide 44 text

RubyVM::InstructionSequence RubyVM::InstructionSequence.compile_option = { :tailcall_optimization => true, :trace_instruction => false }

Slide 45

Slide 45 text

RubyVM::InstructionSequence RubyVM::InstructionSequence.compile_option = { :tailcall_optimization => true, :trace_instruction => false } RubyVM::InstructionSequence.new(<<-EOF).eval def acc(i, n, result) if i == -1 result else acc(i - 1, n + result, n) end end def fib(i) acc(i, 1, 0) end EOF

Slide 46

Slide 46 text

RubyVM::InstructionSequence RubyVM::InstructionSequence.compile_option = { :tailcall_optimization => true, :trace_instruction => false } RubyVM::InstructionSequence.new(<<-EOF).eval def acc(i, n, result) if i == -1 result else acc(i - 1, n + result, n) end end def fib(i) acc(i, 1, 0) end EOF puts fib(10000) # => A number with 2090 digits

Slide 47

Slide 47 text

Fiddle

Slide 48

Slide 48 text

Fiddle require 'fiddle' include Fiddle

Slide 49

Slide 49 text

Fiddle require 'fiddle' include Fiddle libm = DL.dlopen('/usr/lib/libm.dylib')

Slide 50

Slide 50 text

Fiddle require 'fiddle' include Fiddle libm = DL.dlopen('/usr/lib/libm.dylib') f = libm['sqrt']

Slide 51

Slide 51 text

Fiddle require 'fiddle' include Fiddle libm = DL.dlopen('/usr/lib/libm.dylib') f = libm['sqrt'] args = [TYPE_DOUBLE]

Slide 52

Slide 52 text

Fiddle require 'fiddle' include Fiddle libm = DL.dlopen('/usr/lib/libm.dylib') f = libm['sqrt'] args = [TYPE_DOUBLE] ret = TYPE_DOUBLE

Slide 53

Slide 53 text

Fiddle require 'fiddle' include Fiddle libm = DL.dlopen('/usr/lib/libm.dylib') f = libm['sqrt'] args = [TYPE_DOUBLE] ret = TYPE_DOUBLE sqrt = Function.new(f, args, ret)

Slide 54

Slide 54 text

Fiddle require 'fiddle' include Fiddle libm = DL.dlopen('/usr/lib/libm.dylib') f = libm['sqrt'] args = [TYPE_DOUBLE] ret = TYPE_DOUBLE sqrt = Function.new(f, args, ret) puts sqrt.call(81) # => 9.0

Slide 55

Slide 55 text

WeakRef

Slide 56

Slide 56 text

WeakRef require 'weakref' bightml = WeakRef.new(read_html('http:// bigpage.com/')) puts bightml # => "..." puts bightml.weakref_alive? # => true

Slide 57

Slide 57 text

WeakRef require 'weakref' bightml = WeakRef.new(read_html('http:// bigpage.com/')) puts bightml # => "..." puts bightml.weakref_alive? # => true GC.start

Slide 58

Slide 58 text

WeakRef require 'weakref' bightml = WeakRef.new(read_html('http:// bigpage.com/')) puts bightml # => "..." puts bightml.weakref_alive? # => true GC.start puts bightml.weakref_alive? # => false

Slide 59

Slide 59 text

http://www.flickr.com/photos/bobcanada/4506301467/

Slide 60

Slide 60 text

SecureRandom

Slide 61

Slide 61 text

SecureRandom require 'securerandom'

Slide 62

Slide 62 text

SecureRandom require 'securerandom' puts SecureRandom.base64 # => 9d4va7k0/XhK2EqYMXJ2jg==

Slide 63

Slide 63 text

SecureRandom require 'securerandom' puts SecureRandom.base64 # => 9d4va7k0/XhK2EqYMXJ2jg== puts SecureRandom.hex # => 9e70e038fc7faf20106c304854c21b8a

Slide 64

Slide 64 text

SecureRandom require 'securerandom' puts SecureRandom.base64 # => 9d4va7k0/XhK2EqYMXJ2jg== puts SecureRandom.hex # => 9e70e038fc7faf20106c304854c21b8a puts SecureRandom.random_bytes.inspect # => "r>0\xD1\xA4\x00t&\x82\xFCEl_\x17w\xF1"

Slide 65

Slide 65 text

SecureRandom require 'securerandom' puts SecureRandom.base64 # => 9d4va7k0/XhK2EqYMXJ2jg== puts SecureRandom.hex # => 9e70e038fc7faf20106c304854c21b8a puts SecureRandom.random_bytes.inspect # => "r>0\xD1\xA4\x00t&\x82\xFCEl_\x17w\xF1" puts SecureRandom.random_number # => 0.47149176126339587

Slide 66

Slide 66 text

SecureRandom require 'securerandom' puts SecureRandom.base64 # => 9d4va7k0/XhK2EqYMXJ2jg== puts SecureRandom.hex # => 9e70e038fc7faf20106c304854c21b8a puts SecureRandom.random_bytes.inspect # => "r>0\xD1\xA4\x00t&\x82\xFCEl_\x17w\xF1" puts SecureRandom.random_number # => 0.47149176126339587 puts SecureRandom.random_number(50) # => 37

Slide 67

Slide 67 text

SecureRandom require 'securerandom' puts SecureRandom.base64 # => 9d4va7k0/XhK2EqYMXJ2jg== puts SecureRandom.hex # => 9e70e038fc7faf20106c304854c21b8a puts SecureRandom.random_bytes.inspect # => "r>0\xD1\xA4\x00t&\x82\xFCEl_\x17w\xF1" puts SecureRandom.random_number # => 0.47149176126339587 puts SecureRandom.random_number(50) # => 37 puts SecureRandom.uuid # => 3a34412c-4798-4985-9a43-7d36a6e0d116

Slide 68

Slide 68 text

GServer

Slide 69

Slide 69 text

GServer require 'gserver'

Slide 70

Slide 70 text

GServer require 'gserver' require 'securerandom' class RandomServer < GServer def serve(io) cmd = io.read(4).strip case cmd when 'hex' then io.puts(SecureRandom.hex) when 'uuid' then io.puts(SecureRandom.uuid) end end end

Slide 71

Slide 71 text

GServer require 'gserver' require 'securerandom' class RandomServer < GServer def serve(io) cmd = io.read(4).strip case cmd when 'hex' then io.puts(SecureRandom.hex) when 'uuid' then io.puts(SecureRandom.uuid) end end end server = RandomServer.new(10101) server.start server.join

Slide 72

Slide 72 text

Kernel#spawn

Slide 73

Slide 73 text

Kernel#spawn def capture(cmd) r, w = IO.pipe pid = spawn(cmd, :out => w) w.close Process.wait(pid) r.read ensure r.close end output = capture('randomizer') print output

Slide 74

Slide 74 text

Shellwords

Slide 75

Slide 75 text

Shellwords require 'shellwords'

Slide 76

Slide 76 text

Shellwords require 'shellwords' pattern = '; rm -rf /; ' capture("randomizer #{pattern.shellescape} /dev/*")

Slide 77

Slide 77 text

Shellwords require 'shellwords' pattern = '; rm -rf /; ' capture("randomizer #{pattern.shellescape} /dev/*") # Assuming our capture function could take *args like system

Slide 78

Slide 78 text

Shellwords require 'shellwords' pattern = '; rm -rf /; ' capture("randomizer #{pattern.shellescape} /dev/*") # Assuming our capture function could take *args like system capture('randomizer', pattern, '/dev/*') # => Nope

Slide 79

Slide 79 text

PStore

Slide 80

Slide 80 text

PStore require 'pstore' store = PStore.new('randomizer', thread_safe = true) store.ultra_safe = true

Slide 81

Slide 81 text

PStore require 'pstore' store = PStore.new('randomizer', thread_safe = true) store.ultra_safe = true store.transaction do store['App'] = 'The Randomizer' store[:randoms] ||= [] store[:randoms] << Randomizer.uuid end

Slide 82

Slide 82 text

PStore require 'pstore' store = PStore.new('randomizer', thread_safe = true) store.ultra_safe = true store.transaction do store['App'] = 'The Randomizer' store[:randoms] ||= [] store[:randoms] << Randomizer.uuid end store.transaction do puts store[:randoms].inspect # => ["901dcd24-fa10-4194-b25b-8ad49bc875fb"] end

Slide 83

Slide 83 text

PStore require 'pstore' store = PStore.new('randomizer', thread_safe = true) store.ultra_safe = true store.transaction do store['App'] = 'The Randomizer' store[:randoms] ||= [] store[:randoms] << Randomizer.uuid end store.transaction do puts store[:randoms].inspect # => ["901dcd24-fa10-4194-b25b-8ad49bc875fb"] end store.transaction do store[:randoms] = [] store.abort # Or an Exception end

Slide 84

Slide 84 text

PStore require 'pstore' store = PStore.new('randomizer', thread_safe = true) store.ultra_safe = true store.transaction do store['App'] = 'The Randomizer' store[:randoms] ||= [] store[:randoms] << Randomizer.uuid end store.transaction do puts store[:randoms].inspect # => ["901dcd24-fa10-4194-b25b-8ad49bc875fb"] end store.transaction do store[:randoms] = [] store.abort # Or an Exception end store.transaction do puts store[:randoms].inspect # => ["901dcd24-fa10-4194-b25b-8ad49bc875fb"] end

Slide 85

Slide 85 text

I heard you like testing...

Slide 86

Slide 86 text

I heard you like testing...

Slide 87

Slide 87 text

MiniTest

Slide 88

Slide 88 text

MiniTest require 'minitest/autorun' class MathTest < MiniTest::Unit::TestCase def test_addition assert_equal 2, 1 + 1 end end describe Integer do it 'should subtract' do (1 - 1).must_equal(0) end end

Slide 89

Slide 89 text

MiniTest require 'minitest/autorun' class MathTest < MiniTest::Unit::TestCase def test_addition assert_equal 2, 1 + 1 end end describe Integer do it 'should subtract' do (1 - 1).must_equal(0) end end describe 'Mocks' do it 'should mock things' do mock = MiniTest::Mock.new mock.expect(:length, 10) mock.length.must_equal(10) mock.verify end end

Slide 90

Slide 90 text

Other Fun Things • OptionParser/optparse, GetoptLong/getoptlong • Two command line option parsers! • WEBrick => require ‘webrick’ • Threaded HTTP server. • Rss => require ‘rss’ • Parse and generate RSS feeds. In the stdlib. wat.

Slide 91

Slide 91 text

Other Fun Things • Drb => require ‘drb’ • Distributed object system. • Find => require ‘find’ • Recursively iterate the filesystem. • Ripper => require ‘ripper’ • Parse ruby files

Slide 92

Slide 92 text

Other Fun Things • ThreadsWait => require ‘thwait’ • Wait for a bunch of threads, block called for each when it finishes. • Queue/SizedQueue => require ‘thread’ • << things in, #pop things out. • MonitorMixin => require ‘monitor’ • Thread safety with synchronize block.

Slide 93

Slide 93 text

Other Fun Things • Net::POP3 => require ‘net/pop’ • Talk POP3 email. • Net::IMAP => require ‘net/imap’ • Talk IMAP email. • Net::SMTP => require ‘net/smtp’ • Talk to SMTP servers.

Slide 94

Slide 94 text

Other Fun Things • Net::FTP => require ‘net/ftp’ • Talk FTP • Net::HTTP => require ‘net/http’ • Talk HTTP

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

THANKS!! @darkhelmetlive darkhelmet verboselogging.com GetYardstick.com https://www.makesets.com/the-ruby-standard-library