teejayvanslyke-gruff 0.3.6 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Rakefile +11 -53
- data/VERSION +1 -0
- data/lib/gruff/base.rb +47 -8
- data/lib/gruff/side_stacked_bar.rb +28 -2
- data/teejayvanslyke-gruff.gemspec +144 -0
- data/test/test_sidestacked_bar.rb +34 -0
- metadata +16 -22
data/.gitignore
ADDED
data/Rakefile
CHANGED
@@ -1,55 +1,13 @@
|
|
1
|
-
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
p.email = 'boss@topfunky.com'
|
11
|
-
p.summary = "Beautiful graphs for one or multiple datasets."
|
12
|
-
p.url = "http://nubyonrails.com/pages/gruff"
|
13
|
-
p.clean_globs = ['test/output/*.png']
|
14
|
-
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
|
-
p.remote_rdoc_dir = '' # Release to root
|
16
|
-
end
|
17
|
-
|
18
|
-
desc "Simple require on packaged files to make sure they are all there"
|
19
|
-
task :verify => :package do
|
20
|
-
# An error message will be displayed if files are missing
|
21
|
-
if system %(ruby -e "require 'pkg/gruff-#{Gruff::VERSION}/lib/gruff'")
|
22
|
-
puts "\nThe library files are present"
|
23
|
-
end
|
24
|
-
raise "\n*** Gruff::Base::DEBUG must be set to false for releases ***\n\n" if Gruff::Base::DEBUG
|
25
|
-
end
|
26
|
-
|
27
|
-
task :release => :verify
|
28
|
-
|
29
|
-
namespace :test do
|
30
|
-
|
31
|
-
desc "Run mini tests"
|
32
|
-
task :mini => :clean do
|
33
|
-
Dir['test/test_mini*'].each do |file|
|
34
|
-
system "ruby #{file}"
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
##
|
42
|
-
# Catch unmatched tasks and run them as a unit test.
|
43
|
-
#
|
44
|
-
# Makes it possible to do
|
45
|
-
#
|
46
|
-
# rake pie
|
47
|
-
#
|
48
|
-
# To run the +test/test_pie+ and +test/test_mini_pie+ files.
|
49
|
-
|
50
|
-
rule '' do |t|
|
51
|
-
# Rake::Task["clean"].invoke
|
52
|
-
Dir["test/test_*#{t.name}*.rb"].each do |filename|
|
53
|
-
system "ruby #{filename}"
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.name = "teejayvanslyke-gruff"
|
5
|
+
gemspec.summary = "Fork of Geoffrey Grosenbach's Gruff gem with some customizations and fixes"
|
6
|
+
gemspec.description = "Beautiful graphs for one or multiple datasets. Can be used on websites or in documents."
|
7
|
+
gemspec.email = "teejay.vanslyke@gmail.com"
|
8
|
+
gemspec.homepage = "http://github.com/teejayvanslyke/gruff.git"
|
9
|
+
gemspec.authors = ['Geoffrey Grosenbach', 'T.J. VanSlyke']
|
54
10
|
end
|
11
|
+
rescue LoadError
|
12
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
55
13
|
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.8
|
data/lib/gruff/base.rb
CHANGED
@@ -31,9 +31,10 @@ module Gruff
|
|
31
31
|
DEBUG = false
|
32
32
|
|
33
33
|
# Used for navigating the array of data to plot
|
34
|
-
DATA_LABEL_INDEX
|
35
|
-
DATA_VALUES_INDEX
|
36
|
-
DATA_COLOR_INDEX
|
34
|
+
DATA_LABEL_INDEX = 0
|
35
|
+
DATA_VALUES_INDEX = 1
|
36
|
+
DATA_COLOR_INDEX = 2
|
37
|
+
DATA_OVERLAY_INDEX = 3
|
37
38
|
|
38
39
|
# Space around text elements. Mostly used for vertical spacing
|
39
40
|
LEGEND_MARGIN = TITLE_MARGIN = 20.0
|
@@ -251,6 +252,11 @@ module Gruff
|
|
251
252
|
@top_margin = @left_margin = @right_margin = @bottom_margin = margin
|
252
253
|
end
|
253
254
|
|
255
|
+
# Sets whether we sort the data by the largest set first.
|
256
|
+
def sort=(sort)
|
257
|
+
@sort = sort
|
258
|
+
end
|
259
|
+
|
254
260
|
# Sets the font for graph text to the font at +font_path+.
|
255
261
|
def font=(font_path)
|
256
262
|
@font = font_path
|
@@ -454,10 +460,25 @@ module Gruff
|
|
454
460
|
#
|
455
461
|
# Example:
|
456
462
|
# data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
#
|
463
|
+
# data("Bart S.", [95, 45, 78], :overlay => ['95%', '45%', '78%'], :color => '#ffcc00')
|
464
|
+
def data(name, data_points=[], options_or_color=nil)
|
465
|
+
|
466
|
+
# Allow either a color argument or a hash of options in order to
|
467
|
+
# support the original interface.
|
468
|
+
if options_or_color.is_a?(Hash)
|
469
|
+
options = options_or_color
|
470
|
+
color = options[:color]
|
471
|
+
else
|
472
|
+
options = {}
|
473
|
+
color = options_or_color
|
474
|
+
end
|
475
|
+
|
476
|
+
# Make sure it's an array.
|
477
|
+
data_points = Array(data_points)
|
478
|
+
|
479
|
+
@data << [name, data_points, (color || increment_color), options[:overlay]]
|
480
|
+
|
481
|
+
# Set column count if this is larger than previous counts.
|
461
482
|
@column_count = (data_points.length > @column_count) ? data_points.length : @column_count
|
462
483
|
|
463
484
|
# Pre-normalize
|
@@ -555,7 +576,7 @@ module Gruff
|
|
555
576
|
norm_data_points << ((data_point.to_f - @minimum_value.to_f ) / @spread)
|
556
577
|
end
|
557
578
|
end
|
558
|
-
@norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX]]
|
579
|
+
@norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX], data_row[DATA_OVERLAY_INDEX]]
|
559
580
|
end
|
560
581
|
end
|
561
582
|
end
|
@@ -875,6 +896,24 @@ module Gruff
|
|
875
896
|
end
|
876
897
|
end
|
877
898
|
|
899
|
+
# Draw a centered text overlay atop a given rectangular
|
900
|
+
# area of the graph. This is used to superimpose text
|
901
|
+
# atop each chart region.
|
902
|
+
def draw_overlay(left_x, left_y, right_x, right_y, text)
|
903
|
+
puts "left_x: #{left_x}; left_y: #{left_y}; right_x: #{right_x}; right_y: #{right_y}"
|
904
|
+
@d.fill = @font_color
|
905
|
+
@d.font = @font if @font
|
906
|
+
@d.pointsize = scale_fontsize(@marker_font_size) * 1.5
|
907
|
+
@d.font_weight = BoldWeight
|
908
|
+
@d.stroke = 'black'
|
909
|
+
#@d.pointsize = scale_fontsize(@marker_font_size)
|
910
|
+
@d.gravity = CenterGravity
|
911
|
+
@d = @d.annotate_scaled(@base_image,
|
912
|
+
right_x - left_x, right_y - left_y,
|
913
|
+
left_x, left_y,
|
914
|
+
text, @scale)
|
915
|
+
end
|
916
|
+
|
878
917
|
# Shows an error message because you have no data.
|
879
918
|
def draw_no_data
|
880
919
|
@d.fill = @font_color
|
@@ -58,10 +58,36 @@ class Gruff::SideStackedBar < Gruff::SideBar
|
|
58
58
|
label_center = @graph_top + (@bar_width * point_index) + (@bar_width * @bar_spacing / 2.0)
|
59
59
|
draw_label(label_center, point_index)
|
60
60
|
end
|
61
|
-
|
62
61
|
end
|
63
62
|
|
64
|
-
@d.draw(@base_image)
|
63
|
+
@d.draw(@base_image)
|
64
|
+
|
65
|
+
height = Array.new(@column_count, 0)
|
66
|
+
length = Array.new(@column_count, @graph_left)
|
67
|
+
|
68
|
+
@norm_data.each_with_index do |data_row, row_index|
|
69
|
+
data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
|
70
|
+
## using the original calcs from the stacked bar chart to get the difference between
|
71
|
+
## part of the bart chart we wish to stack.
|
72
|
+
temp1 = @graph_left + (@graph_width -
|
73
|
+
data_point * @graph_width -
|
74
|
+
height[point_index])
|
75
|
+
temp2 = @graph_left + @graph_width - height[point_index]
|
76
|
+
difference = temp2 - temp1
|
77
|
+
|
78
|
+
left_x = length[point_index] #+ 1
|
79
|
+
left_y = @graph_top + (@bar_width * point_index) + padding
|
80
|
+
right_x = left_x + difference
|
81
|
+
right_y = left_y + @bar_width * @bar_spacing
|
82
|
+
length[point_index] += difference
|
83
|
+
height[point_index] += (data_point * @graph_width - 2)
|
84
|
+
|
85
|
+
p data_row
|
86
|
+
overlay = data_row[DATA_OVERLAY_INDEX]
|
87
|
+
|
88
|
+
draw_overlay(left_x, left_y, right_x, right_y, overlay.to_s) if overlay
|
89
|
+
end
|
90
|
+
end
|
65
91
|
end
|
66
92
|
|
67
93
|
protected
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{teejayvanslyke-gruff}
|
8
|
+
s.version = "0.3.8"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Geoffrey Grosenbach", "T.J. VanSlyke"]
|
12
|
+
s.date = %q{2009-10-13}
|
13
|
+
s.description = %q{Beautiful graphs for one or multiple datasets. Can be used on websites or in documents.}
|
14
|
+
s.email = %q{teejay.vanslyke@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.txt"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"History.txt",
|
21
|
+
"MIT-LICENSE",
|
22
|
+
"Manifest.txt",
|
23
|
+
"README.txt",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"assets/bubble.png",
|
27
|
+
"assets/city_scene/background/0000.png",
|
28
|
+
"assets/city_scene/background/0600.png",
|
29
|
+
"assets/city_scene/background/2000.png",
|
30
|
+
"assets/city_scene/clouds/cloudy.png",
|
31
|
+
"assets/city_scene/clouds/partly_cloudy.png",
|
32
|
+
"assets/city_scene/clouds/stormy.png",
|
33
|
+
"assets/city_scene/grass/default.png",
|
34
|
+
"assets/city_scene/haze/true.png",
|
35
|
+
"assets/city_scene/number_sample/1.png",
|
36
|
+
"assets/city_scene/number_sample/2.png",
|
37
|
+
"assets/city_scene/number_sample/default.png",
|
38
|
+
"assets/city_scene/sky/0000.png",
|
39
|
+
"assets/city_scene/sky/0200.png",
|
40
|
+
"assets/city_scene/sky/0400.png",
|
41
|
+
"assets/city_scene/sky/0600.png",
|
42
|
+
"assets/city_scene/sky/0800.png",
|
43
|
+
"assets/city_scene/sky/1000.png",
|
44
|
+
"assets/city_scene/sky/1200.png",
|
45
|
+
"assets/city_scene/sky/1400.png",
|
46
|
+
"assets/city_scene/sky/1500.png",
|
47
|
+
"assets/city_scene/sky/1700.png",
|
48
|
+
"assets/city_scene/sky/2000.png",
|
49
|
+
"assets/pc306715.jpg",
|
50
|
+
"assets/plastik/blue.png",
|
51
|
+
"assets/plastik/green.png",
|
52
|
+
"assets/plastik/red.png",
|
53
|
+
"init.rb",
|
54
|
+
"lib/gruff.rb",
|
55
|
+
"lib/gruff/accumulator_bar.rb",
|
56
|
+
"lib/gruff/area.rb",
|
57
|
+
"lib/gruff/bar.rb",
|
58
|
+
"lib/gruff/bar_conversion.rb",
|
59
|
+
"lib/gruff/base.rb",
|
60
|
+
"lib/gruff/bullet.rb",
|
61
|
+
"lib/gruff/deprecated.rb",
|
62
|
+
"lib/gruff/dot.rb",
|
63
|
+
"lib/gruff/line.rb",
|
64
|
+
"lib/gruff/mini/bar.rb",
|
65
|
+
"lib/gruff/mini/legend.rb",
|
66
|
+
"lib/gruff/mini/pie.rb",
|
67
|
+
"lib/gruff/mini/side_bar.rb",
|
68
|
+
"lib/gruff/net.rb",
|
69
|
+
"lib/gruff/photo_bar.rb",
|
70
|
+
"lib/gruff/pie.rb",
|
71
|
+
"lib/gruff/scene.rb",
|
72
|
+
"lib/gruff/side_bar.rb",
|
73
|
+
"lib/gruff/side_stacked_bar.rb",
|
74
|
+
"lib/gruff/spider.rb",
|
75
|
+
"lib/gruff/stacked_area.rb",
|
76
|
+
"lib/gruff/stacked_bar.rb",
|
77
|
+
"lib/gruff/stacked_mixin.rb",
|
78
|
+
"rails_generators/gruff/gruff_generator.rb",
|
79
|
+
"rails_generators/gruff/templates/controller.rb",
|
80
|
+
"rails_generators/gruff/templates/functional_test.rb",
|
81
|
+
"teejayvanslyke-gruff.gemspec",
|
82
|
+
"test/gruff_test_case.rb",
|
83
|
+
"test/test_accumulator_bar.rb",
|
84
|
+
"test/test_area.rb",
|
85
|
+
"test/test_bar.rb",
|
86
|
+
"test/test_base.rb",
|
87
|
+
"test/test_bullet.rb",
|
88
|
+
"test/test_dot.rb",
|
89
|
+
"test/test_legend.rb",
|
90
|
+
"test/test_line.rb",
|
91
|
+
"test/test_mini_bar.rb",
|
92
|
+
"test/test_mini_pie.rb",
|
93
|
+
"test/test_mini_side_bar.rb",
|
94
|
+
"test/test_net.rb",
|
95
|
+
"test/test_photo.rb",
|
96
|
+
"test/test_pie.rb",
|
97
|
+
"test/test_scene.rb",
|
98
|
+
"test/test_side_bar.rb",
|
99
|
+
"test/test_sidestacked_bar.rb",
|
100
|
+
"test/test_sidestacked_bar_percentile.rb",
|
101
|
+
"test/test_spider.rb",
|
102
|
+
"test/test_stacked_area.rb",
|
103
|
+
"test/test_stacked_bar.rb"
|
104
|
+
]
|
105
|
+
s.homepage = %q{http://github.com/teejayvanslyke/gruff.git}
|
106
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
107
|
+
s.require_paths = ["lib"]
|
108
|
+
s.rubygems_version = %q{1.3.4}
|
109
|
+
s.summary = %q{Fork of Geoffrey Grosenbach's Gruff gem with some customizations and fixes}
|
110
|
+
s.test_files = [
|
111
|
+
"test/gruff_test_case.rb",
|
112
|
+
"test/test_accumulator_bar.rb",
|
113
|
+
"test/test_area.rb",
|
114
|
+
"test/test_bar.rb",
|
115
|
+
"test/test_base.rb",
|
116
|
+
"test/test_bullet.rb",
|
117
|
+
"test/test_dot.rb",
|
118
|
+
"test/test_legend.rb",
|
119
|
+
"test/test_line.rb",
|
120
|
+
"test/test_mini_bar.rb",
|
121
|
+
"test/test_mini_pie.rb",
|
122
|
+
"test/test_mini_side_bar.rb",
|
123
|
+
"test/test_net.rb",
|
124
|
+
"test/test_photo.rb",
|
125
|
+
"test/test_pie.rb",
|
126
|
+
"test/test_scene.rb",
|
127
|
+
"test/test_side_bar.rb",
|
128
|
+
"test/test_sidestacked_bar.rb",
|
129
|
+
"test/test_sidestacked_bar_percentile.rb",
|
130
|
+
"test/test_spider.rb",
|
131
|
+
"test/test_stacked_area.rb",
|
132
|
+
"test/test_stacked_bar.rb"
|
133
|
+
]
|
134
|
+
|
135
|
+
if s.respond_to? :specification_version then
|
136
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
137
|
+
s.specification_version = 3
|
138
|
+
|
139
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
140
|
+
else
|
141
|
+
end
|
142
|
+
else
|
143
|
+
end
|
144
|
+
end
|
@@ -73,6 +73,40 @@ class TestGruffSideStackedBar < GruffTestCase
|
|
73
73
|
g.write "test/output/side_stacked_bar_long_label.png"
|
74
74
|
end
|
75
75
|
|
76
|
+
def test_unsorted_order
|
77
|
+
g = Gruff::SideStackedBar.new
|
78
|
+
g.title = "The order should be the same"
|
79
|
+
g.labels = {
|
80
|
+
0 => 'September',
|
81
|
+
1 => 'Oct',
|
82
|
+
2 => 'Nov',
|
83
|
+
3 => 'Dec',
|
84
|
+
}
|
85
|
+
@datasets.each do |data|
|
86
|
+
g.data(data[0], data[1])
|
87
|
+
end
|
88
|
+
g.sort = false
|
89
|
+
g.write "test/output/side_stacked_bar_unsorted_order.png"
|
90
|
+
g
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_sorted_order
|
94
|
+
g = Gruff::SideStackedBar.new
|
95
|
+
g.title = "The order should be the same"
|
96
|
+
g.labels = {
|
97
|
+
0 => 'September',
|
98
|
+
1 => 'Oct',
|
99
|
+
2 => 'Nov',
|
100
|
+
3 => 'Dec',
|
101
|
+
}
|
102
|
+
@datasets.each do |data|
|
103
|
+
g.data(data[0], data[1])
|
104
|
+
end
|
105
|
+
g.sort = true
|
106
|
+
g.write "test/output/side_stacked_bar_sorted_order.png"
|
107
|
+
g
|
108
|
+
end
|
109
|
+
|
76
110
|
protected
|
77
111
|
|
78
112
|
def setup_basic_graph(size=800)
|
metadata
CHANGED
@@ -1,43 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: teejayvanslyke-gruff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Geoffrey Grosenbach
|
8
|
+
- T.J. VanSlyke
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
12
|
|
12
|
-
date: 2009-10-
|
13
|
+
date: 2009-10-13 00:00:00 -07:00
|
13
14
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
name: hoe
|
17
|
-
type: :development
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 2.3.3
|
24
|
-
version:
|
15
|
+
dependencies: []
|
16
|
+
|
25
17
|
description: Beautiful graphs for one or multiple datasets. Can be used on websites or in documents.
|
26
|
-
email:
|
18
|
+
email: teejay.vanslyke@gmail.com
|
27
19
|
executables: []
|
28
20
|
|
29
21
|
extensions: []
|
30
22
|
|
31
23
|
extra_rdoc_files:
|
32
|
-
- History.txt
|
33
|
-
- Manifest.txt
|
34
24
|
- README.txt
|
35
25
|
files:
|
26
|
+
- .gitignore
|
36
27
|
- History.txt
|
37
28
|
- MIT-LICENSE
|
38
29
|
- Manifest.txt
|
39
30
|
- README.txt
|
40
31
|
- Rakefile
|
32
|
+
- VERSION
|
41
33
|
- assets/bubble.png
|
42
34
|
- assets/city_scene/background/0000.png
|
43
35
|
- assets/city_scene/background/0600.png
|
@@ -93,6 +85,7 @@ files:
|
|
93
85
|
- rails_generators/gruff/gruff_generator.rb
|
94
86
|
- rails_generators/gruff/templates/controller.rb
|
95
87
|
- rails_generators/gruff/templates/functional_test.rb
|
88
|
+
- teejayvanslyke-gruff.gemspec
|
96
89
|
- test/gruff_test_case.rb
|
97
90
|
- test/test_accumulator_bar.rb
|
98
91
|
- test/test_area.rb
|
@@ -111,17 +104,17 @@ files:
|
|
111
104
|
- test/test_scene.rb
|
112
105
|
- test/test_side_bar.rb
|
113
106
|
- test/test_sidestacked_bar.rb
|
107
|
+
- test/test_sidestacked_bar_percentile.rb
|
114
108
|
- test/test_spider.rb
|
115
109
|
- test/test_stacked_area.rb
|
116
110
|
- test/test_stacked_bar.rb
|
117
111
|
has_rdoc: true
|
118
|
-
homepage: http://
|
112
|
+
homepage: http://github.com/teejayvanslyke/gruff.git
|
119
113
|
licenses: []
|
120
114
|
|
121
115
|
post_install_message:
|
122
116
|
rdoc_options:
|
123
|
-
- --
|
124
|
-
- README.txt
|
117
|
+
- --charset=UTF-8
|
125
118
|
require_paths:
|
126
119
|
- lib
|
127
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -138,12 +131,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
131
|
version:
|
139
132
|
requirements: []
|
140
133
|
|
141
|
-
rubyforge_project:
|
142
|
-
rubygems_version: 1.3.
|
134
|
+
rubyforge_project:
|
135
|
+
rubygems_version: 1.3.5
|
143
136
|
signing_key:
|
144
137
|
specification_version: 3
|
145
|
-
summary:
|
138
|
+
summary: Fork of Geoffrey Grosenbach's Gruff gem with some customizations and fixes
|
146
139
|
test_files:
|
140
|
+
- test/gruff_test_case.rb
|
147
141
|
- test/test_accumulator_bar.rb
|
148
142
|
- test/test_area.rb
|
149
143
|
- test/test_bar.rb
|