answer-factory 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -0
- data/Thorfile +9 -6
- data/VERSION +1 -1
- data/answer-factory.gemspec +20 -5
- data/lib/answer-factory.rb +14 -2
- data/lib/answers/answer.rb +17 -3
- data/lib/answers/batch.rb +15 -3
- data/lib/factories/workstation.rb +50 -1
- data/lib/operators/all_duplicated_genomes_sampler.rb +14 -0
- data/lib/operators/any_one_sampler.rb +7 -0
- data/lib/operators/dominated_quantile_selector.rb +16 -0
- data/lib/operators/infrastructure.rb +74 -0
- data/lib/operators/most_dominated_subset_sampler.rb +13 -0
- data/lib/operators/nondominated_subset_selector.rb +17 -0
- data/lib/operators/point_crossover_operator.rb +24 -0
- data/lib/operators/point_delete_operator.rb +19 -0
- data/lib/operators/point_mutation_operator.rb +22 -0
- data/lib/operators/program_point_count_evaluator.rb +14 -0
- data/lib/operators/random_guess_operator.rb +30 -0
- data/lib/operators/resample_and_clone_operator.rb +28 -0
- data/lib/operators/resample_values_operator.rb +40 -0
- data/lib/operators/{evaluators.rb → test_case_evaluator.rb} +3 -34
- data/lib/operators/uniform_backbone_crossover_operator.rb +53 -0
- data/readme.md +28 -3
- data/spec/answer_spec.rb +33 -1
- data/spec/batch_spec.rb +25 -12
- data/spec/factories/factory_spec.rb +53 -36
- data/spec/factories/workstation_spec.rb +194 -20
- data/spec/operators/evaluators/program_point_evaluator_spec.rb +1 -1
- data/spec/operators/evaluators/test_case_evaluator_spec.rb +2 -2
- data/spec/operators/nondominated_subset_spec.rb +8 -8
- data/spec/operators/random_guess_spec.rb +16 -11
- data/spec/operators/resample_and_clone_spec.rb +8 -8
- data/spec/operators/uniformBackboneCrossover_spec.rb +7 -7
- data/spec/spec_helper.rb +1 -0
- metadata +38 -12
- data/lib/operators/basic_operators.rb +0 -240
- data/lib/operators/samplers_and_selectors.rb +0 -131
@@ -0,0 +1,19 @@
|
|
1
|
+
module AnswerFactory
|
2
|
+
class PointDeleteOperator < SearchOperator
|
3
|
+
def generate(crowd, howManyCopies = 1)
|
4
|
+
raise(ArgumentError) if !crowd.kind_of?(Array)
|
5
|
+
crowd.each {|dude| raise(ArgumentError) if !dude.kind_of?(Answer) }
|
6
|
+
|
7
|
+
result = Batch.new
|
8
|
+
crowd.each do |dude|
|
9
|
+
howManyCopies.times do
|
10
|
+
where = rand(dude.points)+1
|
11
|
+
variant = dude.delete_point_or_clone(where)
|
12
|
+
baby = Answer.new(variant, progress:dude.progress + 1)
|
13
|
+
result << baby
|
14
|
+
end
|
15
|
+
end
|
16
|
+
return result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module AnswerFactory
|
2
|
+
class PointMutationOperator < SearchOperator
|
3
|
+
|
4
|
+
def generate(crowd, howManyCopies = 1, overridden_options ={})
|
5
|
+
raise(ArgumentError) if !crowd.kind_of?(Array)
|
6
|
+
raise(ArgumentError) if crowd.empty?
|
7
|
+
crowd.each {|dude| raise(ArgumentError) if !dude.kind_of?(Answer) }
|
8
|
+
|
9
|
+
result = Batch.new
|
10
|
+
crowd.each do |dude|
|
11
|
+
howManyCopies.times do
|
12
|
+
where = rand(dude.points)+1
|
13
|
+
newCode = CodeType.any_value(@incoming_options.merge(overridden_options))
|
14
|
+
variant = dude.replace_point_or_clone(where,newCode)
|
15
|
+
baby = Answer.new(variant, progress:dude.progress + 1)
|
16
|
+
result << baby
|
17
|
+
end
|
18
|
+
end
|
19
|
+
return result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module AnswerFactory
|
2
|
+
class ProgramPointEvaluator < Evaluator
|
3
|
+
def evaluate(batch)
|
4
|
+
raise(ArgumentError, "Can only evaluate a Batch of Answers") if !batch.kind_of?(Batch)
|
5
|
+
batch.each do |i|
|
6
|
+
if i.parses?
|
7
|
+
i.scores[@score_label] = i.program.points
|
8
|
+
else
|
9
|
+
raise(ArgumentError, "Program is not parseable")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module AnswerFactory
|
2
|
+
class RandomGuessOperator < SearchOperator
|
3
|
+
|
4
|
+
# returns an Array of random Answers
|
5
|
+
#
|
6
|
+
# the first (optional) parameter specifies how many to make, and defaults to 1
|
7
|
+
# the second (also optional) parameter is a hash that
|
8
|
+
# can temporarily override those set in the initialization
|
9
|
+
#
|
10
|
+
# For example, if
|
11
|
+
# <tt>myRandomGuesser = RandomGuessOperator.new(:randomIntegerLowerBound => -90000)</tt>
|
12
|
+
#
|
13
|
+
# [<tt>myRandomGuesser.generate()</tt>]
|
14
|
+
# produces a list of 1 Answer, and if it has any IntType samples they will be in [-90000,100]
|
15
|
+
# (since the default +:randomIntegerLowerBound+ is 100)
|
16
|
+
# [<tt>myRandomGuesser.generate(1,:randomIntegerLowerBound => 0)</tt>]
|
17
|
+
# makes one Answer whose IntType samples (if any) will be between [0,100]
|
18
|
+
|
19
|
+
def generate(crowd, overridden_options = {})
|
20
|
+
every_option = @incoming_options.merge(overridden_options)
|
21
|
+
how_many = every_option[:how_many] || 1
|
22
|
+
how_many.times do
|
23
|
+
newGenome = CodeType.any_value(every_option)
|
24
|
+
newDude = Answer.new(newGenome, progress:0)
|
25
|
+
crowd << newDude
|
26
|
+
end
|
27
|
+
return crowd
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module AnswerFactory
|
2
|
+
class ResampleAndCloneOperator < SearchOperator
|
3
|
+
|
4
|
+
# returns an Array of clones of Answers randomly selected from the crowd passed in
|
5
|
+
#
|
6
|
+
# the first (required) parameter is an Array of Answers
|
7
|
+
# the second (optional) parameter is how many samples to take, and defaults to 1
|
8
|
+
#
|
9
|
+
# For example, if
|
10
|
+
# <tt>@currentPopulation = [a list of 300 Answers]</tt> and
|
11
|
+
# <tt>myRandomSampler = ResampleAndCloneOperator.new(@currentPopulation)</tt>
|
12
|
+
# [<tt>myRandomSampler.generate()</tt>]
|
13
|
+
# produces a list of 1 Answer, which is a clone of somebody from <tt>@currentPopulation</tt>
|
14
|
+
# [<tt>myRandomGuesser.generate(11)</tt>]
|
15
|
+
# returns a list of 11 Answers cloned from <tt>@currentPopulation</tt>,
|
16
|
+
# possibly including repeats
|
17
|
+
|
18
|
+
def generate(crowd, howMany = 1)
|
19
|
+
result = Batch.new
|
20
|
+
howMany.times do
|
21
|
+
donor = crowd.sample
|
22
|
+
clone = Answer.new(donor.blueprint, progress:donor.progress + 1)
|
23
|
+
result << clone
|
24
|
+
end
|
25
|
+
return result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
module AnswerFactory
|
3
|
+
|
4
|
+
class ResampleValuesOperator < SearchOperator
|
5
|
+
|
6
|
+
def generate(crowd, howManyCopies = 1, overridden_options = {})
|
7
|
+
crowd.each {|dude| raise(ArgumentError) if !dude.kind_of?(Answer) }
|
8
|
+
|
9
|
+
result = Batch.new
|
10
|
+
regenerating_options = @incoming_options.merge(overridden_options)
|
11
|
+
crowd.each do |dude|
|
12
|
+
howManyCopies.times do
|
13
|
+
wildtype_program = dude.program
|
14
|
+
starting_footnotes = wildtype_program.footnote_section.split( /^(?=«)/ )
|
15
|
+
breaker = /^«([a-zA-Z][a-zA-Z0-9_]*)»\s*(.*)\s*/m
|
16
|
+
type_value_pairs = starting_footnotes.collect {|fn| fn.match(breaker)[1..2]}
|
17
|
+
|
18
|
+
mutant_blueprint = wildtype_program.code_section
|
19
|
+
|
20
|
+
type_value_pairs.each do |pair|
|
21
|
+
|
22
|
+
begin
|
23
|
+
type_name = pair[0]
|
24
|
+
type_class = "#{type_name}_type".camelize.constantize
|
25
|
+
reduced_size = regenerating_options[:target_size_in_points] || rand(dude.points/2)
|
26
|
+
reduced_option = {target_size_in_points:reduced_size}
|
27
|
+
resampled_value = type_class.any_value(regenerating_options.merge(reduced_option)).to_s
|
28
|
+
rescue NameError
|
29
|
+
resampled_value = pair[1]
|
30
|
+
end
|
31
|
+
mutant_blueprint << "\n«#{pair[0].strip}» #{resampled_value.strip}"
|
32
|
+
end
|
33
|
+
mutant = Answer.new(mutant_blueprint, progress:dude.progress + 1)
|
34
|
+
result << mutant
|
35
|
+
end
|
36
|
+
end
|
37
|
+
return result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,35 +1,4 @@
|
|
1
1
|
module AnswerFactory
|
2
|
-
|
3
|
-
class Evaluator < SearchOperator
|
4
|
-
attr_accessor :name
|
5
|
-
|
6
|
-
def initialize(params = {})
|
7
|
-
raise(ArgumentError, "Evaluators must be initialized with names") if params[:name] == nil
|
8
|
-
@name = params[:name]
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
class ProgramPointEvaluator < Evaluator
|
17
|
-
def evaluate(batch)
|
18
|
-
raise(ArgumentError, "Can only evaluate a Batch of Answers") if !batch.kind_of?(Batch)
|
19
|
-
batch.each do |i|
|
20
|
-
if i.parses?
|
21
|
-
i.scores[@name] = i.program.points
|
22
|
-
else
|
23
|
-
raise(ArgumentError, "Program is not parseable")
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
2
|
class TestCase
|
34
3
|
attr_accessor :bindings, :expectations, :gauges
|
35
4
|
|
@@ -59,7 +28,7 @@ module AnswerFactory
|
|
59
28
|
variable_names = params[:references] || []
|
60
29
|
|
61
30
|
batch.each do |dude|
|
62
|
-
if !params[:deterministic] || !dude.scores[@
|
31
|
+
if !params[:deterministic] || !dude.scores[@score_label]
|
63
32
|
score = 0
|
64
33
|
readings = {}
|
65
34
|
cases.each do |example|
|
@@ -100,11 +69,11 @@ module AnswerFactory
|
|
100
69
|
score += difference.abs
|
101
70
|
end
|
102
71
|
# aggregate differences
|
103
|
-
dude.scores[@
|
72
|
+
dude.scores[@score_label] = score.to_f / cases.length
|
104
73
|
|
105
74
|
puts "#{score.to_f / cases.length}" if params[:feedback]
|
106
75
|
else
|
107
|
-
puts dude.scores[@
|
76
|
+
puts dude.scores[@score_label] if params[:feedback]
|
108
77
|
end
|
109
78
|
end
|
110
79
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module AnswerFactory
|
2
|
+
class UniformBackboneCrossoverOperator < SearchOperator
|
3
|
+
|
4
|
+
# Returns a Batch of new Answers whose programs are made by stitching together
|
5
|
+
# the programs of pairs of 'parents'. The incoming Batch is divided into pairs based on
|
6
|
+
# adjacency (modulo the Batch.length), one pair for each 'offspring' to be made. To make
|
7
|
+
# an offspring, the number of backbone program points is determined in each parent; 'backbone'
|
8
|
+
# refers to the number of branches directly within the root of the program, not the entire tree.
|
9
|
+
#
|
10
|
+
# To construct an offspring's program, program points are copied from the first parent with
|
11
|
+
# probability p, or the second parent with probability (1-p), for each point in the first
|
12
|
+
# parent's backbone. So if there are 13 and 6 points, respectively, the first six points are
|
13
|
+
# selected randomly, but the last 7 are copied from the first parent. If there are 8 and 11
|
14
|
+
# respectively, then the last 3 will be ignored from the second parent in any case.
|
15
|
+
#
|
16
|
+
# the first (required) parameter is an Array of Answers
|
17
|
+
# the second (optional) parameter is how many crossovers to make,
|
18
|
+
# which defaults to the number of Answers in the incoming Batch
|
19
|
+
|
20
|
+
def generate(crowd, howMany = crowd.length, prob = 0.5)
|
21
|
+
result = Batch.new
|
22
|
+
howMany.times do
|
23
|
+
where = rand(crowd.length)
|
24
|
+
mom = crowd[where]
|
25
|
+
dad = crowd[ (where+1) % crowd.length ]
|
26
|
+
mom_backbone_length = mom.program[1].contents.length
|
27
|
+
dad_backbone_length = dad.program[1].contents.length
|
28
|
+
|
29
|
+
baby_blueprint_parts = ["",""]
|
30
|
+
(0..mom_backbone_length-1).each do |backbone_point|
|
31
|
+
if rand() < prob
|
32
|
+
next_chunks = mom.program[1].contents[backbone_point].blueprint_parts || ["",""]
|
33
|
+
else
|
34
|
+
if backbone_point < dad_backbone_length
|
35
|
+
next_chunks = (dad.program[1].contents[backbone_point].blueprint_parts || ["", ""])
|
36
|
+
else
|
37
|
+
next_chunks = ["",""]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
baby_blueprint_parts[0] << " #{next_chunks[0]}"
|
41
|
+
baby_blueprint_parts[1] << " \n#{next_chunks[1]}"
|
42
|
+
end
|
43
|
+
mom.program.unused_footnotes.each {|fn| baby_blueprint_parts[1] += "\n#{fn}"}
|
44
|
+
|
45
|
+
baby_blueprint = "block {#{baby_blueprint_parts[0]}} #{baby_blueprint_parts[1]}"
|
46
|
+
baby = Answer.new(baby_blueprint, progress:[mom.progress,dad.progress].max + 1)
|
47
|
+
|
48
|
+
result << baby
|
49
|
+
end
|
50
|
+
return result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/readme.md
CHANGED
@@ -22,10 +22,35 @@ The AnswerFactory infrastructure has been designed to help _regular people_ buil
|
|
22
22
|
|
23
23
|
## Getting started
|
24
24
|
|
25
|
-
|
25
|
+
The `answer-factory` gem depends on Ruby 1.9 or higher. We recommend [rvm](http://rvm.beginrescueend.com/) if you'd like to maintain several Ruby installations.
|
26
26
|
|
27
|
-
|
27
|
+
You'll also need a working installation of [CouchDB](http://couchdb.apache.org/) available. This can be a remote instance, as long as you have the necessary permissions to create and manage databases.
|
28
28
|
|
29
|
+
Then:
|
29
30
|
gem install answer-factory
|
30
31
|
|
31
|
-
This
|
32
|
+
This will automatically install several dependencies, including [nudge](http://github.com/Vaguery/Nudge), rspec, and others.
|
33
|
+
|
34
|
+
### Creating a new AnswerFactory project
|
35
|
+
|
36
|
+
Use this command line script to build an AnswerFactory project folder:
|
37
|
+
answer-factory your-project-name-here
|
38
|
+
|
39
|
+
This will create a new directory called 'your-project-name-here', and install a rudimentary subtree of folders and files. Perhaps most important is the `Thorfile`, which contains most of the generators you can use to simplify project creation and management.
|
40
|
+
|
41
|
+
### Replicating a pre-existing project or demo
|
42
|
+
|
43
|
+
TBD
|
44
|
+
|
45
|
+
### Generating new Nudge type defintitions
|
46
|
+
|
47
|
+
The Nudge language gem installed along with `answer-factory` includes a full-featured programming language designed for genetic programming projects, with integer, floating-point, boolean, and code types.
|
48
|
+
|
49
|
+
Often your project's domain model will call for additional types. To generate some basic infrastructure for a new NudgeType subclass, navigate to the root of your project folder and invoke the thor script
|
50
|
+
thor new_nudge_type your-nudge-type-name
|
51
|
+
This will create a template for your class definition in the `/lib/nudge/types` subdirectory (which you should edit as indicated in the comments to use), several standard nudge instruction classes in `/lib/nudge/instructions`, and rspec files.
|
52
|
+
|
53
|
+
### Activating the AnswerFactory daemon
|
54
|
+
|
55
|
+
Make sure CouchDB is running and available, navigate to your project's root folder, and invoke
|
56
|
+
ruby activate.rb
|
data/spec/answer_spec.rb
CHANGED
@@ -78,7 +78,7 @@ describe "Answer" do
|
|
78
78
|
describe "serialization" do
|
79
79
|
describe "writing" do
|
80
80
|
before(:each) do
|
81
|
-
@a1 = Answer.new("block {do a}")
|
81
|
+
@a1 = Answer.new("block {do a}", progress:12)
|
82
82
|
end
|
83
83
|
|
84
84
|
it "should contain the blueprint" do
|
@@ -94,12 +94,44 @@ describe "Answer" do
|
|
94
94
|
@a1.data['scores'].should == @a1.scores
|
95
95
|
end
|
96
96
|
|
97
|
+
it "should contain the progress" do
|
98
|
+
@a1.data['progress'].should == @a1.progress
|
99
|
+
end
|
100
|
+
|
101
|
+
|
97
102
|
it "should contain the timestamp" do
|
98
103
|
@a1.data['timestamp'].should == @a1.timestamp
|
99
104
|
end
|
100
105
|
end
|
101
106
|
|
102
107
|
describe "reading" do
|
108
|
+
before(:each) do
|
109
|
+
@couchified = {"id"=>"0f60c293ad736abfdb083d33f71ef9ab", "key"=>"ws1", "value"=>{"_id"=>"0f60c293ad736abfdb083d33f71ef9ab", "_rev"=>"1-473467b6dc1a4cba3498dd6eeb8e3206", "blueprint"=>"do bar", "tags"=>["quux", "whatevz"], "scores"=>{"badness" => 12.345}, "progress" => 12, "timestamp"=>"2010/04/14 17:09:14 +0000"}}
|
110
|
+
@my_a = Answer.from_serial_hash(@couchified)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should record the couch_doc_id" do
|
114
|
+
@my_a.couch_id.should == "0f60c293ad736abfdb083d33f71ef9ab"
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should accept a blueprint string" do
|
118
|
+
@my_a.blueprint.should == "do bar"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should collect the tag Array into a Set of symbols" do
|
122
|
+
@my_a.tags.should be_a_kind_of(Set)
|
123
|
+
@my_a.tags.should include(:quux)
|
124
|
+
@my_a.tags.should include(:whatevz)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should gather up the scores Hash" do
|
128
|
+
@my_a.scores.should be_a_kind_of(Hash)
|
129
|
+
@my_a.scores.should include(:badness)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should read the progress" do
|
133
|
+
@my_a.progress.should == 12
|
134
|
+
end
|
103
135
|
|
104
136
|
end
|
105
137
|
end
|
data/spec/batch_spec.rb
CHANGED
@@ -74,25 +74,38 @@ describe "Batches" do
|
|
74
74
|
|
75
75
|
describe "reading" do
|
76
76
|
before(:each) do
|
77
|
-
@uri = "http://127.0.0.1
|
77
|
+
@uri = "http://127.0.0.1:5984/my_factory"
|
78
|
+
@design_doc = "ws1/current" # we'll assume this has been set up!
|
79
|
+
@view_uri = "http://127.0.0.1:5984/my_factory/_design/ws1/_view/current"
|
80
|
+
FakeWeb.allow_net_connect = false
|
81
|
+
@canned = '{"total_rows":1,"offset":0,"rows":[{"id":"0f60c293ad736abfdb083d33f71ef9ab","key":"ws1","value":{"_id":"0f60c293ad736abfdb083d33f71ef9ab","_rev":"1-473467b6dc1a4cba3498dd6eeb8e3206","blueprint":"do bar","tags":[],"scores":{},"progress":12,"timestamp":"2010/04/14 17:09:14 +0000"}}]}'
|
82
|
+
|
78
83
|
end
|
79
84
|
|
80
|
-
it "
|
81
|
-
|
85
|
+
it "should connect to the right view in the right design doc in the persistent store" do
|
86
|
+
FakeWeb.register_uri(:any, @view_uri, :body => @canned, :status => [200, "OK"])
|
87
|
+
lambda{Batch.load_from_couch(@uri,@design_doc)}.should_not raise_error
|
88
|
+
# because it hit the right URI!
|
82
89
|
end
|
83
90
|
|
84
|
-
it "should
|
85
|
-
|
86
|
-
|
87
|
-
end
|
91
|
+
it "should handle errors returned from CouchDB"
|
92
|
+
|
93
|
+
it "should handle db connection problems"
|
88
94
|
|
89
|
-
it "should
|
95
|
+
it "should create an Answer for every row received" do
|
96
|
+
FakeWeb.register_uri(:any, @view_uri, :body => @canned, :status => [200, "OK"])
|
97
|
+
little_batch = Batch.load_from_couch(@uri,@design_doc)
|
98
|
+
little_batch.length.should == 1
|
99
|
+
little_batch[0].blueprint.should == "do bar"
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should raise an warning and create an empty Batch if it can't parse the result" do
|
103
|
+
FakeWeb.register_uri(:any, @view_uri, :body => "some random crap", :status => [200, "OK"])
|
104
|
+
little_batch = Batch.load_from_couch(@uri,@design_doc)
|
105
|
+
little_batch.length.should == 0
|
106
|
+
end
|
90
107
|
end
|
91
108
|
|
92
109
|
end
|
93
|
-
|
94
|
-
|
95
|
-
it "should have a Batch.load_from_couch method that reads a bunch of Answers from the db"
|
96
|
-
|
97
110
|
end
|
98
111
|
end
|
@@ -11,6 +11,59 @@ describe "Factory" do
|
|
11
11
|
Factory.new.name.should == "my_factory"
|
12
12
|
end
|
13
13
|
|
14
|
+
|
15
|
+
describe "databases" do
|
16
|
+
describe "#couch_available?" do
|
17
|
+
it "should have a method to check that couchDB is accessible" do
|
18
|
+
f1 = Factory.new("boo")
|
19
|
+
lambda{f1.couch_available?}.should_not raise_error
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return true if the uri is reachable" do
|
23
|
+
uri = "http://mycouch.db/boo"
|
24
|
+
f1 = Factory.new("boo")
|
25
|
+
f1.configatron.couchdb_uri = uri
|
26
|
+
FakeWeb.register_uri(:any, uri, :body => "We are here!", :status => [200, "OK"])
|
27
|
+
f1.couch_available?.should == true
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return false if the uri is offline or 404's out" do
|
31
|
+
uri = "http://mycouch.db/boo"
|
32
|
+
f1 = Factory.new("boo")
|
33
|
+
f1.configatron.couchdb_uri = uri
|
34
|
+
f1.configatron.couchdb_uri.should == uri
|
35
|
+
FakeWeb.register_uri(:any, uri, :body => "Go away!", :status => [404, "Not Found"])
|
36
|
+
f1.couch_available?.should == false
|
37
|
+
|
38
|
+
f1 = Factory.new("boo") # depends on this being wrong
|
39
|
+
f1.configatron.couchdb_uri = "http://127.0.0.1:9991/place"
|
40
|
+
f1.couch_available?.should == false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
describe "build" do
|
47
|
+
it "should read the config files"
|
48
|
+
|
49
|
+
it "should #reset"
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
describe "reset" do
|
54
|
+
it "should erase the couchdb"
|
55
|
+
|
56
|
+
it "should set up a new couchdb"
|
57
|
+
|
58
|
+
it "should set up the necessary design documents in the db"
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
describe "activate" do
|
63
|
+
it "should check the config files"
|
64
|
+
end
|
65
|
+
|
66
|
+
|
14
67
|
describe "ontology" do
|
15
68
|
it "should have a master Instruction list" do
|
16
69
|
Factory.new("foo").instruction_library.should == Instruction.all_instructions
|
@@ -44,43 +97,7 @@ describe "Factory" do
|
|
44
97
|
Factory.new.workstation_names.should == []
|
45
98
|
end
|
46
99
|
|
47
|
-
describe "build_workstation" do
|
48
|
-
it "should create a new workstation"
|
49
|
-
it "should set up all the interior dynamics of the workstation"
|
50
|
-
it "should use the master config for defaults of the new workstation"
|
51
|
-
it "should suffice to create a pass-through workstation just to name it"
|
52
|
-
end
|
53
100
|
end
|
54
101
|
|
55
|
-
describe "activate" do
|
56
|
-
it "should have an #activate method"
|
57
|
-
end
|
58
102
|
|
59
|
-
describe "databases" do
|
60
|
-
|
61
|
-
describe "#couch_available?" do
|
62
|
-
it "should have a method to check that couchDB is accessible" do
|
63
|
-
f1 = Factory.new("boo")
|
64
|
-
lambda{f1.couch_available?}.should_not raise_error
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should return true if the uri is reachable" do
|
68
|
-
uri = "http://mycouch.db/boo"
|
69
|
-
f1 = Factory.new("boo")
|
70
|
-
f1.configatron.couchdb_uri = uri
|
71
|
-
FakeWeb.register_uri(:any, uri, :body => "We are here!", :status => [200, "OK"])
|
72
|
-
f1.couch_available?.should == true
|
73
|
-
end
|
74
|
-
|
75
|
-
it "should return false if the uri is offline or 404's out" do
|
76
|
-
uri = "http://mycouch.db/boo"
|
77
|
-
f1 = Factory.new("boo", couchdb_uri:uri)
|
78
|
-
FakeWeb.register_uri(:any, uri, :body => "Go away!", :status => [404, "Not Found"])
|
79
|
-
f1.couch_available?.should == false
|
80
|
-
|
81
|
-
f1 = Factory.new("boo", couchdb_uri:"http://127.0.0.1:9991/place") # depends on this being wrong
|
82
|
-
f1.couch_available?.should == false
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
103
|
end
|