-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added my old "Better Ruby through FP" talks.
- Loading branch information
1 parent
d7d176a
commit 9aee018
Showing
24 changed files
with
484 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
56 changes: 56 additions & 0 deletions
56
BetterRubyThroughFP/fp-ruby-code-examples/actor-example.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Uses MenTaLguY's Concurrent Gem | ||
# Runs on MRI (1.8) | ||
# Example adapted from http://groups.google.com/group/ruby-talk-google/browse_thread/thread/ec442079705d168a | ||
|
||
require 'rubygems' | ||
require 'concurrent/actors' | ||
require 'case' | ||
|
||
require 'shapes' | ||
|
||
include Concurrent::Actors | ||
|
||
Message = Case::Struct.new :reply_to, :body | ||
|
||
def make_message body | ||
# getting "mailbox" address of the current actor | ||
current = Actor.current | ||
Message.new current, body | ||
end | ||
|
||
display = Actor.spawn do | ||
loop do | ||
# guarded receive (does case-like matching via #===) | ||
Actor.receive do |msg| | ||
msg.when Message[Object, Shape] do |m| | ||
s = m.body.draw | ||
m.reply_to << "drew: #{s}" | ||
end | ||
msg.when Message[Object, :exit] do |m| | ||
m.reply_to << "exiting" | ||
end | ||
msg.when Message[Object, Object] do |m| | ||
m.reply_to << "Error! #{m.body}" | ||
end | ||
end | ||
end | ||
end | ||
|
||
# sending shapes to display. | ||
display << make_message(Rectangle.new) | ||
display << make_message(Circle.new) | ||
# sending other stuff... | ||
display << make_message("Hello Display!") | ||
display << make_message(:exit) | ||
|
||
loop do | ||
Actor.receive do |msg| | ||
msg.when "exiting" do | ||
p "exiting..." | ||
exit | ||
end | ||
msg.when String do |s| | ||
p "reply: #{s}" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
class Age attr_reader :age | ||
def initialize value | ||
raise … unless positive(value) | ||
@age = value | ||
end | ||
def + amount | ||
raise … unless positive(amount) | ||
Age.new (@age + amount) | ||
end | ||
private | ||
def positive(x); x >= 0.0; end | ||
end |
16 changes: 16 additions & 0 deletions
16
BetterRubyThroughFP/fp-ruby-code-examples/case-class-example.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
require 'rubygems' | ||
require 'case' | ||
require 'shapes' | ||
|
||
def example(arg) | ||
case arg | ||
when Shape | ||
p arg.draw | ||
when "exit" | ||
p "exiting..." | ||
end | ||
end | ||
|
||
[Circle.new, Rectangle.new, "exit"].each do |t| | ||
example(t) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Adapted from MenTaLguY's InfoQ interview: http://www.infoq.com/articles/actors-rubinius-interview | ||
require 'rubygems' | ||
require 'case' | ||
|
||
Foo = Case::Struct.new :a, :b | ||
|
||
|
||
def example(arg) | ||
case arg | ||
when Foo[:blarg, Object] # matches any Foo with :a == :blarg | ||
p "matched a :blarg" | ||
when Foo[10, 20] # matches only a Foo with .a == 10 and .b == 20 | ||
p "matched 10 & 20" | ||
when Foo # matches any Foo | ||
p "matched another Foo: #{arg}" | ||
when Case[1, 2, Object] # matches a three-element array with initial elements 1, 2: | ||
p "matched [1, 2, Object], where the Object is #{arg[2].inspect}" | ||
when Case::Any[String, Array] # matches either a String or Array (Note: after previous case!) | ||
p "matched a String or Array: #{arg.inspect}" | ||
when Case::All[Integer, Case.guard { |n| n > 10 }] # matches any Integer > 10: | ||
p "matched an integer > 10" | ||
else | ||
p "matched none of the above! \"#{arg}\"" | ||
end | ||
end | ||
|
||
example(Foo.new(:blarg, :blech)) | ||
example(Foo.new(10, 20)) | ||
example(Foo.new(:aaa, :bbb)) | ||
example([1, 2, "boo!"]) | ||
example([3, 4, "boo!"]) | ||
example("Hello") | ||
example([:c, :d, :e, :f]) | ||
example(11) | ||
example(10) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module Math | ||
class Complex | ||
attrib_reader :real, :imag | ||
|
||
def initialize real, imag | ||
@real = real | ||
@imag = imag | ||
end | ||
|
||
def + other | ||
Complex.new(real + other.real, imag + other.imag) | ||
end | ||
|
||
def - other | ||
Complex.new(real - other.real, imag - other.imag) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
require 'rubygems' | ||
require 'spec' | ||
require 'Complex' | ||
|
||
module Math | ||
|
||
describe "Complex" do | ||
before :all do | ||
@samples = (-3..3).inject([]) do |list, i| | ||
list += (-3..3).inject([]) do |list, j| | ||
list << Complex.new(1.1 * i, 1.1 * j) | ||
end | ||
end | ||
end | ||
|
||
it "should support addition where a new value is returned that sums the input real and imaginary values" do | ||
@samples.each do |c1| | ||
@samples.each do |c2| | ||
c12 = c1 + c2 | ||
c12.real.should == c1.real + c2.real | ||
c12.imag.should == c1.imag + c2.imag | ||
end | ||
end | ||
end | ||
it "should support subtraction where a new value is returned that subtracts the input real and imaginary values" do | ||
@samples.each do |c1| | ||
@samples.each do |c2| | ||
c12 = c1 - c2 | ||
c12.real.should == c1.real - c2.real | ||
c12.imag.should == c1.imag - c2.imag | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
mod = lambda {|m, n| n % m} | ||
p mod.(2,5) # ==> 1 | ||
|
||
modcurry = mod.curry | ||
mod2 = modcurry.(2) | ||
p mod2.(5) # ==> 1 | ||
|
||
mod3 = modcurry.(3) | ||
p mod3.(5) # ==> 2 | ||
p mod3.class | ||
|
||
p mod35 = modcurry.(3,5) # ==> 2 | ||
p mod35.class |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Recursive definition of the Fibonacci sequence. | ||
# f(n) = 0 for n == 0 | ||
# = 1 for n == 1 | ||
# = f(n-1) + f(n-2) for n > 1 | ||
require 'rubygems' | ||
require 'spec' | ||
|
||
describe "Fibonacci sequence" do | ||
def fib n | ||
case n | ||
when 0..1 then n | ||
else fib(n-1) + fib(n-2) | ||
end | ||
end | ||
|
||
it "should return the correct result for an input integer >= 0" do | ||
expected = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55] | ||
(0...expected.length).each do |i| | ||
fib(i).should == expected[i] | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
File.new("file-example.rb").each_with_index do |line, n| | ||
printf "%3d: %s", (n+1), line | ||
end |
30 changes: 30 additions & 0 deletions
30
BetterRubyThroughFP/fp-ruby-code-examples/first-class-funcs.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
def a_first? s | ||
s[0] == ?a | ||
end | ||
|
||
def filter array | ||
array.select {|s| yield s} | ||
end | ||
|
||
array = ["aa", "ab", "bb", "ba", "bc", "ac"] | ||
# The following won’t "compile": | ||
# array2 = filter array, a_first? | ||
# array2 = filter array, &a_first? | ||
|
||
array2 = filter(array) {|s| a_first? s} | ||
p array2 # => ["aa", "ab", "ac"] | ||
|
||
array3 = filter array, &method(:a_first?) | ||
p array3 # => ["aa", "ab", "ac"] | ||
|
||
def filter2 array, test | ||
array.select &test | ||
end | ||
|
||
# Both of the following 2 defs work | ||
pred = self.method(:a_first?).to_proc | ||
pred = Proc.new {|s| a_first? s} | ||
array4 = filter2 array, pred | ||
|
||
p array4 # => ["aa", "ab", "ac"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
for i in [1, 2, 3, 4, 5] | ||
print "#{i}, " | ||
end | ||
print "\n" | ||
|
||
hash = {:a => 'a', :b => 'b', :c => 'c'} | ||
hash.each do |k, v| | ||
puts "#{k} => #{v}" | ||
end | ||
|
||
def print_array array, i = 0 | ||
return if i == array.length | ||
print "#{array[i]}, " | ||
print_array array, i+1 | ||
end | ||
|
||
print_array [1, 2, 3, 4, 5] | ||
print "\n" |
42 changes: 42 additions & 0 deletions
42
BetterRubyThroughFP/fp-ruby-code-examples/frozen-person.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
class Person | ||
attr_accessor :first_name, :last_name, :age, :addresses # etc. | ||
|
||
def initialize first_name, last_name, age, addresses | ||
@first_name = first_name | ||
@last_name = last_name | ||
@age = age | ||
@addresses = addresses.clone | ||
end | ||
|
||
def freeze | ||
super | ||
@addresses.freeze | ||
end | ||
|
||
def to_s | ||
"#{@first_name} #{@last_name}, age #{@age}, at #{@addresses.inspect}" | ||
end | ||
end | ||
|
||
dean = Person.new "Dean", "Wampler", 29, ["1st St.", "2nd St.", "3rd St."] | ||
p dean.first_name # => "Dean" | ||
dean.first_name = "Bubba" | ||
p dean.first_name # => "Bubba" | ||
dean.freeze | ||
begin | ||
dean.first_name = "Joe" # => frozen-person.rb:16:in `first_name=': can't modify frozen object (TypeError) | ||
# from frozen-person.rb:16 | ||
rescue | ||
end | ||
begin | ||
dean.addresses[0] = "Infinity Loop" # => frozen-person.rb:16:in `first_name=': can't modify frozen object (TypeError) | ||
# from frozen-person.rb:16 | ||
rescue | ||
p "Addresses not changed: #{dean.addresses}" | ||
end | ||
p "dean: #{dean}" | ||
# But: | ||
dean = Person.new "Joe", "de Plumber", 40, ["Wisteria Lane"] | ||
p dean.first_name # => "Joe" | ||
|
||
|
19 changes: 19 additions & 0 deletions
19
BetterRubyThroughFP/fp-ruby-code-examples/functional-person.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
class Person | ||
attr_reader :addresses | ||
|
||
def initialize *addresses | ||
@addresses = *addresses | ||
@addresses.clone.freeze | ||
end | ||
end | ||
|
||
def validate address | ||
true # some operation... | ||
end | ||
|
||
dean = Person.new "1 Memory Lane", "1 Hope Drive", "1 Infinite Loop" | ||
dean.addresses.each {|a| validate(a) or raise "..."} | ||
dean.addresses.each {|a| puts a} | ||
dean.addresses.sort {|a1,a2| a1 <=> a2}.each {|a| puts a} | ||
dean.addresses.sort! {|a1,a2| a1 <=> a2}.each {|a| puts a} | ||
|
14 changes: 14 additions & 0 deletions
14
BetterRubyThroughFP/fp-ruby-code-examples/immutable-person.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
class Person | ||
attr_reader :first_name, :last_name, :age # etc. | ||
|
||
def initialize first_name, last_name, age | ||
@first_name = first_name | ||
@last_name = last_name | ||
@age = age | ||
end | ||
end | ||
|
||
dean = Person.new "Dean", "Wampler", 29 | ||
p dean.first_name # => "Dean" | ||
dean.first_name = "Bubba" # => ... undefined method `first_name=' ... | ||
|
Oops, something went wrong.