brewser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ class BeerXML2 < Brewser::Engine
2
+
3
+ require 'nokogiri'
4
+
5
+ class << self
6
+
7
+ def acceptable?(q)
8
+ Nokogiri::XML(q){|config| config.noblanks }.remove_namespaces!.xpath("//version").inner_text.to_i == 2 ? true : false
9
+ # @TODO Add XSD Validation here
10
+ end
11
+
12
+ def deserialize(string_or_io)
13
+ results = parse_xml(string_or_io)
14
+ puts results.inspect
15
+ return results
16
+ end
17
+
18
+ def serialize(brewser_model)
19
+ end
20
+
21
+ def parse_xml(string_or_io)
22
+ raise NotImplemented, "BeerXML2 support is not implemented yet"
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
@@ -0,0 +1,20 @@
1
+ class BrewSON < Brewser::Engine
2
+
3
+ class << self
4
+
5
+ def acceptable?(q)
6
+ return q.valid_json?
7
+ end
8
+
9
+ def deserialize(string_or_io)
10
+ end
11
+
12
+ def serialize(brewser_model)
13
+ brewser_model.deep_json
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+
20
+
@@ -0,0 +1,424 @@
1
+ class ProMashRec < Brewser::Engine
2
+
3
+ class << self
4
+
5
+ def acceptable?(q)
6
+ return true
7
+ end
8
+
9
+ def deserialize(io)
10
+ object = ProMashRec::Recipe.new
11
+ object.from_promash(io)
12
+ return object
13
+ end
14
+
15
+ end
16
+
17
+ module ::Loader
18
+
19
+ require 'bindata'
20
+
21
+ class RecEntry < BinData::Record
22
+ endian :little
23
+ end
24
+
25
+ class Hop < RecEntry
26
+ string :name, :length => 55, :trim_padding => true
27
+ float :alpha_acids
28
+ float :beta_acids
29
+ int8 :noble
30
+ float :cohumulone
31
+ float :myrcene
32
+ float :humulene
33
+ float :caryphylene
34
+ int8 :type
35
+ int8 :form
36
+ float :storage_factor
37
+ string :taste_notes, :length => 155, :trim_padding => true
38
+ string :origin, :length => 55, :trim_padding => true
39
+ string :best_for, :length => 155, :trim_padding => true
40
+ string :substitutes, :length => 155, :trim_padding => true
41
+ skip length: 10
42
+ float :storage_temp_c
43
+ float :actual_alpha_acids
44
+ int8 :flag
45
+ float :amount
46
+ int16 :time
47
+ float :ibus
48
+ end
49
+
50
+ class Fermentable < RecEntry
51
+ string :name, :length => 110, :trim_padding => true
52
+ string :origin, :length => 55, :trim_padding => true
53
+ int8 :type
54
+ int8 :form
55
+ float :potential
56
+ float :color
57
+ float :moisture_content
58
+ float :max_in_batch
59
+ float :diastatic_power
60
+ float :percent_protein
61
+ float :percent_tsn
62
+ string :uses, :length => 155, :trim_padding => true
63
+ string :comments, :length => 155, :trim_padding => true
64
+ skip length: 8
65
+ float :dry_basis_fg
66
+ float :dry_basis_cg
67
+ float :amount
68
+ float :extract
69
+ end
70
+
71
+ class Additive < RecEntry
72
+ string :name, :length => 55, :trim_padding => true
73
+ int8 :type
74
+ int16 :time
75
+ skip length: 2
76
+ int8 :added_when
77
+ int8 :time_in
78
+ int8 :amount_unit
79
+ skip length: 4
80
+ string :uses, :length => 255, :trim_padding => true
81
+ string :comments, :length => 255, :trim_padding => true
82
+ float :amount
83
+ skip length: 8
84
+ end
85
+
86
+ class Yeast < RecEntry
87
+ string :name, :length => 55, :trim_padding => true
88
+ string :supplier, :length => 55, :trim_padding => true
89
+ string :catalog, :length => 26, :trim_padding => true
90
+ string :flavor_note, :length => 155, :trim_padding => true
91
+ string :comment, :length => 155, :trim_padding => true
92
+ skip length: 9
93
+ int32 :aa_low
94
+ int32 :aa_high
95
+ float :optimum_temp
96
+ skip length: 6
97
+ end
98
+
99
+ class WaterProfile < RecEntry
100
+ string :name, :length => 27, :trim_padding => true
101
+ float :calcium
102
+ float :magnesium
103
+ float :sodium
104
+ float :unknown
105
+ float :sulfate
106
+ float :chloride
107
+ float :bicarbonate
108
+ float :ph
109
+ string :comments, :length => 155, :trim_padding => true
110
+ skip length: 8
111
+ end
112
+
113
+ class MashStep < RecEntry
114
+ string :name, :length => 255, :trim_padding => true
115
+ int8 :type
116
+ int32 :start_temp
117
+ int32 :stop_temp
118
+ int32 :step_temp
119
+ int32 :rest_time
120
+ int32 :step_time
121
+ float :thickness
122
+ float :amount
123
+ skip length: 8
124
+ end
125
+
126
+ class MashSchedule < RecEntry
127
+ int32 :_steps_count
128
+ int32 :grain_temp
129
+ skip length: 4
130
+ array :mash_steps, :type => :mash_step, :read_until => lambda { index == 50 }
131
+ string :name, :length => 256, :trim_padding => true
132
+ end
133
+
134
+ class SimpleSchedule < RecEntry
135
+ int32 :num_steps
136
+ skip length: 5
137
+ int32 :acid_rest_temp
138
+ int32 :acid_rest_time
139
+ int32 :protein_rest_temp
140
+ int32 :protein_rest_time
141
+ int32 :int_rest_temp
142
+ int32 :int_rest_time
143
+ int32 :sac_rest_temp
144
+ int32 :sac_rest_time
145
+ int32 :mash_out_temp
146
+ int32 :mash_out_time
147
+ int32 :sparge_temp
148
+ int32 :sparge_time
149
+ float :mash_volume
150
+ skip length: 1
151
+ end
152
+
153
+ class Style < RecEntry
154
+ string :category, :length => 55, :trim_padding => true
155
+ string :sub_category, :length => 55, :trim_padding => true
156
+ int8 :_type
157
+ float :min_og
158
+ float :max_og
159
+ float :min_fg
160
+ float :max_fg
161
+ float :min_abv
162
+ float :max_abv
163
+ float :min_ibu
164
+ float :max_ibu
165
+ float :min_color
166
+ float :max_color
167
+ string :color_note, :length => 155, :trim_padding => true
168
+ string :malt_note, :length => 155, :trim_padding => true
169
+ string :hop_note, :length => 155, :trim_padding => true
170
+ string :yeast_note, :length => 155, :trim_padding => true
171
+ string :examples, :length => 255, :trim_padding => true
172
+ int16 :category_number
173
+ string :sub_category_letter, :length => 2, :trim_padding => true
174
+ int8 :_guideline
175
+ end
176
+
177
+ class Recipe < RecEntry
178
+ string :title, :length => 85, :trim_padding => true
179
+ int32 :_hops_count
180
+ int32 :_fermentables_count
181
+ int32 :_additives_count
182
+ float :recipe_volume
183
+ float :boil_volume
184
+ float :estimated_og
185
+ float :estimated_ibu
186
+ float :recipe_efficiency
187
+ int32 :boil_time
188
+ int32 :_recipe_type
189
+ int8 :_brew_method
190
+ style :style
191
+ array :hops, :type => :hop, :initial_length => :_hops_count
192
+ array :fermentables, :type => :fermentable, :initial_length => :_fermentables_count
193
+ array :additives, :type => :additive, :initial_length => :_additives_count
194
+ yeast :yeast
195
+ water_profile :water_profile
196
+ simple_schedule :simple_schedule
197
+ string :notes, :length => 4029, :trim_padding => true
198
+ string :awards, :length => 3693, :trim_padding => true
199
+ mash_schedule :mash_schedule
200
+ end
201
+ end
202
+
203
+ end
204
+
205
+
206
+ class ProMashRec::Hop < Brewser::Hop
207
+
208
+ @@hop_types = {0 => "Both", 1 => "Bittering", 2 => "Aroma"}
209
+ @@hop_forms = {1 => "Whole", 3 => "Whole", 21 => "Pellet", 23 => "Pellet", 11 => "Plug"}
210
+
211
+ # Pellet 21, 23
212
+ def from_promash(hop,time)
213
+ self.name = hop.name.split("\x00")[0]
214
+ self.origin = hop.origin.split("\x00")[0]
215
+ self.alpha_acids = hop.alpha_acids
216
+ self.beta_acids = hop.beta_acids
217
+ self.type = @@hop_types[hop.type]
218
+ self.form = @@hop_forms[hop.form]
219
+ self.amount = "#{hop.amount} oz".u
220
+ self.time = "#{hop.time} min".u
221
+ self.storageability = hop.storage_factor
222
+ self.humulene = hop.humulene
223
+ self.caryophyllene = hop.caryphylene
224
+ self.cohumulone = hop.cohumulone
225
+ self.myrcene = hop.myrcene
226
+ if hop.time.to_i >= 0 and hop.time.to_i <= time
227
+ self.added_when = "Boil"
228
+ elsif hop.time.to_i == time+1
229
+ self.added_when = "FWH"
230
+ elsif hop.time.to_i == time+2
231
+ self.added_when = "Mash"
232
+ else
233
+ self.added_when = "Dry"
234
+ end
235
+
236
+ return self
237
+ end
238
+
239
+ end
240
+
241
+ class ProMashRec::Fermentable < Brewser::Fermentable
242
+
243
+ @@ferm_types = {0 => { 0 => "Grain", 1 => "Dry Extract", 2 => "Sugar", 3 => "Adjunct"},
244
+ 1 => { 0 => "Grain", 1 => "Extract", 2 => "Sugar", 3 => "Adjunct"}}
245
+
246
+ def from_promash(ferm)
247
+ self.name = ferm.name.split("\x00")[0]
248
+ self.origin = ferm.origin.split("\x00")[0]
249
+ self.type = @@ferm_types[ferm.form][ferm.type]
250
+ self.potential = ferm.potential.round(3)
251
+ self.color = ferm.color
252
+ self.amount = "#{ferm.amount} lbs".u
253
+ self.diastatic_power = ferm.diastatic_power
254
+ self.max_in_batch = ferm.max_in_batch
255
+ self.moisture = ferm.moisture_content
256
+
257
+ return self
258
+ end
259
+
260
+ end
261
+
262
+ class ProMashRec::Additive < Brewser::Additive
263
+
264
+ @@additive_types = { 0 => "Spice", 1 => "Fruit", 2 => "Flavor", 3 => "Other", 4 => "Fining", 5 => "Herb" }
265
+ @@added_whens = { 0 => "Boil", 1 => "Primary", 2 => "Mash" }
266
+ @@additive_unit = { 0 => "oz", 1 => "g", 2 => "lb", 3 => "tsp", 4 => "tbsp", 5 => "cups", 6 => "each" }
267
+ @@additive_time = { 0 => "days", 1 => "min" }
268
+
269
+ def from_promash(add)
270
+ self.name = add.name.split("\x00")[0]
271
+ self.type = @@additive_types[add.type]
272
+ self.added_when = @@added_whens[add.added_when]
273
+ self.time = "#{add.time} #{@@additive_time[add.time_in]}".u
274
+ self.amount = "#{add.amount} #{@@additive_unit[add.amount_unit]}".u
275
+ self.use_for = add.uses
276
+
277
+ return self
278
+ end
279
+
280
+ end
281
+
282
+ class ProMashRec::Yeast < Brewser::Yeast
283
+
284
+ def from_promash(y)
285
+ self.name = y.name.split("\x00")[0]
286
+ self.supplier = y.supplier
287
+ self.catalog = y.catalog
288
+ self.attenuation = (y.aa_high + y.aa_low)/2
289
+ self.min_temperature = self.max_temperature = "#{y.optimum_temp} dF".u
290
+ self.description = y.comment
291
+ self.amount = "1 each".u
292
+
293
+ return self
294
+ end
295
+
296
+ end
297
+
298
+ class ProMashRec::MashStep < Brewser::MashStep
299
+
300
+ def from_simple(idx, name, rest_temp, rest_time)
301
+ self.index = idx
302
+ self.name = name
303
+ self.rest_temperature = rest_temp.u
304
+ self.rest_time = rest_time.u
305
+
306
+ return self
307
+ end
308
+
309
+ end
310
+
311
+ class ProMashRec::MashSchedule < Brewser::MashSchedule
312
+
313
+ def from_promash(mash)
314
+
315
+ return self
316
+ end
317
+
318
+ end
319
+
320
+ class ProMashRec::SimpleSchedule < Brewser::MashSchedule
321
+
322
+ def from_promash(mash)
323
+ self.name = "Simple"
324
+ ["acid_rest", "protein_rest", "int_rest", "sac_rest", "mash_out", "sparge"].each do |step, index|
325
+ next if mash.send("#{step}_temp")==0
326
+ self.mash_steps.push ProMashRec::MashStep.new.from_simple(index, "#{step.gsub("_"," ").capitalize}", "#{mash.send("#{step}_temp")} dF",
327
+ "#{mash.send("#{step}_time")} min")
328
+ end
329
+ return self
330
+ end
331
+
332
+ end
333
+
334
+ class ProMashRec::FermentationStep < Brewser::FermentationStep
335
+ # Not support in ProMash REC files
336
+ end
337
+
338
+ class ProMashRec::FermentationSchedule < Brewser::FermentationSchedule
339
+ # Not supported in ProMash REC files
340
+ end
341
+
342
+ class ProMashRec::WaterProfile < Brewser::WaterProfile
343
+
344
+ def from_promash(water)
345
+ self.name = water.name.split("\x00")[0]
346
+ self.calcium = water.calcium
347
+ self.magnesium = water.magnesium
348
+ self.sodium = water.sodium
349
+ self.chloride = water.chloride
350
+ self.sulfates = water.sulfate
351
+ self.bicarbonate = water.bicarbonate
352
+ self.ph = water.ph.round(2)
353
+
354
+ return self
355
+ end
356
+
357
+ end
358
+
359
+ class ProMashRec::Style < Brewser::Style
360
+
361
+ @@style_guides = { 0 => "AHA", 1 => "BJCP" }
362
+ @@style_types = { 0 => "Ale", 1 => "Lager", 2 => "Cider", 3 => "Mead", 5 => "Hybrid"}
363
+
364
+ def from_promash(style)
365
+ self.name = style.sub_category.split("\x00")[0]
366
+ self.category = style.category.split("\x00")[0]
367
+ self.category_number = style.category_number
368
+ self.style_letter = style.sub_category_letter
369
+ self.style_guide = @@style_guides[style._guideline]
370
+ self.type = @@style_types[style._type]
371
+ self.og_min = style.min_og
372
+ self.og_max = style.max_og
373
+ self.fg_min = style.min_fg
374
+ self.fg_max = style.max_fg
375
+ self.ibu_min = style.min_ibu
376
+ self.ibu_max = style.max_ibu
377
+ self.color_min = style.min_color
378
+ self.color_max = style.max_color
379
+ self.examples = style.examples
380
+
381
+ return self
382
+ end
383
+
384
+ end
385
+
386
+ class ProMashRec::Recipe < Brewser::Recipe
387
+
388
+ @@recipe_types = { 0 => "Other", 15 => "Lager", 25 => "Hybrid", 30 => "Ale" }
389
+ @@brew_methods = { 0 => "All Grain", 1 => "Partial Mash", 2 => "Extract" }
390
+
391
+ def from_promash(data)
392
+ rec = Loader::Recipe.read(data)
393
+ self.name = rec.title.split("\x00")[0]
394
+ self.method = @@brew_methods[rec._brew_method]
395
+ self.recipe_volume = "#{rec.recipe_volume} gal".u
396
+ self.boil_volume = "#{rec.boil_volume} gal".u
397
+ self.boil_time = "#{rec.boil_time} min".u
398
+ self.estimated_og = (1+rec.estimated_og/1000).round(3)
399
+ self.estimated_ibu = rec.estimated_ibu.round(1)
400
+ self.recipe_efficiency = rec.recipe_efficiency*100
401
+ self.style = ProMashRec::Style.new.from_promash(rec.style)
402
+ rec.hops.each do |hop|
403
+ self.hops.push ProMashRec::Hop.new.from_promash(hop,rec.boil_time.to_i)
404
+ end
405
+ rec.fermentables.each do |fermentable|
406
+ self.fermentables.push ProMashRec::Fermentable.new.from_promash(fermentable)
407
+ end
408
+ rec.additives.each do |additive|
409
+ self.additives.push ProMashRec::Additive.new.from_promash(additive)
410
+ end
411
+ self.yeasts.push ProMashRec::Yeast.new.from_promash(rec.yeast)
412
+ self.water_profile = ProMashRec::WaterProfile.new.from_promash(rec.water_profile)
413
+ if rec.simple_schedule.num_steps > 0
414
+ self.mash_schedule = ProMashRec::SimpleSchedule.new.from_promash(rec.simple_schedule)
415
+ else
416
+ self.mash_schedule = ProMashRec::MashSchedule.new.from_promash(rec.mash_schedule)
417
+ end
418
+ self.description = rec.notes
419
+ self.type = self.style.type
420
+ #puts rec.snapshot
421
+ return self
422
+ end
423
+
424
+ end