Skip to content

Instantly share code, notes, and snippets.

@dodecaphonic
Created April 2, 2014 13:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dodecaphonic/9934064 to your computer and use it in GitHub Desktop.
Save dodecaphonic/9934064 to your computer and use it in GitHub Desktop.
Exploring QuickCheck in Ruby via Rantly
source "https://rubygems.org"
gem "minitest"
gem "rantly", github: "hayeah/rantly"
require "singleton"
class Nil
include Singleton
def empty?; true; end
def to_s
"Nil"
end
end
class Cons
def initialize(head, tail = Nil.instance)
@head = head
@tail = tail
end
attr_reader :head, :tail
def empty?; false; end
def to_s
"(#{head} . #{tail.to_s})"
end
end
module List
def self.reverse(list, acc = Nil.instance) # !> assigned but unused variable - total
if list.empty?
acc
else
reverse(list.tail, Cons.new(list.head, acc))
end
end
def self.from_values(*values)
values.reverse.inject(Nil.instance) { |ls, v| Cons.new(v, ls) }
end
end
require "singleton"
class List
def to_s
raise "Don't use this directly, fool"
end
def empty?; true; end
def contains?(v); false; end
def prepend(v)
Cons.new(v, self)
end
def reverse(acc = Nil.instance)
if empty?
acc
else
tail.reverse(Cons.new(head, acc))
end
end
def self.from_values(*values)
values.reverse.inject(Nil.instance) { |ls, v| Cons.new(v, ls) }
end
end
class Nil < List
include Singleton
def to_s
"Nil"
end
end
class Cons < List
def initialize(head, tail = Nil.instance)
@head = head
@tail = tail
end
attr_reader :head, :tail
def empty?; false; end
def contains?(v)
head == v || tail.contains?(v)
end
def to_s
"(#{head} . #{tail.to_s})"
end
end
require "minitest/autorun"
require_relative "minitest_extension"
require_relative "list2"
class ListTest < Minitest::Test
def test_reversing_lists
assert_equal "(3 . (2 . (1 . Nil)))",
List.from_values(1, 2, 3).reverse.to_s
assert_equal "(9 . (400 . (321 . (1 . (10 . Nil)))))",
List.from_values(10, 1, 321, 400, 9).reverse.to_s
assert_equal "Nil", Nil.instance.reverse.to_s
assert_equal "(1 . Nil)", List.from_values(1).reverse.to_s
end
def test_reversing_by_property
property {
length = range(0, 500)
List.from_values(array(length) { integer })
}.check { |list|
assert_equal list.to_s, list.reverse.reverse.to_s
}
end
end
require "minitest/autorun"
require_relative "minitest_extension"
require_relative "list"
class ListTest < Minitest::Test
def test_reversing_lists
assert_equal "(3 . (2 . (1 . Nil)))",
List.reverse(List.from_values(1, 2, 3)).to_s
assert_equal "(9 . (400 . (321 . (1 . (10 . Nil)))))",
List.reverse(List.from_values(10, 1, 321, 400, 9)).to_s
assert_equal "Nil", List.reverse(Nil.instance).to_s
assert_equal "(1 . Nil)", List.reverse(List.from_values(1)).to_s
end
def test_reversing_by_property
property {
length = range(0, 500)
List.from_values(array(length) { integer })
}.check { |list|
assert_equal list.to_s, List.reverse(List.reverse(list)).to_s
}
end
end
require "minitest"
require "rantly"
require "rantly/property"
class Minitest::Test
def property(&blk)
Rantly::Property.new(blk)
end
end
require_relative "list2"
class DumbSet
def initialize(storage = Nil.instance)
@storage = storage
end
attr_reader :storage
private :storage
def push(v)
if !storage.contains?(v)
DumbSet.new(storage.prepend(v))
else
self
end
end
alias_method :<<, :push
def contains?(v)
storage.contains?(v)
end
def delete(v)
ls = storage
tmp = DumbSet.new
while !ls.empty?
if (ls.head != v)
tmp = tmp << ls.head
end
ls = ls.tail
end
tmp
end
def to_a
values = []
list = storage
until list.empty?
values << list.head
list = list.tail
end
values
end
end
require "minitest/autorun"
require_relative "minitest_extension"
require_relative "set"
class DumbSetTest < Minitest::Test
def setup
@s = (((DumbSet.new << 1) << 2) << 3)
end
attr_reader :s
def test_contains
assert s.contains?(3)
assert s.contains?(2)
assert s.contains?(1)
assert !s.contains?(4)
end
def test_uniqueness
assert_equal [-32, 1, 2, 3], (s << -32 << -32 << -32).to_a.sort
end
def test_contains_property
property {
array(range(0, 100)) { integer }
}.check { |vs|
s = vs.inject(DumbSet.new) { |ds, v| ds << v }
assert vs.all? { |v| s.contains?(v) }
}
end
def test_uniqueness_property
property {
array(range(0, 100)) { integer }
}.check { |vs|
ns = vs.inject(DumbSet.new) { |ds, v| ds << v }
rs = vs.inject(ns) { |ds, v| ds << v }
assert_equal vs.sort, ns.to_a.sort
}
end
def test_delete
os = DumbSet.new << 1 << 2 << 3
ns = os.delete(1337)
assert_equal [1, 2, 3], ns.to_a.sort
ns = os.delete(3)
assert_equal [1, 2], ns.to_a.sort
ns = ns.delete(2)
assert_equal [1], ns.to_a.sort
ns = (ns << 432).delete(1)
assert_equal [432], ns.to_a.sort
ns = ns.delete(432)
assert_equal [], ns.to_a.sort
end
def test_delete_property
property {
array(10) { range(0, 5000) }.uniq
}.check { |values|
os = values.inject(DumbSet.new) { |s, v| s << v }
ds = values[0..1].inject(os) { |s, v| s.delete(v) }
assert_equal (values.size - 2), ds.to_a.size
}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment