toji 1.6.7 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/example/calendar.ipynb +123 -0
  3. data/example/{schedule.yaml → calendar.yaml} +6 -30
  4. data/example/calendar_file.ipynb +338 -0
  5. data/example/example_core.rb +336 -0
  6. data/example/kake_recipe.rb +27 -0
  7. data/example/koji_making.ipynb +16 -15
  8. data/example/koji_making.rb +2 -1
  9. data/example/koji_making.yaml +9 -9
  10. data/example/koji_making_multi.ipynb +26 -25
  11. data/example/koji_recipe.rb +1 -1
  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 +10 -10
  19. data/lib/toji.rb +3 -1
  20. data/lib/toji/brew.rb +1 -2
  21. data/lib/toji/brew/base.rb +7 -71
  22. data/lib/toji/brew/builder.rb +47 -4
  23. data/lib/toji/brew/graph/bmd.rb +0 -1
  24. data/lib/toji/brew/graph/progress.rb +1 -1
  25. data/lib/toji/brew/koji.rb +0 -10
  26. data/lib/toji/brew/moromi.rb +2 -36
  27. data/lib/toji/brew/shubo.rb +0 -5
  28. data/lib/toji/brew/state.rb +90 -103
  29. data/lib/toji/brew/state_wrapper.rb +135 -0
  30. data/lib/toji/calendar.rb +123 -0
  31. data/lib/toji/{schedule → calendar}/date_column.rb +3 -6
  32. data/lib/toji/{schedule → calendar}/date_row.rb +6 -6
  33. data/lib/toji/ingredient.rb +10 -0
  34. data/lib/toji/ingredient/kake.rb +17 -0
  35. data/lib/toji/ingredient/kake/actual.rb +27 -0
  36. data/lib/toji/ingredient/kake/base.rb +18 -0
  37. data/lib/toji/ingredient/kake/expected.rb +41 -0
  38. data/lib/toji/ingredient/koji.rb +19 -0
  39. data/lib/toji/ingredient/koji/actual.rb +30 -0
  40. data/lib/toji/ingredient/koji/actual_fermentable.rb +15 -0
  41. data/lib/toji/ingredient/koji/base.rb +35 -0
  42. data/lib/toji/ingredient/koji/expected.rb +46 -0
  43. data/lib/toji/ingredient/koji/expected_fermentable.rb +15 -0
  44. data/lib/toji/{recipe → ingredient}/koji_rate.rb +1 -1
  45. data/lib/toji/ingredient/rice.rb +10 -0
  46. data/lib/toji/ingredient/rice/actual_steamable.rb +27 -0
  47. data/lib/toji/ingredient/rice/base.rb +41 -0
  48. data/lib/toji/ingredient/rice/expected_steamable.rb +29 -0
  49. data/lib/toji/ingredient/rice_rate.rb +35 -0
  50. data/lib/toji/product.rb +65 -0
  51. data/lib/toji/{schedule/product_event.rb → product/event.rb} +4 -4
  52. data/lib/toji/recipe.rb +120 -5
  53. data/lib/toji/recipe/step.rb +46 -59
  54. data/lib/toji/version.rb +1 -1
  55. metadata +31 -37
  56. data/example/rice_recipe.rb +0 -28
  57. data/example/schedule.ipynb +0 -393
  58. data/example/schedule_file.ipynb +0 -337
  59. data/example/three_step_mashing_recipe.rb +0 -67
  60. data/lib/toji/brew/state_accessor.rb +0 -13
  61. data/lib/toji/brew/state_record.rb +0 -72
  62. data/lib/toji/recipe/ingredient.rb +0 -10
  63. data/lib/toji/recipe/ingredient/koji.rb +0 -21
  64. data/lib/toji/recipe/ingredient/koji/actual.rb +0 -32
  65. data/lib/toji/recipe/ingredient/koji/actual_fermentable.rb +0 -17
  66. data/lib/toji/recipe/ingredient/koji/base.rb +0 -37
  67. data/lib/toji/recipe/ingredient/koji/expected.rb +0 -48
  68. data/lib/toji/recipe/ingredient/koji/expected_fermentable.rb +0 -17
  69. data/lib/toji/recipe/ingredient/rice.rb +0 -21
  70. data/lib/toji/recipe/ingredient/rice/actual.rb +0 -29
  71. data/lib/toji/recipe/ingredient/rice/actual_steamable.rb +0 -29
  72. data/lib/toji/recipe/ingredient/rice/base.rb +0 -51
  73. data/lib/toji/recipe/ingredient/rice/expected.rb +0 -43
  74. data/lib/toji/recipe/ingredient/rice/expected_steamable.rb +0 -31
  75. data/lib/toji/recipe/ingredient/yeast.rb +0 -21
  76. data/lib/toji/recipe/rice_rate.rb +0 -10
  77. data/lib/toji/recipe/rice_rate/base.rb +0 -21
  78. data/lib/toji/recipe/rice_rate/cooked.rb +0 -67
  79. data/lib/toji/recipe/rice_rate/steamed.rb +0 -30
  80. data/lib/toji/recipe/three_step_mashing.rb +0 -274
  81. data/lib/toji/recipe/yeast_rate.rb +0 -41
  82. data/lib/toji/schedule.rb +0 -11
  83. data/lib/toji/schedule/calendar.rb +0 -139
  84. data/lib/toji/schedule/date_interval_enumerator.rb +0 -45
  85. data/lib/toji/schedule/product.rb +0 -96
@@ -2,11 +2,6 @@ module Toji
2
2
  module Brew
3
3
  class Shubo < Base
4
4
 
5
- state_reader :mizukoji
6
- state_reader :shikomi
7
- state_reader :utase
8
- state_reader :wake
9
-
10
5
  def progress(name: nil, dash: :solid, enable_annotations: true)
11
6
  Graph::Progress.new(self, name: name, dash: dash, enable_annotations: enable_annotations)
12
7
  end
@@ -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 StateWrapper==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
@@ -0,0 +1,135 @@
1
+ require 'forwardable'
2
+
3
+ module Toji
4
+ module Brew
5
+ class StateWrapper
6
+ extend Forwardable
7
+
8
+ attr_accessor :elapsed_time
9
+ attr_accessor :time
10
+ attr_reader :state
11
+ attr_reader :brew
12
+
13
+ def_delegators :@state, :mark
14
+ def_delegators :@state, :temps
15
+ def_delegators :@state, :preset_temp
16
+ def_delegators :@state, :room_temp
17
+ def_delegators :@state, :room_psychrometry
18
+ def_delegators :@state, :acid
19
+ def_delegators :@state, :amino_acid
20
+ def_delegators :@state, :alcohol
21
+ def_delegators :@state, :warmings
22
+ def_delegators :@state, :note
23
+
24
+ def initialize(elapsed_time, state, brew)
25
+ @elapsed_time = elapsed_time
26
+ @state = state
27
+ @brew = brew
28
+ end
29
+
30
+ def day
31
+ ((elapsed_time_with_offset.to_f + 1) / DAY).ceil
32
+ end
33
+
34
+ def day_label
35
+ @brew.day_labels[day - 1]
36
+ end
37
+
38
+ def elapsed_time_with_offset
39
+ @elapsed_time + @brew.day_offset
40
+ end
41
+
42
+ def baume
43
+ if @state.baume
44
+ @state.baume
45
+ elsif @state.nihonshudo
46
+ @state.nihonshudo * -0.1
47
+ end
48
+ end
49
+
50
+ def nihonshudo
51
+ if @state.nihonshudo
52
+ @state.nihonshudo
53
+ elsif @state.baume
54
+ @state.baume * -10
55
+ end
56
+ end
57
+
58
+ def display_baume
59
+ if @state.baume || @state.nihonshudo
60
+ b = baume
61
+ if b<3.0
62
+ nihonshudo
63
+ else
64
+ b
65
+ end
66
+ end
67
+ end
68
+
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)
78
+ end
79
+ end
80
+
81
+ def moromi_day
82
+ _tome_day = @brew.moromi_tome_day
83
+ _now_day = day
84
+
85
+ if _tome_day && _tome_day < _now_day
86
+ _now_day - _tome_day + 1
87
+ end
88
+ end
89
+
90
+ def bmd
91
+ _moromi_day = moromi_day
92
+ _baume = baume
93
+
94
+ if _moromi_day && _baume
95
+ _moromi_day * _baume
96
+ end
97
+ end
98
+
99
+ def expected_alcohol(target_alc, target_nihonshudo, coef)
100
+ _baume = baume
101
+
102
+ if _baume
103
+ target_alc - (_baume - target_nihonshudo * -0.1) * coef
104
+ end
105
+ end
106
+
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
+ }
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,123 @@
1
+ require 'toji/calendar/date_row'
2
+ require 'toji/calendar/date_column'
3
+
4
+ module Toji
5
+ class Calendar
6
+ attr_reader :products
7
+
8
+ def initialize
9
+ @products = []
10
+ end
11
+
12
+ def <<(product)
13
+ @products << product
14
+ self
15
+ end
16
+ alias_method :add, :<<
17
+
18
+ def date_rows
19
+ events = @products.map{|product| product.events}.flatten
20
+
21
+ result = {}
22
+ events.each {|event|
23
+ result[event.date] ||= DateRow.new(event.date)
24
+ result[event.date] << event
25
+ }
26
+
27
+ result
28
+ end
29
+
30
+ def table_data
31
+ events = @products.map{|product| product.events}.flatten
32
+
33
+ koji_len = events.select{|e| e.type==:koji}.map(&:group_index).max + 1
34
+ kake_len = events.select{|e| e.type==:kake}.map(&:group_index).max + 1
35
+ min_date = events.map(&:date).min
36
+ max_date = events.map(&:date).max
37
+
38
+ headers = [:date]
39
+
40
+ case koji_len
41
+ when 1
42
+ headers += [:koji]
43
+ when 2
44
+ headers += [:moto_koji, :moromi_koji]
45
+ else
46
+ headers += [:moto_koji]
47
+ (2..koji_len).each {|i|
48
+ headers << "moromi_koji#{i-1}"
49
+ }
50
+ end
51
+
52
+ headers += [:moto, :soe, :naka, :tome, :yodan][0...kake_len]
53
+ (5...kake_len).each {|i|
54
+ headers << "#{i}dan"
55
+ }
56
+
57
+ _date_rows = date_rows
58
+
59
+ rows = []
60
+
61
+ date = min_date
62
+ while date<=max_date
63
+ columns = [date.strftime("%m/%d")]
64
+
65
+ date_row = _date_rows[date]
66
+ if date_row
67
+ koji_len.times {|i|
68
+ columns << (date_row.kojis[i]&.column_events || [])
69
+ }
70
+ kake_len.times {|i|
71
+ columns << (date_row.kakes[i]&.column_events || [])
72
+ }
73
+ else
74
+ (koji_len + kake_len).times {
75
+ columns << []
76
+ }
77
+ end
78
+
79
+ rows << columns
80
+
81
+ date = date.tomorrow
82
+ end
83
+
84
+ {header: headers, rows: rows}
85
+ end
86
+
87
+ def table_text_data
88
+ data = table_data
89
+ data[:rows] = data[:rows].map {|row|
90
+ row.map {|column|
91
+ if Array===column
92
+ column.map{|c|
93
+ name = c[:product].name
94
+ weight = "%.17g" % c[:weight]
95
+ "#{name}: #{weight}"
96
+ }.join("<br>")
97
+ else
98
+ column
99
+ end
100
+ }
101
+ }
102
+ data
103
+ end
104
+
105
+ def table
106
+ data = table_text_data
107
+
108
+ Plotly::Plot.new(
109
+ data: [{
110
+ type: :table,
111
+ header: {
112
+ values: data[:header]
113
+ },
114
+ cells: {
115
+ values: data[:rows].transpose
116
+ },
117
+ }],
118
+ layout: {
119
+ }
120
+ )
121
+ end
122
+ end
123
+ end