forked from fujin/sieve_actors
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[maint] extract celluloid sieve version for test overhaul
- Loading branch information
AJ Christensen
committed
Aug 17, 2012
0 parents
commit fc9ee6a
Showing
16 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
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 @@ | ||
jruby-1.6.7.2 |
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,9 @@ | ||
source :rubygems | ||
|
||
gem "celluloid" | ||
|
||
group :test do | ||
gem "rake" | ||
gem "guard" | ||
gem "guard-minitest" | ||
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,34 @@ | ||
GEM | ||
remote: http://rubygems.org/ | ||
specs: | ||
celluloid (0.11.1) | ||
timers (>= 1.0.0) | ||
ffi (1.1.5) | ||
ffi (1.1.5-java) | ||
guard (1.3.2) | ||
listen (>= 0.4.2) | ||
thor (>= 0.14.6) | ||
guard-minitest (0.5.0) | ||
guard (>= 0.4) | ||
listen (0.4.7) | ||
rb-fchange (~> 0.0.5) | ||
rb-fsevent (~> 0.9.1) | ||
rb-inotify (~> 0.8.8) | ||
rake (0.8.7) | ||
rb-fchange (0.0.5) | ||
ffi | ||
rb-fsevent (0.9.1) | ||
rb-inotify (0.8.8) | ||
ffi (>= 0.5.0) | ||
thor (0.16.0) | ||
timers (1.0.1) | ||
|
||
PLATFORMS | ||
java | ||
ruby | ||
|
||
DEPENDENCIES | ||
celluloid | ||
guard | ||
guard-minitest | ||
rake |
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,9 @@ | ||
# -*- coding: utf-8 -*- | ||
# A sample Guardfile | ||
# More info at https://github.com/guard/guard#readme | ||
|
||
guard 'minitest' do | ||
watch(%r|^test/(.*)\/?test_(.*)\.rb|) | ||
watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "test/#{m[1]}test_#{m[2]}.rb" } | ||
watch(%r|^test/test_helper\.rb|) { "test" } | ||
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,10 @@ | ||
require 'rake/testtask' | ||
|
||
Rake::TestTask.new do |t| | ||
t.libs = ["lib"] | ||
t.warning = true | ||
t.verbose = true | ||
t.test_files = FileList['test/**/*_test.rb'] | ||
end | ||
|
||
task :default => :test |
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,5 @@ | ||
require 'bundler/setup' | ||
|
||
module Sieve | ||
require 'sieve/version' | ||
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,22 @@ | ||
module Sieve | ||
# Enumerable implementation representing the set of prime number candidates > 10. Use of an | ||
# enumerable here allows us to isolate the state associated with candidate selection to this | ||
# class, freeing up the model and controller actors to focus on other parts of the computation | ||
class Candidates | ||
include Enumerable | ||
|
||
def initialize | ||
# Note that this initial value is never actually returned; we're only setting the stage for the | ||
# first increment to generate the first candidate | ||
@next = 9 | ||
end | ||
|
||
# Primes must be a number ending in 1, 3, 7 or 9... a bit of reflection will make it clear why | ||
def each | ||
loop do | ||
@next += (@next % 10 == 3) ? 4 : 2 | ||
yield @next | ||
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,41 @@ | ||
require 'celluloid' | ||
require_relative "candidates" | ||
|
||
module Sieve | ||
class Controller | ||
include Celluloid | ||
|
||
def initialize | ||
@models = 0.upto(3).map { |i| Model.new } | ||
|
||
# Seed models with a few initial values... just to get things going | ||
@seeds = [2,3,5,7] | ||
0.upto(3).each { |idx| @models[idx].add! @seeds[idx] } | ||
|
||
@candidates = Candidates.new | ||
end | ||
|
||
# Revert back to the old future-based semantics here. This function has to support both | ||
# synchronous and async execution so it always has to return an answer when called. | ||
def next | ||
# If we still have seeds to return do so up front | ||
seed = @seeds.shift | ||
if seed | ||
return seed | ||
end | ||
|
||
# Otherwise loop through candidates and build a collection of futures (one for each model) for each | ||
# of those candidates. The first value that returns all true values wins! | ||
nextprime = @candidates.find do |candidate| | ||
@models.map { |m| m.future :is_prime,candidate }.all? { |f| f.value } | ||
end | ||
|
||
# We found our next prime so update one of the models... | ||
@models[(rand @models.size)].add! nextprime | ||
|
||
# ... and return | ||
nextprime | ||
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,31 @@ | ||
module Sieve | ||
# A model represents a fragment of the state of our sieve, specifically some subset | ||
# of the primes discovered so far. | ||
# | ||
# In the Celluloid model there is no one unified entry point for message handling. Each handled | ||
# message type is now implemented as a distinct method that can be called synchronously or | ||
# asynchronously. Since method calls are logically equivalent to messages (see Smalltalk) | ||
# this should work reasonably well. | ||
class Model | ||
include Celluloid | ||
|
||
def initialize | ||
@primes = [] | ||
end | ||
|
||
def add newprime | ||
@primes << newprime | ||
end | ||
|
||
def is_prime candidate | ||
# Upfront validation; make sure we have some primes | ||
if @primes.empty? | ||
return nil | ||
end | ||
|
||
# The model only considers a value prime if it doesn't equal or divide evenly into any previously | ||
# observed prime. | ||
@primes.none? { |prime| candidate != prime and candidate % prime == 0 } | ||
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,17 @@ | ||
require_relative "controller" | ||
|
||
module Sieve | ||
class Primes | ||
include Enumerable | ||
|
||
def initialize | ||
@controller = Controller.new | ||
end | ||
|
||
def each | ||
loop do | ||
yield @controller.next | ||
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,3 @@ | ||
module Sieve | ||
VERSION = "0.0.1" | ||
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 @@ | ||
require 'minitest/autorun' |
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,2 @@ | ||
require 'minitest/autorun' | ||
require 'sieve/controller' |
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,48 @@ | ||
require 'minitest/autorun' | ||
|
||
require 'sieve/model' | ||
|
||
class ModelTest < MiniTest::Unit::TestCase | ||
|
||
# Empty models shouldn't match anything | ||
def test_model_empty | ||
|
||
model = Sieve::Model.new | ||
|
||
1.upto(10).each { |val| assert_equal(model.is_prime(val),nil) } | ||
end | ||
|
||
# Verify that we can match some data after adding it | ||
def test_model_add | ||
|
||
model = Sieve::Model.new | ||
|
||
seeds = [2,3,5,7] | ||
|
||
# Add in a few known primes | ||
seeds.each { |seed| model.add seed } | ||
|
||
# Verify that the values themselves show up as prime | ||
seeds.each { |seed| assert(model.is_prime(seed),"Seed #{seed} failed") } | ||
|
||
# Verify that multiples of the known primes are NOT marked as primes | ||
seeds.each do |seed| | ||
2.upto(100) do |multiplier| | ||
testval = seed * multiplier | ||
resp = model.is_prime testval | ||
assert(!resp.nil?,"Multiplier #{multiplier} for seed #{seed} failed unexpectedly") | ||
assert(!resp,"Multiplier #{multiplier} for seed #{seed} unexpectedly indicated to be prime") | ||
end | ||
end | ||
|
||
# Verify that integers which aren't multiples of these primes aren't marked | ||
# as primes | ||
10.upto(1000) do |c| | ||
|
||
resp = model.is_prime c | ||
assert(!resp.nil?,"Candidate #{c} failed unexpectedly") | ||
assert(resp,"Candidate #{c} should be prime based on seeds but returned false") if seeds.all? { |seed| c % seed != 0 } | ||
assert(!resp,"Candidate #{c} should not be prime based on seeds but returned true") if seeds.any? { |seed| c % seed == 0 } | ||
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,18 @@ | ||
require 'minitest/autorun' | ||
require 'prime' | ||
require 'sieve/primes' | ||
|
||
class PrimesTest < MiniTest::Unit::TestCase | ||
|
||
# Verify that we can at least obtain the seeded values from the controller | ||
def test_controller_seeds_only | ||
assert_equal([2,3,5,7],Sieve::Primes.new.take(4)) | ||
end | ||
|
||
# Now verify that the controller correctly computes new primes. Don't forget | ||
# to skip past the seeded values! | ||
def test_controller_computed_primes | ||
|
||
assert_equal(Sieve::Primes.new.take(104)[4,-1], Prime.each.take(104)[4,-1]) | ||
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,2 @@ | ||
require 'minitest/autorun' | ||
|