toji 1.2.0 → 1.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.
@@ -0,0 +1,115 @@
1
+ module Toji
2
+ module Schedule
3
+ class Calendar
4
+ attr_reader :products
5
+
6
+ def initialize
7
+ @products = []
8
+ end
9
+
10
+ def <<(product)
11
+ @products << product
12
+ self
13
+ end
14
+ alias_method :add, :<<
15
+
16
+ def date_rows
17
+ events = @products.map{|product| product.events}.flatten
18
+
19
+ result = {}
20
+ events.each {|event|
21
+ result[event.date] ||= DateRow.new(event.date)
22
+ result[event.date] << event
23
+ }
24
+
25
+ result
26
+ end
27
+
28
+ def table_data
29
+ events = @products.map{|product| product.events}.flatten
30
+
31
+ koji_len = events.select{|e| e.type==:koji}.map(&:group_index).max + 1
32
+ rice_len = events.select{|e| e.type==:rice}.map(&:group_index).max + 1
33
+ min_date = events.map(&:date).min
34
+ max_date = events.map(&:date).max
35
+
36
+ headers = [:date]
37
+
38
+ case koji_len
39
+ when 1
40
+ headers += [:koji]
41
+ when 2
42
+ headers += [:moto_koji, :moromi_koji]
43
+ else
44
+ headers += [:moto_koji]
45
+ (2..koji_len).each {|i|
46
+ headers << "moromi_koji#{i-1}"
47
+ }
48
+ end
49
+
50
+ case rice_len
51
+ when 1
52
+ headers += [:moto]
53
+ when 2
54
+ headers += [:moto, :soe]
55
+ when 3
56
+ headers += [:moto, :soe, :naka]
57
+ when 4
58
+ headers += [:moto, :soe, :naka, :tome]
59
+ else
60
+ headers += [:moto, :soe, :naka, :tome]
61
+ (4...rice_len).each {|i|
62
+ headers << "#{i}dan"
63
+ }
64
+ end
65
+
66
+ rows = date_rows
67
+
68
+ cells = []
69
+
70
+ date = min_date
71
+ while date<=max_date
72
+ columns = [date.strftime("%m/%d")]
73
+
74
+ row = rows[date]
75
+ if row
76
+ koji_len.times {|i|
77
+ columns << (row.kojis[i]&.text || "")
78
+ }
79
+ rice_len.times {|i|
80
+ columns << (row.rices[i]&.text || "")
81
+ }
82
+ else
83
+ (koji_len + rice_len).times {
84
+ columns << ""
85
+ }
86
+ end
87
+
88
+ cells << columns
89
+
90
+ date = date.tomorrow
91
+ end
92
+
93
+ {header: headers, cells: cells.transpose}
94
+ end
95
+
96
+ def table
97
+ data = table_data
98
+
99
+ Plotly::Plot.new(
100
+ data: [{
101
+ type: :table,
102
+ header: {
103
+ values: data[:header]
104
+ },
105
+ cells: {
106
+ values: data[:cells]
107
+ },
108
+ }],
109
+ layout: {
110
+ }
111
+ )
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,30 @@
1
+ module Toji
2
+ module Schedule
3
+ class DateColumn
4
+ attr_reader :events
5
+
6
+ def initialize
7
+ @events = []
8
+ end
9
+
10
+ def <<(event)
11
+ @events << event
12
+ end
13
+ alias_method :add, :<<
14
+
15
+ def event_groups
16
+ @events.group_by {|e|
17
+ e.group_key
18
+ }.values
19
+ end
20
+
21
+ def text
22
+ event_groups.map {|es|
23
+ name = es.first.product.name
24
+ weight = "%.17g" % es.map(&:weight).sum
25
+ "#{name}: #{weight}"
26
+ }.join("<br>")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,45 @@
1
+ module Toji
2
+ module Schedule
3
+ class DateIntervalEnumerator
4
+ include Enumerable
5
+
6
+ def initialize(intervals, afterwards)
7
+ @intervals = intervals
8
+ @afterwards = afterwards
9
+ end
10
+
11
+ def each(&block)
12
+ Enumerator.new do |y|
13
+ y << 0
14
+ @intervals.each {|interval|
15
+ y << interval
16
+ }
17
+ loop {
18
+ y << @afterwards
19
+ }
20
+ end.each(&block)
21
+ end
22
+
23
+ def merge(dates, length)
24
+ dates = [dates].flatten
25
+ enum = each
26
+
27
+ length.times {|i|
28
+ add = enum.next
29
+
30
+ if i==0
31
+ dates[i] = dates[i].to_time
32
+ elsif Integer===dates[i] && dates[i-1]
33
+ dates[i] = dates[i-1].since(dates[i].days)
34
+ elsif !dates[i] && dates[i-1]
35
+ dates[i] = dates[i-1].since(add.days)
36
+ else
37
+ dates[i] = dates[i].to_time
38
+ end
39
+ }
40
+
41
+ dates
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ module Toji
2
+ module Schedule
3
+ class DateRow
4
+ attr_reader :date
5
+ attr_reader :kojis
6
+ attr_reader :rices
7
+
8
+ def initialize(date)
9
+ @date = date
10
+ @kojis = []
11
+ @rices = []
12
+ end
13
+
14
+ def <<(event)
15
+ case event.type
16
+ when :koji
17
+ index = event.group_index
18
+ @kojis[index] ||= DateColumn.new
19
+ @kojis[index] << event
20
+ when :rice
21
+ index = event.group_index
22
+ @rices[index] ||= DateColumn.new
23
+ @rices[index] << event
24
+ end
25
+ end
26
+ alias_method :add, :<<
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,80 @@
1
+ module Toji
2
+ module Schedule
3
+ class Product
4
+ attr_reader :name
5
+ attr_reader :description
6
+ attr_reader :recipe
7
+
8
+ attr_reader :koji_dates
9
+ attr_reader :rice_dates
10
+
11
+ attr_reader :color
12
+
13
+ def initialize(name, description, recipe, koji_dates, rice_dates, color=nil)
14
+ @name = name
15
+ @description = description
16
+ @recipe = recipe
17
+
18
+ @koji_dates = DateIntervalEnumerator.new([], 0).merge(koji_dates, recipe.steps.length)
19
+ @rice_dates = DateIntervalEnumerator.new([recipe.moto_days, recipe.odori_days+1, 1], 1).merge(rice_dates, recipe.steps.length)
20
+
21
+ @color = color
22
+ end
23
+
24
+ def events
25
+ events = []
26
+
27
+ @koji_dates.length.times {|i|
28
+ events << ProductEvent.new(self, :koji, i)
29
+ }
30
+
31
+ @rice_dates.length
32
+ .times.map {|i|
33
+ ProductEvent.new(self, :rice, i)
34
+ }
35
+ .delete_if {|e|
36
+ 4<=e.index && e.weight==0
37
+ }
38
+ .each {|e|
39
+ events << e
40
+ }
41
+
42
+ events
43
+ end
44
+
45
+ def self.create(args)
46
+ if self===args
47
+ args
48
+ elsif Hash===args
49
+ recipe = args.fetch(:recipe)
50
+ if Symbol===recipe
51
+ recipe = Recipe::ThreeStepMashing::TEMPLATES.fetch(recipe)
52
+ end
53
+ if args[:scale]
54
+ recipe = recipe.scale(args[:scale])
55
+ end
56
+ if args[:round]
57
+ recipe = recipe.round(args[:round])
58
+ end
59
+ if args[:moto_days]
60
+ recipe.moto_days = args[:moto_days]
61
+ end
62
+ if args[:odori_days]
63
+ recipe.odori_days = args[:odori_days]
64
+ end
65
+
66
+ new(
67
+ args[:name],
68
+ args[:description],
69
+ recipe,
70
+ args[:koji_dates],
71
+ args[:rice_dates],
72
+ args[:color]
73
+ )
74
+ else
75
+ raise "not supported class: #{args.class}"
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,44 @@
1
+ module Toji
2
+ module Schedule
3
+ class ProductEvent
4
+ attr_reader :product
5
+ attr_reader :type
6
+ attr_reader :index
7
+
8
+ def initialize(product, type, index)
9
+ @product = product
10
+ @type = type
11
+ @index = index
12
+ end
13
+
14
+ def date
15
+ method = "#{@type}_dates".to_sym
16
+ @product.send(method)[@index]
17
+ end
18
+
19
+ def group_index
20
+ method = "#{@type}_dates".to_sym
21
+ dates = @product.send(method)
22
+ date = dates[@index]
23
+
24
+ if @type==:koji && dates.all? {|d| d==date}
25
+ 1
26
+ else
27
+ dates.index(date)
28
+ end
29
+ end
30
+
31
+ def group_key
32
+ a = []
33
+ a << product.name
34
+ a << type
35
+ a << group_index
36
+ a.map(&:to_s).join(":")
37
+ end
38
+
39
+ def weight
40
+ @product.recipe.steps[@index].send(@type).raw
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ require 'toji/schedule/calendar'
2
+ require 'toji/schedule/product'
3
+ require 'toji/schedule/product_event'
4
+ require 'toji/schedule/date_row'
5
+ require 'toji/schedule/date_column'
6
+ require 'toji/schedule/date_interval_enumerator'
7
+
8
+ module Toji
9
+ module Schedule
10
+ end
11
+ end
data/lib/toji/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Toji
2
- VERSION = "1.2.0"
2
+ VERSION = "1.3.0"
3
3
  end
data/lib/toji.rb CHANGED
@@ -3,6 +3,7 @@ require 'active_support/all'
3
3
 
4
4
  require 'toji/recipe'
5
5
  require 'toji/brew'
6
+ require 'toji/schedule'
6
7
 
7
8
  module Toji
8
9
  class Error < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toji
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yoshida Tetsuya
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-13 00:00:00.000000000 Z
11
+ date: 2020-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -115,6 +115,7 @@ files:
115
115
  - example/moromi.ipynb
116
116
  - example/moromi.rb
117
117
  - example/rice_recipe.rb
118
+ - example/schedule.ipynb
118
119
  - example/shubo.ipynb
119
120
  - example/shubo.rb
120
121
  - example/three_step_mashing_recipe.rb
@@ -140,7 +141,6 @@ files:
140
141
  - lib/toji/recipe/ingredient/koji/base.rb
141
142
  - lib/toji/recipe/ingredient/koji/expected.rb
142
143
  - lib/toji/recipe/ingredient/koji/expected_fermentable.rb
143
- - lib/toji/recipe/ingredient/lactic_acid.rb
144
144
  - lib/toji/recipe/ingredient/rice.rb
145
145
  - lib/toji/recipe/ingredient/rice/actual.rb
146
146
  - lib/toji/recipe/ingredient/rice/actual_steamable.rb
@@ -149,7 +149,6 @@ files:
149
149
  - lib/toji/recipe/ingredient/rice/expected_steamable.rb
150
150
  - lib/toji/recipe/ingredient/yeast.rb
151
151
  - lib/toji/recipe/koji_rate.rb
152
- - lib/toji/recipe/lactic_acid_rate.rb
153
152
  - lib/toji/recipe/rice_rate.rb
154
153
  - lib/toji/recipe/rice_rate/base.rb
155
154
  - lib/toji/recipe/rice_rate/cooked.rb
@@ -157,6 +156,13 @@ files:
157
156
  - lib/toji/recipe/step.rb
158
157
  - lib/toji/recipe/three_step_mashing.rb
159
158
  - lib/toji/recipe/yeast_rate.rb
159
+ - lib/toji/schedule.rb
160
+ - lib/toji/schedule/calendar.rb
161
+ - lib/toji/schedule/date_column.rb
162
+ - lib/toji/schedule/date_interval_enumerator.rb
163
+ - lib/toji/schedule/date_row.rb
164
+ - lib/toji/schedule/product.rb
165
+ - lib/toji/schedule/product_event.rb
160
166
  - lib/toji/version.rb
161
167
  - toji.gemspec
162
168
  homepage: https://github.com/yoshida-eth0/ruby-toji
@@ -1,21 +0,0 @@
1
- module Toji
2
- module Recipe
3
- module Ingredient
4
- class LacticAcid
5
-
6
- def initialize(total, rate: Recipe::LacticAcidRate::SIMPLE_SOKUJO)
7
- @total = total
8
- @rate = rate
9
- end
10
-
11
- def moto
12
- @total * @rate.moto_rate
13
- end
14
-
15
- def soe
16
- @total * @rate.soe_rate
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,17 +0,0 @@
1
- module Toji
2
- module Recipe
3
- class LacticAcidRate
4
- attr_reader :moto_rate
5
- attr_reader :soe_rate
6
-
7
- def initialize(moto_rate, soe_rate)
8
- @moto_rate = moto_rate
9
- @soe_rate = soe_rate
10
- end
11
-
12
- SOKUJO = new(0.007, 0.0)
13
- SIMPLE_SOKUJO = new(0.006, 0.002)
14
- KIMOTO = new(0.0, 0.0)
15
- end
16
- end
17
- end