gravitheque 0.4.0 → 0.5.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.
@@ -0,0 +1,52 @@
1
+ # Calculate how many calories a beer contains
2
+ module Calories
3
+
4
+ # Calculates calories from alcohol
5
+ #
6
+ # @note
7
+ # Extract must be measured in specific gravity
8
+ #
9
+ # @example
10
+ # Calories.from_alcohol 1.055, 1.01
11
+ #
12
+ # @param [Float] original original gravity
13
+ # @param [Float] terminal terminal gravity
14
+ # @return [Fixnum] calories from alcohol
15
+ def self.from_alcohol original, terminal
16
+ ((1881.22 * terminal) *
17
+ ((original - terminal) / (1.775 - original))).round
18
+ end
19
+
20
+ # Calculates calories from extract
21
+ #
22
+ # @note
23
+ # Extract must be measured in specific gravity
24
+ #
25
+ # @example
26
+ # Calories.from_extract 1.055, 1.01
27
+ #
28
+ # @param [Float] original original gravity
29
+ # @param [Float] terminal terminal gravity
30
+ # @return [Fixnum] calories from extract
31
+ def self.from_extract original, terminal
32
+ (3550.0 * terminal *
33
+ ((0.1808 * original) + (0.8192 * terminal) - 1.0004)).round
34
+ end
35
+
36
+ # Calculates calories per serving; i.e. 500ml
37
+ #
38
+ # @note
39
+ # Extract must be measured in specific gravity
40
+ #
41
+ # @example
42
+ # Calories.per_serving 1.055, 1.01
43
+ #
44
+ # @param [Float] original original gravity
45
+ # @param [Float] terminal terminal gravity
46
+ # @return [Fixnum] calories per serving
47
+ def self.per_serving original, terminal
48
+ (from_alcohol original, terminal) +
49
+ (from_extract original, terminal)
50
+ end
51
+
52
+ end
@@ -0,0 +1,140 @@
1
+ # Various hop calculations
2
+ module Hops
3
+
4
+ # Calculates hop utilization.
5
+ #
6
+ # @note
7
+ # Extract must be measured in specific gravity
8
+ #
9
+ # @example
10
+ # Hops.utilization 20, 1.055
11
+ #
12
+ # @param [Fixnum] time remaining boil time
13
+ # @param [Float] extract specific gravity of wort
14
+ # @return [Float] hop utilization
15
+ def self.utilization time, extract
16
+ ((extract_adjustment extract) *
17
+ ((time_adjustment time) / 4.15)).round 2
18
+ end
19
+
20
+ # Calculate boil time adjustment
21
+ #
22
+ # @example
23
+ # Hops.time_adjustment 60
24
+ #
25
+ # @param [Fixnum] time remaining boil time
26
+ # @return [Float] boil time adjustment
27
+ def self.time_adjustment time
28
+ (1 - Math.exp(-0.04 * time)).round 2
29
+ end
30
+
31
+ # Calculate extract adjustment
32
+ #
33
+ # @note
34
+ # Extract must be measured in specific gravity
35
+ #
36
+ # @example
37
+ # Hops.extract_adjustment 1.065
38
+ #
39
+ # @param [Float] extract specific gravity of wort
40
+ # @return [Float] extract adjustment
41
+ def self.extract_adjustment extract
42
+ (1.65 * 0.000125 ** (extract - 1)).round 2
43
+ end
44
+
45
+ # Calculates IBUs for hop addition
46
+ #
47
+ # @note
48
+ # Extract must be measured specific gravity, mass in grams and volume in liters
49
+ #
50
+ # @example
51
+ # Hops.ibus({
52
+ # alpha: 12.4,
53
+ # extract: 1.055,
54
+ # mass: 56,
55
+ # time: 90,
56
+ # volume: 20
57
+ # })
58
+ #
59
+ # @param [Hash] data data required to calculate IBUs; `alpha`, `extract`, `mass`, `time`, `volume`
60
+ # @return [Fixnum] IBUs from hop addition
61
+ def self.ibus data
62
+ (extract_adjustment(data[:extract]) *
63
+ time_adjustment(data[:time]) * (data[:alpha] / 100) *
64
+ data[:mass] * 1000 / (data[:volume] * 4.15)).round
65
+ end
66
+
67
+ # Calculates hop mass required to achieve specific IBUs.
68
+ #
69
+ # @note
70
+ # Extract must be measured specific gravity, mass in grams and volume in liters
71
+ #
72
+ # @example
73
+ # Hops.hop_mass_required({
74
+ # alpha: 1.05,
75
+ # extract: 16,
76
+ # ibus: 25,
77
+ # time: 60,
78
+ # volume: 20
79
+ # })
80
+ #
81
+ # @param [Hash] data data required to calculate hop mass required; `alpha`, `extract`, `ibus`, `time`, `volume`
82
+ # @return [Float] hop mass required to achieve specific IBUs
83
+ def self.mass_required data
84
+ ((data[:volume] * data[:ibus]) /
85
+ (utilization(data[:time], data[:extract]) *
86
+ data[:alpha] * 10)).round
87
+ end
88
+
89
+ # Calculate milliliters of HopShot required to achieve specific IBUs.
90
+ #
91
+ # @note
92
+ # Extract must be measured specific gravity, mass in grams and volume in liters
93
+ #
94
+ # @example
95
+ # Hops.hopshot_required({
96
+ # alpha: 13.5,
97
+ # extract: 1.05,
98
+ # ibus: 25,
99
+ # time: 60,
100
+ # volume: 20
101
+ # })
102
+ #
103
+ # @param [Hash] data data required to calculate HopShot required; `alpha`, `extract`, `ibus`, `time`, `volume`
104
+ # @return [Float] milliliters of HopShot required to achieve specific IBUs
105
+ def self.hopshot_required data
106
+ unadjusted_amount = (data[:ibus] / 10.0) * (data[:volume] / 19.0)
107
+
108
+ hopshot_required = unadjusted_amount +
109
+ (unadjusted_amount * hopshot_extract_adjustment(data[:extract]))
110
+
111
+ if data[:time] >= 90
112
+ hopshot_required = hopshot_required - (unadjusted_amount * 0.1)
113
+ end
114
+
115
+ hopshot_required.round 1
116
+ end
117
+
118
+ # Calculate extract adjustment for HopShot
119
+ #
120
+ # @note
121
+ # Extract must be measured in specific gravity
122
+ #
123
+ # @example
124
+ # Hops.hopshot_extract_adjustment 1.065
125
+ #
126
+ # @param [Float] extract specific gravity of wort
127
+ # @return [Float] HopShot extract adjustment
128
+ def self.hopshot_extract_adjustment extract
129
+ if extract >= 1.08 && extract < 1.1
130
+ 0.1
131
+ elsif extract >= 1.1 && extract < 1.15
132
+ 0.2
133
+ elsif extract >= 1.15
134
+ 0.3
135
+ else
136
+ 0
137
+ end
138
+ end
139
+
140
+ end
@@ -0,0 +1,57 @@
1
+ # Various mash calculations
2
+ module Mash
3
+
4
+ # Calculates strike water temperature
5
+ #
6
+ # @note
7
+ # Temperatures must be measured in Celsius, ratio is liters per kilograms
8
+ #
9
+ # @example
10
+ # Mash.strike_water({
11
+ # initial: 20, # temperature of grain; i.e. ambient temperature
12
+ # target: 60, # target mash temperature
13
+ # ratio: 1.25 # water to grain ratio; e.g. 1.25L/kg
14
+ # })
15
+ #
16
+ # Mash.strike_water({
17
+ # initial: 20,
18
+ # target: 60,
19
+ # ratio: 1.25,
20
+ # adjustment: 1.015 # calculated temperature is multiplied by the adjustment to compensate for heat lost to the mash tun
21
+ # })
22
+ #
23
+ # @param [Hash] data data required to calculate strike temperature; `initial`, `target`, `ratio` and optionally `adjustment`
24
+ # @return [Fixnum] strike water temperature
25
+ def self.strike_temperature data
26
+ adjustment = data[:adjustment] || 1
27
+ target = data[:target]
28
+
29
+ (((0.41 / data[:ratio]) *
30
+ (target - data[:initial]) +
31
+ target) * adjustment).round
32
+ end
33
+
34
+ # Calculates volume of boiling water needed to increase mash temperature
35
+ #
36
+ # @note
37
+ # Temperatures must be measured in Celsius, mass in kilograms and volume in liters
38
+ #
39
+ # @example
40
+ # Mash.infusion_volume({
41
+ # initial: 40, # current mash temperature
42
+ # target: 60, # target mash temperature
43
+ # mass: 4, # grain mass in mash
44
+ # volume: 6 # water volume in mash
45
+ # })
46
+ #
47
+ # @param [Hash] data data required to calculate strike temperature; `initial`, `target`, `mass`, `volume`
48
+ # @return [Float] liters of infusion water needed for step
49
+ def self.infusion_volume data
50
+ target = data[:target]
51
+
52
+ ((target - data[:initial]) *
53
+ ((0.41 * data[:mass]) + data[:volume]) /
54
+ (100 - target)).round 1
55
+ end
56
+
57
+ end
@@ -0,0 +1,201 @@
1
+ # Methods for converting Fixnums between units
2
+ class Fixnum
3
+
4
+ # Covert Plato to specific gravity
5
+ #
6
+ # @example
7
+ # 14.to_specific_gravity
8
+ #
9
+ # @return [Float] degrees Plato
10
+ def to_specific_gravity
11
+ self.to_f.to_specific_gravity
12
+ end
13
+
14
+ # Covert Fahrenheit to Celsius
15
+ #
16
+ # @example
17
+ # 104.to_celsius
18
+ #
19
+ # @return [Fixnum] temperature in Celsius
20
+ def to_celsius
21
+ ((self - 32) / 1.8).round
22
+ end
23
+
24
+ # Covert Celsius to Fahrenheit
25
+ #
26
+ # @example
27
+ # 60.to_fahrenheit
28
+ #
29
+ # @return [Fixnum] temperature in Fahrenheit
30
+ def to_fahrenheit
31
+ ((self * 1.8) + 32).round
32
+ end
33
+
34
+ # Covert gallons (or quarts) to liters
35
+ #
36
+ # @example
37
+ # 5.to_liters
38
+ # 15.to_liters :quarts
39
+ #
40
+ # @return [Float] volume in liters
41
+ def to_liters unit = :gallons
42
+ self.to_f.to_liters unit
43
+ end
44
+
45
+ # Covert ounces to grams
46
+ #
47
+ # @example
48
+ # 2.to_grams
49
+ #
50
+ # @return [Float] mass in grams
51
+ def to_grams
52
+ self.to_f.to_grams
53
+ end
54
+
55
+ # Covert grams to ounces
56
+ #
57
+ # @example
58
+ # 56.to_ounces
59
+ #
60
+ # @return [Float] mass in ounces
61
+ def to_ounces
62
+ self.to_f.to_ounces
63
+ end
64
+
65
+ # Covert pounds to kilograms
66
+ #
67
+ # @example
68
+ # 10.to_kilograms
69
+ #
70
+ # @return [Float] mass in kilograms
71
+ def to_kilograms
72
+ self.to_f.to_kilograms
73
+ end
74
+
75
+ # Covert kilograms to pounds
76
+ #
77
+ # @example
78
+ # 10.to_pounds
79
+ #
80
+ # @return [Float] mass in pounds
81
+ def to_pounds
82
+ self.to_f.to_pounds
83
+ end
84
+
85
+ # Gravity correction based on sample temperature
86
+ #
87
+ # @note
88
+ # Temperature must be measured in Celsius
89
+ #
90
+ # @example
91
+ # 40.gravity_correction
92
+ #
93
+ # @return [Float] mass in pounds
94
+ def gravity_correction
95
+ if self < 3.98
96
+ -0.000032692 * self - 0.000740644
97
+ elsif self < 50
98
+ -0.0008031922 - 0.0000473773 * self + 0.000007231263 * self * self - 0.00000003078278 * self * self * self
99
+ else
100
+ -0.005431719 + 0.0001963596 * self + 0.000002661056 * self * self
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ # Methods for converting Floats between units
107
+ class Float
108
+
109
+ # Covert specific gravity to Plato
110
+ #
111
+ # @example
112
+ # 1.055.to_plato
113
+ #
114
+ # @return [Float] degrees Plato
115
+ def to_plato
116
+ (-676.67 + 1286.4 * self - 800.47 * self * self + 190.74 * self * self * self).round 1
117
+ end
118
+
119
+ # Covert Plato to specific gravity
120
+ #
121
+ # @example
122
+ # 13.6.to_specific_gravity
123
+ #
124
+ # @return [Float] degrees Plato
125
+ def to_specific_gravity
126
+ (self / (258.6 - ((self / 258.2) * 227.1)) + 1.0).round 3
127
+ end
128
+
129
+ # Covert specific gravity to temperature corrected specific gravity
130
+ #
131
+ # @example
132
+ # 1.055.to_temperature_corrected_specific_gravity 40
133
+ # 1.055.to_temperature_corrected_specific_gravity 110, :fahrenheit
134
+ #
135
+ # @param [Fixnum] temperature temperature of sample
136
+ # @param [Symbol] unit unit of temperature used; `:celsius` or `:fahrenheit`
137
+ # @return [Float] temperature corrected specific gravity
138
+ def to_temperature_corrected_specific_gravity temperature, unit = :celsius
139
+ temperature = temperature.to_celsius unless unit == :celsius
140
+ correction = temperature.gravity_correction
141
+
142
+ (self + correction).round 3
143
+ end
144
+
145
+ # Covert gallons (or quarts) to liters
146
+ #
147
+ # @example
148
+ # 5.to_liters
149
+ # 15.to_liters :quarts
150
+ #
151
+ # @return [Float] volume in liters
152
+ def to_liters unit = :gallons
153
+ case unit
154
+ when :gallons
155
+ (self * 3.785412).round 1
156
+ when :quarts
157
+ (self * 0.946353).round 1
158
+ end
159
+ end
160
+
161
+ # Covert ounces to grams
162
+ #
163
+ # @example
164
+ # 5.5.to_grams
165
+ #
166
+ # @return [Float] mass in grams
167
+ def to_grams
168
+ (self * 28.3495231).round 1
169
+ end
170
+
171
+ # Covert grams to ounces
172
+ #
173
+ # @example
174
+ # 100.5.to_ounces
175
+ #
176
+ # @return [Float] mass in ounces
177
+ def to_ounces
178
+ (self * 0.0352739619).round 1
179
+ end
180
+
181
+ # Covert pounds to kilograms
182
+ #
183
+ # @example
184
+ # 15.5.to_kilograms
185
+ #
186
+ # @return [Float] mass in kilograms
187
+ def to_kilograms
188
+ (self * 0.453592).round 1
189
+ end
190
+
191
+ # Covert kilograms to pounds
192
+ #
193
+ # @example
194
+ # 7.5.to_pounds
195
+ #
196
+ # @return [Float] mass in pounds
197
+ def to_pounds
198
+ (self * 2.204623).round 1
199
+ end
200
+
201
+ end