gruff 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,6 @@
1
+ CHANGELOG
2
+
3
+ == 0.0.1
4
+
5
+ Initial release.
6
+ Line graphs only. Other graph styles coming soon.
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2005 Geoffrey Grosenbach boss@topfunky.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README ADDED
@@ -0,0 +1,11 @@
1
+ == Gruff Graphs
2
+
3
+ A library for making beautiful graphs.
4
+
5
+ See samples at http://nubyonrails.topfunky.com/articles/2005/10/24/gruff-graphing-library-for-ruby
6
+
7
+ See the test suite in test/line_test.rb for examples. (More documentation coming soon.)
8
+
9
+ == WARNING
10
+
11
+ This is alpha-quality software. It works well according to my tests, but the API may change and other features will be added. Backwards compatibility is not guaranteed until the 1.0 release.
data/lib/gruff.rb ADDED
@@ -0,0 +1,5 @@
1
+
2
+ %w{base area bar line pie}.each do |filename|
3
+ #puts "Requiring #{filename}"
4
+ require "gruff/#{filename}"
5
+ end
data/lib/gruff/area.rb ADDED
@@ -0,0 +1,15 @@
1
+
2
+ require 'gruff/base'
3
+
4
+ module Gruff
5
+ class Area < Base
6
+
7
+ # TODO Not yet implemented.
8
+ def draw
9
+ super
10
+
11
+ @d.draw(@base_image)
12
+ end
13
+
14
+ end
15
+ end
data/lib/gruff/bar.rb ADDED
@@ -0,0 +1,15 @@
1
+
2
+ require 'gruff/base'
3
+
4
+ module Gruff
5
+ class Bar < Base
6
+
7
+ # TODO Not yet implemented.
8
+ def draw
9
+ super
10
+
11
+ @d.draw(@base_image)
12
+ end
13
+
14
+ end
15
+ end
data/lib/gruff/base.rb ADDED
@@ -0,0 +1,364 @@
1
+ #
2
+ # = Gruff. Graphs.
3
+ #
4
+ # Author:: Geoffrey Grosenbach boss@topfunky.com
5
+ #
6
+ # Date:: October 23, 2005
7
+ #
8
+ #
9
+
10
+ require 'rmagick'
11
+ require 'yaml'
12
+
13
+ module Gruff
14
+
15
+ VERSION = '0.0.1'
16
+
17
+ class Base
18
+
19
+ include Magick
20
+
21
+ # A hash of names for the individual columns, where the key is the array index for the column this label represents.
22
+ #
23
+ # Not all columns need to be named.
24
+ #
25
+ # Example: 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008
26
+ attr_accessor :labels
27
+
28
+ # The large title of the graph displayed at the top
29
+ attr_accessor :title
30
+
31
+ # Font used for titles, labels, etc. Works best if you provide the full path to the TTF font file.
32
+ # RMagick must be built with the Freetype libraries for this to work properly.
33
+ attr_accessor :font
34
+
35
+ # Graph is drawn at 4/3 ratio (800x600, 400x300, etc.).
36
+ #
37
+ # Looks for Bitstream Vera as the default font. Expects an environment var of MAGICK_FONT_PATH to be set.
38
+ # (Uses RMagick's default font otherwise.)
39
+ def initialize(target_width=800)
40
+ @columns = target_width.to_f
41
+ @rows = target_width.to_f * 0.75
42
+
43
+ # Internal for calculations
44
+ @font = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH'])
45
+ @marker_pointsize = 21.0
46
+ @raw_columns = 800.0
47
+ @raw_rows = 600.0
48
+ @column_count = 0
49
+ @maximum_value = 0
50
+ @data = Array.new
51
+ @labels = Hash.new
52
+ @labels_seen = Hash.new
53
+ @scale = @columns / @raw_columns
54
+
55
+ reset_themes()
56
+ theme_keynote()
57
+ end
58
+
59
+ # Add a color to the list of available colors for lines.
60
+ #
61
+ # Example:
62
+ # add_color('#c0e9d3')
63
+ def add_color(colorname)
64
+ @colors << colorname
65
+ end
66
+
67
+ # Replace the entire color list with a new array of colors. You need to have one more color
68
+ # than the number of datasets you intend to draw.
69
+ #
70
+ # Example:
71
+ # replace_colors('#cc99cc', '#d9e043', '#34d8a2')
72
+ def replace_colors(color_list=[])
73
+ @colors = color_list
74
+ end
75
+
76
+ # A color scheme similar to the popular presentation software.
77
+ def theme_keynote
78
+ reset_themes()
79
+ # Colors
80
+ @blue = '#6886B4'
81
+ @yellow = '#FDD84E'
82
+ @green = '#72AE6E'
83
+ @red = '#D1695E'
84
+ @purple = '#8A6EAF'
85
+ @orange = '#EFAA43'
86
+ @white = 'white'
87
+ @colors = [@yellow, @blue, @green, @red, @purple, @orange, @white]
88
+
89
+ @marker_color = 'white'
90
+
91
+ @base_image = render_gradiated_background('black', '#4a465a')
92
+ end
93
+
94
+ # A color scheme plucked from the colors on the popular usability blog.
95
+ def theme_37signals
96
+ reset_themes()
97
+ # Colors
98
+ @green = '#339933'
99
+ @purple = '#cc99cc'
100
+ @blue = '#336699'
101
+ @yellow = '#FFF804'
102
+ @red = '#ff0000'
103
+ @orange = '#cf5910'
104
+ @black = 'black'
105
+ @colors = [@yellow, @blue, @green, @red, @purple, @orange, @black]
106
+
107
+ @marker_color = 'black'
108
+
109
+ @base_image = render_gradiated_background('#d1edf5', 'white')
110
+ end
111
+
112
+ # A color scheme from the colors used on the 2005 Rails keynote presentation at RubyConf.
113
+ def theme_rails_keynote
114
+ reset_themes()
115
+ # Colors
116
+ @green = '#00ff00'
117
+ @grey = '#333333'
118
+ @orange = '#ff5d00'
119
+ @red = '#f61100'
120
+ @white = 'white'
121
+ @light_grey = '#999999'
122
+ @black = 'black'
123
+ @colors = [@green, @grey, @orange, @red, @white, @light_grey, @black]
124
+
125
+ @marker_color = 'white'
126
+
127
+ @base_image = render_gradiated_background('#0083a3', '#0083a3')
128
+ end
129
+
130
+ # A color scheme similar to that used on the popular podcast site.
131
+ def theme_odeo
132
+ reset_themes()
133
+ # Colors
134
+ @grey = '#202020'
135
+ @white = 'white'
136
+ @dark_pink = '#a21764'
137
+ @green = '#8ab438'
138
+ @light_grey = '#999999'
139
+ @dark_blue = '#3a5b87'
140
+ @black = 'black'
141
+ @colors = [@grey, @white, @dark_blue, @dark_pink, @green, @light_grey, @black]
142
+
143
+ @marker_color = 'white'
144
+
145
+ @base_image = render_gradiated_background('#ff47a4', '#ff1f81')
146
+ end
147
+
148
+ # dataset is an array where the first element is the name of the dataset
149
+ # and the value is an array of values to plot.
150
+ #
151
+ # Can be called multiple times with different datasets
152
+ # for a multi-valued graph.
153
+ #
154
+ # Example:
155
+ # data("Bart S.", [95, 45, 78, 89, 88, 76])
156
+ def data(name, data_points=[])
157
+ @data << [name, data_points]
158
+ # Set column count if this is larger than previous counts
159
+ @column_count = (data_points.length > @column_count) ? data_points.length : @column_count
160
+
161
+ # Pre-normalize
162
+ data_points.each do |data_point|
163
+ @maximum_value = (data_point > @maximum_value) ? data_point : @maximum_value
164
+ end
165
+ end
166
+
167
+ # Writes the graph to a file. Defaults to 'graph.png'
168
+ #
169
+ # Example: write('graphs/my_pretty_graph.png')
170
+ def write(filename="graph.png")
171
+ draw()
172
+ @base_image.write(filename)
173
+ end
174
+
175
+ # TODO Return the graph as a rendered binary blob.
176
+ def to_blob(filename="graph.png")
177
+ draw()
178
+ @base_image = @base_image.to_blob()
179
+ end
180
+
181
+ protected
182
+
183
+ # Overridden by subclasses to do the actual plotting of the graph.
184
+ #
185
+ # Subclasses should start by calling super() for this method.
186
+ def draw
187
+ setup_drawing()
188
+
189
+ # Subclasses will do some drawing here...
190
+ #@d.draw(@base_image)
191
+ end
192
+
193
+ # Draws the decorations.
194
+ # - line markers
195
+ # - legend
196
+ # - title
197
+ def setup_drawing
198
+ normalize()
199
+
200
+ draw_line_markers()
201
+ draw_legend()
202
+ draw_title
203
+ end
204
+
205
+ # Make copy of data with values scaled between 0-100
206
+ def normalize
207
+ @norm_data = Array.new
208
+ @data.each do |data_row|
209
+ norm_data_points = Array.new
210
+ data_row[1].each do |data_point|
211
+ norm_data_points << (data_point.to_f/@maximum_value.to_f)
212
+ end
213
+ @norm_data << [data_row[0], norm_data_points]
214
+ end
215
+ end
216
+
217
+ # Draws horizontal background lines and labels
218
+ def draw_line_markers
219
+ @graph_left = 130.0
220
+ @graph_right = @raw_columns - 100.0
221
+ @graph_top = 150.0
222
+ @graph_bottom = @raw_rows - 110.0
223
+ @graph_height = @graph_bottom - @graph_top
224
+ @graph_width = @graph_right - @graph_left
225
+
226
+ # Draw horizontal line markers and annotate with numbers
227
+ @d = @d.stroke(@marker_color)
228
+ @d = @d.stroke_width 1
229
+ (0..4).each do |index|
230
+ #y = ( index.to_f * (@graph_height.to_f/4.0) ) + @graph_top.to_f
231
+ y = @graph_top + @graph_height - ( index.to_f * (@graph_height.to_f/4.0) )
232
+ @d = @d.line(@graph_left, y, @graph_right, y)
233
+
234
+ marker_label = 0
235
+ marker_label = @maximum_value.to_f * (index.to_f/4.to_f) if index > 0
236
+
237
+ @d.fill = @marker_color
238
+ @d.font = @font
239
+ @d.stroke = 'transparent'
240
+ @d.pointsize = scale_fontsize(@marker_pointsize)
241
+ @d.gravity = EastGravity
242
+ @d = @d.annotate_scaled( @base_image,
243
+ 100, 20,
244
+ -10, y - (@marker_pointsize/2.0),
245
+ marker_label.to_s, @scale)
246
+ end
247
+ end
248
+
249
+ # Draws a legend with the names of the datasets matched to the colors used to draw them.
250
+ def draw_legend
251
+ @color_index = 0
252
+ @legend_labels = @data.collect {|item| item[0] }
253
+
254
+ legend_square_width = 20 # small square with color of this item
255
+
256
+ metrics = @d.get_type_metrics(@base_image, @legend_labels.join(''))
257
+ legend_text_width = metrics.width
258
+ legend_width = legend_text_width + @legend_labels.length * (legend_square_width * 2.7)
259
+ legend_left = scale(@raw_columns - legend_width) / 2
260
+ legend_increment = legend_width / @legend_labels.length.to_f
261
+
262
+ current_x_offset = legend_left
263
+ @legend_labels.each_with_index do |legend_label, index|
264
+ # Draw label
265
+ @d.fill = @marker_color
266
+ @d.font = @font
267
+ @d.pointsize = scale_fontsize(20)
268
+ @d.stroke = 'transparent'
269
+ @d.font_weight = NormalWeight
270
+ @d.gravity = WestGravity
271
+ @d = @d.annotate_scaled( @base_image,
272
+ @raw_columns, 24,
273
+ current_x_offset + (legend_square_width * 1.7), 70,
274
+ legend_label.to_s, @scale)
275
+
276
+ # Now draw box with color of this dataset
277
+ legend_box_y_offset = 2 # Move box down slightly to center
278
+ @d = @d.stroke 'transparent'
279
+ @d = @d.fill current_color
280
+ @d = @d.rectangle(current_x_offset, 70 + legend_box_y_offset,
281
+ current_x_offset + legend_square_width, 70 + legend_square_width + legend_box_y_offset)
282
+
283
+ increment_color()
284
+
285
+ @d.pointsize = 20
286
+ metrics = @d.get_type_metrics(@base_image, legend_label.to_s)
287
+ current_string_offset = metrics.width + (legend_square_width * 2.7)
288
+ current_x_offset += current_string_offset
289
+ end
290
+ @color_index = 0
291
+ end
292
+
293
+ def draw_title
294
+ @d.fill = @marker_color
295
+ @d.font = @font
296
+ @d.stroke = 'transparent'
297
+ @d.pointsize = scale_fontsize(36)
298
+ @d.font_weight = BoldWeight
299
+ @d.gravity = CenterGravity
300
+ @d = @d.annotate_scaled( @base_image,
301
+ @raw_columns, 50,
302
+ 0, 10,
303
+ @title, @scale)
304
+ end
305
+
306
+ def render_gradiated_background(top_color, bottom_color)
307
+ Image.new(@columns, @rows,
308
+ GradientFill.new(0, 0, 100, 0, top_color, bottom_color))
309
+ end
310
+
311
+ def current_color
312
+ @colors[@color_index]
313
+ end
314
+
315
+ def increment_color
316
+ @color_index += 1
317
+ raise(ColorlistExhaustedException, "There are no more colors left to use.") if @color_index == @colors.length
318
+ current_color
319
+ end
320
+
321
+ def reset_themes
322
+ @color_index = 0
323
+ @labels_seen = Hash.new
324
+
325
+ @d = Draw.new
326
+ # Scale down from 800x600 used to calculate drawing.
327
+ # NOTE: Font annotation is now affected and has to be done manually.
328
+ @d = @d.scale(@scale, @scale)
329
+ end
330
+
331
+ def scale(value)
332
+ value * @scale
333
+ end
334
+
335
+ def scale_fontsize(value)
336
+ new_fontsize = value * @scale
337
+ return 10 if new_fontsize < 10
338
+ return new_fontsize
339
+ end
340
+
341
+ end
342
+
343
+ class ColorlistExhaustedException < StandardError; end
344
+
345
+
346
+ end
347
+
348
+
349
+ module Magick
350
+ class Draw
351
+
352
+ # Additional method since Draw.scale doesn't affect annotations.
353
+ def annotate_scaled(img, width, height, x, y, text, scale)
354
+ scaled_width = (width * scale) >= 1 ? (width * scale) : 1
355
+ scaled_height = (height * scale) >= 1 ? (height * scale) : 1
356
+
357
+ self.annotate( img,
358
+ scaled_width, scaled_height,
359
+ x * scale, y * scale,
360
+ text)
361
+ end
362
+
363
+ end
364
+ end
data/lib/gruff/line.rb ADDED
@@ -0,0 +1,62 @@
1
+
2
+ require 'gruff/base'
3
+
4
+ module Gruff
5
+ class Line < Base
6
+
7
+ def draw
8
+ super
9
+
10
+ @x_increment = @graph_width / (@column_count - 1).to_f
11
+ circle_radius = 5.0
12
+
13
+ @d = @d.stroke_opacity 1.0
14
+ @d = @d.stroke_width 5.0
15
+
16
+ @norm_data.each do |data_row|
17
+ prev_x = prev_y = 0.0
18
+ @d = @d.stroke current_color
19
+ @d = @d.fill current_color
20
+
21
+ data_row[1].each_with_index do |data_point, index|
22
+ # Use incremented x and scaled y
23
+ new_x = @graph_left + (@x_increment * index)
24
+ new_y = @graph_top + (@graph_height - data_point * @graph_height)
25
+
26
+ @d = @d.line(prev_x, prev_y, new_x, new_y) if (prev_x > 0) && (prev_y > 0)
27
+ @d = @d.circle(new_x, new_y, new_x - circle_radius, new_y)
28
+
29
+ draw_label(new_x, index)
30
+
31
+ prev_x = new_x
32
+ prev_y = new_y
33
+ end
34
+
35
+ increment_color()
36
+ end
37
+
38
+ @d.draw(@base_image)
39
+ end
40
+
41
+ private
42
+
43
+ # Draws column labels below graph
44
+ def draw_label(x_offset, index)
45
+ if !@labels[index].nil? && @labels_seen[index].nil?
46
+ @d.fill = @marker_color
47
+ @d.font = @font
48
+ @d.stroke = 'transparent'
49
+ @d.font_weight = NormalWeight
50
+ @d.pointsize = scale_fontsize(@marker_pointsize)
51
+ @d.gravity = CenterGravity
52
+ @d = @d.annotate_scaled(@base_image,
53
+ 1, 1,
54
+ #150, 30,
55
+ x_offset, @raw_rows - 80,
56
+ @labels[index], @scale)
57
+ @labels_seen[index] = 1
58
+ end
59
+ end
60
+
61
+ end
62
+ end
data/lib/gruff/pie.rb ADDED
@@ -0,0 +1,15 @@
1
+
2
+ require 'gruff/base'
3
+
4
+ module Gruff
5
+ class Pie < Base
6
+
7
+ # TODO Not yet implemented.
8
+ def draw
9
+ super
10
+
11
+ @d.draw(@base_image)
12
+ end
13
+
14
+ end
15
+ end
data/rakefile ADDED
@@ -0,0 +1,192 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/contrib/rubyforgepublisher'
8
+
9
+ $:.unshift(File.dirname(__FILE__) + "/lib")
10
+ require 'gruff'
11
+
12
+ PKG_NAME = 'gruff'
13
+ PKG_VERSION = Gruff::VERSION
14
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
15
+
16
+ RELEASE_NAME = "REL #{PKG_VERSION}"
17
+
18
+ RUBY_FORGE_PROJECT = "gruff"
19
+ RUBY_FORGE_USER = "topfunky"
20
+
21
+ desc "Default Task"
22
+ task :default => [ :test ]
23
+
24
+ # Run the unit tests
25
+ Rake::TestTask.new { |t|
26
+ t.libs << "test"
27
+ t.pattern = 'test/*_test.rb'
28
+ t.verbose = true
29
+ }
30
+
31
+
32
+ # Genereate the RDoc documentation
33
+ Rake::RDocTask.new { |rdoc|
34
+ rdoc.rdoc_dir = 'doc'
35
+ rdoc.title = "Gruff -- Beautiful graphs"
36
+ rdoc.options << '--line-numbers --inline-source --main README --accessor adv_attr_accessor=M'
37
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
38
+ rdoc.rdoc_files.include('README', 'CHANGELOG')
39
+ rdoc.rdoc_files.include('lib/gruff.rb')
40
+ rdoc.rdoc_files.include('lib/gruff/*.rb')
41
+ }
42
+
43
+
44
+ # Create compressed packages
45
+ spec = Gem::Specification.new do |s|
46
+ s.platform = Gem::Platform::RUBY
47
+ s.name = PKG_NAME
48
+ s.summary = "Beautiful graphs for one or multiple datasets."
49
+ s.description = %q{Make colorful graphs for use on websites or documents.}
50
+ s.version = PKG_VERSION
51
+
52
+ s.author = "Geoffrey Grosenbach"
53
+ s.email = "boss@topfunky.com"
54
+ s.rubyforge_project = RUBY_FORGE_PROJECT
55
+ s.homepage = "http://www.topfunky.com"
56
+
57
+ s.has_rdoc = true
58
+ s.requirements << 'none'
59
+ s.require_path = 'lib'
60
+ s.autorequire = 'gruff'
61
+
62
+ s.files = [ "rakefile", "README", "CHANGELOG", "MIT-LICENSE" ]
63
+ s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
64
+ s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
65
+ end
66
+
67
+ Rake::GemPackageTask.new(spec) do |p|
68
+ p.gem_spec = spec
69
+ p.need_tar = true
70
+ p.need_zip = true
71
+ end
72
+
73
+
74
+ desc "Publish the API documentation"
75
+ task :pgem => [:package] do
76
+ Rake::SshFilePublisher.new("boss@topfunky.com", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
77
+ end
78
+
79
+ desc "Publish the release files to RubyForge."
80
+ task :release => [:package] do
81
+ files = ["gem", "tgz", "zip"].map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
82
+
83
+ if RUBY_FORGE_PROJECT then
84
+ require 'net/http'
85
+ require 'open-uri'
86
+
87
+ project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
88
+ project_data = open(project_uri) { |data| data.read }
89
+ group_id = project_data[/[?&]group_id=(\d+)/, 1]
90
+ raise "Couldn't get group id" unless group_id
91
+
92
+ # This echos password to shell which is a bit sucky
93
+ if ENV["RUBY_FORGE_PASSWORD"]
94
+ password = ENV["RUBY_FORGE_PASSWORD"]
95
+ else
96
+ print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
97
+ password = STDIN.gets.chomp
98
+ end
99
+
100
+ login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
101
+ data = [
102
+ "login=1",
103
+ "form_loginname=#{RUBY_FORGE_USER}",
104
+ "form_pw=#{password}"
105
+ ].join("&")
106
+ http.post("/account/login.php", data)
107
+ end
108
+
109
+ cookie = login_response["set-cookie"]
110
+ raise "Login failed" unless cookie
111
+ headers = { "Cookie" => cookie }
112
+
113
+ release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
114
+ release_data = open(release_uri, headers) { |data| data.read }
115
+ package_id = release_data[/[?&]package_id=(\d+)/, 1]
116
+ raise "Couldn't get package id" unless package_id
117
+
118
+ first_file = true
119
+ release_id = ""
120
+
121
+ files.each do |filename|
122
+ basename = File.basename(filename)
123
+ file_ext = File.extname(filename)
124
+ file_data = File.open(filename, "rb") { |file| file.read }
125
+
126
+ puts "Releasing #{basename}..."
127
+
128
+ release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
129
+ release_date = Time.now.strftime("%Y-%m-%d %H:%M")
130
+ type_map = {
131
+ ".zip" => "3000",
132
+ ".tgz" => "3110",
133
+ ".gz" => "3110",
134
+ ".gem" => "1400"
135
+ }; type_map.default = "9999"
136
+ type = type_map[file_ext]
137
+ boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
138
+
139
+ query_hash = if first_file then
140
+ {
141
+ "group_id" => group_id,
142
+ "package_id" => package_id,
143
+ "release_name" => RELEASE_NAME,
144
+ "release_date" => release_date,
145
+ "type_id" => type,
146
+ "processor_id" => "8000", # Any
147
+ "release_notes" => "",
148
+ "release_changes" => "",
149
+ "preformatted" => "1",
150
+ "submit" => "1"
151
+ }
152
+ else
153
+ {
154
+ "group_id" => group_id,
155
+ "release_id" => release_id,
156
+ "package_id" => package_id,
157
+ "step2" => "1",
158
+ "type_id" => type,
159
+ "processor_id" => "8000", # Any
160
+ "submit" => "Add This File"
161
+ }
162
+ end
163
+
164
+ query = "?" + query_hash.map do |(name, value)|
165
+ [name, URI.encode(value)].join("=")
166
+ end.join("&")
167
+
168
+ data = [
169
+ "--" + boundary,
170
+ "Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
171
+ "Content-Type: application/octet-stream",
172
+ "Content-Transfer-Encoding: binary",
173
+ "", file_data, ""
174
+ ].join("\x0D\x0A")
175
+
176
+ release_headers = headers.merge(
177
+ "Content-Type" => "multipart/form-data; boundary=#{boundary}"
178
+ )
179
+
180
+ target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
181
+ http.post(target + query, data, release_headers)
182
+ end
183
+
184
+ if first_file then
185
+ release_id = release_response.body[/release_id=(\d+)/, 1]
186
+ raise("Couldn't get release id") unless release_id
187
+ end
188
+
189
+ first_file = false
190
+ end
191
+ end
192
+ end
data/test/line_test.rb ADDED
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift(File.dirname(__FILE__) + "/../lib/")
4
+ #$:.unshift File.dirname(__FILE__) + "/fixtures/helpers"
5
+
6
+ require 'test/unit'
7
+ require 'gruff'
8
+
9
+ class TestGruffLines < Test::Unit::TestCase
10
+
11
+ # TODO Delete old output files once when starting tests
12
+
13
+ def setup
14
+ @datasets = [
15
+ [:Jimmy, [25, 36, 86, 39, 25, 31, 79, 88]],
16
+ [:Charles, [80, 54, 67, 54, 68, 70, 90, 95]],
17
+ [:Julie, [22, 29, 35, 38, 36, 40, 46, 57]],
18
+ [:Jane, [95, 95, 95, 90, 85, 80, 88, 100]],
19
+ [:Philip, [90, 34, 23, 12, 78, 89, 98, 88]],
20
+ ["Arthur", [5, 10, 13, 11, 6, 16, 22, 32]],
21
+ ]
22
+ end
23
+
24
+ def test_line_graph_with_themes
25
+ g = Gruff::Line.new
26
+ g.title = "Visual Multi-Line Graph Test"
27
+ g.labels = {
28
+ 0 => '5/6',
29
+ 2 => '5/15',
30
+ 4 => '5/24',
31
+ 6 => '5/30',
32
+ }
33
+ @datasets.each do |data|
34
+ g.data(data[0], data[1])
35
+ end
36
+
37
+ # Default theme
38
+ g.write("test/output/line_keynote.png")
39
+
40
+ g.theme_37signals
41
+ g.write("test/output/line_37signals.png")
42
+
43
+ g.theme_rails_keynote
44
+ g.write("test/output/line_rails_keynote.png")
45
+
46
+ g.theme_odeo
47
+ g.write("test/output/line_odeo.png")
48
+ end
49
+
50
+ def test_line_small_values
51
+ @datasets = [
52
+ [:small, [0.25, 0.14356, 0.0, 0.5674839, 0.456]],
53
+ [:small2, [0.2, 0.3, 0.1, 0.05, 0.9]]
54
+ ]
55
+
56
+ g = Gruff::Line.new
57
+ g.title = "Small Values Line Graph Test"
58
+ @datasets.each do |data|
59
+ g.data(data[0], data[1])
60
+ end
61
+
62
+ g.write("test/output/line_small.png")
63
+ end
64
+
65
+ def test_line_large_values
66
+ @datasets = [
67
+ [:large, [100_005, 35_000, 28_000, 27_000]],
68
+ [:large2, [35_000, 28_000, 27_000, 100_005]],
69
+ [:large3, [28_000, 27_000, 100_005, 35_000]],
70
+ [:large4, [1_238, 39_092, 27_938, 48_876]]
71
+ ]
72
+
73
+ g = Gruff::Line.new
74
+ g.title = "Very Large Values Line Graph Test"
75
+ @datasets.each do |data|
76
+ g.data(data[0], data[1])
77
+ end
78
+
79
+ g.write("test/output/line_large.png")
80
+ end
81
+
82
+ def test_resize
83
+ g = Gruff::Line.new(400)
84
+ g.title = "Small Size Multi-Line Graph Test"
85
+ g.labels = {
86
+ 0 => '5/6',
87
+ 2 => '5/15',
88
+ 4 => '5/24',
89
+ 6 => '5/30',
90
+ }
91
+ @datasets.each do |data|
92
+ g.data(data[0], data[1])
93
+ end
94
+
95
+ # Default theme
96
+ g.write("test/output/line_keynote_small.png")
97
+
98
+ g.theme_37signals
99
+ g.write("test/output/line_37signals_small.png")
100
+
101
+ g.theme_rails_keynote
102
+ g.write("test/output/line_rails_keynote_small.png")
103
+
104
+ g.theme_odeo
105
+ g.write("test/output/line_odeo_small.png")
106
+ end
107
+
108
+ def test_long_title
109
+
110
+ end
111
+
112
+ def test_add_colors
113
+
114
+ end
115
+
116
+ def test_request_too_many_colors
117
+
118
+ end
119
+
120
+ def test_add_data
121
+
122
+ end
123
+
124
+ def test_many_datapoints
125
+ g = Gruff::Line.new
126
+ g.title = "Many Multi-Line Graph Test"
127
+ g.labels = {
128
+ 0 => 'June',
129
+ 10 => 'July',
130
+ 30 => 'August',
131
+ 50 => 'September',
132
+ }
133
+ g.data('many points', (0..50).collect {|i| rand(100) })
134
+
135
+ # Default theme
136
+ g.write("test/output/line_many.png")
137
+ end
138
+
139
+
140
+ def test_similar_high_end_values
141
+ g = Gruff::Line.new
142
+ g.title = "Similar High End Values Test"
143
+ g.data('similar points', [100, 98, 99, 97, 96, 95, 96, 97, 98, 99, 100, 96] )
144
+
145
+ # Default theme
146
+ g.write("test/output/similar_high_end_values.png")
147
+ end
148
+
149
+
150
+ # Requires the Creative Block font from http://www.blambot.com
151
+ def test_font
152
+ g = Gruff::Line.new
153
+ g.title = "Font Test"
154
+ g.labels = {
155
+ 0 => '5/6',
156
+ 2 => '5/15',
157
+ 4 => '5/24',
158
+ 6 => '5/30',
159
+ 8 => '6/2',
160
+ 10 => '6/4',
161
+ }
162
+ g.data('many points', (0..10).collect {|i| rand(100) })
163
+ g.font = File.expand_path('CREABBRG.TTF', ENV['MAGICK_FONT_PATH'])
164
+
165
+ # Default theme
166
+ g.write("test/output/line_font.png")
167
+ end
168
+
169
+ =begin
170
+ def test_very_small_graphs
171
+ [300, 200, 100].each do |size|
172
+ g = Gruff::Line.new(size)
173
+ g.title = "#{size}px Graph Test"
174
+ g.labels = {
175
+ 0 => '5/6',
176
+ 2 => '5/15',
177
+ 4 => '5/24',
178
+ 6 => '5/30',
179
+ }
180
+ @datasets.each do |data|
181
+ g.data(data[0], data[1])
182
+ end
183
+
184
+ # Default theme
185
+ g.write("test/output/line_#{size}.png")
186
+ end
187
+ end
188
+ =end
189
+
190
+ =begin
191
+ def test_for_blog
192
+ g = Gruff::Line.new
193
+ g.labels = {
194
+ 0 => '2002',
195
+ 2 => '2003',
196
+ 4 => '2004',
197
+ 6 => '2005',
198
+ }
199
+ @datasets.each do |data|
200
+ g.data(data[0], data[1])
201
+ end
202
+
203
+ # Default theme
204
+ g.title = "Gruff...graphs"
205
+ g.write("test/output/1.png")
206
+
207
+ g.theme_odeo
208
+ g.title = "Themes, Colors, and Fonts!"
209
+ g.font = File.expand_path('CREABBRG.TTF', ENV['MAGICK_FONT_PATH'])
210
+ g.write("test/output/2.png")
211
+
212
+ g.theme_rails_keynote
213
+ g.title = "Source Coming Soon..."
214
+ g.font = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH'])
215
+ g.write("test/output/3.png")
216
+
217
+ end
218
+
219
+ def test_for_blog_small
220
+ g = Gruff::Line.new(400)
221
+ g.labels = {
222
+ 0 => '2002',
223
+ 2 => '2003',
224
+ 4 => '2004',
225
+ 6 => '2005',
226
+ }
227
+ @datasets.each do |data|
228
+ g.data(data[0], data[1])
229
+ end
230
+
231
+ # Default theme
232
+ g.title = "Gruff...graphs"
233
+ g.write("test/output/1_small.png")
234
+
235
+ g.theme_odeo
236
+ g.title = "Themes, Colors, and Fonts!"
237
+ g.font = File.expand_path('CREABBRG.TTF', ENV['MAGICK_FONT_PATH'])
238
+ g.write("test/output/2_small.png")
239
+
240
+ g.theme_rails_keynote
241
+ g.title = "Source Coming Soon..."
242
+ g.font = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH'])
243
+ g.write("test/output/3_small.png")
244
+
245
+ end
246
+ =end
247
+
248
+
249
+ end
250
+
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: gruff
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2005-10-25 00:00:00 -07:00
8
+ summary: Beautiful graphs for one or multiple datasets.
9
+ require_paths:
10
+ - lib
11
+ email: boss@topfunky.com
12
+ homepage: http://www.topfunky.com
13
+ rubyforge_project: gruff
14
+ description: Make colorful graphs for use on websites or documents.
15
+ autorequire: gruff
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ signing_key:
28
+ cert_chain:
29
+ authors:
30
+ - Geoffrey Grosenbach
31
+ files:
32
+ - rakefile
33
+ - README
34
+ - CHANGELOG
35
+ - MIT-LICENSE
36
+ - lib/gruff
37
+ - lib/gruff.rb
38
+ - lib/gruff/area.rb
39
+ - lib/gruff/bar.rb
40
+ - lib/gruff/base.rb
41
+ - lib/gruff/line.rb
42
+ - lib/gruff/pie.rb
43
+ - test/line_test.rb
44
+ - test/output
45
+ - test/output/line_37signals.png
46
+ - test/output/line_37signals_small.png
47
+ - test/output/line_font.png
48
+ - test/output/line_keynote.png
49
+ - test/output/line_keynote_small.png
50
+ - test/output/line_large.png
51
+ - test/output/line_many.png
52
+ - test/output/line_odeo.png
53
+ - test/output/line_odeo_small.png
54
+ - test/output/line_rails_keynote.png
55
+ - test/output/line_rails_keynote_small.png
56
+ - test/output/line_small.png
57
+ - test/output/similar_high_end_values.png
58
+ test_files: []
59
+ rdoc_options: []
60
+ extra_rdoc_files: []
61
+ executables: []
62
+ extensions: []
63
+ requirements:
64
+ - none
65
+ dependencies: []