toji 2.8.0 → 2.13.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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/example/calendar.ipynb +42 -51
  3. data/example/calendar.yaml +6 -6
  4. data/example/calendar_file.ipynb +36 -36
  5. data/example/example_core.rb +877 -205
  6. data/example/kake_ingredient.rb +21 -15
  7. data/example/koji_ingredient.rb +31 -21
  8. data/example/{koji_making.ipynb → koji_progress.ipynb} +14 -14
  9. data/example/{koji_making.rb → koji_progress.rb} +3 -2
  10. data/example/{koji_making.yaml → koji_progress.yaml} +8 -9
  11. data/example/{koji_making_multi.ipynb → koji_progress_multi.ipynb} +21 -22
  12. data/example/{moromi.ipynb → moromi_progress.ipynb} +22 -22
  13. data/example/{moromi.rb → moromi_progress.rb} +3 -2
  14. data/example/{moromi.yaml → moromi_progress.yaml} +0 -0
  15. data/example/moto_progress.ipynb +121 -0
  16. data/example/{moto.rb → moto_progress.rb} +3 -2
  17. data/example/{moto.yaml → moto_progress.yaml} +14 -15
  18. data/example/recipe.rb +44 -32
  19. data/lib/toji.rb +4 -1
  20. data/lib/toji/calendar.rb +18 -18
  21. data/lib/toji/calendar/date_column.rb +7 -22
  22. data/lib/toji/calendar/date_row.rb +6 -6
  23. data/lib/toji/ingredient.rb +6 -2
  24. data/lib/toji/ingredient/alcohol.rb +14 -0
  25. data/lib/toji/ingredient/base.rb +11 -0
  26. data/lib/toji/ingredient/kake.rb +3 -9
  27. data/lib/toji/ingredient/koji.rb +19 -10
  28. data/lib/toji/ingredient/lactic_acid.rb +14 -0
  29. data/lib/toji/ingredient/rice.rb +50 -4
  30. data/lib/toji/ingredient/tanekoji.rb +29 -0
  31. data/lib/toji/ingredient/water.rb +18 -0
  32. data/lib/toji/ingredient/yeast.rb +20 -0
  33. data/lib/toji/processing.rb +18 -0
  34. data/lib/toji/processing/base.rb +7 -0
  35. data/lib/toji/processing/cooled_rice.rb +22 -0
  36. data/lib/toji/processing/cooled_rice_element.rb +8 -0
  37. data/lib/toji/processing/dekoji.rb +22 -0
  38. data/lib/toji/processing/dekoji_element.rb +8 -0
  39. data/lib/toji/processing/kake_processing.rb +7 -0
  40. data/lib/toji/processing/koji_processing.rb +10 -0
  41. data/lib/toji/processing/rice_processing.rb +19 -0
  42. data/lib/toji/processing/soaked_rice.rb +49 -0
  43. data/lib/toji/processing/soaked_rice_element.rb +18 -0
  44. data/lib/toji/processing/steamed_rice.rb +22 -0
  45. data/lib/toji/processing/steamed_rice_element.rb +8 -0
  46. data/lib/toji/product.rb +11 -83
  47. data/lib/toji/product/schedule_factory.rb +74 -0
  48. data/lib/toji/progress.rb +23 -0
  49. data/lib/toji/progress/base_progress.rb +37 -0
  50. data/lib/toji/progress/base_state.rb +39 -0
  51. data/lib/toji/progress/builder.rb +53 -0
  52. data/lib/toji/progress/graph.rb +11 -0
  53. data/lib/toji/{brew → progress}/graph/ab.rb +4 -4
  54. data/lib/toji/{brew → progress}/graph/bmd.rb +2 -2
  55. data/lib/toji/{brew/graph/multi_progress.rb → progress/graph/multi_progress_note.rb} +11 -11
  56. data/lib/toji/{brew/graph/progress.rb → progress/graph/progress_note.rb} +20 -18
  57. data/lib/toji/progress/koji_progress.rb +15 -0
  58. data/lib/toji/progress/koji_state.rb +23 -0
  59. data/lib/toji/{brew/moromi.rb → progress/moromi_progress.rb} +9 -5
  60. data/lib/toji/progress/moromi_state.rb +77 -0
  61. data/lib/toji/progress/moto_progress.rb +15 -0
  62. data/lib/toji/progress/moto_state.rb +31 -0
  63. data/lib/toji/progress/progress.rb +15 -0
  64. data/lib/toji/progress/state.rb +9 -0
  65. data/lib/toji/progress/state/baume_to_nihonshudo.rb +21 -0
  66. data/lib/toji/progress/state/nihonshudo_to_baume.rb +21 -0
  67. data/lib/toji/recipe.rb +54 -39
  68. data/lib/toji/recipe/ab_expect.rb +2 -2
  69. data/lib/toji/recipe/action.rb +8 -0
  70. data/lib/toji/recipe/step.rb +97 -71
  71. data/lib/toji/schedule.rb +5 -0
  72. data/lib/toji/schedule/action_schedule.rb +9 -0
  73. data/lib/toji/schedule/base.rb +9 -0
  74. data/lib/toji/schedule/kake_schedule.rb +11 -0
  75. data/lib/toji/schedule/koji_schedule.rb +11 -0
  76. data/lib/toji/schedule/rice_schedule.rb +16 -0
  77. data/lib/toji/utils.rb +43 -0
  78. data/lib/toji/version.rb +1 -1
  79. metadata +59 -40
  80. data/lib/toji/brew.rb +0 -18
  81. data/lib/toji/brew/base.rb +0 -55
  82. data/lib/toji/brew/builder.rb +0 -98
  83. data/lib/toji/brew/graph.rb +0 -11
  84. data/lib/toji/brew/koji.rb +0 -11
  85. data/lib/toji/brew/moto.rb +0 -11
  86. data/lib/toji/brew/state.rb +0 -122
  87. data/lib/toji/brew/wrapped_state.rb +0 -109
  88. data/lib/toji/ingredient/kake/actual.rb +0 -26
  89. data/lib/toji/ingredient/kake/base.rb +0 -18
  90. data/lib/toji/ingredient/kake/expected.rb +0 -40
  91. data/lib/toji/ingredient/koji/actual.rb +0 -29
  92. data/lib/toji/ingredient/koji/actual_fermentable.rb +0 -15
  93. data/lib/toji/ingredient/koji/base.rb +0 -35
  94. data/lib/toji/ingredient/koji/expected.rb +0 -45
  95. data/lib/toji/ingredient/koji/expected_fermentable.rb +0 -15
  96. data/lib/toji/ingredient/koji_rate.rb +0 -16
  97. data/lib/toji/ingredient/rice/actual_steamable.rb +0 -27
  98. data/lib/toji/ingredient/rice/base.rb +0 -40
  99. data/lib/toji/ingredient/rice/expected_steamable.rb +0 -27
  100. data/lib/toji/ingredient/rice_rate.rb +0 -23
  101. data/lib/toji/product/event.rb +0 -13
  102. data/lib/toji/product/rice_event.rb +0 -28
  103. data/lib/toji/product/rice_event_group.rb +0 -19
@@ -1,87 +1,222 @@
1
+ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
2
+ require 'toji'
1
3
  require 'securerandom'
2
4
 
3
5
  module Example
4
6
 
5
- module Brew
6
- class State
7
- include Toji::Brew::State
8
- include Toji::Brew::State::BaumeToNihonshudo
7
+ class Product
8
+ include Toji::Product
9
+ include Toji::Product::ScheduleFactory
9
10
 
10
- def self.create(val)
11
- s = new
12
- KEYS.each {|k|
13
- if val.has_key?(k)
14
- s.send("#{k}=", val[k])
15
- end
16
- }
17
- s
18
- end
11
+ attr_accessor :description
12
+ attr_accessor :color
13
+
14
+ def initialize(id, name, description, recipe, base_date, color=nil)
15
+ @id = id
16
+ @name = name
17
+ @description = description
18
+ @recipe = recipe
19
+ @base_date = base_date
20
+ @color = color
19
21
  end
20
22
 
21
- module BrewGenerator
22
- def builder
23
- Toji::Brew::Builder.new(self)
24
- end
23
+ def create_koji_schedule(date:, step_indexes:, kojis:)
24
+ expect = kojis.first.dup
25
+ expect.weight = kojis.map(&:weight).sum
25
26
 
26
- def load_hash(hash)
27
- hash = hash.deep_symbolize_keys
27
+ KojiSchedule.new(
28
+ product: self,
29
+ date: date,
30
+ step_indexes: step_indexes,
31
+ expect: expect,
32
+ )
33
+ end
28
34
 
29
- builder
30
- .add((hash[:states] || []).map{|s| State.create(s)})
31
- .date_line(hash[:date_line] || 0, Toji::Brew::HOUR)
32
- .prefix_day_labels(hash[:prefix_day_labels])
33
- .time_interpolation(nil)
34
- .elapsed_time_interpolation
35
- .build
36
- end
35
+ def create_kake_schedule(date:, step_indexes:, kakes:)
36
+ expect = kakes.first.dup
37
+ expect.weight = kakes.map(&:weight).sum
37
38
 
38
- def load_yaml_file(fname)
39
- hash = YAML.load_file(fname)
40
- load_hash(hash)
41
- end
39
+ KakeSchedule.new(
40
+ product: self,
41
+ date: date,
42
+ step_indexes: step_indexes,
43
+ expect: expect,
44
+ )
42
45
  end
43
46
 
44
- class Base
45
- include Toji::Brew::Base
46
- extend BrewGenerator
47
+ def create_action_schedule(date:, action_index:, action:)
48
+ ActionSchedule.new(
49
+ product: self,
50
+ date: date,
51
+ type: action.type,
52
+ action_index: index,
53
+ )
54
+ end
47
55
 
48
- def initialize
49
- @states = []
50
- @day_offset = 0
51
- @base_time = 0
56
+ def self.create(args)
57
+ if self===args
58
+ args
59
+ elsif Hash===args
60
+ recipe = args.fetch(:recipe)
61
+ if Symbol===recipe
62
+ recipe = Recipe::TEMPLATES.fetch(recipe)
63
+ end
64
+ if args[:scale_rice_total]
65
+ recipe = recipe.scale_rice_total(args[:scale_rice_total])
66
+ end
67
+ if args[:round]
68
+ recipe = recipe.round(args[:round])
69
+ end
70
+
71
+ new(
72
+ args[:id],
73
+ args[:name],
74
+ args[:description],
75
+ recipe,
76
+ args[:base_date],
77
+ args[:color]
78
+ )
79
+ else
80
+ raise "not supported class: #{args.class}"
52
81
  end
53
82
  end
83
+ end
54
84
 
55
- class Koji < Base
56
- include Toji::Brew::Koji
57
- end
58
85
 
59
- class Moto < Base
60
- include Toji::Brew::Moto
86
+ class Step
87
+ include Toji::Recipe::Step
88
+
89
+ def initialize(kojis: [], kakes: [], waters: [], lactic_acids: [], alcohols: [], yeasts: [])
90
+ @kojis = kojis
91
+ @kakes = kakes
92
+ @waters = waters
93
+ @lactic_acids = lactic_acids
94
+ @alcohols = alcohols
95
+ @yeasts = yeasts
61
96
  end
62
97
 
63
- class Moromi < Base
64
- include Toji::Brew::Moromi
98
+ def initialize_copy(obj)
99
+ @kojis = obj.kojis.deep_dup
100
+ @kakes = obj.kakes.deep_dup
101
+ @waters = obj.waters.deep_dup
102
+ @lactic_acids = obj.lactic_acids.deep_dup
103
+ @alcohols = obj.alcohols.deep_dup
104
+ @yeasts = obj.yeasts.deep_dup
65
105
  end
66
106
  end
67
107
 
108
+ class Koji
109
+ include Toji::Ingredient::Koji
110
+
111
+ def initialize(weight:, brand:, polishing_ratio:, made_in:, year:, soaking_ratio:, steaming_ratio:, cooling_ratio:, tanekojis:, dekoji_ratio:, interval_days:)
112
+ @weight = weight
113
+ @brand = brand
114
+ @polishing_ratio = polishing_ratio
115
+ @made_in = made_in
116
+ @year = year
117
+ @soaking_ratio = soaking_ratio
118
+ @steaming_ratio = steaming_ratio
119
+ @cooling_ratio = cooling_ratio
120
+ @tanekojis = tanekojis.map {|tanekoji|
121
+ tanekoji.koji = self
122
+ tanekoji
123
+ }
124
+ @dekoji_ratio = dekoji_ratio
125
+ @interval_days = interval_days
126
+ end
68
127
 
69
- class Step
70
- include Toji::Recipe::Step
71
- attr_accessor :name
72
-
73
- def self.create(name:, kake: 0, koji: 0, water: 0, lactic_acid: 0, alcohol: 0, yeast: 0, koji_interval_days: 0, kake_interval_days: 0)
74
- new.tap {|o|
75
- o.name = name
76
- o.kake = kake.to_f
77
- o.koji = koji.to_f
78
- o.water = water.to_f
79
- o.lactic_acid = lactic_acid.to_f
80
- o.alcohol = alcohol.to_f
81
- o.yeast = yeast.to_f
82
- o.koji_interval_days = koji_interval_days.to_i
83
- o.kake_interval_days = kake_interval_days.to_i
128
+ def initialize_copy(obj)
129
+ @weight = obj.weight.dup
130
+ @brand = obj.brand.dup
131
+ @polishing_ratio = obj.polishing_ratio.dup
132
+ @made_in = obj.made_in.dup
133
+ @year = obj.year.dup
134
+ @soaking_ratio = obj.soaking_ratio.dup
135
+ @steaming_ratio = obj.steaming_ratio.dup
136
+ @cooling_ratio = obj.cooling_ratio.dup
137
+
138
+ @tanekojis = obj.tanekojis.map {|tanekoji|
139
+ tanekoji = tanekoji.dup
140
+ tanekoji.koji = self
141
+ tanekoji
84
142
  }
143
+
144
+ @dekoji_ratio = obj.dekoji_ratio.dup
145
+ @interval_days = obj.interval_days.dup
146
+ end
147
+ end
148
+
149
+ class Tanekoji
150
+ include Toji::Ingredient::Tanekoji
151
+
152
+ attr_accessor :koji
153
+
154
+ def initialize(koji: nil, brand:, ratio:)
155
+ @brand = brand
156
+ @ratio = ratio
157
+ end
158
+
159
+ def initialize_copy(obj)
160
+ @brand = obj.brand.dup
161
+ @ratio = obj.ratio.dup
162
+ end
163
+ end
164
+
165
+ class Kake
166
+ include Toji::Ingredient::Kake
167
+
168
+ def initialize(weight:, brand:, polishing_ratio:, made_in:, year:, soaking_ratio:, steaming_ratio:, cooling_ratio:, interval_days:)
169
+ @weight = weight
170
+ @brand = brand
171
+ @polishing_ratio = polishing_ratio
172
+ @made_in = made_in
173
+ @year = year
174
+ @soaking_ratio = soaking_ratio
175
+ @steaming_ratio = steaming_ratio
176
+ @cooling_ratio = cooling_ratio
177
+ @interval_days = interval_days
178
+ end
179
+ end
180
+
181
+ class Water
182
+ include Toji::Ingredient::Water
183
+
184
+ def initialize(weight:)
185
+ @weight = weight
186
+ end
187
+ end
188
+
189
+ class LacticAcid
190
+ include Toji::Ingredient::LacticAcid
191
+
192
+ def initialize(weight:)
193
+ @weight = weight
194
+ end
195
+ end
196
+
197
+ class Alcohol
198
+ include Toji::Ingredient::Alcohol
199
+
200
+ def initialize(weight:)
201
+ @weight = weight
202
+ end
203
+ end
204
+
205
+ class Yeast
206
+ include Toji::Ingredient::Yeast
207
+
208
+ def initialize(weight:)
209
+ @weight = weight
210
+ end
211
+ end
212
+
213
+
214
+ class Action
215
+ include Toji::Recipe::Action
216
+
217
+ def initialize(type:, interval_days:)
218
+ @type = type
219
+ @interval_days = interval_days
85
220
  end
86
221
  end
87
222
 
@@ -89,14 +224,12 @@ module Example
89
224
  class Recipe
90
225
  include Toji::Recipe
91
226
 
92
- def initialize
93
- @steps = []
227
+ def initialize(steps)
228
+ @steps = steps
94
229
  end
95
230
 
96
- def self.create(steps)
97
- new.tap {|o|
98
- o.steps = steps
99
- }
231
+ def initialize_copy(obj)
232
+ @steps = obj.steps.deep_dup
100
233
  end
101
234
 
102
235
  # 乳酸は汲水100L当たり比重1.21の乳酸(90%乳酸と称される)を650〜720ml添加する。
@@ -108,135 +241,563 @@ module Example
108
241
  TEMPLATES = {
109
242
  # 酒造教本による標準型仕込配合
110
243
  # 出典: 酒造教本 P97
111
- sokujo_textbook: create(
244
+ sokujo_textbook: new(
112
245
  [
113
- Step.create(
114
- name: :moto,
115
- kake: 45,
116
- koji: 20,
117
- water: 70,
118
- lactic_acid: 70/100.0*0.685,
119
- yeast: (45+20)/100.0*1.5,
120
- koji_interval_days: 0,
121
- kake_interval_days: 5,
246
+ Step.new(
247
+ kojis: [
248
+ Koji.new(
249
+ weight: 20,
250
+ brand: :yamadanishiki,
251
+ polishing_ratio: 0.55,
252
+ made_in: :hyogo,
253
+ year: 2020,
254
+ soaking_ratio: 0.33,
255
+ steaming_ratio: 0.41,
256
+ cooling_ratio: 0.33,
257
+ tanekojis: [
258
+ Tanekoji.new(
259
+ brand: :byakuya,
260
+ ratio: 0.001,
261
+ ),
262
+ ],
263
+ dekoji_ratio: 0.18,
264
+ interval_days: 0,
265
+ ),
266
+ ],
267
+ kakes: [
268
+ Kake.new(
269
+ weight: 45,
270
+ brand: :yamadanishiki,
271
+ polishing_ratio: 0.55,
272
+ made_in: :hyogo,
273
+ year: 2020,
274
+ soaking_ratio: 0.33,
275
+ steaming_ratio: 0.41,
276
+ cooling_ratio: 0.33,
277
+ interval_days: 5,
278
+ ),
279
+ ],
280
+ waters: [
281
+ Water.new(
282
+ weight: 70,
283
+ ),
284
+ ],
285
+ lactic_acids: [
286
+ LacticAcid.new(
287
+ weight: 70/100.0*0.685,
288
+ ),
289
+ ],
290
+ yeasts: [
291
+ Yeast.new(
292
+ weight: (45+20)/100.0*1.5,
293
+ ),
294
+ ]
122
295
  ),
123
- Step.create(
124
- name: :soe,
125
- kake: 100,
126
- koji: 40,
127
- water: 130,
128
- koji_interval_days: 14,
129
- kake_interval_days: 15,
296
+ Step.new(
297
+ kojis: [
298
+ Koji.new(
299
+ weight: 40,
300
+ brand: :yamadanishiki,
301
+ polishing_ratio: 0.55,
302
+ made_in: :hyogo,
303
+ year: 2020,
304
+ soaking_ratio: 0.33,
305
+ steaming_ratio: 0.41,
306
+ cooling_ratio: 0.33,
307
+ tanekojis: [
308
+ Tanekoji.new(
309
+ brand: :byakuya,
310
+ ratio: 0.001,
311
+ ),
312
+ ],
313
+ dekoji_ratio: 0.18,
314
+ interval_days: 14,
315
+ ),
316
+ ],
317
+ kakes: [
318
+ Kake.new(
319
+ weight: 100,
320
+ brand: :yamadanishiki,
321
+ polishing_ratio: 0.55,
322
+ made_in: :hyogo,
323
+ year: 2020,
324
+ soaking_ratio: 0.33,
325
+ steaming_ratio: 0.41,
326
+ cooling_ratio: 0.33,
327
+ interval_days: 20,
328
+ ),
329
+ ],
330
+ waters: [
331
+ Water.new(
332
+ weight: 130,
333
+ ),
334
+ ],
130
335
  ),
131
- Step.create(
132
- name: :naka,
133
- kake: 215,
134
- koji: 60,
135
- water: 330,
136
- koji_interval_days: 0,
137
- kake_interval_days: 2,
336
+ Step.new(
337
+ kojis: [
338
+ Koji.new(
339
+ weight: 60,
340
+ brand: :yamadanishiki,
341
+ polishing_ratio: 0.55,
342
+ made_in: :hyogo,
343
+ year: 2020,
344
+ soaking_ratio: 0.33,
345
+ steaming_ratio: 0.41,
346
+ cooling_ratio: 0.33,
347
+ tanekojis: [
348
+ Tanekoji.new(
349
+ brand: :byakuya,
350
+ ratio: 0.001,
351
+ ),
352
+ ],
353
+ dekoji_ratio: 0.18,
354
+ interval_days: 14,
355
+ ),
356
+ ],
357
+ kakes: [
358
+ Kake.new(
359
+ weight: 215,
360
+ brand: :yamadanishiki,
361
+ polishing_ratio: 0.55,
362
+ made_in: :hyogo,
363
+ year: 2020,
364
+ soaking_ratio: 0.33,
365
+ steaming_ratio: 0.41,
366
+ cooling_ratio: 0.33,
367
+ interval_days: 22,
368
+ ),
369
+ ],
370
+ waters: [
371
+ Water.new(
372
+ weight: 330,
373
+ ),
374
+ ],
138
375
  ),
139
- Step.create(
140
- name: :tome,
141
- kake: 360,
142
- koji: 80,
143
- water: 630,
144
- koji_interval_days: 0,
145
- kake_interval_days: 1,
376
+ Step.new(
377
+ kojis: [
378
+ Koji.new(
379
+ weight: 80,
380
+ brand: :yamadanishiki,
381
+ polishing_ratio: 0.55,
382
+ made_in: :hyogo,
383
+ year: 2020,
384
+ soaking_ratio: 0.33,
385
+ steaming_ratio: 0.41,
386
+ cooling_ratio: 0.33,
387
+ tanekojis: [
388
+ Tanekoji.new(
389
+ brand: :byakuya,
390
+ ratio: 0.001,
391
+ ),
392
+ ],
393
+ dekoji_ratio: 0.18,
394
+ interval_days: 14,
395
+ ),
396
+ ],
397
+ kakes: [
398
+ Kake.new(
399
+ weight: 360,
400
+ brand: :yamadanishiki,
401
+ polishing_ratio: 0.55,
402
+ made_in: :hyogo,
403
+ year: 2020,
404
+ soaking_ratio: 0.33,
405
+ steaming_ratio: 0.41,
406
+ cooling_ratio: 0.33,
407
+ interval_days: 23,
408
+ ),
409
+ ],
410
+ waters: [
411
+ Water.new(
412
+ weight: 630,
413
+ ),
414
+ ],
146
415
  ),
147
- Step.create(
148
- name: :yodan,
149
- kake: 80,
150
- water: 120,
151
- kake_interval_days: 25,
416
+ Step.new(
417
+ kakes: [
418
+ Kake.new(
419
+ weight: 80,
420
+ brand: :yamadanishiki,
421
+ polishing_ratio: 0.55,
422
+ made_in: :hyogo,
423
+ year: 2020,
424
+ soaking_ratio: 0.33,
425
+ steaming_ratio: 0.41,
426
+ cooling_ratio: 0.33,
427
+ interval_days: 48,
428
+ ),
429
+ ],
430
+ waters: [
431
+ Water.new(
432
+ weight: 120,
433
+ ),
434
+ ],
152
435
  ),
153
436
  ].map(&:freeze).freeze
154
437
  ).freeze,
155
438
  # 灘における仕込配合の平均値
156
439
  # 出典: http://www.nada-ken.com/main/jp/index_shi/234.html
157
- sokujo_nada: create(
440
+ sokujo_nada: new(
158
441
  [
159
- Step.create(
160
- name: :moto,
161
- kake: 93,
162
- koji: 47,
163
- water: 170,
164
- lactic_acid: 170/100.0*0.685,
165
- yeast: (93+47)/100.0*1.5,
166
- koji_interval_days: 0,
167
- kake_interval_days: 5,
442
+ Step.new(
443
+ kojis: [
444
+ Koji.new(
445
+ weight: 47,
446
+ brand: :yamadanishiki,
447
+ polishing_ratio: 0.55,
448
+ made_in: :hyogo,
449
+ year: 2020,
450
+ soaking_ratio: 0.33,
451
+ steaming_ratio: 0.41,
452
+ cooling_ratio: 0.33,
453
+ tanekojis: [
454
+ Tanekoji.new(
455
+ brand: :byakuya,
456
+ ratio: 0.001,
457
+ ),
458
+ ],
459
+ dekoji_ratio: 0.18,
460
+ interval_days: 0,
461
+ ),
462
+ ],
463
+ kakes: [
464
+ Kake.new(
465
+ weight: 93,
466
+ brand: :yamadanishiki,
467
+ polishing_ratio: 0.55,
468
+ made_in: :hyogo,
469
+ year: 2020,
470
+ soaking_ratio: 0.33,
471
+ steaming_ratio: 0.41,
472
+ cooling_ratio: 0.33,
473
+ interval_days: 5,
474
+ ),
475
+ ],
476
+ waters: [
477
+ Water.new(
478
+ weight: 170,
479
+ ),
480
+ ],
481
+ lactic_acids: [
482
+ LacticAcid.new(
483
+ weight: 170/100.0*0.685,
484
+ ),
485
+ ],
486
+ yeasts: [
487
+ Yeast.new(
488
+ weight: (93+47)/100.0*1.5,
489
+ ),
490
+ ],
168
491
  ),
169
- Step.create(
170
- name: :soe,
171
- kake: 217,
172
- koji: 99,
173
- water: 270,
174
- koji_interval_days: 14,
175
- kake_interval_days: 15,
492
+ Step.new(
493
+ kojis: [
494
+ Koji.new(
495
+ weight: 99,
496
+ brand: :yamadanishiki,
497
+ polishing_ratio: 0.55,
498
+ made_in: :hyogo,
499
+ year: 2020,
500
+ soaking_ratio: 0.33,
501
+ steaming_ratio: 0.41,
502
+ cooling_ratio: 0.33,
503
+ tanekojis: [
504
+ Tanekoji.new(
505
+ brand: :byakuya,
506
+ ratio: 0.001,
507
+ ),
508
+ ],
509
+ dekoji_ratio: 0.18,
510
+ interval_days: 14,
511
+ ),
512
+ ],
513
+ kakes: [
514
+ Kake.new(
515
+ weight: 217,
516
+ brand: :yamadanishiki,
517
+ polishing_ratio: 0.55,
518
+ made_in: :hyogo,
519
+ year: 2020,
520
+ soaking_ratio: 0.33,
521
+ steaming_ratio: 0.41,
522
+ cooling_ratio: 0.33,
523
+ interval_days: 20,
524
+ ),
525
+ ],
526
+ waters: [
527
+ Water.new(
528
+ weight: 270,
529
+ ),
530
+ ],
176
531
  ),
177
- Step.create(
178
- name: :naka,
179
- kake: 423,
180
- koji: 143,
181
- water: 670,
182
- koji_interval_days: 0,
183
- kake_interval_days: 2,
532
+ Step.new(
533
+ kojis: [
534
+ Koji.new(
535
+ weight: 143,
536
+ brand: :yamadanishiki,
537
+ polishing_ratio: 0.55,
538
+ made_in: :hyogo,
539
+ year: 2020,
540
+ soaking_ratio: 0.33,
541
+ steaming_ratio: 0.41,
542
+ cooling_ratio: 0.33,
543
+ tanekojis: [
544
+ Tanekoji.new(
545
+ brand: :byakuya,
546
+ ratio: 0.001,
547
+ ),
548
+ ],
549
+ dekoji_ratio: 0.18,
550
+ interval_days: 14,
551
+ ),
552
+ ],
553
+ kakes: [
554
+ Kake.new(
555
+ weight: 423,
556
+ brand: :yamadanishiki,
557
+ polishing_ratio: 0.55,
558
+ made_in: :hyogo,
559
+ year: 2020,
560
+ soaking_ratio: 0.33,
561
+ steaming_ratio: 0.41,
562
+ cooling_ratio: 0.33,
563
+ interval_days: 22,
564
+ ),
565
+ ],
566
+ waters: [
567
+ Water.new(
568
+ weight: 670,
569
+ ),
570
+ ],
184
571
  ),
185
- Step.create(
186
- name: :tome,
187
- kake: 813,
188
- koji: 165,
189
- water: 1330,
190
- koji_interval_days: 0,
191
- kake_interval_days: 1,
572
+ Step.new(
573
+ kojis: [
574
+ Koji.new(
575
+ weight: 165,
576
+ brand: :yamadanishiki,
577
+ polishing_ratio: 0.55,
578
+ made_in: :hyogo,
579
+ year: 2020,
580
+ soaking_ratio: 0.33,
581
+ steaming_ratio: 0.41,
582
+ cooling_ratio: 0.33,
583
+ tanekojis: [
584
+ Tanekoji.new(
585
+ brand: :byakuya,
586
+ ratio: 0.001,
587
+ ),
588
+ ],
589
+ dekoji_ratio: 0.18,
590
+ interval_days: 14,
591
+ ),
592
+ ],
593
+ kakes: [
594
+ Kake.new(
595
+ weight: 813,
596
+ brand: :yamadanishiki,
597
+ polishing_ratio: 0.55,
598
+ made_in: :hyogo,
599
+ year: 2020,
600
+ soaking_ratio: 0.33,
601
+ steaming_ratio: 0.41,
602
+ cooling_ratio: 0.33,
603
+ interval_days: 23,
604
+ ),
605
+ ],
606
+ waters: [
607
+ Water.new(
608
+ weight: 1330,
609
+ ),
610
+ ],
192
611
  ),
193
- Step.create(
194
- name: :alcohol,
195
- alcohol: 900
612
+ Step.new(
613
+ alcohols: [
614
+ Alcohol.new(
615
+ weight: 900,
616
+ ),
617
+ ],
196
618
  ),
197
619
  ].map(&:freeze).freeze
198
620
  ).freeze,
199
621
  # 簡易酒母省略仕込
200
622
  # 出典: https://www.jstage.jst.go.jp/article/jbrewsocjapan1915/60/11/60_11_999/_article/-char/ja/
201
- simple_sokujo_himeno: create(
623
+ simple_sokujo_himeno: new(
202
624
  [
203
- Step.create(
204
- name: :moto,
205
- kake: 0,
206
- koji: 70,
207
- water: 245,
208
- lactic_acid: 1.6,
209
- yeast: 5,
210
- koji_interval_days: 0,
211
- kake_interval_days: 6,
625
+ Step.new(
626
+ kojis: [
627
+ Koji.new(
628
+ weight: 70,
629
+ brand: :yamadanishiki,
630
+ polishing_ratio: 0.55,
631
+ made_in: :hyogo,
632
+ year: 2020,
633
+ soaking_ratio: 0.33,
634
+ steaming_ratio: 0.41,
635
+ cooling_ratio: 0.33,
636
+ tanekojis: [
637
+ Tanekoji.new(
638
+ brand: :byakuya,
639
+ ratio: 0.001,
640
+ ),
641
+ ],
642
+ dekoji_ratio: 0.18,
643
+ interval_days: 0,
644
+ ),
645
+ ],
646
+ kakes: [
647
+ Kake.new(
648
+ weight: 0,
649
+ brand: :yamadanishiki,
650
+ polishing_ratio: 0.55,
651
+ made_in: :hyogo,
652
+ year: 2020,
653
+ soaking_ratio: 0.33,
654
+ steaming_ratio: 0.41,
655
+ cooling_ratio: 0.33,
656
+ interval_days: 6,
657
+ ),
658
+ ],
659
+ waters: [
660
+ Water.new(
661
+ weight: 245,
662
+ ),
663
+ ],
664
+ lactic_acids: [
665
+ LacticAcid.new(
666
+ weight: 1.6,
667
+ ),
668
+ ],
669
+ yeasts: [
670
+ Yeast.new(
671
+ weight: 5,
672
+ ),
673
+ ],
212
674
  ),
213
- Step.create(
214
- name: :soe,
215
- kake: 130,
216
- koji: 0,
217
- water: 0,
218
- koji_interval_days: 0,
219
- kake_interval_days: 1,
675
+ Step.new(
676
+ kojis: [
677
+ Koji.new(
678
+ weight: 0,
679
+ brand: :yamadanishiki,
680
+ polishing_ratio: 0.55,
681
+ made_in: :hyogo,
682
+ year: 2020,
683
+ soaking_ratio: 0.33,
684
+ steaming_ratio: 0.41,
685
+ cooling_ratio: 0.33,
686
+ tanekojis: [
687
+ Tanekoji.new(
688
+ brand: :byakuya,
689
+ ratio: 0.001,
690
+ ),
691
+ ],
692
+ dekoji_ratio: 0.18,
693
+ interval_days: 0,
694
+ ),
695
+ ],
696
+ kakes: [
697
+ Kake.new(
698
+ weight: 130,
699
+ brand: :yamadanishiki,
700
+ polishing_ratio: 0.55,
701
+ made_in: :hyogo,
702
+ year: 2020,
703
+ soaking_ratio: 0.33,
704
+ steaming_ratio: 0.41,
705
+ cooling_ratio: 0.33,
706
+ interval_days: 7,
707
+ ),
708
+ ],
709
+ waters: [
710
+ Water.new(
711
+ weight: 0,
712
+ ),
713
+ ],
220
714
  ),
221
- Step.create(
222
- name: :naka,
223
- kake: 300,
224
- koji: 100,
225
- water: 400,
226
- koji_interval_days: 0,
227
- kake_interval_days: 2,
715
+ Step.new(
716
+ kojis: [
717
+ Koji.new(
718
+ weight: 100,
719
+ brand: :yamadanishiki,
720
+ polishing_ratio: 0.55,
721
+ made_in: :hyogo,
722
+ year: 2020,
723
+ soaking_ratio: 0.33,
724
+ steaming_ratio: 0.41,
725
+ cooling_ratio: 0.33,
726
+ tanekojis: [
727
+ Tanekoji.new(
728
+ brand: :byakuya,
729
+ ratio: 0.001,
730
+ ),
731
+ ],
732
+ dekoji_ratio: 0.18,
733
+ interval_days: 0,
734
+ ),
735
+ ],
736
+ kakes: [
737
+ Kake.new(
738
+ weight: 300,
739
+ brand: :yamadanishiki,
740
+ polishing_ratio: 0.55,
741
+ made_in: :hyogo,
742
+ year: 2020,
743
+ soaking_ratio: 0.33,
744
+ steaming_ratio: 0.41,
745
+ cooling_ratio: 0.33,
746
+ interval_days: 9,
747
+ ),
748
+ ],
749
+ waters: [
750
+ Water.new(
751
+ weight: 400,
752
+ ),
753
+ ],
228
754
  ),
229
- Step.create(
230
- name: :tome,
231
- kake: 490,
232
- koji: 110,
233
- water: 800,
234
- koji_interval_days: 0,
235
- kake_interval_days: 1,
755
+ Step.new(
756
+ kojis: [
757
+ Koji.new(
758
+ weight: 110,
759
+ brand: :yamadanishiki,
760
+ polishing_ratio: 0.55,
761
+ made_in: :hyogo,
762
+ year: 2020,
763
+ soaking_ratio: 0.33,
764
+ steaming_ratio: 0.41,
765
+ cooling_ratio: 0.33,
766
+ tanekojis: [
767
+ Tanekoji.new(
768
+ brand: :byakuya,
769
+ ratio: 0.001,
770
+ ),
771
+ ],
772
+ dekoji_ratio: 0.18,
773
+ interval_days: 0,
774
+ ),
775
+ ],
776
+ kakes: [
777
+ Kake.new(
778
+ weight: 490,
779
+ brand: :yamadanishiki,
780
+ polishing_ratio: 0.55,
781
+ made_in: :hyogo,
782
+ year: 2020,
783
+ soaking_ratio: 0.33,
784
+ steaming_ratio: 0.41,
785
+ cooling_ratio: 0.33,
786
+ interval_days: 10,
787
+ ),
788
+ ],
789
+ waters: [
790
+ Water.new(
791
+ weight: 800,
792
+ ),
793
+ ],
236
794
  ),
237
- Step.create(
238
- name: :yodan,
239
- water: 255
795
+ Step.new(
796
+ waters: [
797
+ Water.new(
798
+ weight: 255,
799
+ ),
800
+ ],
240
801
  ),
241
802
  ].map(&:freeze).freeze
242
803
  ).freeze,
@@ -244,46 +805,157 @@ module Example
244
805
  end
245
806
 
246
807
 
247
- class Product
248
- include Toji::Product
808
+ class KojiSchedule
809
+ include Toji::Schedule::KojiSchedule
249
810
 
250
- attr_accessor :description
251
- attr_accessor :color
811
+ def initialize(product:, date:, step_indexes:, expect:)
812
+ @product = product
813
+ @date = date
814
+ @step_indexes = step_indexes
815
+ @expect = expect
816
+ end
817
+ end
252
818
 
253
- def initialize(reduce_key, name, description, recipe, base_date, color=nil)
254
- @reduce_key = reduce_key || SecureRandom.uuid
255
- @name = name
256
- @description = description
257
- @recipe = recipe
258
- @base_date = base_date
259
- @color = color
819
+ class KakeSchedule
820
+ include Toji::Schedule::KakeSchedule
821
+
822
+ def initialize(product:, date:, step_indexes:, expect:)
823
+ @product = product
824
+ @date = date
825
+ @step_indexes = step_indexes
826
+ @expect = expect
260
827
  end
828
+ end
261
829
 
262
- def self.create(args)
263
- if self===args
264
- args
265
- elsif Hash===args
266
- recipe = args.fetch(:recipe)
267
- if Symbol===recipe
268
- recipe = Recipe::TEMPLATES.fetch(recipe)
269
- end
270
- if args[:scale]
271
- recipe = recipe.scale(args[:scale])
272
- end
273
- if args[:round]
274
- recipe = recipe.round(args[:round])
275
- end
830
+ class ActionSchedule
831
+ include Toji::Schedule::ActionSchedule
276
832
 
277
- new(
278
- args[:id],
279
- args[:name],
280
- args[:description],
281
- recipe,
282
- args[:base_date],
283
- args[:color]
284
- )
285
- else
286
- raise "not supported class: #{args.class}"
833
+ def initialize(product:, date:, type:, action_index:)
834
+ @product = product
835
+ @date = date
836
+ @type = type
837
+ @action_index = action_index
838
+ end
839
+ end
840
+
841
+
842
+ module Progress
843
+ module ProgressGenerator
844
+ def load_hash(hash)
845
+ hash = hash.deep_symbolize_keys
846
+
847
+ builder
848
+ .add(hash[:states] || [])
849
+ .date_line(hash[:date_line] || 0, Toji::Progress::HOUR)
850
+ .prefix_day_labels(hash[:prefix_day_labels])
851
+ .build
852
+ end
853
+
854
+ def load_yaml_file(fname)
855
+ hash = YAML.load_file(fname)
856
+ load_hash(hash)
857
+ end
858
+ end
859
+
860
+ class KojiProgress
861
+ include Toji::Progress::KojiProgress
862
+ extend ProgressGenerator
863
+
864
+ attr_accessor :states
865
+ attr_accessor :date_line
866
+
867
+ def self.builder
868
+ Toji::Progress::Builder.new(KojiProgress, KojiState)
869
+ end
870
+ end
871
+
872
+ class KojiState
873
+ include Toji::Progress::KojiState
874
+
875
+ def self.create(args)
876
+ new.tap {|s|
877
+ s.progress = args[:progress]
878
+ s.time = args[:time].to_time
879
+ s.mark = args[:mark]
880
+ s.temps = [args[:temps]].flatten.compact
881
+ s.preset_temp = args[:preset_temp]
882
+ s.room_temp = args[:room_temp]
883
+ s.room_psychrometry = args[:room_psychrometry]
884
+ s.note = args[:note]
885
+ }
886
+ end
887
+ end
888
+
889
+ class MotoProgress
890
+ include Toji::Progress::MotoProgress
891
+ extend ProgressGenerator
892
+
893
+ attr_accessor :states
894
+ attr_accessor :date_line
895
+
896
+ def self.builder
897
+ Toji::Progress::Builder.new(MotoProgress, MotoState)
898
+ end
899
+ end
900
+
901
+ class MotoState
902
+ include Toji::Progress::MotoState
903
+
904
+ def self.create(args)
905
+ new.tap {|s|
906
+ s.progress = args[:progress]
907
+ s.time = args[:time].to_time
908
+ s.mark = args[:mark]
909
+ s.temps = [args[:temps]].flatten.compact
910
+ s.preset_temp = args[:preset_temp]
911
+ s.room_temp = args[:room_temp]
912
+ s.room_psychrometry = args[:room_psychrometry]
913
+ s.baume = args[:baume]
914
+ s.acid = args[:acid]
915
+ s.warmings = [args[:warmings]].flatten.compact
916
+ s.note = args[:note]
917
+ }
918
+ end
919
+ end
920
+
921
+
922
+ class MoromiProgress
923
+ include Toji::Progress::MoromiProgress
924
+ extend ProgressGenerator
925
+
926
+ attr_accessor :states
927
+ attr_accessor :date_line
928
+ attr_accessor :prefix_day_labels
929
+
930
+ def self.builder
931
+ Toji::Progress::Builder.new(MoromiProgress, MoromiState)
932
+ end
933
+ end
934
+
935
+ class MoromiState
936
+ include Toji::Progress::MoromiState
937
+ include Toji::Progress::State::BaumeToNihonshudo
938
+
939
+ def self.create(args)
940
+ new.tap {|s|
941
+ s.progress = args[:progress]
942
+ s.time = args[:time].to_time
943
+ s.mark = args[:mark]
944
+ s.temps = [args[:temps]].flatten.compact
945
+ s.preset_temp = args[:preset_temp]
946
+ s.room_temp = args[:room_temp]
947
+ s.room_psychrometry = args[:room_psychrometry]
948
+ if args[:baume]
949
+ s.baume = args[:baume]
950
+ else
951
+ s.nihonshudo = args[:nihonshudo]
952
+ end
953
+ s.acid = args[:acid]
954
+ s.amino_acid = args[:amino_acid]
955
+ s.alcohol = args[:alcohol]
956
+ s.warmings = [args[:warmings]].flatten.compact
957
+ s.note = args[:note]
958
+ }
287
959
  end
288
960
  end
289
961
  end