toji 1.6.8 → 2.3.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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/example/calendar.ipynb +383 -0
  3. data/example/{schedule.yaml → calendar.yaml} +6 -30
  4. data/example/calendar_file.ipynb +338 -0
  5. data/example/example_core.rb +354 -0
  6. data/example/kake_ingredient.rb +26 -0
  7. data/example/{koji_recipe.rb → koji_ingredient.rb} +1 -2
  8. data/example/koji_making.ipynb +16 -15
  9. data/example/koji_making.rb +2 -1
  10. data/example/koji_making.yaml +10 -9
  11. data/example/koji_making_multi.ipynb +27 -61
  12. data/example/moromi.ipynb +25 -24
  13. data/example/moromi.rb +1 -0
  14. data/example/moromi.yaml +10 -4
  15. data/example/recipe.rb +75 -0
  16. data/example/shubo.ipynb +15 -14
  17. data/example/shubo.rb +2 -1
  18. data/example/shubo.yaml +12 -11
  19. data/lib/toji.rb +3 -1
  20. data/lib/toji/brew.rb +4 -3
  21. data/lib/toji/brew/base.rb +8 -92
  22. data/lib/toji/brew/builder.rb +77 -6
  23. data/lib/toji/brew/graph/bmd.rb +1 -2
  24. data/lib/toji/brew/graph/multi_progress.rb +0 -121
  25. data/lib/toji/brew/graph/progress.rb +17 -52
  26. data/lib/toji/brew/koji.rb +2 -11
  27. data/lib/toji/brew/moromi.rb +4 -37
  28. data/lib/toji/brew/shubo.rb +2 -6
  29. data/lib/toji/brew/state.rb +90 -103
  30. data/lib/toji/brew/wrapped_state.rb +136 -0
  31. data/lib/toji/calendar.rb +123 -0
  32. data/lib/toji/{schedule → calendar}/date_column.rb +3 -6
  33. data/lib/toji/{schedule → calendar}/date_row.rb +6 -6
  34. data/lib/toji/ingredient.rb +10 -0
  35. data/lib/toji/ingredient/kake.rb +17 -0
  36. data/lib/toji/ingredient/kake/actual.rb +26 -0
  37. data/lib/toji/ingredient/kake/base.rb +18 -0
  38. data/lib/toji/ingredient/kake/expected.rb +40 -0
  39. data/lib/toji/ingredient/koji.rb +19 -0
  40. data/lib/toji/ingredient/koji/actual.rb +29 -0
  41. data/lib/toji/ingredient/koji/actual_fermentable.rb +15 -0
  42. data/lib/toji/ingredient/koji/base.rb +35 -0
  43. data/lib/toji/ingredient/koji/expected.rb +45 -0
  44. data/lib/toji/ingredient/koji/expected_fermentable.rb +15 -0
  45. data/lib/toji/{recipe → ingredient}/koji_rate.rb +1 -1
  46. data/lib/toji/ingredient/rice.rb +10 -0
  47. data/lib/toji/ingredient/rice/actual_steamable.rb +27 -0
  48. data/lib/toji/ingredient/rice/base.rb +40 -0
  49. data/lib/toji/ingredient/rice/expected_steamable.rb +27 -0
  50. data/lib/toji/ingredient/rice_rate.rb +23 -0
  51. data/lib/toji/product.rb +65 -0
  52. data/lib/toji/{schedule/product_event.rb → product/event.rb} +4 -4
  53. data/lib/toji/recipe.rb +111 -5
  54. data/lib/toji/recipe/step.rb +49 -64
  55. data/lib/toji/version.rb +1 -1
  56. metadata +33 -39
  57. data/example/rice_recipe.rb +0 -28
  58. data/example/schedule.ipynb +0 -393
  59. data/example/schedule_file.ipynb +0 -337
  60. data/example/three_step_mashing_recipe.rb +0 -67
  61. data/lib/toji/brew/state_accessor.rb +0 -13
  62. data/lib/toji/brew/state_record.rb +0 -72
  63. data/lib/toji/recipe/ingredient.rb +0 -10
  64. data/lib/toji/recipe/ingredient/koji.rb +0 -21
  65. data/lib/toji/recipe/ingredient/koji/actual.rb +0 -32
  66. data/lib/toji/recipe/ingredient/koji/actual_fermentable.rb +0 -17
  67. data/lib/toji/recipe/ingredient/koji/base.rb +0 -37
  68. data/lib/toji/recipe/ingredient/koji/expected.rb +0 -48
  69. data/lib/toji/recipe/ingredient/koji/expected_fermentable.rb +0 -17
  70. data/lib/toji/recipe/ingredient/rice.rb +0 -21
  71. data/lib/toji/recipe/ingredient/rice/actual.rb +0 -29
  72. data/lib/toji/recipe/ingredient/rice/actual_steamable.rb +0 -29
  73. data/lib/toji/recipe/ingredient/rice/base.rb +0 -51
  74. data/lib/toji/recipe/ingredient/rice/expected.rb +0 -43
  75. data/lib/toji/recipe/ingredient/rice/expected_steamable.rb +0 -31
  76. data/lib/toji/recipe/ingredient/yeast.rb +0 -21
  77. data/lib/toji/recipe/rice_rate.rb +0 -10
  78. data/lib/toji/recipe/rice_rate/base.rb +0 -21
  79. data/lib/toji/recipe/rice_rate/cooked.rb +0 -67
  80. data/lib/toji/recipe/rice_rate/steamed.rb +0 -30
  81. data/lib/toji/recipe/three_step_mashing.rb +0 -274
  82. data/lib/toji/recipe/yeast_rate.rb +0 -41
  83. data/lib/toji/schedule.rb +0 -11
  84. data/lib/toji/schedule/calendar.rb +0 -139
  85. data/lib/toji/schedule/date_interval_enumerator.rb +0 -45
  86. data/lib/toji/schedule/product.rb +0 -117
@@ -5,7 +5,6 @@ module Toji
5
5
 
6
6
  def initialize
7
7
  @actuals = []
8
- @expects = []
9
8
  end
10
9
 
11
10
  def actual(moromi, name=:actual)
@@ -17,7 +16,7 @@ module Toji
17
16
  result = []
18
17
 
19
18
  @actuals.each {|moromi, name|
20
- states = moromi.states.select{|s| s.moromi_day && s.bmd}
19
+ states = moromi.wrapped_states.select{|s| s.moromi_day && s.bmd}
21
20
 
22
21
  xs = states.map(&:moromi_day).map{|d| d*DAY}
23
22
  ys = states.map(&:bmd)
@@ -69,127 +69,6 @@ module Toji
69
69
  }
70
70
  )
71
71
  end
72
-
73
- def state_group_order(group_by)
74
- result = {}
75
-
76
- @progresses.map{|progress|
77
- progress.state_group_by(group_by)
78
- }.map{|group|
79
- group.map{|key,states|
80
- [key, states.first.elapsed_time_with_offset]
81
- }.to_h
82
- }.each {|group|
83
- result.merge!(group) {|key,self_val,other_val|
84
- [self_val, other_val].min
85
- }
86
- }
87
-
88
- result.sort_by(&:last).map(&:first)
89
- end
90
-
91
- def state_group_count(group_by)
92
- result = {}
93
-
94
- @progresses.map{|progress|
95
- progress.state_group_count(group_by)
96
- }.each {|group|
97
- result.merge!(group) {|key,self_val,other_val|
98
- [self_val, other_val].max
99
- }
100
- }
101
-
102
- state_group_order(group_by).map {|val|
103
- [val, result[val]]
104
- }.to_h
105
- end
106
-
107
- def table_data(group_by=nil, keys=nil)
108
- case group_by
109
- when :elapsed_time, :elapsed_time_with_offset, nil
110
- table_data_group_by_elapsed_time(keys)
111
- else
112
- table_data_group_by(group_by, keys)
113
- end
114
- end
115
-
116
- def table_data_group_by(group_by, keys=nil)
117
- header = []
118
- cells = []
119
-
120
- group_count = state_group_count(group_by)
121
-
122
- header << ["", group_by]
123
- cells << group_count.inject([]) {|result,(group,num)|
124
- if 0<num
125
- result << group
126
- (num-1).times {
127
- result << ""
128
- }
129
- end
130
- result
131
- }
132
-
133
- @progresses.each {|progress|
134
- data = progress.table_data(keys, group_by, group_count)
135
- header += data[:header].map.with_index{|h,i|
136
- name = i==0 ? progress.name : ""
137
- [name, h]
138
- }
139
- cells += data[:rows].transpose
140
- }
141
-
142
- {header: header, rows: cells.transpose}
143
- end
144
-
145
- def table_data_group_by_elapsed_time(keys=nil, date_format="%m/%d %H:%M")
146
- header = []
147
- cells = []
148
-
149
- elapsed_times = state_group_count(:elapsed_time_with_offset)
150
-
151
- header << ["", :elapsed_time]
152
- utc_offset = Time.at(0).utc_offset
153
-
154
- cells << elapsed_times.inject([]) {|result,(elapsed_time,num)|
155
- if 0<num
156
- result << Time.at(elapsed_time - utc_offset).strftime(date_format)
157
- (num-1).times {
158
- result << ""
159
- }
160
- end
161
- result
162
- }
163
-
164
- @progresses.each {|progress|
165
- data = progress.table_data(keys, :elapsed_time_with_offset, elapsed_times)
166
- header += data[:header].map.with_index{|h,i|
167
- name = i==0 ? progress.name : ""
168
- [name, h]
169
- }
170
- cells += data[:rows].transpose
171
- }
172
-
173
- {header: header, rows: cells.transpose}
174
- end
175
-
176
- def table(group_by=nil, keys=nil)
177
- data = table_data(group_by, keys)
178
-
179
- Plotly::Plot.new(
180
- data: [{
181
- type: :table,
182
- header: {
183
- values: data[:header]
184
- },
185
- cells: {
186
- values: data[:rows].transpose
187
- },
188
- }],
189
- layout: {
190
- }
191
- )
192
- end
193
72
  end
194
73
  end
195
74
  end
@@ -75,7 +75,7 @@ module Toji
75
75
  result << {x: xs, y: ys, text: text, name: "#{name}#{key}", line: {dash: @dash, shape: line_shape}, marker: {color: PLOT_COLORS[key]}}
76
76
  }
77
77
 
78
- if 0<@brew.states.length && 0<@brew.day_offset
78
+ if 0<@brew.wrapped_states.length && 0<@brew.day_offset
79
79
  result = result.map{|h|
80
80
  h[:x].unshift(0)
81
81
  h[:y].unshift(nil)
@@ -84,8 +84,8 @@ module Toji
84
84
  }
85
85
  end
86
86
 
87
- #if 0<@brew.states.length && @brew.states.last.time.strftime("%T")!="00:00:00"
88
- # t = @brew.states.last.elapsed_time_with_offset
87
+ #if 0<@brew.wrapped_states.length && @brew.wrapped_states.last.time.strftime("%T")!="00:00:00"
88
+ # t = @brew.wrapped_states.last.elapsed_time_with_offset
89
89
  # t -= (t % DAY) - DAY
90
90
  #
91
91
  # result = result.map{|h|
@@ -100,7 +100,7 @@ module Toji
100
100
  end
101
101
 
102
102
  def annotations
103
- return [] if @enable_annotations
103
+ return [] if !@enable_annotations
104
104
 
105
105
  @brew.select{|s| s.mark}.map {|s|
106
106
  {
@@ -117,28 +117,7 @@ module Toji
117
117
  }
118
118
  end
119
119
 
120
- def state_group_by(group_by)
121
- group = {}
122
- prev = nil
123
-
124
- @brew.each {|state|
125
- val = state.send(group_by) || prev
126
- prev = val
127
-
128
- group[val] ||= []
129
- group[val] << state
130
- }
131
-
132
- group
133
- end
134
-
135
- def state_group_count(group_by)
136
- state_group_by(group_by).map{|val,states|
137
- [val, states.length]
138
- }.to_h
139
- end
140
-
141
- def table_data(keys=nil, group_by=nil, group_count=nil)
120
+ def table_data(keys=nil)
142
121
  if !keys
143
122
  keys = @brew.has_keys
144
123
  keys.delete(:elapsed_time)
@@ -151,33 +130,19 @@ module Toji
151
130
  keys &= @brew.has_keys
152
131
  end
153
132
 
154
- if group_by && group_count
155
- brew_hash = state_group_by(group_by)
156
- else
157
- group_count = state_group_count(:itself)
158
- brew_hash = state_group_by(:itself)
159
- end
160
-
161
133
  rows = []
162
- group_count.each {|group_value,num|
163
- states = brew_hash[group_value] || []
164
- num ||= states.length
165
-
166
- num.times {|i|
167
- state = states[i]
168
-
169
- rows << keys.map {|k|
170
- v = state&.send(k)
171
- if Array===v
172
- v.map(&:to_s).join(", ")
173
- elsif Float===v
174
- v.round(3)
175
- elsif v
176
- v
177
- else
178
- ""
179
- end
180
- }
134
+ @brew.each {|state|
135
+ rows << keys.map {|k|
136
+ v = state&.send(k)
137
+ if Array===v
138
+ v.map(&:to_s).join(", ")
139
+ elsif Float===v
140
+ v.round(3).to_s
141
+ elsif v
142
+ v.to_s
143
+ else
144
+ ""
145
+ end
181
146
  }
182
147
  }
183
148
 
@@ -1,16 +1,7 @@
1
1
  module Toji
2
2
  module Brew
3
- class Koji < Base
4
-
5
- state_reader :hikikomi
6
- state_reader :tokomomi
7
- state_reader :kirikaeshi
8
- state_reader :mori
9
- state_reader :naka_shigoto
10
- state_reader :shimai_shigoto
11
- state_reader :tsumikae
12
- state_reader :dekoji
13
-
3
+ module Koji
4
+ include Base
14
5
 
15
6
  def progress(name: nil, dash: :solid, enable_annotations: true)
16
7
  Graph::Progress.new(self, name: name, dash: dash, enable_annotations: enable_annotations)
@@ -1,42 +1,9 @@
1
1
  module Toji
2
2
  module Brew
3
- class Moromi < Base
3
+ module Moromi
4
+ include Base
4
5
 
5
- state_reader :moto
6
- state_reader :soe
7
- state_reader :naka
8
- state_reader :tome
9
- state_reader :yodan
10
-
11
- attr_writer :prefix_day_labels
12
-
13
- def prefix_day_labels
14
- if @prefix_day_labels
15
- @prefix_day_labels
16
- elsif !self[:soe] && !self[:tome]
17
- nil
18
- else
19
- labels = []
20
- [:soe, :naka, :tome].each {|mark|
21
- s = self[mark]
22
- if s
23
- i = s.day - 1
24
- labels[i] = mark
25
- end
26
- }
27
-
28
- soe_i = labels.index(:soe)
29
- labels.map.with_index {|label,i|
30
- if label
31
- label
32
- elsif !soe_i || i<soe_i
33
- :moto
34
- else
35
- :odori
36
- end
37
- }
38
- end
39
- end
6
+ attr_accessor :prefix_day_labels
40
7
 
41
8
  def moromi_tome_day
42
9
  prefix_day_labels&.length
@@ -57,7 +24,7 @@ module Toji
57
24
  if _prefix
58
25
  _prefix + moromi_days.times.map{|i| i+2}.map(&:to_s)
59
26
  else
60
- self.days.times.map{|i| i+1}.map(&:to_s)
27
+ super
61
28
  end
62
29
  end
63
30
 
@@ -1,11 +1,7 @@
1
1
  module Toji
2
2
  module Brew
3
- class Shubo < Base
4
-
5
- state_reader :mizukoji
6
- state_reader :shikomi
7
- state_reader :utase
8
- state_reader :wake
3
+ module Shubo
4
+ include Base
9
5
 
10
6
  def progress(name: nil, dash: :solid, enable_annotations: true)
11
7
  Graph::Progress.new(self, name: name, dash: dash, enable_annotations: enable_annotations)
@@ -1,134 +1,121 @@
1
- require 'forwardable'
2
-
3
1
  module Toji
4
2
  module Brew
5
- class State
6
- extend Forwardable
3
+ module State
4
+ KEYS = [
5
+ :time,
6
+ :elapsed_time,
7
+ :mark,
8
+ :temps,
9
+ :preset_temp,
10
+ :room_temp,
11
+ :room_psychrometry,
12
+ :baume,
13
+ :nihonshudo,
14
+ :acid,
15
+ :amino_acid,
16
+ :alcohol,
17
+ :warmings,
18
+ :note,
19
+ ].freeze
7
20
 
8
- attr_accessor :elapsed_time
9
21
  attr_accessor :time
10
- attr_reader :record
11
- attr_reader :brew
12
-
13
- def_delegators :@record, :mark
14
- def_delegators :@record, :temps
15
- def_delegators :@record, :preset_temp
16
- def_delegators :@record, :room_temp
17
- def_delegators :@record, :room_psychrometry
18
- def_delegators :@record, :acid
19
- def_delegators :@record, :amino_acid
20
- def_delegators :@record, :alcohol
21
- def_delegators :@record, :warmings
22
- def_delegators :@record, :note
23
-
24
- def initialize(elapsed_time, record, brew)
25
- @elapsed_time = elapsed_time
26
- @record = record
27
- @brew = brew
28
- end
22
+ attr_accessor :elapsed_time
23
+ attr_accessor :mark
24
+ attr_accessor :temps
29
25
 
30
- def day
31
- ((elapsed_time_with_offset.to_f + 1) / DAY).ceil
32
- end
26
+ attr_accessor :preset_temp
27
+ attr_accessor :room_temp
28
+ attr_accessor :room_psychrometry
33
29
 
34
- def day_label
35
- @brew.day_labels[day - 1]
36
- end
30
+ attr_accessor :baume
31
+ attr_accessor :nihonshudo
32
+ attr_accessor :acid
33
+ attr_accessor :amino_acid
34
+ attr_accessor :alcohol
37
35
 
38
- def elapsed_time_with_offset
39
- @elapsed_time + @brew.day_offset
40
- end
36
+ attr_accessor :warmings
37
+ attr_accessor :note
41
38
 
42
- def baume
43
- if @record.baume
44
- @record.baume
45
- elsif @record.nihonshudo
46
- @record.nihonshudo * -0.1
47
- end
39
+
40
+ def self.included(cls)
41
+ cls.prepend PrependMethods
48
42
  end
49
43
 
50
- def nihonshudo
51
- if @record.nihonshudo
52
- @record.nihonshudo
53
- elsif @record.baume
54
- @record.baume * -10
44
+ module PrependMethods
45
+ def temps
46
+ (super || []).map(&:to_f)
55
47
  end
56
- end
57
48
 
58
- def display_baume
59
- if @record.baume || @record.nihonshudo
60
- b = baume
61
- if b<3.0
62
- nihonshudo
63
- else
64
- b
65
- end
49
+ def temps=(val)
50
+ super([val].flatten.compact.map(&:to_f))
66
51
  end
67
- end
68
52
 
69
- def display_time(format="%m/%d %H:%M")
70
- if @time
71
- @time.strftime(format)
72
- elsif @brew.min_time
73
- time = @brew.min_time + @elapsed_time
74
- time.strftime(format)
75
- else
76
- utc_offset = Time.at(0).utc_offset
77
- Time.at(@elapsed_time - utc_offset).strftime(format)
53
+ def time=(val)
54
+ super(val&.to_time)
78
55
  end
79
- end
80
56
 
81
- def moromi_day
82
- _tome_day = @brew.moromi_tome_day
83
- _now_day = day
57
+ def warmings
58
+ super || []
59
+ end
84
60
 
85
- if _tome_day && _tome_day < _now_day
86
- _now_day - _tome_day + 1
61
+ def warmings=(val)
62
+ super([val].flatten.compact)
87
63
  end
88
64
  end
89
65
 
90
- def bmd
91
- _moromi_day = moromi_day
92
- _baume = baume
66
+ module BaumeToNihonshudo
67
+ def nihonshudo
68
+ if self.baume
69
+ self.baume * -10
70
+ end
71
+ end
93
72
 
94
- if _moromi_day && _baume
95
- _moromi_day * _baume
73
+ def nihonshudo=(val)
74
+ if val
75
+ self.baume = val.to_f / -10.0
76
+ else
77
+ self.baume = nil
78
+ end
96
79
  end
97
80
  end
98
81
 
99
- def expected_alcohol(target_alc, target_nihonshudo, coef)
100
- _baume = baume
82
+ module NihonshudoToBaume
83
+ def baume
84
+ if self.nihonshudo
85
+ self.nihonshudo / -10.0
86
+ end
87
+ end
101
88
 
102
- if _baume
103
- target_alc - (_baume - target_nihonshudo * -0.1) * coef
89
+ def baume=(val)
90
+ if val
91
+ self.nihonshudo = val.to_f * -10
92
+ else
93
+ self.nihonshudo = nil
94
+ end
104
95
  end
105
96
  end
106
97
 
107
- def to_h
108
- {
109
- elapsed_time: elapsed_time,
110
- time: time,
111
- mark: mark,
112
- temps: temps,
113
- preset_temp: preset_temp,
114
- room_temp: room_temp,
115
- room_psychrometry: room_psychrometry,
116
- acid: acid,
117
- amino_acid: amino_acid,
118
- alcohol: alcohol,
119
- warmings: warmings,
120
- note: note,
121
-
122
- day: day,
123
- day_label: day_label,
124
- elapsed_time_with_offset: elapsed_time_with_offset,
125
- baume: baume,
126
- nihonshudo: nihonshudo,
127
- display_baume: display_baume,
128
- display_time: display_time,
129
- moromi_day: moromi_day,
130
- bmd: bmd,
131
- }
98
+ def self.create(val)
99
+ if State===val
100
+ val
101
+ elsif WrappedState==val
102
+ val.state
103
+ #elsif Hash===val
104
+ # #s = Class.new {
105
+ # # include State
106
+ # #}.new
107
+ # s = Object.new.tap {|o|
108
+ # o.extend State
109
+ # o.extend State::PrependMethods
110
+ # }
111
+
112
+ # KEYS.each {|k|
113
+ # s.send("#{k}=", val[k])
114
+ # }
115
+ # s
116
+ else
117
+ raise Error, "ArgumentError: cant cast to Toji::Brew::State"
118
+ end
132
119
  end
133
120
  end
134
121
  end