toji 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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