answer-factory 0.0.15 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|