gruff 0.13.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +79 -0
  3. data/.rubocop.yml +29 -31
  4. data/CHANGELOG.md +43 -0
  5. data/README.md +11 -5
  6. data/gruff.gemspec +8 -10
  7. data/lib/gruff/accumulator_bar.rb +4 -2
  8. data/lib/gruff/area.rb +9 -12
  9. data/lib/gruff/bar.rb +46 -31
  10. data/lib/gruff/base.rb +236 -207
  11. data/lib/gruff/bezier.rb +6 -8
  12. data/lib/gruff/box_plot.rb +174 -0
  13. data/lib/gruff/bullet.rb +17 -16
  14. data/lib/gruff/candlestick.rb +112 -0
  15. data/lib/gruff/dot.rb +14 -14
  16. data/lib/gruff/font.rb +42 -0
  17. data/lib/gruff/helper/bar_conversion.rb +5 -5
  18. data/lib/gruff/helper/bar_value_label.rb +26 -20
  19. data/lib/gruff/helper/stacked_mixin.rb +4 -3
  20. data/lib/gruff/histogram.rb +9 -7
  21. data/lib/gruff/line.rb +96 -83
  22. data/lib/gruff/mini/bar.rb +9 -6
  23. data/lib/gruff/mini/legend.rb +16 -12
  24. data/lib/gruff/mini/pie.rb +9 -6
  25. data/lib/gruff/mini/side_bar.rb +9 -6
  26. data/lib/gruff/net.rb +16 -22
  27. data/lib/gruff/patch/rmagick.rb +0 -1
  28. data/lib/gruff/patch/string.rb +2 -1
  29. data/lib/gruff/pie.rb +42 -75
  30. data/lib/gruff/renderer/bezier.rb +8 -9
  31. data/lib/gruff/renderer/circle.rb +8 -9
  32. data/lib/gruff/renderer/dash_line.rb +10 -10
  33. data/lib/gruff/renderer/dot.rb +15 -14
  34. data/lib/gruff/renderer/ellipse.rb +8 -9
  35. data/lib/gruff/renderer/line.rb +8 -11
  36. data/lib/gruff/renderer/polygon.rb +9 -10
  37. data/lib/gruff/renderer/polyline.rb +8 -9
  38. data/lib/gruff/renderer/rectangle.rb +11 -8
  39. data/lib/gruff/renderer/renderer.rb +25 -40
  40. data/lib/gruff/renderer/text.rb +21 -37
  41. data/lib/gruff/scatter.rb +86 -85
  42. data/lib/gruff/side_bar.rb +50 -37
  43. data/lib/gruff/side_stacked_bar.rb +26 -35
  44. data/lib/gruff/spider.rb +52 -28
  45. data/lib/gruff/stacked_area.rb +20 -16
  46. data/lib/gruff/stacked_bar.rb +44 -22
  47. data/lib/gruff/store/store.rb +6 -10
  48. data/lib/gruff/store/xy_data.rb +2 -0
  49. data/lib/gruff/themes.rb +6 -6
  50. data/lib/gruff/version.rb +1 -1
  51. data/lib/gruff.rb +70 -57
  52. data/rails_generators/gruff/templates/controller.rb +1 -1
  53. metadata +25 -28
  54. data/.rubocop_todo.yml +0 -182
  55. data/.travis.yml +0 -23
  56. data/assets/plastik/blue.png +0 -0
  57. data/assets/plastik/green.png +0 -0
  58. data/assets/plastik/red.png +0 -0
  59. data/lib/gruff/photo_bar.rb +0 -93
  60. data/lib/gruff/scene.rb +0 -198
  61. data/lib/gruff/store/custom_data.rb +0 -36
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gruff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geoffrey Grosenbach
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-05-09 00:00:00.000000000 Z
12
+ date: 2022-05-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rmagick
@@ -17,64 +17,64 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '0'
20
+ version: '4.2'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: '0'
27
+ version: '4.2'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rubocop
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 1.12.1
34
+ version: 1.27.0
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 1.12.1
41
+ version: 1.27.0
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rubocop-performance
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: 1.10.2
48
+ version: 1.13.3
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: 1.10.2
55
+ version: 1.13.3
56
56
  - !ruby/object:Gem::Dependency
57
- name: histogram
57
+ name: rubocop-rake
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - ">="
60
+ - - "~>"
61
61
  - !ruby/object:Gem::Version
62
- version: '0'
63
- type: :runtime
62
+ version: 0.6.0
63
+ type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - ">="
67
+ - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: '0'
69
+ version: 0.6.0
70
70
  - !ruby/object:Gem::Dependency
71
- name: rake
71
+ name: histogram
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - ">="
75
75
  - !ruby/object:Gem::Version
76
76
  version: '0'
77
- type: :development
77
+ type: :runtime
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
@@ -82,7 +82,7 @@ dependencies:
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
84
  - !ruby/object:Gem::Dependency
85
- name: parallel
85
+ name: rake
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
88
  - - ">="
@@ -146,10 +146,9 @@ extra_rdoc_files: []
146
146
  files:
147
147
  - ".editorconfig"
148
148
  - ".github/ISSUE_TEMPLATE.md"
149
+ - ".github/workflows/ci.yml"
149
150
  - ".gitignore"
150
151
  - ".rubocop.yml"
151
- - ".rubocop_todo.yml"
152
- - ".travis.yml"
153
152
  - ".yardopts"
154
153
  - CHANGELOG.md
155
154
  - Gemfile
@@ -158,9 +157,6 @@ files:
158
157
  - assets/fonts/LICENSE.txt
159
158
  - assets/fonts/Roboto-Bold.ttf
160
159
  - assets/fonts/Roboto-Regular.ttf
161
- - assets/plastik/blue.png
162
- - assets/plastik/green.png
163
- - assets/plastik/red.png
164
160
  - gruff.gemspec
165
161
  - init.rb
166
162
  - lib/gruff.rb
@@ -169,8 +165,11 @@ files:
169
165
  - lib/gruff/bar.rb
170
166
  - lib/gruff/base.rb
171
167
  - lib/gruff/bezier.rb
168
+ - lib/gruff/box_plot.rb
172
169
  - lib/gruff/bullet.rb
170
+ - lib/gruff/candlestick.rb
173
171
  - lib/gruff/dot.rb
172
+ - lib/gruff/font.rb
174
173
  - lib/gruff/helper/bar_conversion.rb
175
174
  - lib/gruff/helper/bar_value_label.rb
176
175
  - lib/gruff/helper/stacked_mixin.rb
@@ -183,7 +182,6 @@ files:
183
182
  - lib/gruff/net.rb
184
183
  - lib/gruff/patch/rmagick.rb
185
184
  - lib/gruff/patch/string.rb
186
- - lib/gruff/photo_bar.rb
187
185
  - lib/gruff/pie.rb
188
186
  - lib/gruff/renderer/bezier.rb
189
187
  - lib/gruff/renderer/circle.rb
@@ -197,14 +195,12 @@ files:
197
195
  - lib/gruff/renderer/renderer.rb
198
196
  - lib/gruff/renderer/text.rb
199
197
  - lib/gruff/scatter.rb
200
- - lib/gruff/scene.rb
201
198
  - lib/gruff/side_bar.rb
202
199
  - lib/gruff/side_stacked_bar.rb
203
200
  - lib/gruff/spider.rb
204
201
  - lib/gruff/stacked_area.rb
205
202
  - lib/gruff/stacked_bar.rb
206
203
  - lib/gruff/store/basic_data.rb
207
- - lib/gruff/store/custom_data.rb
208
204
  - lib/gruff/store/store.rb
209
205
  - lib/gruff/store/xy_data.rb
210
206
  - lib/gruff/themes.rb
@@ -215,7 +211,8 @@ files:
215
211
  homepage: https://github.com/topfunky/gruff
216
212
  licenses:
217
213
  - MIT
218
- metadata: {}
214
+ metadata:
215
+ rubygems_mfa_required: 'true'
219
216
  post_install_message:
220
217
  rdoc_options: []
221
218
  require_paths:
@@ -224,14 +221,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
224
221
  requirements:
225
222
  - - ">="
226
223
  - !ruby/object:Gem::Version
227
- version: 2.4.0
224
+ version: 2.5.0
228
225
  required_rubygems_version: !ruby/object:Gem::Requirement
229
226
  requirements:
230
227
  - - ">="
231
228
  - !ruby/object:Gem::Version
232
229
  version: '0'
233
230
  requirements: []
234
- rubygems_version: 3.1.4
231
+ rubygems_version: 3.3.7
235
232
  signing_key:
236
233
  specification_version: 4
237
234
  summary: Beautiful graphs for one or multiple datasets.
data/.rubocop_todo.yml DELETED
@@ -1,182 +0,0 @@
1
- # This configuration was generated by
2
- # `rubocop --auto-gen-config`
3
- # on 2021-05-07 13:38:24 UTC using RuboCop version 1.12.1.
4
- # The point is for the user to remove these configuration records
5
- # one by one as the offenses are removed from the code base.
6
- # Note that changes in the inspected code, or installation of new
7
- # versions of RuboCop, may require this file to be generated again.
8
-
9
- # Offense count: 1
10
- # Cop supports --auto-correct.
11
- # Configuration parameters: Include.
12
- # Include: **/*.gemspec
13
- Gemspec/DateAssignment:
14
- Exclude:
15
- - 'gruff.gemspec'
16
-
17
- # Offense count: 1
18
- # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches.
19
- Lint/DuplicateBranch:
20
- Exclude:
21
- - 'test/gruff_test_case.rb'
22
-
23
- # Offense count: 1
24
- Lint/DuplicateMethods:
25
- Exclude:
26
- - 'lib/gruff/photo_bar.rb'
27
-
28
- # Offense count: 13
29
- Lint/FloatComparison:
30
- Exclude:
31
- - 'Rakefile'
32
- - 'lib/gruff/base.rb'
33
- - 'lib/gruff/renderer/renderer.rb'
34
- - 'lib/gruff/scatter.rb'
35
-
36
- # Offense count: 1
37
- Lint/UnreachableCode:
38
- Exclude:
39
- - 'lib/gruff/photo_bar.rb'
40
-
41
- # Offense count: 1
42
- Lint/UselessAssignment:
43
- Exclude:
44
- - 'lib/gruff/photo_bar.rb'
45
-
46
- # Offense count: 1
47
- # Configuration parameters: CheckForMethodsWithNoSideEffects.
48
- Lint/Void:
49
- Exclude:
50
- - 'lib/gruff/patch/rmagick.rb'
51
-
52
- # Offense count: 56
53
- # Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
54
- Metrics/AbcSize:
55
- Max: 75
56
-
57
- # Offense count: 1
58
- # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
59
- # IgnoredMethods: refine
60
- Metrics/BlockLength:
61
- Max: 29
62
-
63
- # Offense count: 14
64
- # Configuration parameters: CountComments, CountAsOne.
65
- Metrics/ClassLength:
66
- Max: 669
67
-
68
- # Offense count: 8
69
- # Configuration parameters: IgnoredMethods.
70
- Metrics/CyclomaticComplexity:
71
- Max: 21
72
-
73
- # Offense count: 126
74
- # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
75
- Metrics/MethodLength:
76
- Max: 81
77
-
78
- # Offense count: 3
79
- # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
80
- Metrics/ParameterLists:
81
- Max: 7
82
-
83
- # Offense count: 7
84
- # Configuration parameters: IgnoredMethods.
85
- Metrics/PerceivedComplexity:
86
- Max: 22
87
-
88
- # Offense count: 1
89
- # Configuration parameters: EnforcedStyleForLeadingUnderscores.
90
- # SupportedStylesForLeadingUnderscores: disallowed, required, optional
91
- Naming/MemoizedInstanceVariableName:
92
- Exclude:
93
- - 'lib/gruff/scene.rb'
94
-
95
- # Offense count: 9
96
- # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
97
- # AllowedNames: at, by, db, id, in, io, ip, of, on, os, pp, to
98
- Naming/MethodParameterName:
99
- Exclude:
100
- - 'lib/gruff/base.rb'
101
- - 'lib/gruff/patch/rmagick.rb'
102
- - 'lib/gruff/pie.rb'
103
- - 'lib/gruff/renderer/text.rb'
104
-
105
- # Offense count: 6
106
- # Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers.
107
- # SupportedStyles: snake_case, normalcase, non_integer
108
- # AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339
109
- Naming/VariableNumber:
110
- Exclude:
111
- - 'test/test_bar.rb'
112
- - 'test/test_bezier.rb'
113
- - 'test/test_line.rb'
114
-
115
- # Offense count: 1
116
- # Configuration parameters: MinSize.
117
- Performance/CollectionLiteralInLoop:
118
- Exclude:
119
- - 'test/test_legend.rb'
120
-
121
- # Offense count: 1
122
- # Cop supports --auto-correct.
123
- Performance/RedundantMatch:
124
- Exclude:
125
- - 'lib/gruff/photo_bar.rb'
126
-
127
- # Offense count: 1
128
- # Cop supports --auto-correct.
129
- Performance/RegexpMatch:
130
- Exclude:
131
- - 'lib/gruff/photo_bar.rb'
132
-
133
- # Offense count: 2
134
- # Cop supports --auto-correct.
135
- Performance/StringReplacement:
136
- Exclude:
137
- - 'lib/gruff/scene.rb'
138
-
139
- # Offense count: 2
140
- Security/Eval:
141
- Exclude:
142
- - 'test/gruff_test_case.rb'
143
-
144
- # Offense count: 1
145
- Style/CombinableLoops:
146
- Exclude:
147
- - 'test/test_line.rb'
148
-
149
- # Offense count: 3
150
- Style/DocumentDynamicEvalDefinition:
151
- Exclude:
152
- - 'test/gruff_test_case.rb'
153
-
154
- # Offense count: 137
155
- # Configuration parameters: RequireForNonPublicMethods.
156
- Style/DocumentationMethod:
157
- Enabled: false
158
-
159
- # Offense count: 3
160
- # Cop supports --auto-correct.
161
- Style/EvalWithLocation:
162
- Exclude:
163
- - 'test/gruff_test_case.rb'
164
-
165
- # Offense count: 1
166
- Style/MissingRespondToMissing:
167
- Exclude:
168
- - 'lib/gruff/scene.rb'
169
-
170
- # Offense count: 1
171
- # Configuration parameters: AllowedMethods.
172
- # AllowedMethods: respond_to_missing?
173
- Style/OptionalBooleanParameter:
174
- Exclude:
175
- - 'lib/gruff/base.rb'
176
-
177
- # Offense count: 3
178
- # Cop supports --auto-correct.
179
- Style/StringConcatenation:
180
- Exclude:
181
- - 'lib/gruff/photo_bar.rb'
182
- - 'test/gruff_test_case.rb'
data/.travis.yml DELETED
@@ -1,23 +0,0 @@
1
- language: ruby
2
- dist: bionic
3
- cache: bundler
4
-
5
- rvm:
6
- - 2.4
7
- - 2.5
8
- - 2.6
9
- - 2.7
10
- - 3.0
11
- - jruby-9.2.14.0
12
-
13
- jobs:
14
- include:
15
- - name: 'Lint'
16
- rvm: 2.4
17
- script: bundle exec rubocop
18
-
19
- addons:
20
- apt:
21
- packages:
22
- - gsfonts
23
- - ghostscript
Binary file
Binary file
Binary file
@@ -1,93 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # EXPERIMENTAL!
4
- #
5
- # Doesn't work yet.
6
- #
7
- class Gruff::PhotoBar < Gruff::Base
8
- # TODO
9
- #
10
- # define base and cap in yml
11
- # allow for image directory to be located elsewhere
12
- # more exact measurements for bar heights (go all the way to the bottom of the graph)
13
- # option to tile images instead of use a single image
14
- # drop base label a few px lower so photo bar graphs can have a base dropping over the lower marker line
15
- #
16
-
17
- # The name of a pre-packaged photo-based theme.
18
- attr_reader :theme
19
-
20
- # def initialize(target_width=800)
21
- # super
22
- # init_photo_bar_graphics()
23
- # end
24
-
25
- def draw
26
- super
27
- return unless data_given?
28
-
29
- return # TODO: Remove for further development
30
-
31
- init_photo_bar_graphics
32
-
33
- #Draw#define_clip_path()
34
- #Draw#clip_path(pathname)
35
- #Draw#composite....with bar graph image OverCompositeOp
36
- #
37
- # See also
38
- #
39
- # Draw.pattern # define an image to tile as the filling of a draw object
40
- #
41
-
42
- # Setup spacing.
43
- #
44
- # Columns sit side-by-side.
45
- spacing_factor = 0.9
46
- bar_width = store.norm_data[0].color.columns
47
-
48
- store.norm_data.each_with_index do |data_row, row_index|
49
- data_row.points.each_with_index do |data_point, point_index|
50
- data_point = 0 if data_point.nil?
51
- # Use incremented x and scaled y
52
- left_x = @graph_left + (bar_width * (row_index + point_index + ((store.length - 1) * point_index)))
53
- left_y = @graph_top + (@graph_height - data_point * @graph_height) + 1
54
- right_x = left_x + bar_width * spacing_factor
55
- right_y = @graph_top + @graph_height - 1
56
-
57
- bar_image_width = data_row.color.columns
58
- bar_image_height = right_y.to_f - left_y.to_f
59
-
60
- # Crop to scale for data
61
- bar_image = data_row.color.crop(0, 0, bar_image_width, bar_image_height)
62
-
63
- @d.gravity = Magick::NorthWestGravity
64
- @d.composite(left_x, left_y, bar_image_width, bar_image_height, bar_image)
65
-
66
- # Calculate center based on bar_width and current row
67
- label_center = @graph_left + (store.length * bar_width * point_index) + (store.length * bar_width / 2.0)
68
- draw_label(label_center, point_index)
69
- end
70
- end
71
- end
72
-
73
- # Return the chosen theme or the default
74
- def theme
75
- @theme || 'plastik'
76
- end
77
-
78
- protected
79
-
80
- # Sets up colors with a list of images that will be used.
81
- # Images should be 340px tall
82
- def init_photo_bar_graphics
83
- color_list = []
84
- theme_dir = File.dirname(__FILE__) + '/../../assets/' + theme
85
-
86
- Dir.open(theme_dir).each do |file|
87
- next unless /\.png$/.match(file)
88
-
89
- color_list << Magick::Image.read("#{theme_dir}/#{file}").first
90
- end
91
- @colors = color_list
92
- end
93
- end
data/lib/gruff/scene.rb DELETED
@@ -1,198 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'observer'
4
-
5
- # A scene is a non-linear graph that assembles layers together to tell a story.
6
- # Layers are folders with appropriately named files (see below). You can group
7
- # layers and control them together or just set their values individually.
8
- #
9
- # Examples:
10
- #
11
- # * A city scene that changes with the time of day and the weather conditions.
12
- # * A traffic map that shows red lines on streets that are crowded and green on free-flowing ones.
13
- #
14
- # g = Gruff::Scene.new("500x100", "path/to/city_scene_directory")
15
- #
16
- # # Define order of layers, back to front
17
- # g.layers = %w(background haze sky clouds)
18
- #
19
- # # Define groups that will be controlled by the same input
20
- # g.weather_group = %w(clouds)
21
- # g.time_group = %w(background sky)
22
- #
23
- # # Set values for the layers or groups
24
- # g.weather = "cloudy"
25
- # g.time = Time.now
26
- # g.haze = true
27
- #
28
- # # Write the final graph to disk
29
- # g.write "hazy_daytime_city_scene.png"
30
- #
31
- # There are several rules that will magically select a layer when possible.
32
- #
33
- # * Numbered files will be selected according to the closest value that is less than the input value.
34
- # * +'true.png'+ and +'false.png'+ will be used as booleans.
35
- # * Other named files will be used if the input matches the filename (without the filetype extension).
36
- # * If there is a file named +'default.png'+, it will be used unless other input values are set for the corresponding layer.
37
- class Gruff::Scene < Gruff::Base
38
- # An array listing the folder names that will be rendered, from back to front.
39
- #
40
- # @example
41
- # g.layers = %w(sky clouds buildings street people)
42
- attr_reader :layers
43
-
44
- def initialize(target_width, base_dir)
45
- @base_dir = base_dir
46
- @groups = {}
47
- @layers = []
48
- super target_width
49
- end
50
-
51
- def draw
52
- # Join all the custom paths and filter out the empty ones
53
- image_paths = @layers.map(&:path).reject(&:empty?)
54
- images = Magick::ImageList.new(*image_paths)
55
- Gruff::Renderer.background_image = images.flatten_images
56
- end
57
-
58
- def layers=(ordered_list)
59
- ordered_list.each do |layer_name|
60
- @layers << Gruff::Layer.new(@base_dir, layer_name)
61
- end
62
- end
63
-
64
- # Group layers to input values
65
- #
66
- # g.weather_group = ["sky", "sea", "clouds"]
67
- #
68
- # Set input values
69
- #
70
- # g.weather = "cloudy"
71
- #
72
- def method_missing(method_name, *args)
73
- case method_name.to_s
74
- when /^(\w+)_group=$/
75
- add_group Regexp.last_match(1), *args
76
- return
77
- when /^(\w+)=$/
78
- set_input Regexp.last_match(1), args.first
79
- return
80
- end
81
- super
82
- end
83
-
84
- private
85
-
86
- def add_group(input_name, layer_names)
87
- @groups[input_name] = Gruff::Group.new(input_name, @layers.select { |layer| layer_names.include?(layer.name) })
88
- end
89
-
90
- def set_input(input_name, input_value)
91
- if !@groups[input_name].nil?
92
- @groups[input_name].send_updates(input_value)
93
- elsif chosen_layer = @layers.find { |layer| layer.name == input_name }
94
- chosen_layer.update input_value
95
- end
96
- end
97
- end
98
-
99
- # @private
100
- class Gruff::Group
101
- include Observable
102
- attr_reader :name
103
-
104
- def initialize(folder_name, layers)
105
- @name = folder_name
106
- layers.each do |layer|
107
- layer.observe self
108
- end
109
- end
110
-
111
- def send_updates(value)
112
- changed
113
- notify_observers value
114
- end
115
- end
116
-
117
- # @private
118
- class Gruff::Layer
119
- attr_reader :name
120
-
121
- def initialize(base_dir, folder_name)
122
- @base_dir = base_dir.to_s
123
- @name = folder_name.to_s
124
- @filenames = Dir.open(File.join(base_dir, folder_name)).entries.select { |file| file =~ /^[^.]+\.png$/ }.sort
125
- @selected_filename = select_default
126
- end
127
-
128
- # Register this layer so it receives updates from the group
129
- def observe(obj)
130
- obj.add_observer self
131
- end
132
-
133
- # Choose the appropriate filename for this layer, based on the input
134
- def update(value)
135
- @selected_filename = case value.to_s
136
- when /^(true|false)$/
137
- select_boolean value
138
- when /^(\w|\s)+$/
139
- select_string value
140
- when /^-?(\d+\.)?\d+$/
141
- select_numeric value
142
- when /(\d\d):(\d\d):\d\d/
143
- select_time "#{Regexp.last_match(1)}#{Regexp.last_match(2)}"
144
- else
145
- select_default
146
- end
147
- # Finally, try to use 'default' if we're still blank
148
- @selected_filename ||= select_default
149
- end
150
-
151
- # Returns the full path to the selected image, or a blank string
152
- def path
153
- unless @selected_filename.nil? || @selected_filename.empty?
154
- return File.join(@base_dir, @name, @selected_filename)
155
- end
156
-
157
- ''
158
- end
159
-
160
- private
161
-
162
- # Match "true.png" or "false.png"
163
- def select_boolean(value)
164
- file_exists_or_blank value.to_s
165
- end
166
-
167
- # Match -5 to _5.png
168
- def select_numeric(value)
169
- file_exists_or_blank value.to_s.gsub('-', '_')
170
- end
171
-
172
- def select_time(value)
173
- times = @filenames.map { |filename| filename.gsub('.png', '') }
174
- times.each_with_index do |time, index|
175
- if (time > value) && (index > 0)
176
- return "#{times[index - 1]}.png"
177
- end
178
- end
179
-
180
- "#{times.last}.png"
181
- end
182
-
183
- # Match "partly cloudy" to "partly_cloudy.png"
184
- def select_string(value)
185
- file_exists_or_blank value.to_s.gsub(' ', '_')
186
- end
187
-
188
- def select_default
189
- @filenames.include?('default.png') ? 'default.png' : ''
190
- end
191
-
192
- # Returns the string "#{filename}.png", if it exists.
193
- #
194
- # Failing that, it returns default.png, or '' if that doesn't exist.
195
- def file_exists_or_blank(filename)
196
- @filenames.include?("#{filename}.png") ? "#{filename}.png" : select_default
197
- end
198
- end