wayneeseguin-dynamic_reports 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+ module GoogleChart
3
+
4
+ # Generates a Scatter chart.
5
+ #
6
+ # ==== Example
7
+ # sc = GoogleChart::ScatterChart.new('320x200',"Scatter Chart")
8
+ # sc.data "Scatter Set", [[1,1,], [2,2], [3,3], [4,4]]
9
+ # sc.point_sizes [10,15,30,55]
10
+ # puts sc.to_url
11
+ class ScatterChart < Base
12
+
13
+ # Initializes the Scatter Chart with a +chart_size+ (in WIDTHxHEIGHT format) and a +chart_title+
14
+ def initialize(chart_size='300x200', chart_title=nil) # :yield: self
15
+ super(chart_size, chart_title)
16
+ self.chart_type = :s
17
+ self.show_legend = false
18
+ @point_sizes = []
19
+ yield self if block_given?
20
+ end
21
+
22
+ def process_data
23
+ # Interleave X and Y co-ordinate data
24
+ encoded_data = join_encoded_data([encode_data(x_data[0],max_x_value), encode_data(y_data[0],max_y_value)])
25
+ # Add point sizes data if it exists
26
+ unless @point_sizes.empty?
27
+ encoded_data = join_encoded_data([encoded_data, encode_data(@point_sizes)])
28
+ end
29
+ return encoded_data
30
+ end
31
+
32
+ # Specify the data point sizes of the Scatter chart (optional). The data point sizes are scaled with this data set.
33
+ def point_sizes(values)
34
+ @point_sizes = values
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+ module GoogleChart
3
+ # Generates a Venn Diagram.
4
+ #
5
+ # Supply three vd.data statements of label, size, color for circles A, B, C. Then, intersections with four values:
6
+ # * the first value specifies the area of A intersecting B
7
+ # * the second value specifies the area of B intersecting C
8
+ # * the third value specifies the area of C intersecting A
9
+ # * the fourth value specifies the area of A intersecting B intersecting C
10
+ #
11
+ # vd = GoogleChart::VennDiagram.new("320x200", 'Venn Diagram')
12
+ # vd.data "Blue", 100, '0000ff'
13
+ # vd.data "Green", 80, '00ff00'
14
+ # vd.data "Red", 60, 'ff0000'
15
+ # vd.intersections 30,30,30,10
16
+ # puts vd.to_url
17
+ class VennDiagram < Base
18
+
19
+ # Initializes the Venn Diagram with a +chart_size+ (in WIDTHxHEIGHT format) and a +chart_title+
20
+ def initialize(chart_size='300x200', chart_title=nil) # :yield: self
21
+ super(chart_size, chart_title)
22
+ self.chart_type = :v
23
+ @intersections = []
24
+ yield self if block_given?
25
+ end
26
+
27
+ def process_data
28
+ encode_data(@data + @intersections)
29
+ end
30
+
31
+ # Specify the intersections of the circles in the Venn Diagram. See the Rdoc for class for sample
32
+ def intersections(*values)
33
+ @intersections = values
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ %w(
2
+ base
3
+ pie_chart
4
+ line_chart
5
+ bar_chart
6
+ venn_diagram
7
+ scatter_chart
8
+ financial_line_chart
9
+ ).each do |filename|
10
+ require File.dirname(__FILE__) + "/google_chart/#{filename}"
11
+ end
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1,73 @@
1
+ <% if report.class_name.nil? %>
2
+ <style type="text/css">
3
+ .dynamic_report .report_title {
4
+ font-size:16pt;
5
+ font-weight:bold;
6
+ margin:10px 0px;
7
+ }
8
+ .dynamic_report .report_sub_title {
9
+ font-size:14pt;
10
+ color:black;
11
+ margin:10px 0px;
12
+ }
13
+ .dynamic_report table tr th {
14
+ color: white;
15
+ background: gray;
16
+ padding:5px;
17
+ }
18
+ .dynamic_report table tr td {
19
+ border: 1px solid black;
20
+ padding:3px 15px;
21
+ }
22
+ .dynamic_report .report_charts {
23
+ width:100%;
24
+ }
25
+
26
+ .dynamic_report .report_chart {
27
+ margin:15px;
28
+ }
29
+ </style>
30
+ <% end %>
31
+
32
+ <div id="<%= report.class_name %>" class="dynamic_report">
33
+ <%= "<div class='report_title'>#{report.title}</div>" if report.title %>
34
+ <%= "<div class='report_sub_title'>#{report.sub_title}</div>" if report.sub_title %>
35
+ <table class="report" border="0" cellpadding="0" cellspacing="0">
36
+ <thead class="report_header">
37
+ <tr class="report_header_row">
38
+ <% report.columns.each do |column| %>
39
+ <th>
40
+ <%= options[:titleize] ? titleize(column) : column %>
41
+ </th>
42
+ <% end %>
43
+ </tr>
44
+ </thead>
45
+ <tbody class="report_body">
46
+ <% report.records.each do |record| %>
47
+ <tr class="report_row">
48
+ <% report.columns.each do |column| %>
49
+ <td>
50
+ <% if record.is_a?(Hash) %>
51
+ <%= (options[:commas] == true) ? commify(record[column]) : record[column] %>
52
+ <% elsif record.respond_to?(column.to_sym) %>
53
+ <%= (options[:commas] == true) ? commify(record.send(column.to_sym)) : record.send(column.to_sym) %>
54
+ <% else %>
55
+ <%= column %>
56
+ <% end %>
57
+ </td>
58
+ <% end %>
59
+ </tr>
60
+ <% end %>
61
+ </tbody>
62
+ </table>
63
+
64
+ <div class="report_charts">
65
+ <% report.charts.to_a.each do |chart| %>
66
+ <span class="report_chart">
67
+ <%= "<img src='#{chart_url(chart,report)}' alt='#{chart.name}'>" %>
68
+ </span>
69
+ <% end %>
70
+ </div>
71
+
72
+ </div>
73
+
@@ -0,0 +1,62 @@
1
+ - if report.class_name.nil?
2
+ %style{type => "text/css"}
3
+ \.dynamic_report .report_title {
4
+ font-size:16pt;
5
+ font-weight:bold;
6
+ margin:10px 0px;
7
+ }
8
+ \.dynamic_report .report_sub_title {
9
+ font-size:14pt;
10
+ color:black;
11
+ margin:10px 0px;
12
+ }
13
+ \.dynamic_report table tr th {
14
+ color: white;
15
+ background: gray;
16
+ padding:5px;
17
+ }
18
+ \.dynamic_report table tr td {
19
+ border: 1px solid black;
20
+ padding:3px 15px;
21
+ }
22
+ \.dynamic_report .report_charts {
23
+ width:100%;
24
+ }
25
+ \.dynamic_report .report_chart {
26
+ margin:15px;
27
+ }
28
+
29
+ .dynamic_report{ :id => report.class_name }
30
+ - if report.title
31
+ %h2.report_title
32
+ = report.title
33
+
34
+ - if report.sub_title
35
+ %h3.report_sub_title
36
+ = report.sub_title
37
+
38
+ %table.report{ :cellspacing => "0", :border => "0", :cellpadding => "0" }
39
+ %thead.report_header
40
+ %tr.report_header_row
41
+ - report.columns.each do |column|
42
+ %th
43
+ = options[:titleize] ? titleize(column) : column
44
+ %tbody.report_body
45
+ - report.records.each do |record|
46
+ %tr.report_row
47
+ - report.columns.each do |column|
48
+ %td
49
+ - if record.is_a?(Hash)
50
+ = (options[:commas] == true) ? commify(record[column]) : record[column]
51
+ - elsif record.respond_to?(column.to_sym)
52
+ = (options[:commas] == true) ? commify(record.send(column.to_sym)) : record.send(column.to_sym)
53
+ - else
54
+ = column
55
+
56
+ - if report.charts && report.charts.class === Hash
57
+ - report.charts.each_pair do |name, chart|
58
+ .chart
59
+ %h2
60
+ = name
61
+ %img{:src => chart_url(chart), :alt => name}
62
+
@@ -0,0 +1,30 @@
1
+ module DynamicReports
2
+ class View
3
+
4
+ include Templates
5
+
6
+ attr_accessor :template, :views, :report
7
+ @@cached_templates = {}
8
+ @template = {}
9
+ @views = {}
10
+
11
+ def options
12
+ @options ||= {}
13
+ end
14
+
15
+ def initialize(report)
16
+ @template = report.template
17
+ @report = report
18
+ @views = report.views
19
+ end
20
+
21
+ class << self
22
+ def cached_templates
23
+ @@cached_templates
24
+ end
25
+ end
26
+
27
+ # TODO: Investigate if we can remove the need for caller_locations here?
28
+ def self.caller_locations ; [] ; end
29
+ end
30
+ end
@@ -0,0 +1,47 @@
1
+ # :include: README
2
+
3
+ # Library Files
4
+ module DynamicReports
5
+ @@default_view_paths = ["#{File::dirname(File::expand_path(__FILE__))}/dynamic_reports/views/"]
6
+ def self.default_view_paths
7
+ @@default_view_paths
8
+ end
9
+ def self.default_view_paths=(paths)
10
+ @@default_view_paths = paths
11
+ end
12
+ end
13
+
14
+ require "dynamic_reports/charts"
15
+ require "dynamic_reports/reports"
16
+ require "dynamic_reports/templates"
17
+ require "dynamic_reports/views"
18
+ require "dynamic_reports/vendor/google_chart"
19
+
20
+
21
+ # TODO: Figure out why this will not load:
22
+ # require "dynamic_reports/rails"
23
+ # For now placing the code right here:
24
+ if defined?(Rails)
25
+ # Load all defined reports.
26
+ # Question: How to get Rails to reload files other than ones matching the requested constant...
27
+ #Dir.glob("#{File.join(Rails.root, "app", "reports")}/*.rb").each { |file| require file }
28
+ ActiveSupport::Dependencies.load_paths << File.join(Rails.root, "app", "reports")
29
+ # Question: Should we allow for report directory nesting ?
30
+
31
+ # Set default views directory
32
+ # TODO: These should be added to Rails views directories?
33
+ DynamicReports.default_view_paths += [
34
+ File.join(Rails.root, "app", "views", "reports"),
35
+ File.join(Rails.root, "app", "views", "layouts")
36
+ ]
37
+
38
+ # TODO: Render extension
39
+
40
+ # TODO: AR extensions:
41
+ # has_report :daily, :columns => [...], :options => {...}, :title => ...
42
+ # Which will generate a report object DailyReport with the given definition.
43
+ # Everything after the name corresponds to options available in the configuration block.
44
+
45
+ # TODO: Generator
46
+ end
47
+
@@ -0,0 +1,61 @@
1
+ class ChartsTest < Test::Unit::TestCase
2
+ context "charts" do
3
+ setup do
4
+ class TheReport < DynamicReports::Report
5
+ chart :the_chart_name, :an => "option", :another => "option" do
6
+ title "awesome report!"
7
+ type :svg
8
+ height "350"
9
+ width "250"
10
+ columns :pageviews
11
+ label_column "created_at"
12
+ end
13
+ chart :the_other_chart_name do
14
+ title "Some other chart"
15
+ end
16
+ end
17
+ end
18
+
19
+ should "allow specification of options to the chart beyond it's attributes." do
20
+ hash = {
21
+ :name => :the_chart_name,
22
+ :an => "option",
23
+ :type => :svg,
24
+ :another => "option",
25
+ :title=>"awesome report!",
26
+ :height=>"350",
27
+ :width=>"250",
28
+ :columns=>[:pageviews],
29
+ :label_column => "created_at"
30
+ }
31
+ assert_equal hash, TheReport.chart_with_name(:the_chart_name).options
32
+ end
33
+
34
+ should "allow setting their name" do
35
+ assert_equal :the_chart_name, TheReport.chart_with_name(:the_chart_name).name
36
+ end
37
+
38
+ should "allow setting their title" do
39
+ assert_equal "awesome report!", TheReport.chart_with_name(:the_chart_name).title
40
+ end
41
+
42
+ should "allow setting their type" do
43
+ assert_equal :svg, TheReport.chart_with_name(:the_chart_name).type
44
+ end
45
+
46
+ should "allow setting their width" do
47
+ assert_equal "250" ,TheReport.chart_with_name(:the_chart_name).width
48
+ end
49
+
50
+ should "allow setting their height" do
51
+ assert_equal "350", TheReport.chart_with_name(:the_chart_name).height
52
+ end
53
+
54
+ should "allow definition of multiple charts" do
55
+ #require "ruby-debug" ; debugger
56
+ assert_contains TheReport.charts[0].name, :the_chart_name
57
+ assert_contains TheReport.charts[1].name, :the_other_chart_name
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,77 @@
1
+ class ReportsTest < Test::Unit::TestCase
2
+ context "a report" do
3
+
4
+ setup do
5
+ class TheReport < DynamicReports::Report
6
+ name "The Report!"
7
+ title "Daily Report"
8
+ sub_title "Happens every day, ya!"
9
+ columns :recorded_at, :viewed_on, :pageviews_count, :visits_count, :conversions_count
10
+
11
+ chart :visits do
12
+ title "testing chart"
13
+ columns :visits
14
+ type "line"
15
+ end
16
+ end
17
+ @array_records = DynamicReports::Test::ArrayRecords.generate(TheReport, :count => 10)
18
+ @object_records = DynamicReports::Test::ObjectRecords.generate(TheReport, :count => 10)
19
+ end
20
+
21
+ should "allow setting the title of a report" do
22
+ assert_equal "Daily Report", TheReport.title
23
+ end
24
+
25
+ should "allow setting the sub title of a report" do
26
+ assert_equal "Happens every day, ya!", TheReport.sub_title
27
+ end
28
+
29
+ should "allow setting the columns to report on" do
30
+ assert_equal [:recorded_at, :viewed_on, :pageviews_count, :visits_count, :conversions_count], TheReport.columns
31
+ end
32
+
33
+ should "return an instantiated report .on is called" do
34
+ assert_kind_of DynamicReports::Report,
35
+ TheReport.on(@array_records)
36
+ end
37
+
38
+ should "An instantiated report should return html table report when to_html is called" do
39
+ assert_match(/<table class="report"/, TheReport.on(@array_records).to_html)
40
+ end
41
+
42
+ should "An instantiated report should contain the rendered chart that was defined" do
43
+ assert_match(/class="report_charts"/, TheReport.on(@array_records).to_html)
44
+ end
45
+
46
+ context "Report with templates and views specified" do
47
+ setup do
48
+ class SpecificTemplateReport < DynamicReports::Report
49
+ name "A report with specified template!"
50
+ title "Specify Template Report"
51
+ sub_title "template is 'other_template'"
52
+ columns :recorded_at, :viewed_on, :pageviews_count, :visits_count, :conversions_count
53
+ template :specific_template
54
+ views "#{File::dirname(File::expand_path(__FILE__))}/views/"
55
+ end
56
+ @array_records = DynamicReports::Test::ArrayRecords.generate(SpecificTemplateReport, :count => 10)
57
+ @object_records = DynamicReports::Test::ObjectRecords.generate(SpecificTemplateReport, :count => 10)
58
+ end
59
+
60
+ should "allow setting of the views directories" do
61
+ assert_contains SpecificTemplateReport.views,
62
+ "#{File::dirname(File::expand_path(__FILE__))}/views/"
63
+ end
64
+
65
+ should "the instance should have the same views as the class" do
66
+ assert_contains SpecificTemplateReport.on(@array_records).views,
67
+ "#{File::dirname(File::expand_path(__FILE__))}/views/"
68
+ end
69
+
70
+ should "render with the specified template, from the specified views directory" do
71
+ assert_equal "This is the specified template!",
72
+ SpecificTemplateReport.on(@array_records).to_html.strip
73
+ end
74
+ end
75
+ end
76
+
77
+ end
@@ -0,0 +1,3 @@
1
+ class TemplatesTest < Test::Unit::TestCase
2
+
3
+ end
@@ -0,0 +1,5 @@
1
+ class ReportsTest < Test::Unit::TestCase
2
+ context "View" do
3
+
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ require "test/unit/testsuite"
4
+ require "test/unit/ui/console/testrunner"
5
+ #require "test/unit/color"
6
+ require "shoulda"
7
+ require "zentest"
8
+
9
+ # Libraries
10
+ require "dynamic_reports"
11
+ require "test/test_helper"
12
+
13
+ # Test files.
14
+ require "test/dynamic_reports/charts_test"
15
+ require "test/dynamic_reports/reports_test"
16
+ require "test/dynamic_reports/views_test"
17
+
18
+ require "test/unit"
File without changes
@@ -0,0 +1,64 @@
1
+ require "ostruct"
2
+
3
+ module DynamicReports
4
+ module Test
5
+
6
+ class ArrayRecords
7
+ def self.generate(report, *options)
8
+ records = []
9
+ options = options.shift || {}
10
+ (0..(options[:count].to_i)).each do |index|
11
+ hash = {}
12
+ report.columns.each do |column|
13
+ hash[column.to_s] =
14
+ case column.to_s
15
+ when /_at$/
16
+ (DateTime.now-100)+index
17
+ when /_on$/
18
+ (Date.today-100)+index
19
+ when /_id$/,/_count$/
20
+ rand(10000)
21
+ else
22
+ column
23
+ end
24
+ end
25
+ records << hash
26
+ end
27
+ records
28
+ end
29
+ end
30
+
31
+ class ObjectRecords
32
+ def self.generate(report,*options)
33
+ records = []
34
+ options = options.shift || {}
35
+ (0..(options[:count].to_i)).each do |index|
36
+ object = OpenStruct.new(report.columns)
37
+ report.columns.each do |column|
38
+ value = case column.to_s
39
+ when /_at$/
40
+ (DateTime.now-100)+index
41
+ when /_on$/
42
+ (Date.today-100)+index
43
+ when /_id$/,/_count$/
44
+ rand(10000)
45
+ else
46
+ column
47
+ end
48
+
49
+ object.send(column.to_sym, value)
50
+
51
+ records << object
52
+ end
53
+ records
54
+ end
55
+ end
56
+ end
57
+
58
+ class ARRecords
59
+ def self.generate(*options)
60
+ end
61
+ end
62
+ end
63
+
64
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wayneeseguin-dynamic_reports
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Wayne E. Seguin
8
+ - Joshua Lippiner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-07-01 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Dynamic Ruby Reporting Engine with support for Charts.
18
+ email: wayneeseguin@gmail.com, jlippiner@gmail.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - README
25
+ - README.rdoc
26
+ files:
27
+ - HISTORY
28
+ - README
29
+ - dynamic_reports.gemspec
30
+ - lib/dynamic_reports.rb
31
+ - lib/dynamic_reports/charts.rb
32
+ - lib/dynamic_reports/reports.rb
33
+ - lib/dynamic_reports/templates.rb
34
+ - lib/dynamic_reports/vendor/google_chart.rb
35
+ - lib/dynamic_reports/vendor/google_chart/bar_chart.rb
36
+ - lib/dynamic_reports/vendor/google_chart/base.rb
37
+ - lib/dynamic_reports/vendor/google_chart/financial_line_chart.rb
38
+ - lib/dynamic_reports/vendor/google_chart/line_chart.rb
39
+ - lib/dynamic_reports/vendor/google_chart/pie_chart.rb
40
+ - lib/dynamic_reports/vendor/google_chart/scatter_chart.rb
41
+ - lib/dynamic_reports/vendor/google_chart/venn_diagram.rb
42
+ - lib/dynamic_reports/views.rb
43
+ - lib/dynamic_reports/views/default_layout.html.erb
44
+ - lib/dynamic_reports/views/default_report.html.erb
45
+ - lib/dynamic_reports/views/default_report.html.haml
46
+ - README.rdoc
47
+ has_rdoc: false
48
+ homepage: http://dynamicreports.rubyforge.org/
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --inline-source
52
+ - --charset=UTF-8
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project: dynamicreports
70
+ rubygems_version: 1.2.0
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Dynamic Ruby Reporting Engine with support for Charts
74
+ test_files:
75
+ - test/dynamic_reports/charts_test.rb
76
+ - test/dynamic_reports/reports_test.rb
77
+ - test/dynamic_reports/templates_test.rb
78
+ - test/dynamic_reports/views_test.rb
79
+ - test/dynamic_reports.rb
80
+ - test/factories/records.rb
81
+ - test/test_helper.rb