brewser 0.1.0 → 0.2.0

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.
@@ -7,6 +7,30 @@ module Brewser
7
7
  property :grain_temp, Temperature
8
8
  property :sparge_temp, Temperature
9
9
 
10
- has n, :mash_steps
10
+ has n, :mash_steps
11
+
12
+ def self.json_create(o)
13
+ return nil if o.blank?
14
+ a = self.new
15
+ a.name = o['name']
16
+ a.description = o['description']
17
+ a.grain_temp = o['grain_temperature'].u unless o['grain_temperature'].blank?
18
+ a.sparge_temp = o['sparge_temperature'].u unless o['sparge_temperature'].blank?
19
+ o['mash_steps'].each do |step|
20
+ a.mash_steps.push step
21
+ end unless o['mash_steps'].nil?
22
+
23
+ return a
24
+ end
25
+
26
+ def as_json(options={})
27
+ {
28
+ JSON.create_id => "Brewser::MashSchedule",
29
+ 'name' => name, 'description' => description,
30
+ 'grain_temperature' => grain_temp.to_s, 'sparge_temperature' => sparge_temp.to_s,
31
+ 'mash_steps' => mash_steps.to_a
32
+ }
33
+ end
34
+
11
35
  end
12
36
  end
@@ -13,12 +13,45 @@ module Brewser
13
13
 
14
14
  property :step_volume, Volume
15
15
  property :ramp_time, Time
16
+ property :water_to_grain_ratio, Float
16
17
 
17
18
  property :infusion_volume, Volume
18
19
  property :infusion_temperature, Temperature
19
20
 
20
21
  property :rest_temperature, Temperature, :required => true
21
22
  property :rest_time, Time, :required => true
23
+
24
+ def self.json_create(o)
25
+ return nil if o.blank?
26
+ a = self.new
27
+ a.name = o['name']
28
+ a.index = o['index']
29
+ a.description = o['description']
30
+ a.type = o['type']
31
+ a.purpose = o['purpose']
32
+ a.step_volume = o['step_volume'].u unless o['step_volume'].blank?
33
+ a.ramp_time = o['ramp_time'].u unless o['ramp_time'].blank?
34
+ a.water_to_grain_ratio = o['water_to_grain_ratio']
35
+ a.infusion_volume = o['infusion_volume'].u unless o['infusion_volume'].blank?
36
+ a.infusion_temperature = o['infusion_temperature'].u unless o['infusion_temperature'].blank?
37
+ a.rest_temperature = o['rest_temperature'].u unless o['rest_temperature'].blank?
38
+ a.rest_time = o['rest_time'].u unless o['rest_time'].blank?
39
+
40
+ return a
41
+ end
42
+
43
+ def as_json(options={})
44
+ {
45
+ JSON.create_id => "Brewser::MashStep",
46
+ 'name' => name, 'index' => index, 'description' => description,
47
+ 'type' => type, 'purpose' => purpose,
48
+ 'step_volume' => step_volume.to_s, 'ramp_time' => ramp_time.to_s,
49
+ 'infusion_volume' => infusion_volume.to_s, 'infusion_temperature' => infusion_temperature.to_s,
50
+ 'rest_temperature' => rest_temperature.to_s, 'rest_time' => rest_time.to_s,
51
+ 'water_to_grain_ratio' => water_to_grain_ratio
52
+ }
53
+ end
54
+
22
55
  end
23
56
 
24
57
  end
@@ -45,6 +45,69 @@ module Brewser
45
45
 
46
46
  validates_presence_of :mash_schedule, :if => proc { |t| t.method != 'Extract' }
47
47
 
48
+ def as_json(options={})
49
+ {
50
+ JSON.create_id => "Brewser::Recipe",
51
+ 'name' => name,
52
+ 'description' => description,
53
+ 'type' => type,
54
+ 'method' => method,
55
+ 'brewer' => brewer,
56
+ 'style' => style,
57
+ 'recipe_volume' => recipe_volume.to_s,
58
+ 'boil_volume' => boil_volume.to_s,
59
+ 'boil_time' => boil_time.to_s,
60
+ 'recipe_efficiency' => recipe_efficiency,
61
+ 'hops' => hops.to_a, 'fermentables' => fermentables.to_a,
62
+ 'additives' => additives.to_a, 'yeasts' => yeasts.to_a,
63
+ 'mash_schedule' => mash_schedule, 'fermentation_schedule' => fermentation_schedule,
64
+ 'water_profile' => water_profile,
65
+ 'estimated_og' => estimated_og, 'estimated_fg' => estimated_fg,
66
+ 'estimated_color' => estimated_color, 'estimated_ibu' => estimated_ibu,
67
+ 'estimated_abv' => estimated_abv, 'carbonation_level' => carbonation_level,
68
+ 'source' => source, 'url' => url
69
+ }
70
+ end
71
+
72
+ def self.json_create(o)
73
+ a = self.new
74
+ a.name = o['name']
75
+ a.description = o['description']
76
+ a.brewer = o['brewer']
77
+ a.method = o['method']
78
+ a.type = o['type']
79
+ a.style = o['style']
80
+ a.mash_schedule = o['mash_schedule']
81
+ a.fermentation_schedule = o['fermentation_schedule']
82
+ a.water_profile = o['water_profile']
83
+ o['fermentables'].each do |fermentable|
84
+ a.fermentables.push fermentable
85
+ end unless o['fermentables'].nil?
86
+ o['hops'].each do |hop|
87
+ a.hops.push hop
88
+ end unless o['hops'].nil?
89
+ o['additives'].each do |additive|
90
+ a.additives.push additive
91
+ end unless o['additives'].nil?
92
+ o['yeasts'].each do |yeast|
93
+ a.yeasts.push yeast
94
+ end unless o['yeasts'].nil?
95
+ a.recipe_volume = o['recipe_volume'].u unless o['recipe_volume'].blank?
96
+ a.boil_volume = o['boil_volume'].u unless o['boil_volume'].blank?
97
+ a.boil_time = o['boil_time'].u unless o['boil_time'].blank?
98
+ a.recipe_efficiency = o['recipe_efficiency']
99
+ a.estimated_og = o['estimated_og']
100
+ a.estimated_fg = o['estimated_fg']
101
+ a.estimated_color = o['estimated_color']
102
+ a.estimated_ibu = o['estimated_ibu']
103
+ a.estimated_abv = o['estimated_abv']
104
+ a.carbonation_level = o['carbonation_level']
105
+ a.source = o['source']
106
+ a.url = o['url']
107
+
108
+ return a
109
+ end
110
+
48
111
  end
49
112
 
50
113
  end
@@ -25,5 +25,27 @@ module Brewser
25
25
  property :profile, String, :length => 65535
26
26
  property :ingredients, String, :length => 65535
27
27
  property :examples, String, :length => 65535
28
+
29
+ def self.json_create(o)
30
+ a = self.new
31
+ a.name = o['name']
32
+ a.category = o['category']
33
+ a.category_number = o['category_number']
34
+ a.style_letter = o['style_letter']
35
+ a.type = o['type']
36
+ a.style_guide = o['style_guide']
37
+
38
+ return a
39
+ end
40
+
41
+ def as_json(options={})
42
+ {
43
+ JSON.create_id => "Brewser::Style",
44
+ 'name' => name, 'category' => category,
45
+ 'category_number' => category_number, 'style_letter' => style_letter,
46
+ 'type' => type, 'style_guide' => style_guide
47
+ }
48
+ end
49
+
28
50
  end
29
51
  end
@@ -25,7 +25,7 @@ module Brewser::Model::Units
25
25
  def load(value)
26
26
  return if value.nil?
27
27
  if !value.u.unitless?
28
- raise(ArgumentError, "#{value.inspect} is not a #{kind_of}") unless value.u.kind == kind_of
28
+ raise(ArgumentError, "#{value.inspect} is not a #{kind_of}") unless kind_of.nil? or value.u.kind == kind_of
29
29
  value.u
30
30
  else
31
31
  "#{value} #{base_unit}".u
@@ -65,9 +65,14 @@ module Brewser::Model::Units
65
65
 
66
66
  class WeightOrVolume < Units
67
67
 
68
+ def kind_of
69
+ nil
70
+ end
71
+
68
72
  def valid_kind?(value)
69
73
  value.kind == :mass || value.kind == :volume
70
74
  end
75
+
71
76
  def base_unit
72
77
  end
73
78
  end
@@ -3,7 +3,8 @@ module Brewser
3
3
  belongs_to :recipe
4
4
 
5
5
  property :name, String, :required => true
6
-
6
+ property :description, String, :length => 65535
7
+
7
8
  property :calcium, Float, :required => true
8
9
  property :magnesium, Float, :required => true
9
10
  property :sodium, Float, :required => true
@@ -12,5 +13,33 @@ module Brewser
12
13
  property :bicarbonate, Float
13
14
  property :alkalinity, Float
14
15
  property :ph, Float
16
+
17
+ def self.json_create(o)
18
+ a = self.new
19
+ a.name = o['name']
20
+ a.description = o['description']
21
+ a.calcium = o['calcium']
22
+ a.sodium = o['sodium']
23
+ a.magnesium = o['magnesium']
24
+ a.chloride = o['chloride']
25
+ a.sulfates = o['sulfates']
26
+ a.bicarbonate = o['bicarbonate']
27
+ a.alkalinity = o['alkalinity']
28
+ a.ph = o['ph']
29
+
30
+ return a
31
+ end
32
+
33
+ def as_json(options={})
34
+ {
35
+ JSON.create_id => "Brewser::WaterProfile",
36
+ 'name' => name, 'description' => description,
37
+ 'calcium' => calcium, 'magnesium' => magnesium,
38
+ 'sodium' => sodium, 'chloride' => chloride,
39
+ 'sulfates' => sulfates, 'bicarbonate' => bicarbonate,
40
+ 'alkalinity' => alkalinity, 'ph' => ph
41
+ }
42
+ end
43
+
15
44
  end
16
45
  end
@@ -25,5 +25,42 @@ module Brewser
25
25
  # These are applicable only in Batches
26
26
  property :times_cultured, Integer
27
27
 
28
+ def self.json_create(o)
29
+ a = self.new
30
+ a.name = o['name']
31
+ a.description = o['description']
32
+ a.type = o['type']
33
+ a.best_for = o['best_for']
34
+ a.supplier = o['supplier']
35
+ a.catalog = o['catalog']
36
+ a.min_temperature = o['min_temperature'].u unless o['min_temperature'].blank?
37
+ a.max_temperature = o['max_temperature'].u unless o['max_temperature'].blank?
38
+ a.flocculation = o['flocculation']
39
+ a.attenuation = o['attenuation']
40
+
41
+ a.add_to_secondary = o['add_to_secondary']
42
+ a.form = o['form']
43
+ a.amount = o['amount'].u unless o['amount'].blank?
44
+ a.max_reuse = o['max_reuse']
45
+ a.times_cultured = o['times_cultured']
46
+
47
+ return a
48
+ end
49
+
50
+ def as_json(options={})
51
+ {
52
+ JSON.create_id => "Brewser::Yeast",
53
+ 'name' => name,
54
+ 'description' => description,
55
+ 'type' => type, 'best_for' => best_for,
56
+ 'supplier' => supplier, 'catalog' => catalog,
57
+ 'min_temperature' => min_temperature.to_s, 'max_temperature' => max_temperature.to_s,
58
+ 'flocculation' => flocculation, 'attenuation' => attenuation,
59
+ 'add_to_secondary' => add_to_secondary?,
60
+ 'form' => form, 'amount' => amount.to_s,
61
+ 'max_reuse' => max_reuse, 'times_cultured' => times_cultured
62
+ }
63
+ end
64
+
28
65
  end
29
66
  end
@@ -1,3 +1,3 @@
1
1
  module Brewser
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -18,7 +18,7 @@ describe "Basic spec" do
18
18
  Brewser.identify(read_file('promash/PumpkinAle.txt')).should == ProMashTxt
19
19
  end
20
20
 
21
- it "should raise an error if it cannot identify content" do
21
+ it "should identify as ProMash rec when unknown" do
22
22
  Brewser.identify("Some unknown content").should == ProMashRec
23
23
  end
24
24
 
@@ -112,7 +112,6 @@ describe "BeerXML tests" do
112
112
  m=@recipe.mash_schedule
113
113
  m.mash_steps.count.should == 2
114
114
  s=m.mash_steps[0]
115
- # @TODO Fix this
116
115
  s.index.should == 1
117
116
  s.name.should == "Mash In"
118
117
  s.type.should == "Infusion"
@@ -0,0 +1,207 @@
1
+ require "spec_helper"
2
+
3
+ describe "BrewSON spec" do
4
+
5
+ before :each do
6
+ @recipe = Brewser.parse(read_file('beerxmlv1/recipes.xml')).first
7
+ end
8
+
9
+ it "should generate JSON" do
10
+ json = BrewSON.serialize(@recipe)
11
+ json.valid_json?.should be_true
12
+ end
13
+
14
+ context "round trip" do
15
+
16
+ before :each do
17
+ json = @recipe.to_json
18
+ @return = Brewser.parse(json)
19
+ end
20
+
21
+ it "should survive the round trip" do
22
+ @return.class.should == Brewser::Recipe
23
+ @return.name.should == "Burton Ale"
24
+ @return.style.name.should == "English Pale Ale"
25
+ end
26
+
27
+ it "should deserialize the base recipe data" do
28
+ @return.name.should == "Burton Ale"
29
+ @return.brewer.should == "Brad Smith"
30
+ @return.method.should == "All Grain"
31
+ @return.type.should == "Ale"
32
+
33
+ @return.recipe_volume.class.should == Unit
34
+ @return.recipe_volume.kind.should == :volume
35
+ @return.recipe_volume.scalar_in('gal').should be_within(0.01).of(5)
36
+
37
+ @return.boil_volume.class.should == Unit
38
+ @return.boil_volume.kind.should == :volume
39
+ @return.boil_volume.scalar_in('gal').should be_within(0.01).of(5.5)
40
+
41
+ @return.boil_time.class.should == Unit
42
+ @return.boil_time.kind.should == :time
43
+ @return.boil_time.should == "60 min".u
44
+
45
+ @return.recipe_efficiency.should == 72.0
46
+
47
+ @return.estimated_og.should == 1.056
48
+ @return.estimated_fg.should == 1.015
49
+ @return.estimated_color.should == 7.0
50
+ @return.estimated_ibu.should == 32.4
51
+ @return.estimated_abv.should == 5.3
52
+ end
53
+
54
+ it "should deserialize the hop data" do
55
+ @return.hops.count.should == 4
56
+ h=@return.hops[1]
57
+ h.name.should == "Northern Brewer"
58
+ h.origin.should == "Germany"
59
+ h.alpha_acids.should == 7.5
60
+ h.amount.should === "0.50 oz".u
61
+ h.added_when.should == "Boil"
62
+ h.time.should === "60 min".u
63
+ h.description.should_not be_nil
64
+ h.type.should == "Both"
65
+ h.form.should == "Pellet"
66
+ h.beta_acids.should == 4.0
67
+ h.storageability.should == 35.0
68
+ end
69
+
70
+ it "should deserialize the fermentable data" do
71
+ @return.fermentables.count.should == 3
72
+ f=@return.fermentables[0]
73
+ f.name.should == "Pale Malt (2 Row) UK"
74
+ f.origin.should == "United Kingdom"
75
+ f.type.should == "Grain"
76
+ f.description.should_not be_nil
77
+ f.amount.should === "8 lb".u
78
+ f.potential.should == 1.036
79
+ f.color.should == 2.5
80
+ f.moisture.should == 4.0
81
+ f.diastatic_power.should == 45.0
82
+ f.protein.should == 10.1
83
+ f.late_addition.should == false
84
+ f.recommend_mash?.should == false
85
+ f.max_in_batch.should == 100.0
86
+ f.ibu_gal_per_lb.should == 0.0
87
+ end
88
+
89
+ it "should deserialize the additive data" do
90
+ @return.additives.count.should == 2
91
+ a=@return.additives[0]
92
+ a.name.should == "Irish Moss"
93
+ a.type.should == "Fining"
94
+ a.description.should_not be_nil
95
+ a.added_when.should == "Boil"
96
+ a.amount.should == "0.25 tsp".u
97
+ a.time.should == "10 min".u
98
+ end
99
+
100
+ it "should deserialize the yeast data" do
101
+ @return.yeasts.count.should == 1
102
+ y=@return.yeasts.first
103
+ y.name.should == "Burton Ale"
104
+ y.type.should == "Ale"
105
+ y.form.should == "Liquid"
106
+ y.supplier.should == "White Labs"
107
+ y.catalog.should == "WLP023"
108
+ y.description.should_not be_nil
109
+ y.best_for.should_not be_nil
110
+ y.min_temperature.should == "68 dF".u
111
+ y.max_temperature.should == "73 dF".u
112
+ y.amount.should == "35 ml".u
113
+ y.add_to_secondary?.should == false
114
+ y.flocculation.should == "Medium"
115
+ y.attenuation.should == 72.0
116
+ y.max_reuse.should == 5
117
+ y.times_cultured.should == 0
118
+ end
119
+
120
+ it "should deserialize the mash schedule data" do
121
+ m=@return.mash_schedule
122
+ m.name.should == "Single Infusion, Full Body"
123
+ m.grain_temp.should == "72 dF".u
124
+ m.sparge_temp.should == "168 dF".u
125
+ end
126
+
127
+ it "should deserialize the mash step data" do
128
+ m=@return.mash_schedule
129
+ m.mash_steps.count.should == 2
130
+ s=m.mash_steps[0]
131
+ s.index.should == 1
132
+ s.name.should == "Mash In"
133
+ s.type.should == "Infusion"
134
+ s.description.should_not be_nil
135
+ s.rest_time.should == "45 min".u
136
+ s.rest_temperature.should == "70 dC".u
137
+ s.infusion_volume.should == "11.25 qt".u
138
+ s.infusion_temperature.should == "170.5 dF".u
139
+ s.water_to_grain_ratio.should == 1.25
140
+ end
141
+
142
+ it "should deserialize the fermentation step data" do
143
+ f=@return.fermentation_schedule
144
+ f.fermentation_steps.count.should == 3
145
+ s=f.fermentation_steps[0]
146
+ s.index.should == 1
147
+ s.name.should == "Primary"
148
+ s.time.should == "4 days".u
149
+ s.temperature.should == "68 dF".u
150
+ end
151
+
152
+ it "should deserialize the water profile data" do
153
+ w=@return.water_profile
154
+ w.name.should == "Burton On Trent, UK"
155
+ w.description.should == "Distinctive pale ales strongly hopped. Very hard water accentuates the hops flavor.\nExample: Bass Ale"
156
+ w.calcium.should == 295.0
157
+ w.bicarbonate.should == 300.0
158
+ w.sulfates.should == 725.0
159
+ w.chloride.should == 25.0
160
+ w.sodium.should == 55.0
161
+ w.magnesium.should == 45.0
162
+ w.ph.should ==8.0
163
+ end
164
+
165
+ it "should deserialize the style data" do
166
+ s=@return.style
167
+ s.name.should == "English Pale Ale"
168
+ s.category.should == "Bitter & English Pale Ale"
169
+ s.style_letter.should == "A"
170
+ s.style_guide.should == "BJCP 1999"
171
+ s.type.should == "Ale"
172
+ end
173
+ end
174
+
175
+ context "should deserialize json file" do
176
+
177
+ before :each do
178
+ @recipe = Brewser.parse(read_file('brewson/belgian_white.json'))
179
+ end
180
+
181
+ it "should deserialize the base recipe data" do
182
+ @recipe.name.should == "Jeffrey's Winter White"
183
+ @recipe.brewer.should == "Nobody"
184
+ @recipe.method.should == "All Grain"
185
+ @recipe.type.should == "Ale"
186
+
187
+ @recipe.recipe_volume.class.should == Unit
188
+ @recipe.recipe_volume.kind.should == :volume
189
+ @recipe.recipe_volume.should == "5 gal".u
190
+
191
+ @recipe.boil_volume.class.should == Unit
192
+ @recipe.boil_volume.kind.should == :volume
193
+ @recipe.boil_volume.should == "5 gal".u
194
+
195
+ @recipe.boil_time.class.should == Unit
196
+ @recipe.boil_time.kind.should == :time
197
+ @recipe.boil_time.should == "60 min".u
198
+
199
+ @recipe.recipe_efficiency.should == 75.0
200
+
201
+ @recipe.estimated_og.should == 1.049
202
+ @recipe.estimated_ibu.should == 16.3
203
+ end
204
+
205
+ end
206
+
207
+ end