toji 2.12.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 (106) 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 +35 -35
  5. data/example/example_core.rb +850 -230
  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 -2
  20. data/lib/toji/calendar.rb +12 -12
  21. data/lib/toji/calendar/date_column.rb +8 -8
  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 -32
  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 +53 -39
  68. data/lib/toji/recipe/ab_expect.rb +2 -2
  69. data/lib/toji/recipe/action.rb +2 -2
  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/{event → schedule}/base.rb +1 -1
  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 +58 -44
  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/event.rb +0 -5
  89. data/lib/toji/event/action_event.rb +0 -12
  90. data/lib/toji/event/kake_event.rb +0 -13
  91. data/lib/toji/event/koji_event.rb +0 -19
  92. data/lib/toji/event/rice_event.rb +0 -34
  93. data/lib/toji/ingredient/kake/actual.rb +0 -26
  94. data/lib/toji/ingredient/kake/base.rb +0 -18
  95. data/lib/toji/ingredient/kake/expected.rb +0 -40
  96. data/lib/toji/ingredient/koji/actual.rb +0 -29
  97. data/lib/toji/ingredient/koji/actual_fermentable.rb +0 -15
  98. data/lib/toji/ingredient/koji/base.rb +0 -35
  99. data/lib/toji/ingredient/koji/expected.rb +0 -45
  100. data/lib/toji/ingredient/koji/expected_fermentable.rb +0 -15
  101. data/lib/toji/ingredient/koji_rate.rb +0 -16
  102. data/lib/toji/ingredient/rice/actual_steamable.rb +0 -27
  103. data/lib/toji/ingredient/rice/base.rb +0 -40
  104. data/lib/toji/ingredient/rice/expected_steamable.rb +0 -27
  105. data/lib/toji/ingredient/rice_rate.rb +0 -23
  106. data/lib/toji/product/event_factory.rb +0 -70
@@ -1,88 +1,222 @@
1
+ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
1
2
  require 'toji'
2
3
  require 'securerandom'
3
4
 
4
5
  module Example
5
6
 
6
- module Brew
7
- class State
8
- include Toji::Brew::State
9
- include Toji::Brew::State::BaumeToNihonshudo
7
+ class Product
8
+ include Toji::Product
9
+ include Toji::Product::ScheduleFactory
10
10
 
11
- def self.create(val)
12
- s = new
13
- KEYS.each {|k|
14
- if val.has_key?(k)
15
- s.send("#{k}=", val[k])
16
- end
17
- }
18
- s
19
- 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
20
21
  end
21
22
 
22
- module BrewGenerator
23
- def builder
24
- Toji::Brew::Builder.new(self)
25
- end
23
+ def create_koji_schedule(date:, step_indexes:, kojis:)
24
+ expect = kojis.first.dup
25
+ expect.weight = kojis.map(&:weight).sum
26
26
 
27
- def load_hash(hash)
28
- 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
29
34
 
30
- builder
31
- .add((hash[:states] || []).map{|s| State.create(s)})
32
- .date_line(hash[:date_line] || 0, Toji::Brew::HOUR)
33
- .prefix_day_labels(hash[:prefix_day_labels])
34
- .time_interpolation(nil)
35
- .elapsed_time_interpolation
36
- .build
37
- end
35
+ def create_kake_schedule(date:, step_indexes:, kakes:)
36
+ expect = kakes.first.dup
37
+ expect.weight = kakes.map(&:weight).sum
38
38
 
39
- def load_yaml_file(fname)
40
- hash = YAML.load_file(fname)
41
- load_hash(hash)
42
- end
39
+ KakeSchedule.new(
40
+ product: self,
41
+ date: date,
42
+ step_indexes: step_indexes,
43
+ expect: expect,
44
+ )
43
45
  end
44
46
 
45
- class Base
46
- include Toji::Brew::Base
47
- 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
48
55
 
49
- def initialize
50
- @states = []
51
- @day_offset = 0
52
- @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}"
53
81
  end
54
82
  end
83
+ end
55
84
 
56
- class Koji < Base
57
- include Toji::Brew::Koji
58
- end
59
85
 
60
- class Moto < Base
61
- 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
62
96
  end
63
97
 
64
- class Moromi < Base
65
- 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
66
105
  end
67
106
  end
68
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
69
127
 
70
- class Step
71
- include Toji::Recipe::Step
72
- attr_accessor :name
73
-
74
- 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)
75
- new.tap {|o|
76
- o.name = name
77
- o.kake = kake.to_f
78
- o.koji = koji.to_f
79
- o.water = water.to_f
80
- o.lactic_acid = lactic_acid.to_f
81
- o.alcohol = alcohol.to_f
82
- o.yeast = yeast.to_f
83
- o.koji_interval_days = koji_interval_days.to_i
84
- 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
85
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
86
220
  end
87
221
  end
88
222
 
@@ -90,14 +224,12 @@ module Example
90
224
  class Recipe
91
225
  include Toji::Recipe
92
226
 
93
- def initialize
94
- @steps = []
227
+ def initialize(steps)
228
+ @steps = steps
95
229
  end
96
230
 
97
- def self.create(steps)
98
- new.tap {|o|
99
- o.steps = steps
100
- }
231
+ def initialize_copy(obj)
232
+ @steps = obj.steps.deep_dup
101
233
  end
102
234
 
103
235
  # 乳酸は汲水100L当たり比重1.21の乳酸(90%乳酸と称される)を650〜720ml添加する。
@@ -109,135 +241,563 @@ module Example
109
241
  TEMPLATES = {
110
242
  # 酒造教本による標準型仕込配合
111
243
  # 出典: 酒造教本 P97
112
- sokujo_textbook: create(
244
+ sokujo_textbook: new(
113
245
  [
114
- Step.create(
115
- name: :moto,
116
- kake: 45,
117
- koji: 20,
118
- water: 70,
119
- lactic_acid: 70/100.0*0.685,
120
- yeast: (45+20)/100.0*1.5,
121
- koji_interval_days: 0,
122
- 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
+ ]
123
295
  ),
124
- Step.create(
125
- name: :soe,
126
- kake: 100,
127
- koji: 40,
128
- water: 130,
129
- koji_interval_days: 14,
130
- 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
+ ],
131
335
  ),
132
- Step.create(
133
- name: :naka,
134
- kake: 215,
135
- koji: 60,
136
- water: 330,
137
- koji_interval_days: 0,
138
- 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
+ ],
139
375
  ),
140
- Step.create(
141
- name: :tome,
142
- kake: 360,
143
- koji: 80,
144
- water: 630,
145
- koji_interval_days: 0,
146
- 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
+ ],
147
415
  ),
148
- Step.create(
149
- name: :yodan,
150
- kake: 80,
151
- water: 120,
152
- 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
+ ],
153
435
  ),
154
436
  ].map(&:freeze).freeze
155
437
  ).freeze,
156
438
  # 灘における仕込配合の平均値
157
439
  # 出典: http://www.nada-ken.com/main/jp/index_shi/234.html
158
- sokujo_nada: create(
440
+ sokujo_nada: new(
159
441
  [
160
- Step.create(
161
- name: :moto,
162
- kake: 93,
163
- koji: 47,
164
- water: 170,
165
- lactic_acid: 170/100.0*0.685,
166
- yeast: (93+47)/100.0*1.5,
167
- koji_interval_days: 0,
168
- 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
+ ],
169
491
  ),
170
- Step.create(
171
- name: :soe,
172
- kake: 217,
173
- koji: 99,
174
- water: 270,
175
- koji_interval_days: 14,
176
- 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
+ ],
177
531
  ),
178
- Step.create(
179
- name: :naka,
180
- kake: 423,
181
- koji: 143,
182
- water: 670,
183
- koji_interval_days: 0,
184
- 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
+ ],
185
571
  ),
186
- Step.create(
187
- name: :tome,
188
- kake: 813,
189
- koji: 165,
190
- water: 1330,
191
- koji_interval_days: 0,
192
- 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
+ ],
193
611
  ),
194
- Step.create(
195
- name: :alcohol,
196
- alcohol: 900
612
+ Step.new(
613
+ alcohols: [
614
+ Alcohol.new(
615
+ weight: 900,
616
+ ),
617
+ ],
197
618
  ),
198
619
  ].map(&:freeze).freeze
199
620
  ).freeze,
200
621
  # 簡易酒母省略仕込
201
622
  # 出典: https://www.jstage.jst.go.jp/article/jbrewsocjapan1915/60/11/60_11_999/_article/-char/ja/
202
- simple_sokujo_himeno: create(
623
+ simple_sokujo_himeno: new(
203
624
  [
204
- Step.create(
205
- name: :moto,
206
- kake: 0,
207
- koji: 70,
208
- water: 245,
209
- lactic_acid: 1.6,
210
- yeast: 5,
211
- koji_interval_days: 0,
212
- 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
+ ],
213
674
  ),
214
- Step.create(
215
- name: :soe,
216
- kake: 130,
217
- koji: 0,
218
- water: 0,
219
- koji_interval_days: 0,
220
- 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
+ ],
221
714
  ),
222
- Step.create(
223
- name: :naka,
224
- kake: 300,
225
- koji: 100,
226
- water: 400,
227
- koji_interval_days: 0,
228
- 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
+ ],
229
754
  ),
230
- Step.create(
231
- name: :tome,
232
- kake: 490,
233
- koji: 110,
234
- water: 800,
235
- koji_interval_days: 0,
236
- 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
+ ],
237
794
  ),
238
- Step.create(
239
- name: :yodan,
240
- water: 255
795
+ Step.new(
796
+ waters: [
797
+ Water.new(
798
+ weight: 255,
799
+ ),
800
+ ],
241
801
  ),
242
802
  ].map(&:freeze).freeze
243
803
  ).freeze,
@@ -245,97 +805,157 @@ module Example
245
805
  end
246
806
 
247
807
 
248
- class KojiEvent
249
- include Toji::Event::KojiEvent
808
+ class KojiSchedule
809
+ include Toji::Schedule::KojiSchedule
250
810
 
251
- def initialize(product:, date:, group_index:, indexes:, raw:)
811
+ def initialize(product:, date:, step_indexes:, expect:)
252
812
  @product = product
253
813
  @date = date
254
- @group_index = group_index
255
- @indexes = indexes
256
- @raw = raw
814
+ @step_indexes = step_indexes
815
+ @expect = expect
257
816
  end
258
817
  end
259
818
 
819
+ class KakeSchedule
820
+ include Toji::Schedule::KakeSchedule
260
821
 
261
- class KakeEvent
262
- include Toji::Event::KakeEvent
263
-
264
- def initialize(product:, date:, group_index:, indexes:, raw:)
822
+ def initialize(product:, date:, step_indexes:, expect:)
265
823
  @product = product
266
824
  @date = date
267
- @group_index = group_index
268
- @indexes = indexes
269
- @raw = raw
825
+ @step_indexes = step_indexes
826
+ @expect = expect
270
827
  end
271
828
  end
272
829
 
830
+ class ActionSchedule
831
+ include Toji::Schedule::ActionSchedule
273
832
 
274
- class ActionEvent
275
- include Toji::Event::ActionEvent
276
-
277
- def initialize(product:, date:, type:, index:)
833
+ def initialize(product:, date:, type:, action_index:)
278
834
  @product = product
279
835
  @date = date
280
836
  @type = type
281
- @index = index
837
+ @action_index = action_index
282
838
  end
283
839
  end
284
840
 
285
841
 
286
- class Product
287
- include Toji::Product
288
- include Toji::Product::EventFactory
842
+ module Progress
843
+ module ProgressGenerator
844
+ def load_hash(hash)
845
+ hash = hash.deep_symbolize_keys
289
846
 
290
- attr_accessor :description
291
- attr_accessor :color
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
292
853
 
293
- def initialize(id, name, description, recipe, base_date, color=nil)
294
- @id = id
295
- @name = name
296
- @description = description
297
- @recipe = recipe
298
- @base_date = base_date
299
- @color = color
854
+ def load_yaml_file(fname)
855
+ hash = YAML.load_file(fname)
856
+ load_hash(hash)
857
+ end
300
858
  end
301
859
 
302
- def create_koji_event(date:, group_index:, indexes:, raw:)
303
- KojiEvent.new(product: self, date: date, group_index: group_index, indexes: indexes, raw: raw)
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
304
870
  end
305
871
 
306
- def create_kake_event(date:, group_index:, indexes:, raw:)
307
- KakeEvent.new(product: self, date: date, group_index: group_index, indexes: indexes, raw: raw)
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
308
887
  end
309
888
 
310
- def create_action_event(date:, type:, index:)
311
- ActionEvent.new(product: self, date: date, type: type, index: index)
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
312
899
  end
313
900
 
314
- def self.create(args)
315
- if self===args
316
- args
317
- elsif Hash===args
318
- recipe = args.fetch(:recipe)
319
- if Symbol===recipe
320
- recipe = Recipe::TEMPLATES.fetch(recipe)
321
- end
322
- if args[:scale]
323
- recipe = recipe.scale(args[:scale])
324
- end
325
- if args[:round]
326
- recipe = recipe.round(args[:round])
327
- end
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
328
920
 
329
- new(
330
- args[:id],
331
- args[:name],
332
- args[:description],
333
- recipe,
334
- args[:base_date],
335
- args[:color]
336
- )
337
- else
338
- raise "not supported class: #{args.class}"
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
+ }
339
959
  end
340
960
  end
341
961
  end