answer-factory 0.0.15 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/answer-factory.gemspec +3 -4
- data/lib/answers/answer.rb +12 -3
- data/lib/answers/batch.rb +1 -0
- data/lib/factories/factory.rb +0 -1
- data/lib/factories/workstation.rb +12 -4
- data/spec/answer_spec.rb +48 -3
- data/spec/factories/workstation_spec.rb +21 -48
- data/spec/integration_specs/couch_db_integration.rspec +142 -0
- data/tasks/setup_factory.thor +1 -0
- data/templates/answer_factory_activate_template.erb +69 -55
- metadata +5 -6
- data/spec/integration_specs/couch_db_integration.rb +0 -60
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.1
|
data/answer-factory.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{answer-factory}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.1.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Bill Tozier", "Trek Glowacki", "Jesse Sielaff"]
|
12
|
-
s.date = %q{2010-05-
|
12
|
+
s.date = %q{2010-05-11}
|
13
13
|
s.default_executable = %q{answer-factory}
|
14
14
|
s.description = %q{The pragmaticgp gem provides a simple framework for building, running and managing genetic programming experiments which automatically discover algorithms and equations to solve user-defined problems.}
|
15
15
|
s.email = %q{bill@vagueinnovation.com}
|
@@ -42,7 +42,7 @@ Gem::Specification.new do |s|
|
|
42
42
|
"spec/batch_spec.rb",
|
43
43
|
"spec/factories/factory_spec.rb",
|
44
44
|
"spec/factories/workstation_spec.rb",
|
45
|
-
"spec/integration_specs/couch_db_integration.
|
45
|
+
"spec/integration_specs/couch_db_integration.rspec",
|
46
46
|
"spec/machines/any_one_spec.rb",
|
47
47
|
"spec/machines/build_random_spec.rb",
|
48
48
|
"spec/machines/evaluate_simple_score_spec.rb",
|
@@ -65,7 +65,6 @@ Gem::Specification.new do |s|
|
|
65
65
|
"spec/batch_spec.rb",
|
66
66
|
"spec/factories/factory_spec.rb",
|
67
67
|
"spec/factories/workstation_spec.rb",
|
68
|
-
"spec/integration_specs/couch_db_integration.rb",
|
69
68
|
"spec/machines/any_one_spec.rb",
|
70
69
|
"spec/machines/build_random_spec.rb",
|
71
70
|
"spec/machines/evaluate_simple_score_spec.rb",
|
data/lib/answers/answer.rb
CHANGED
@@ -2,7 +2,7 @@ require 'set'
|
|
2
2
|
|
3
3
|
module AnswerFactory
|
4
4
|
class Answer
|
5
|
-
attr_accessor :scores, :tags
|
5
|
+
attr_accessor :scores, :tags, :location
|
6
6
|
attr_reader :draft_blueprint, :program, :timestamp, :ancestors
|
7
7
|
attr_reader :initialization_options, :progress
|
8
8
|
attr_accessor :couch_id, :couch_rev
|
@@ -19,6 +19,7 @@ module AnswerFactory
|
|
19
19
|
end
|
20
20
|
@timestamp = Time.now
|
21
21
|
@couch_id = options[:couch_id] || ""
|
22
|
+
@location = options[:location] || :NOWHERE
|
22
23
|
@couch_rev = options[:couch_rev] || ""
|
23
24
|
@progress = options[:progress] || 0
|
24
25
|
@ancestors = options[:ancestors] || []
|
@@ -112,6 +113,12 @@ module AnswerFactory
|
|
112
113
|
end
|
113
114
|
end
|
114
115
|
|
116
|
+
def move_to(where)
|
117
|
+
raise ArgumentError, "#{where} is not a Symbol" unless where.kind_of?(Symbol)
|
118
|
+
@location = where.to_sym
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
115
122
|
|
116
123
|
def add_tag(new_tag)
|
117
124
|
raise ArgumentError, "#{new_tag} is not a Symbol" unless new_tag.kind_of?(Symbol)
|
@@ -130,6 +137,7 @@ module AnswerFactory
|
|
130
137
|
basics["_rev"] = self.couch_rev unless self.couch_rev.empty?
|
131
138
|
|
132
139
|
basics.merge!({'blueprint' => self.blueprint,
|
140
|
+
'location' => self.location.to_sym,
|
133
141
|
'tags' => self.tags.to_a,
|
134
142
|
'scores' => self.scores,
|
135
143
|
'progress' => self.progress,
|
@@ -144,8 +152,9 @@ module AnswerFactory
|
|
144
152
|
symbolized_scores = value_hash["scores"].inject({}) {|memo,(k,v)| memo[k.to_sym] = v; memo }
|
145
153
|
|
146
154
|
Answer.new(value_hash["blueprint"],
|
147
|
-
couch_id:value_hash['
|
148
|
-
couch_rev:value_hash['
|
155
|
+
couch_id:value_hash['_id'],
|
156
|
+
couch_rev:value_hash['_rev'],
|
157
|
+
location:(value_hash["location"] || "NOWHERE").to_sym,
|
149
158
|
tags:tag_set,
|
150
159
|
scores:symbolized_scores,
|
151
160
|
progress:value_hash["progress"],
|
data/lib/answers/batch.rb
CHANGED
data/lib/factories/factory.rb
CHANGED
@@ -58,10 +58,17 @@ module AnswerFactory
|
|
58
58
|
end
|
59
59
|
|
60
60
|
|
61
|
-
def ship_to(where
|
61
|
+
def ship_to(where)
|
62
62
|
raise ArgumentError, "Workstation#ship_to cannot ship to a #{where.class}" unless
|
63
63
|
where.kind_of?(Symbol)
|
64
|
-
|
64
|
+
|
65
|
+
@answers.each do |a|
|
66
|
+
next unless a.location.to_sym == @name.to_sym
|
67
|
+
if block_given?
|
68
|
+
next unless yield(a)
|
69
|
+
end
|
70
|
+
a.move_to(where)
|
71
|
+
end
|
65
72
|
end
|
66
73
|
|
67
74
|
|
@@ -72,11 +79,12 @@ module AnswerFactory
|
|
72
79
|
|
73
80
|
|
74
81
|
def scrap_if(why, &filter)
|
75
|
-
(
|
82
|
+
ship_to(:SCRAP, &filter)
|
83
|
+
# (@answers.find_all &filter).each {|a| a.add_tag :SCRAP; a.remove_tag @name}
|
76
84
|
end
|
77
85
|
|
78
86
|
def scrap_everything
|
79
|
-
|
87
|
+
ship_to(:SCRAP)
|
80
88
|
end
|
81
89
|
|
82
90
|
|
data/spec/answer_spec.rb
CHANGED
@@ -57,6 +57,30 @@ describe "Answer" do
|
|
57
57
|
Answer.new("foo").scores.should == {}
|
58
58
|
end
|
59
59
|
|
60
|
+
it "should have a tags attribute" do
|
61
|
+
Answer.new("").should respond_to(:tags)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should be possible to set the :tags via initialization option" do
|
65
|
+
Answer.new("", tags:["hi"]).tags.to_a.should == ["hi"]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should not report duplicate entries" do
|
69
|
+
Answer.new("", tags:["hi", "hi"]).tags.to_a.should == ["hi"]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should have a :location attribute" do
|
73
|
+
Answer.new("").should respond_to(:location)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should have a default :location of :NOWHERE" do
|
77
|
+
Answer.new("").location.should == :NOWHERE
|
78
|
+
end
|
79
|
+
|
80
|
+
it "be possible to set :location via an initialization option" do
|
81
|
+
Answer.new("", location:"nearby").location.should == "nearby"
|
82
|
+
end
|
83
|
+
|
60
84
|
it "should have a #timestamp, which is when (wall clock time) it was made" do
|
61
85
|
tn = Time.now
|
62
86
|
Time.should_receive(:now).and_return(tn)
|
@@ -78,7 +102,7 @@ describe "Answer" do
|
|
78
102
|
describe "serialization" do
|
79
103
|
describe "writing" do
|
80
104
|
before(:each) do
|
81
|
-
@a1 = Answer.new("block {do a}", progress:12)
|
105
|
+
@a1 = Answer.new("block {do a}", progress:12, location: :here)
|
82
106
|
end
|
83
107
|
|
84
108
|
it "should not contain the CouchDB _id, if none was set" do
|
@@ -99,11 +123,14 @@ describe "Answer" do
|
|
99
123
|
@a1.data['_rev'].should == "88888"
|
100
124
|
end
|
101
125
|
|
102
|
-
|
103
126
|
it "should contain the blueprint" do
|
104
127
|
@a1.data['blueprint'].should == @a1.blueprint
|
105
128
|
end
|
106
129
|
|
130
|
+
it "should contain the location" do
|
131
|
+
@a1.data['location'].should == @a1.location
|
132
|
+
end
|
133
|
+
|
107
134
|
it "should contain the tags" do
|
108
135
|
@a1.data['tags'].should == @a1.tags.to_a
|
109
136
|
end
|
@@ -125,7 +152,7 @@ describe "Answer" do
|
|
125
152
|
|
126
153
|
describe "reading" do
|
127
154
|
before(:each) do
|
128
|
-
@couchified = {"id"=>"0f60c293ad736abfdb083d33f71ef9ab", "key"=>"ws1", "value"=>{"
|
155
|
+
@couchified = {"id"=>"0f60c293ad736abfdb083d33f71ef9ab", "key"=>"ws1", "value"=>{"_id"=>"0f60c293ad736abfdb083d33f71ef9ab", "_rev"=>"1-473467b6dc1a4cba3498dd6eeb8e3206", "blueprint"=>"do bar", "location"=>"here","tags"=>["quux", "whatevz"], "scores"=>{"badness" => 12.345}, "progress" => 12, "timestamp"=>"2010/04/14 17:09:14 +0000"}}
|
129
156
|
@my_a = Answer.from_serial_hash(@couchified)
|
130
157
|
end
|
131
158
|
|
@@ -142,6 +169,10 @@ describe "Answer" do
|
|
142
169
|
@my_a.blueprint.should == "do bar"
|
143
170
|
end
|
144
171
|
|
172
|
+
it "should accumulate the :location" do
|
173
|
+
@my_a.location.should == :here
|
174
|
+
end
|
175
|
+
|
145
176
|
it "should collect the tag Array into a Set of symbols" do
|
146
177
|
@my_a.tags.should be_a_kind_of(Set)
|
147
178
|
@my_a.tags.should include(:quux)
|
@@ -438,6 +469,20 @@ describe "Answer" do
|
|
438
469
|
end
|
439
470
|
|
440
471
|
|
472
|
+
describe "locations" do
|
473
|
+
describe "move_to" do
|
474
|
+
it "should change the :location" do
|
475
|
+
a = Answer.new("do a", location: :dzz)
|
476
|
+
a.move_to(:zzd).location.should == :zzd
|
477
|
+
end
|
478
|
+
|
479
|
+
it "should raise an error if the argument isn't a Symbol" do
|
480
|
+
lambda{Answer.new("do a").move_to(99123)}.should raise_error(ArgumentError)
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
|
441
486
|
describe "tags" do
|
442
487
|
it "should have a tags array" do
|
443
488
|
Answer.new("").tags.should be_a_kind_of(Set)
|
@@ -208,15 +208,20 @@ describe "Workstation" do
|
|
208
208
|
describe "ship_to" do
|
209
209
|
before(:each) do
|
210
210
|
@w2 = Workstation.new(:lulu)
|
211
|
-
@a1 = Answer.new("do fun_stuff",
|
212
|
-
@a2 = Answer.new("do sad_stuff",
|
211
|
+
@a1 = Answer.new("do fun_stuff", location: :lulu)
|
212
|
+
@a2 = Answer.new("do sad_stuff", location: :lulu)
|
213
213
|
@w2.answers = Batch[@a1,@a2]
|
214
214
|
end
|
215
215
|
|
216
|
+
|
216
217
|
it "should accept a single argument" do
|
217
218
|
@w2.method(:ship_to).arity.should == 1
|
218
219
|
end
|
219
220
|
|
221
|
+
it "should be comfortable without any block" do
|
222
|
+
@w2.ship_to(:here)
|
223
|
+
end
|
224
|
+
|
220
225
|
it "should check the argument is a symbol" do
|
221
226
|
lambda{@w2.ship_to(8)}.should raise_error(ArgumentError)
|
222
227
|
lambda{@w2.ship_to(:heaven)}.should_not raise_error
|
@@ -227,25 +232,17 @@ describe "Workstation" do
|
|
227
232
|
@w2.ship_to(:heaven) {|a| Math.sin(12.0)}
|
228
233
|
end
|
229
234
|
|
230
|
-
it "should
|
231
|
-
@a1.should_receive(:
|
232
|
-
@a2.should_receive(:
|
233
|
-
@w2.ship_to(:xyzzy) {|a| true}
|
234
|
-
end
|
235
|
-
|
236
|
-
it "should remove the old location tag to the answers in the filtered subset" do
|
237
|
-
@a1.should_receive(:remove_tag).with(:lulu)
|
238
|
-
@a2.should_receive(:remove_tag).with(:lulu)
|
235
|
+
it "should change the :location of the answers in the filtered subset" do
|
236
|
+
@a1.should_receive(:move_to).with(:xyzzy)
|
237
|
+
@a2.should_receive(:move_to).with(:xyzzy)
|
239
238
|
@w2.ship_to(:xyzzy) {|a| true}
|
240
239
|
end
|
241
240
|
|
242
|
-
it "should
|
243
|
-
@
|
244
|
-
@
|
245
|
-
@
|
241
|
+
it "should only ship things that are still there" do
|
242
|
+
@a2.location = :far_away
|
243
|
+
@w2.ship_to(:other_place) {|a| true}
|
244
|
+
@a2.location.should == :far_away
|
246
245
|
end
|
247
|
-
|
248
|
-
it "should only ship things that are still there"
|
249
246
|
end
|
250
247
|
end
|
251
248
|
|
@@ -259,8 +256,8 @@ describe "Workstation" do
|
|
259
256
|
describe "scrap_if" do
|
260
257
|
before(:each) do
|
261
258
|
@w3 = Workstation.new(:falafel)
|
262
|
-
@a1 = Answer.new("do fun_stuff", progress:1,
|
263
|
-
@a2 = Answer.new("do sad_stuff", progress:99,
|
259
|
+
@a1 = Answer.new("do fun_stuff", progress:1, location: :falafel)
|
260
|
+
@a2 = Answer.new("do sad_stuff", progress:99, location: :falafel)
|
264
261
|
@w3.answers = Batch[@a1,@a2]
|
265
262
|
end
|
266
263
|
|
@@ -273,32 +270,14 @@ describe "Workstation" do
|
|
273
270
|
@w3.scrap_if("Math says so") {|a| Math.cos(12.0)}
|
274
271
|
end
|
275
272
|
|
276
|
-
it "should add a new location tag :SCRAP to the answers in the filtered subset" do
|
277
|
-
@a1.should_receive(:add_tag).with(:SCRAP)
|
278
|
-
@a2.should_receive(:add_tag).with(:SCRAP)
|
279
|
-
@w3.scrap_if("everything dies") {|a| true}
|
280
|
-
end
|
281
|
-
|
282
|
-
it "should remove the old location tag to the answers in the filtered subset" do
|
283
|
-
@a1.should_receive(:remove_tag).with(:falafel)
|
284
|
-
@a2.should_receive(:remove_tag).with(:falafel)
|
285
|
-
@w3.scrap_if("entropy") {|a| true}
|
286
|
-
end
|
287
|
-
|
288
|
-
it "should not touch the tags of answers not in the filtered subset" do
|
289
|
-
@a1.should_receive(:remove_tag).with(:falafel)
|
290
|
-
@a2.should_not_receive(:remove_tag)
|
291
|
-
@w3.scrap_if("insufficient progress") {|a| a.progress < 10}
|
292
|
-
end
|
293
|
-
|
294
273
|
it "should not scrap things that aren't at that location"
|
295
274
|
end
|
296
275
|
|
297
276
|
describe "scrap_everything" do
|
298
277
|
before(:each) do
|
299
278
|
@w4 = Workstation.new(:ice_station_zebra)
|
300
|
-
@a1 = Answer.new("do anything",
|
301
|
-
@a2 = Answer.new("do whatevz",
|
279
|
+
@a1 = Answer.new("do anything", location: :ice_station_zebra)
|
280
|
+
@a2 = Answer.new("do whatevz", location: :ice_station_zebra)
|
302
281
|
@w4.answers = Batch[@a1,@a2]
|
303
282
|
end
|
304
283
|
|
@@ -307,20 +286,14 @@ describe "Workstation" do
|
|
307
286
|
end
|
308
287
|
|
309
288
|
it "should call scrap_if" do
|
310
|
-
@w4.should_receive(:
|
289
|
+
@w4.should_receive(:ship_to)
|
311
290
|
@w4.scrap_everything
|
312
291
|
end
|
313
292
|
|
314
293
|
it "should send every answer to :SCRAP" do
|
315
|
-
@w4.answers.each {|a| a.
|
316
|
-
@w4.scrap_everything
|
317
|
-
@w4.answers.each {|a| a.tags.should include(:SCRAP)}
|
318
|
-
end
|
319
|
-
|
320
|
-
it "should remove the current location from every answer" do
|
321
|
-
@w4.answers.each {|a| a.tags.should include(:ice_station_zebra)}
|
294
|
+
@w4.answers.each {|a| a.location.should_not == :SCRAP}
|
322
295
|
@w4.scrap_everything
|
323
|
-
@w4.answers.each {|a| a.
|
296
|
+
@w4.answers.each {|a| a.location.should == :SCRAP}
|
324
297
|
end
|
325
298
|
|
326
299
|
it "should be safe to repeat the statement" do
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
+
|
3
|
+
# CouchDB MUST BE RUNNING BEFORE YOU RUN THESE
|
4
|
+
|
5
|
+
class ShipperStation < Workstation
|
6
|
+
def receive!
|
7
|
+
gather_mine
|
8
|
+
end
|
9
|
+
|
10
|
+
def ship!
|
11
|
+
ship_to(:that_place) {|answer| true}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
describe "CouchDB stuff" do
|
17
|
+
before(:each) do
|
18
|
+
|
19
|
+
configatron.factory.couchdb.server = "http://127.0.0.1:5984"
|
20
|
+
configatron.factory.couchdb.name = "integration_test_db"
|
21
|
+
break("CouchDB is offline") unless Factory.couch_available?
|
22
|
+
@db_uri = "#{configatron.factory.couchdb.server}/#{configatron.factory.couchdb.name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
after(:all) do
|
26
|
+
CouchRest.database!(@db_uri).delete!
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
describe "Factory CouchDB interaction" do
|
31
|
+
it "should actually return 'true' if the db is reachable" do
|
32
|
+
Factory.couch_available?.should be true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should actually return 'false' if the db is unavailable" do
|
36
|
+
FakeWeb.allow_net_connect = false
|
37
|
+
Factory.couch_available?.should be false
|
38
|
+
FakeWeb.allow_net_connect = true
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "Batch reading and writing" do
|
44
|
+
describe "updating a Batch" do
|
45
|
+
before(:each) do
|
46
|
+
@batch = Batch.[](Answer.new("do a"), Answer.new("do b"))
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "Batch#bulk_save!" do
|
50
|
+
it "should capture the couch_id values in the Answers themselves" do
|
51
|
+
old_ids = @batch.collect {|a| a.couch_id}
|
52
|
+
@batch.bulk_save!(@db_uri)
|
53
|
+
new_ids = @batch.collect {|a| a.couch_id}
|
54
|
+
old_ids.should_not == new_ids
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should capture the couch_rev values in the Answers themselves" do
|
58
|
+
@batch.bulk_save!(@db_uri)
|
59
|
+
new_revs = @batch.collect {|a| a.couch_rev}
|
60
|
+
new_revs.each {|r| r.should_not == ""}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
it "should be possible to set the couchdb_id and have that be actually used" do
|
66
|
+
@batch[0].couch_id = "001"
|
67
|
+
@batch[1].couch_id = "002"
|
68
|
+
ids = @batch.bulk_save!(@db_uri).collect {|r| r["id"]}
|
69
|
+
ids.should == ["001", "002"]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be possible to overwrite a document with new info" do
|
73
|
+
@batch.bulk_save!(@db_uri)
|
74
|
+
|
75
|
+
db = CouchRest.database!(@db_uri)
|
76
|
+
as_saved = db.get(@batch[0].couch_id)["_rev"]
|
77
|
+
@batch[0].scores[:wellness] = 0
|
78
|
+
@batch.bulk_save!(@db_uri)
|
79
|
+
and_now = db.get(@batch[0].couch_id)["_rev"]
|
80
|
+
as_saved[0].should == "1"
|
81
|
+
and_now[0].should == "2"
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
describe "Workstations passing Batches around" do
|
89
|
+
|
90
|
+
describe "gathering" do
|
91
|
+
before(:each) do
|
92
|
+
@ws1 = ShipperStation.new(:this_place)
|
93
|
+
@batch = Batch.[](
|
94
|
+
Answer.new("do a", location: :this_place),
|
95
|
+
Answer.new("do b", location: :this_place),
|
96
|
+
Answer.new("do c", location: :elsewhere))
|
97
|
+
CouchRest.database!(@db_uri).
|
98
|
+
batch_save_doc({'_id' => "_design/this_place",
|
99
|
+
views: { current: { map:
|
100
|
+
"function(doc) { if(doc.location == 'this_place') { emit(doc._id, doc); } }"}}})
|
101
|
+
@batch.bulk_save!(@db_uri)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should gather the right ones" do
|
105
|
+
@ws1.receive!
|
106
|
+
@ws1.answers.length.should == 2
|
107
|
+
@ws1.answers.collect {|a| a.blueprint}.sort.should == ["do a", "do b"]
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should capture the :_id and :_rev fields of the records" do
|
111
|
+
@ws1.receive!
|
112
|
+
@ws1.answers.each {|a| a.couch_id.should_not == ""}
|
113
|
+
@ws1.answers.each {|a| a.couch_rev.should_not == ""}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
describe "shipping" do
|
119
|
+
before(:each) do
|
120
|
+
@ws1 = ShipperStation.new(:this_place)
|
121
|
+
@batch = Batch.[](
|
122
|
+
Answer.new("do a", location: :this_place),
|
123
|
+
Answer.new("do b", location: :this_place),
|
124
|
+
Answer.new("do c", location: :elsewhere))
|
125
|
+
CouchRest.database!(@db_uri).
|
126
|
+
batch_save_doc({'_id' => "_design/this_place",
|
127
|
+
views: { current: { map:
|
128
|
+
"function(doc) { if(doc.location == 'this_place') { emit(doc._id, doc); } }"}}})
|
129
|
+
@batch.bulk_save!(@db_uri)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should not be able to re-gather Answers it has shipped away" do
|
133
|
+
@ws1.cycle # load, ship, and save
|
134
|
+
@ws1.receive!
|
135
|
+
@ws1.answers.length.should == 0
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
end
|
data/tasks/setup_factory.thor
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#encoding: utf-8
|
1
2
|
require 'answer-factory'
|
2
3
|
include Nudge
|
3
4
|
include AnswerFactory
|
@@ -23,102 +24,102 @@ configatron.project.nudge.instructions.path = '/lib/nudge/instructions/*'
|
|
23
24
|
configatron.project.nudge.types.path = '/lib/nudge/types/*'
|
24
25
|
|
25
26
|
|
26
|
-
|
27
27
|
#### normally these should be in /lib/factory/workstations/**
|
28
28
|
|
29
|
-
class
|
29
|
+
class GenerationStation < Workstation
|
30
30
|
attr_reader :random_program_maker
|
31
31
|
|
32
32
|
def initialize(name, options = {})
|
33
33
|
super
|
34
34
|
@random_program_maker = Machines::BuildRandom.new(
|
35
35
|
how_many:10,
|
36
|
-
target_size_in_points:
|
36
|
+
target_size_in_points:20,
|
37
37
|
reference_names:["x1", "x2"])
|
38
38
|
end
|
39
39
|
|
40
|
-
def receive!
|
41
|
-
gather_mine
|
42
|
-
puts "#{self.name}: received and now have: #{@answers.length}"
|
43
|
-
puts "\n\n#{self.name}: tags begin as #{(@answers.collect {|a| a.tags.to_a}).flatten}"
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
40
|
def build!
|
48
41
|
@answers = process_with @random_program_maker
|
49
|
-
|
42
|
+
@answers.each {|a| a.location = :maker}
|
43
|
+
puts
|
44
|
+
puts "MAKER BUILD: made #{@answers.length}"
|
50
45
|
end
|
51
46
|
|
52
47
|
def ship!
|
53
|
-
ship_to(:
|
54
|
-
puts "
|
48
|
+
ship_to(:polisher) {|answer| true}
|
49
|
+
puts "MAKER SHIP -> POLISHER"
|
55
50
|
end
|
56
51
|
end
|
57
52
|
|
58
53
|
|
59
|
-
class
|
54
|
+
class VariationStation < Workstation
|
60
55
|
attr_reader :my_length_evaluator
|
61
56
|
|
62
57
|
def initialize(name, options = {})
|
63
58
|
super
|
64
|
-
@
|
65
|
-
|
66
|
-
|
59
|
+
@mutator = Machines::MutateFootnotesUniform.new(
|
60
|
+
)
|
61
|
+
@score_1 = Machines::EvaluateSimpleScore.new(
|
62
|
+
:name => :number_of_footnotes,
|
63
|
+
scorer:Proc.new {|a| a.blueprint.scan(/^«/).length})
|
67
64
|
end
|
68
65
|
|
69
66
|
def receive!
|
70
67
|
gather_mine
|
71
|
-
puts "
|
72
|
-
puts "\n\n#{self.name}: tags begin as #{(@answers.collect {|a| a.tags.to_a}).flatten}"
|
68
|
+
puts "POLISHER RECEIVE: got #{@answers.length}"
|
73
69
|
end
|
74
70
|
|
75
71
|
def build!
|
76
|
-
@
|
77
|
-
|
72
|
+
@mutants = process_with @mutator
|
73
|
+
@mutants.each {|a| @answers << a}
|
74
|
+
@answers = process_with @score_1
|
75
|
+
puts "POLISHER BUILD: has #{@answers.length}"
|
78
76
|
end
|
79
77
|
|
80
78
|
def ship!
|
81
|
-
ship_to(:
|
82
|
-
puts "#{self.name}: shipping to #{@answers.collect {|a| a.tags.to_a}.inspect}"
|
79
|
+
ship_to(:picker) {|answer| true}
|
83
80
|
end
|
84
81
|
|
85
82
|
def scrap!
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
83
|
+
best_score = (@answers.collect {|a| a.scores[:number_of_footnotes]}).min
|
84
|
+
worst_score = (@answers.collect {|a| a.scores[:number_of_footnotes]}).max
|
85
|
+
puts "#{worst_score}..#{best_score}"
|
86
|
+
scrap_if("too many footnotes") {|a| a.scores[:number_of_footnotes] >
|
87
|
+
((worst_score - best_score)/2.0 + best_score)}
|
88
|
+
puts "PICKER SCRAP: kept #{@answers.find_all {|a| a.location == :polisher}.length}"
|
91
89
|
end
|
92
90
|
end
|
93
91
|
|
94
92
|
|
95
|
-
class
|
96
|
-
attr_reader :
|
93
|
+
class ScreeningStation < Workstation
|
94
|
+
attr_reader :letters
|
97
95
|
|
98
96
|
def initialize(name, options = {})
|
99
97
|
super
|
100
|
-
@
|
101
|
-
:name => :
|
102
|
-
scorer:Proc.new {|a| a.blueprint.
|
98
|
+
@letters = Machines::EvaluateSimpleScore.new(
|
99
|
+
:name => :letters,
|
100
|
+
scorer:Proc.new {|a| a.blueprint.length})
|
101
|
+
@so_far_so_good = Machines::SelectNondominated.new
|
103
102
|
end
|
104
103
|
|
105
104
|
def receive!
|
106
105
|
gather_mine
|
107
|
-
puts "
|
108
|
-
puts "\n\n#{self.name}: tags begin as #{(@answers.collect {|a| a.tags.to_a}).flatten}"
|
106
|
+
puts "PICKER RECEIVE: got #{@answers.length}"
|
109
107
|
end
|
110
108
|
|
111
109
|
def build!
|
112
|
-
@answers = process_with @
|
113
|
-
|
110
|
+
@answers = process_with @letters
|
111
|
+
@best = process_with @so_far_so_good
|
112
|
+
puts "PICKER EVERYTHING: #{@answers.length}"
|
113
|
+
@answers.each {|a| puts a.scores}
|
114
|
+
puts "----------"
|
115
|
+
puts "PICKER NONDOMINATED SET: #{@best.length}"
|
116
|
+
@best.each {|a| puts a.scores}
|
117
|
+
|
114
118
|
end
|
115
119
|
|
116
120
|
def scrap!
|
117
|
-
|
118
|
-
|
119
|
-
scrap_if("too_long") {|a| (a.scores[:points] > @best_score)}
|
120
|
-
puts "#{self.name}: tags ended as #{(@answers.collect {|a| a.tags.to_a}).flatten}"
|
121
|
-
puts "#{self.name}: scores ended as #{(@answers.collect {|a| a.scores.values}).flatten}\n\n"
|
121
|
+
scrap_if("dominated") {|a| !@best.include?(a)}
|
122
|
+
puts "PICKER SCRAP: kept #{@answers.find_all {|a| a.location == :picker}.length}"
|
122
123
|
end
|
123
124
|
end
|
124
125
|
|
@@ -141,30 +142,43 @@ raise "CouchDB not available at #{configatron.factory.couchdb.server}" unless
|
|
141
142
|
# extend Workstation
|
142
143
|
Dir.glob(File.dirname(__FILE__) + configatron.project.workstations.path) {|file| require file}
|
143
144
|
|
145
|
+
|
146
|
+
### these should get tucked away elsewhere:
|
147
|
+
|
144
148
|
project = Factory.new()
|
145
|
-
workstations =
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
+
workstations =[
|
150
|
+
GenerationStation.new(:maker),
|
151
|
+
VariationStation.new(:polisher),
|
152
|
+
ScreeningStation.new(:picker)]
|
149
153
|
|
150
|
-
#
|
154
|
+
# reset database
|
151
155
|
db = CouchRest.database!("#{configatron.factory.couchdb.server}/#{configatron.factory.name}")
|
152
156
|
db.delete!
|
153
157
|
db.create!
|
154
158
|
|
155
|
-
db.batch_save_doc({'_id' => "_design/marker", views: { current: { map: "function(doc) { if(doc.tags.length > 0) { for(var idx in doc.tags) { if(doc.tags[idx] == 'marker') {emit(doc._id, doc) }}}}"}}})
|
156
159
|
|
157
|
-
|
160
|
+
# create required view document(s) [should be part of generating each workstation]
|
161
|
+
db.batch_save_doc({'_id' => "_design/maker", views: { current: { map: "function(doc) {
|
162
|
+
if(doc.location == 'maker') {
|
163
|
+
emit(doc._id, doc);
|
164
|
+
}
|
165
|
+
}"}}})
|
158
166
|
|
159
|
-
db.batch_save_doc({'_id' => "_design/
|
167
|
+
db.batch_save_doc({'_id' => "_design/polisher", views: { current: { map: "function(doc) {
|
168
|
+
if(doc.location == 'polisher') {
|
169
|
+
emit(doc._id, doc);
|
170
|
+
}
|
171
|
+
}"}}})
|
160
172
|
|
173
|
+
db.batch_save_doc({'_id' => "_design/picker", views: { current: { map: "function(doc) {
|
174
|
+
if(doc.location == 'picker') {
|
175
|
+
emit(doc._id, doc);
|
176
|
+
}
|
177
|
+
}"}}})
|
161
178
|
|
162
|
-
test = {"_id" => "test_doc", "wild" => "and random"}
|
163
|
-
db.save_doc(test)
|
164
|
-
test["foo" => "bar"]
|
165
|
-
db.save_doc(test)
|
166
179
|
|
167
|
-
|
180
|
+
# final workcycle behavior
|
181
|
+
100.times do
|
168
182
|
workstations.each do |ws|
|
169
183
|
ws.cycle
|
170
184
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Bill Tozier
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-05-
|
19
|
+
date: 2010-05-11 00:00:00 -04:00
|
20
20
|
default_executable: answer-factory
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -146,7 +146,7 @@ files:
|
|
146
146
|
- spec/batch_spec.rb
|
147
147
|
- spec/factories/factory_spec.rb
|
148
148
|
- spec/factories/workstation_spec.rb
|
149
|
-
- spec/integration_specs/couch_db_integration.
|
149
|
+
- spec/integration_specs/couch_db_integration.rspec
|
150
150
|
- spec/machines/any_one_spec.rb
|
151
151
|
- spec/machines/build_random_spec.rb
|
152
152
|
- spec/machines/evaluate_simple_score_spec.rb
|
@@ -194,7 +194,6 @@ test_files:
|
|
194
194
|
- spec/batch_spec.rb
|
195
195
|
- spec/factories/factory_spec.rb
|
196
196
|
- spec/factories/workstation_spec.rb
|
197
|
-
- spec/integration_specs/couch_db_integration.rb
|
198
197
|
- spec/machines/any_one_spec.rb
|
199
198
|
- spec/machines/build_random_spec.rb
|
200
199
|
- spec/machines/evaluate_simple_score_spec.rb
|
@@ -1,60 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "./../spec_helper")
|
2
|
-
|
3
|
-
# CouchDB MUST BE RUNNING BEFORE YOU RUN THESE
|
4
|
-
|
5
|
-
|
6
|
-
describe "CouchDB stuff" do
|
7
|
-
before(:each) do
|
8
|
-
configatron.factory.couchdb.server = "http://127.0.0.1:5984"
|
9
|
-
configatron.factory.couchdb.name = "integration_test_db"
|
10
|
-
break("CouchDB is offline") unless Factory.couch_available?
|
11
|
-
@db_uri = "#{configatron.factory.couchdb.server}/#{configatron.factory.couchdb.name}"
|
12
|
-
end
|
13
|
-
|
14
|
-
after(:all) do
|
15
|
-
CouchRest.database!(@db_uri).delete!
|
16
|
-
end
|
17
|
-
|
18
|
-
describe "updating a Batch" do
|
19
|
-
before(:each) do
|
20
|
-
@batch = Batch.[](Answer.new("do a"), Answer.new("do b"))
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "Batch#bulk_save!" do
|
24
|
-
it "should capture the couch_id values in the Answers themselves" do
|
25
|
-
old_ids = @batch.collect {|a| a.couch_id}
|
26
|
-
@batch.bulk_save!(@db_uri)
|
27
|
-
new_ids = @batch.collect {|a| a.couch_id}
|
28
|
-
old_ids.should_not == new_ids
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should capture the couch_rev values in the Answers themselves" do
|
32
|
-
@batch.bulk_save!(@db_uri)
|
33
|
-
new_revs = @batch.collect {|a| a.couch_rev}
|
34
|
-
new_revs.each {|r| r.should_not == ""}
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
|
-
it "should be possible to set the couchdb_id and have that be actually used" do
|
40
|
-
@batch[0].couch_id = "001"
|
41
|
-
@batch[1].couch_id = "002"
|
42
|
-
ids = @batch.bulk_save!(@db_uri).collect {|r| r["id"]}
|
43
|
-
ids.should == ["001", "002"]
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should be possible to overwrite a document with new info" do
|
47
|
-
@batch.bulk_save!(@db_uri)
|
48
|
-
|
49
|
-
db = CouchRest.database!(@db_uri)
|
50
|
-
as_saved = db.get(@batch[0].couch_id)["_rev"]
|
51
|
-
@batch[0].scores[:wellness] = 0
|
52
|
-
@batch.bulk_save!(@db_uri)
|
53
|
-
and_now = db.get(@batch[0].couch_id)["_rev"]
|
54
|
-
as_saved[0].should == "1"
|
55
|
-
and_now[0].should == "2"
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|