Robert W. Hasker, 2011-2015. Blocked Previous uses of blocks words.each { |w| puts “word:...

17
BLOCKED RUBY Robert W. Hasker, 2011-2015

Transcript of Robert W. Hasker, 2011-2015. Blocked Previous uses of blocks words.each { |w| puts “word:...

Page 1: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

BLOCKED RUBYRobert W. Hasker, 2011-2015

Page 2: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Blocked

Previous uses of blocks words.each { |w| puts “word: #{w}” } words.find { |x| x.size > 2 } Voter.where { |v| v.name.empty? }

Note type of Voter.all: ActiveRecord::Relation .where, etc: return WhereChain – delayed result

Other uses: infinite computations Infinite range: nats = 0..(1.0/0) Some evens:

nats.step(2).lazy.drop(50).take(10)

Page 3: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Uses of infinity

squares = nats.lazy.map { |n| n * n } Prime numbers:

require ‘prime’ Prime.first(10) Prime.lazy.drop(1000).

select { |x| (x+1)%2 == 0 }.first 5

Page 4: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

How does this work? Ruby code to delay evaluation:

class Promise def initialize(&block) @block = block @delayed = true end def force @value = @block.call if @delayed @delayed = false @value end def method_missing(*args, &block) @value.__send__(*args, &block) endend

Page 5: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

How does this work?

In general: Delay: promise to provide value when

requested Force: call in the promise

Processing list: force head when required, delay rest

Ruby implementation: blocks Useful tool when want to delay execution

in general

Page 6: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Yet more blockhead actions Computing Fibonacci numbers:fibonacci =

Hash.new{ |h,k|

h[k] = k < 2 ? k : h[k-1] + h[k-2] }

From Ruby documentation: If a block is specified, it will be called

with the hash object and the key, and should return the default value. It is the block’s responsibility to store the value in the hash if required.

Page 7: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Using blocks creatively

From Eloquent Ruby by Russ Olsen, 2011 How to log events smoothly? Consider:

class WonderApplication

def do_something doc = Document.load ‘masterwork.txt’

doc.save end

end

Page 8: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Adding loggingclass WonderApplication def initialize(logger) @logger = logger end

def do_something @logger.post ‘Starting load’ doc = Document.load ‘masterwork.txt’ @logger.post ‘Completed load’

… @logger.post ‘Starting save’ doc.save @logger.post ‘Completed save’ endend

Page 9: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

And rescues…def do_something begin @logger.post ‘Starting load’ doc = Document.load ‘masterwork.txt’ @logger.post ‘Completed load’ rescue

@logger.post ‘Load failed’; raise end … begin @logger.post ‘Starting save’ doc.save @logger.post ‘Completed save’ rescue @logger.post ‘Save failed’; raise endend

Page 10: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Fix:def with_logging(description) begin @logger.post “Starting #{description}” yield @logger.post “Completed #{description}” rescue

@logger.post “#{description} failed”; raise endend

def do_somethingwith_logging(‘load’) { @doc = Document.load ‘masterwork.txt’ } … with_logging(‘save’) { @doc.save }

end

Page 11: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Fix:def with_logging(description) begin @logger.post “Starting #{description}” yield @logger.post “Completed #{description}” rescue

@logger.post “#{description} failed”; raise endend

def do_somethingwith_logging(‘load’) { @doc = Document.load ‘masterwork.txt’ } … with_logging(‘save’) { @doc.save }

end

“Execute around”

Page 12: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Blocks and initialization

Basic concept behind lazy lists: delayed initialization Consider:

class ArchivalDocument attr_reader :title, :author

def initialize(title, author, path) @title = title @author = author @path = path end def content @content = @content || File.read(path) end

end

Page 13: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Blocks and initialization

Basic concept behind lazy lists: delayed initialization Consider:

class ArchivalDocument attr_reader :title, :author

def initialize(title, author, path) @title = title @author = author @path = path end def content @content = @content || File.read(path) end

end

Assumption: don’t usually need content for archived object

Page 14: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Blocks and initialization

Basic concept behind lazy lists: delayed initialization Consider:

class ArchivalDocument attr_reader :title, :author

def initialize(title, author, path) @title = title @author = author @path = path end def content @content = @content || File.read(path) end

end

Assumption: don’t usually need content for archived object

Limitation: only works for files

Page 15: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Blocks to the rescue:

class ArchivalDocument attr_reader :title, :author

def initialize(title, author, &reader_block) @title = title @author = author @reader = reader_block end def content if @reader @content = @reader.call @reader = nil end @content end

end

Page 16: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Usage

simple_file_doc =ArchivalDocument.new(‘Rubies Forever’, ‘Tim’) doFile.read(‘c:/books/rubies_forever.txt’)

end

google_doc = ArchivalDocument.new(‘Sherlock Holmes’, ‘Conan Doyle’) do

Net::HTTP.get_response(‘books.google.com’, ‘/books?id=QhPgEq5ZeY8C’).body

end

boring_doc = ArchivalDocument.new(‘silly’, ‘Rob’) do ‘Ya’ * 100end

Page 17: Robert W. Hasker, 2011-2015. Blocked  Previous uses of blocks  words.each { |w| puts “word: #{w}” }  words.find { |x| x.size > 2 }  Voter.where {

Summary

Infinite ranges, lists Generating streams

Execute around Embed computations in a context

Lazy initialization Application of lazy list concept to

initialization Basic principles:

Delayed execution Stored behaviors