ruport 0.2.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +26 -0
- data/README +1 -1
- data/Rakefile +1 -1
- data/TODO +8 -3
- data/bin/ruport +5 -5
- data/lib/ruport/report/data_row.rb +67 -0
- data/lib/ruport/report/data_set.rb +104 -0
- data/lib/ruport/report/engine.rb +214 -0
- data/lib/ruport/report/fake_db.rb +54 -0
- data/lib/ruport/report/fake_engine.rb +46 -0
- data/lib/ruport/report/mailer.rb +46 -0
- data/lib/ruport/report/sql.rb +95 -0
- data/lib/ruportlib.rb +8 -7
- data/test/tc_data_row.rb +1 -1
- data/test/tc_data_set.rb +4 -4
- data/test/{tc_report.rb → tc_engine.rb} +3 -3
- data/test/ts_all.rb +1 -1
- metadata +10 -10
- data/lib/ruport/db/data_row.rb +0 -64
- data/lib/ruport/db/data_set.rb +0 -101
- data/lib/ruport/db/mailer.rb +0 -42
- data/lib/ruport/db/mock_db.rb +0 -49
- data/lib/ruport/db/mock_report.rb +0 -44
- data/lib/ruport/db/report.rb +0 -212
- data/lib/ruport/db/sql.rb +0 -93
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
# fake_db.rb
|
3
|
+
# Created by Gregory Thomas Brown on 2005-08-02
|
4
|
+
# Copyright 2005 (Gregory Brown) All rights reserved.
|
5
|
+
#
|
6
|
+
# This product is free software, you may distribute it as such
|
7
|
+
# under your choice of the Ruby license or the GNU GPL
|
8
|
+
# See LICENSE for details
|
9
|
+
|
10
|
+
module Ruport
|
11
|
+
module Report
|
12
|
+
class FakeDB
|
13
|
+
|
14
|
+
# Creates a new FakeDB e.g.
|
15
|
+
#
|
16
|
+
# FakeDB.new([ "ruport", "ruport_example",
|
17
|
+
# "localhost", "test", "123"] )
|
18
|
+
#
|
19
|
+
# Which would create a fake database ruport_example at
|
20
|
+
# localhost with the username test and the password 123
|
21
|
+
# using the driver 'ruport'
|
22
|
+
def initialize(args)
|
23
|
+
@db_driver, @db_name, @db_host, @username, @password = *args
|
24
|
+
@data = Hash.new
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Verifies account info and retrieves information
|
29
|
+
def process( dsn, user, password, query )
|
30
|
+
if ( dsn.eql?("#{@db_driver}:#{@db_name}:#{@db_host}") and
|
31
|
+
user.eql?(@username) and password.eql?(@password) )
|
32
|
+
@data[query]
|
33
|
+
else
|
34
|
+
throw "Processing Error"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Allows query to be looked up in the data
|
40
|
+
def [](query)
|
41
|
+
@data[query]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Used to setup fake queries E.g:
|
45
|
+
#
|
46
|
+
# DataSet#fake_db["SELECT * FROM address_book"] =
|
47
|
+
# DataSet.load("data/addressbook.csv")
|
48
|
+
def []=(query, contents)
|
49
|
+
@data[query] = contents
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
# fake_engine.rb
|
3
|
+
# Created by Gregory Thomas Brown on 2005-08-02
|
4
|
+
# Copyright 2005 (Gregory Brown) All rights reserved.
|
5
|
+
#
|
6
|
+
# This product is free software, you may distribute it as such
|
7
|
+
# under your choice of the Ruby license or the GNU GPL
|
8
|
+
# See LICENSE for details
|
9
|
+
|
10
|
+
module Ruport
|
11
|
+
module Report
|
12
|
+
class FakeEngine < Ruport::Report::Engine
|
13
|
+
|
14
|
+
attr_accessor :fake_db
|
15
|
+
|
16
|
+
def execute (query, source = :string)
|
17
|
+
query = get_query(source, query)
|
18
|
+
yield(@fake_db.process(@dsn,@user,@password, query))
|
19
|
+
end
|
20
|
+
|
21
|
+
def select( query, source = :string, &action )
|
22
|
+
source != :string || query = "SELECT " + query
|
23
|
+
execute( query, source ) do |table|
|
24
|
+
if table.kind_of?(DataSet)
|
25
|
+
@column_names = table.fields
|
26
|
+
else
|
27
|
+
@column_names = table[0].keys
|
28
|
+
end
|
29
|
+
@first_row = true
|
30
|
+
table.each do |row|
|
31
|
+
row = row.to_hash if table.kind_of?(DataSet)
|
32
|
+
action.call(row) if block_given?
|
33
|
+
@first_row = false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def query ( query, source = :string, &action)
|
39
|
+
execute( query, source ) do |table|
|
40
|
+
action.call(table)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# mailer.rb
|
2
|
+
# Created by Gregory Brown on 2005-08-16
|
3
|
+
# Copyright 2005 (Gregory Brown) All Rights Reserved.
|
4
|
+
# This product is free software, you may distribute it as such
|
5
|
+
# under your choice of the Ruby license or the GNU GPL
|
6
|
+
# See LICENSE for details
|
7
|
+
require "net/smtp"
|
8
|
+
module Ruport
|
9
|
+
module Report
|
10
|
+
class Mailer
|
11
|
+
|
12
|
+
# Creates a new Mailer object. User must specify their mail host, email
|
13
|
+
# address, and account. Password, port, and authentication method are all
|
14
|
+
# optional.
|
15
|
+
def initialize( host, address, account,
|
16
|
+
password=nil , port=25, authentication=nil )
|
17
|
+
@host = host
|
18
|
+
@account = account
|
19
|
+
@password = password
|
20
|
+
@address = address
|
21
|
+
@port = port
|
22
|
+
@auth = authentication
|
23
|
+
@recipients = []
|
24
|
+
@body = ""
|
25
|
+
end
|
26
|
+
|
27
|
+
#A list of email addresses to send the message to.
|
28
|
+
attr_accessor :recipients
|
29
|
+
|
30
|
+
#The body of the message to be sent
|
31
|
+
attr_accessor :body
|
32
|
+
|
33
|
+
# This takes _report_name_ as argument and sends the contents of @body to
|
34
|
+
# @recipients
|
35
|
+
def send_report(report_name="No Subject")
|
36
|
+
return if @body.empty?
|
37
|
+
Net::SMTP.start(@host,@port,@host,@account,@password,@auth) do |smtp|
|
38
|
+
smtp.send_message( "Subject: #{report_name}\n\n#{@body}",
|
39
|
+
@address,
|
40
|
+
@recipients )
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
# sql.rb:
|
3
|
+
# Generates queries from simple ruby syntax
|
4
|
+
#
|
5
|
+
# Created by Gregory Thomas Brown on 2005-08-02
|
6
|
+
# Copyright 2005 (Gregory Brown) All rights reserved.
|
7
|
+
#
|
8
|
+
# This product is free software, you may distribute it as such
|
9
|
+
# under your choice of the Ruby license or the GNU GPL
|
10
|
+
# See LICENSE for details
|
11
|
+
#
|
12
|
+
# Special thanks and acknowledgement go to James Edward Gray II
|
13
|
+
# for providing the original source code for this application
|
14
|
+
module Ruport
|
15
|
+
module Report
|
16
|
+
class SQL
|
17
|
+
|
18
|
+
# Generates an SQL object which can generate queries.
|
19
|
+
def initialize( statement, &init )
|
20
|
+
@statement = statement
|
21
|
+
|
22
|
+
@fields = Array.new
|
23
|
+
@tables = Array.new
|
24
|
+
@conditions = Array.new
|
25
|
+
@order_by = Array.new
|
26
|
+
|
27
|
+
instance_eval(&init) unless init.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
#Specifies the fields to select from
|
31
|
+
def columns( *fields )
|
32
|
+
fields.each { |field| @fields << "'#{field}'" }
|
33
|
+
end
|
34
|
+
|
35
|
+
#generates an FROM clause for the given tables
|
36
|
+
def from( *tables )
|
37
|
+
tables.each { |table| @tables << table }
|
38
|
+
end
|
39
|
+
|
40
|
+
# generates a conditional expression.
|
41
|
+
# condition :name, :LIKE, :jim -> "name LIKE 'jim'"
|
42
|
+
def condition( field, operator, match )
|
43
|
+
@conditions << "#{field} #{operator.to_s.upcase} '#{match}'"
|
44
|
+
end
|
45
|
+
|
46
|
+
# generates an ORDER BY clause for list +order+
|
47
|
+
def order( *order )
|
48
|
+
order.each { |table| @order_by << table }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Converts SQL object into a query string
|
52
|
+
def to_s
|
53
|
+
sql = "#{@statement} "
|
54
|
+
|
55
|
+
sql << if @fields.empty?
|
56
|
+
"* "
|
57
|
+
else
|
58
|
+
@fields.join(", ") + " "
|
59
|
+
end
|
60
|
+
|
61
|
+
sql << "FROM #{@tables.join(', ')} "
|
62
|
+
|
63
|
+
unless @conditions.empty?
|
64
|
+
sql << "WHERE #{@conditions.join(' AND ')} "
|
65
|
+
end
|
66
|
+
|
67
|
+
unless @order_by.empty?
|
68
|
+
sql << "ORDER BY #{@order_by.join(', ')} "
|
69
|
+
end
|
70
|
+
|
71
|
+
sql.sub!(/ \Z/, "")
|
72
|
+
sql << ";"
|
73
|
+
|
74
|
+
sql
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
class String
|
80
|
+
def with( other_table, field = nil )
|
81
|
+
if field.nil?
|
82
|
+
"#{self} NATURAL JOIN #{other_table}"
|
83
|
+
else
|
84
|
+
"#{self} LEFT JOIN #{other_table} " +
|
85
|
+
"ON #{self}.#{field} = #{other_table}.#{field}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Symbol
|
91
|
+
def with( other_table, field = nil )
|
92
|
+
to_s.with(other_table, field)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
data/lib/ruportlib.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
require "ruport/
|
2
|
-
require "ruport/
|
3
|
-
require "ruport/
|
4
|
-
require "ruport/
|
5
|
-
require "ruport/
|
6
|
-
require "ruport/
|
7
|
-
require "ruport/
|
1
|
+
require "ruport/report/engine"
|
2
|
+
require "ruport/report/mailer"
|
3
|
+
require "ruport/report/sql"
|
4
|
+
require "ruport/report/fake_db"
|
5
|
+
require "ruport/report/fake_engine"
|
6
|
+
require "ruport/report/data_set"
|
7
|
+
require "ruport/report/data_row"
|
8
|
+
include Ruport
|
data/test/tc_data_row.rb
CHANGED
data/test/tc_data_set.rb
CHANGED
@@ -5,7 +5,7 @@ require "ruportlib"
|
|
5
5
|
|
6
6
|
class TestDataSet < Test::Unit::TestCase
|
7
7
|
def setup
|
8
|
-
@data = DataSet.new
|
8
|
+
@data = Report::DataSet.new
|
9
9
|
@data.fields = %w[ col1 col2 col3 ]
|
10
10
|
@data.default = ""
|
11
11
|
@data << %w[ a b c ]
|
@@ -35,7 +35,7 @@ class TestDataSet < Test::Unit::TestCase
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_eql?
|
38
|
-
data2 = DataSet.new
|
38
|
+
data2 = Report::DataSet.new
|
39
39
|
data2.fields = %w[ col1 col2 col3 ]
|
40
40
|
data2.default = ""
|
41
41
|
data2 << %w[ a b c ]
|
@@ -54,12 +54,12 @@ class TestDataSet < Test::Unit::TestCase
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def test_load
|
57
|
-
loaded_data = DataSet.load("test/data.csv")
|
57
|
+
loaded_data = Report::DataSet.load("test/data.csv")
|
58
58
|
assert(@data.eql?(loaded_data))
|
59
59
|
end
|
60
60
|
|
61
61
|
def test_to_csv
|
62
|
-
loaded_data = DataSet.load("test/data.csv" )
|
62
|
+
loaded_data = Report::DataSet.load("test/data.csv" )
|
63
63
|
csv = loaded_data.to_csv
|
64
64
|
assert_equal("col1,col2,col3\na,b,c\nd,\"\",e\n",csv)
|
65
65
|
end
|
@@ -8,10 +8,10 @@ require "lib/ruportlib"
|
|
8
8
|
class TestRuport < Test::Unit::TestCase
|
9
9
|
|
10
10
|
def setup
|
11
|
-
@report =
|
11
|
+
@report = Report::FakeEngine.new( "DBI:mysql:ruport:localhost", "test", "123")
|
12
12
|
@report.query_table = "ruport_queries"
|
13
13
|
|
14
|
-
@report.fake_db =
|
14
|
+
@report.fake_db = Report::FakeDB.new([ "DBI:mysql","ruport",
|
15
15
|
"localhost", "test", "123"])
|
16
16
|
|
17
17
|
@report.fake_db["SELECT * FROM ruport_test"] = @data =
|
@@ -97,7 +97,7 @@ def test_sql
|
|
97
97
|
|
98
98
|
def test_query
|
99
99
|
@report.query("SELECT * FROM ruport_test") do |result|
|
100
|
-
|
100
|
+
assert_equal(@data,result)
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
data/test/ts_all.rb
CHANGED
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruport
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
7
|
-
date: 2005-11-
|
6
|
+
version: 0.2.2
|
7
|
+
date: 2005-11-11
|
8
8
|
summary: A generalized Ruby report generation and templating engine.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -28,17 +28,17 @@ authors:
|
|
28
28
|
- Gregory Brown
|
29
29
|
files:
|
30
30
|
- lib/ruportlib.rb
|
31
|
-
- lib/ruport/db/data_row.rb
|
32
|
-
- lib/ruport/db/data_set.rb
|
33
|
-
- lib/ruport/db/mailer.rb
|
34
|
-
- lib/ruport/db/mock_db.rb
|
35
|
-
- lib/ruport/db/mock_report.rb
|
36
|
-
- lib/ruport/db/report.rb
|
37
|
-
- lib/ruport/db/sql.rb
|
38
31
|
- lib/ruport/format/chart.rb
|
32
|
+
- lib/ruport/report/data_row.rb
|
33
|
+
- lib/ruport/report/data_set.rb
|
34
|
+
- lib/ruport/report/engine.rb
|
35
|
+
- lib/ruport/report/fake_db.rb
|
36
|
+
- lib/ruport/report/fake_engine.rb
|
37
|
+
- lib/ruport/report/mailer.rb
|
38
|
+
- lib/ruport/report/sql.rb
|
39
39
|
- test/tc_data_row.rb
|
40
40
|
- test/tc_data_set.rb
|
41
|
-
- test/
|
41
|
+
- test/tc_engine.rb
|
42
42
|
- test/ts_all.rb
|
43
43
|
- Rakefile
|
44
44
|
- README
|
data/lib/ruport/db/data_row.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
#!/usr/local/bin/ruby
|
2
|
-
# data_row.rb
|
3
|
-
# Created by Gregory Thomas Brown on 2005-08-02
|
4
|
-
# Copyright 2005 (Gregory Brown) All rights reserved.
|
5
|
-
#
|
6
|
-
# This product is free software, you may distribute it as such
|
7
|
-
# under your choice of the Ruby license or the GNU GPL
|
8
|
-
# See LICENSE for details
|
9
|
-
|
10
|
-
|
11
|
-
class DataRow
|
12
|
-
|
13
|
-
attr_accessor :fields
|
14
|
-
|
15
|
-
|
16
|
-
# DataRows are essentially arrays with named ordinal fields and awareness of
|
17
|
-
# their oddness and position.
|
18
|
-
def initialize( data, fields, oddness=nil, position=nil )
|
19
|
-
@data = data
|
20
|
-
@fields = fields
|
21
|
-
@oddness = oddness
|
22
|
-
@position = position
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
# Lets you access individual fields
|
27
|
-
#
|
28
|
-
# i.e. row["phone"]
|
29
|
-
def [](key)
|
30
|
-
key.kind_of?(String) ? @data[@fields.index(key)] : @data[key]
|
31
|
-
end
|
32
|
-
|
33
|
-
# Lets you set field values
|
34
|
-
#
|
35
|
-
# i.e. row["phone"] = '2038291203'
|
36
|
-
def []=(key,value)
|
37
|
-
key.kind_of?(String) ? @data[@fields.index(key)] = value :
|
38
|
-
@data[key] = value
|
39
|
-
end
|
40
|
-
|
41
|
-
# Converts the DataRow to a plain old Array
|
42
|
-
def to_a
|
43
|
-
@data
|
44
|
-
end
|
45
|
-
|
46
|
-
# Converts the DataRow to a string representation for outputting to screen.
|
47
|
-
def to_s
|
48
|
-
"[" + @data.join(",") + "]"
|
49
|
-
end
|
50
|
-
|
51
|
-
# implements
|
52
|
-
# DataRow#first? DataRow#last? DataRow#middle? DataRow#odd? DataRow#even?
|
53
|
-
# which are all conditional methods.
|
54
|
-
def method_missing(method)
|
55
|
-
if %[last? first? middle?].include? method.to_s
|
56
|
-
return @position.eql?(method.to_s[0..-2].to_sym)
|
57
|
-
elsif %[odd? even?].include? method.to_s
|
58
|
-
return @oddness.eql?(method.to_s[0..-2].to_sym)
|
59
|
-
end
|
60
|
-
super
|
61
|
-
end
|
62
|
-
|
63
|
-
attr_accessor :position
|
64
|
-
end
|
data/lib/ruport/db/data_set.rb
DELETED
@@ -1,101 +0,0 @@
|
|
1
|
-
#!/usr/local/bin/ruby
|
2
|
-
# data_set.rb
|
3
|
-
# Created by Gregory Thomas Brown on 2005-08-02
|
4
|
-
# Copyright 2005 (Gregory Brown) All rights reserved.
|
5
|
-
#
|
6
|
-
# This product is free software, you may distribute it as such
|
7
|
-
# under your choice of the Ruby license or the GNU GPL
|
8
|
-
# See LICENSE for details
|
9
|
-
|
10
|
-
class DataSet
|
11
|
-
def initialize
|
12
|
-
@data = []
|
13
|
-
end
|
14
|
-
|
15
|
-
#fields are the column names, default is the default cell value
|
16
|
-
attr_accessor :fields, :default
|
17
|
-
|
18
|
-
#data is the core Array that holds all the rows
|
19
|
-
attr_reader :data
|
20
|
-
|
21
|
-
|
22
|
-
#Allows ordinal access to rows
|
23
|
-
def [](index)
|
24
|
-
@data[index]
|
25
|
-
end
|
26
|
-
|
27
|
-
#allows setting of rows (providing a DataRow is passed in)
|
28
|
-
def []=(index,value)
|
29
|
-
throw "Invalid object type" unless value.kind_of?(DataRow)
|
30
|
-
@data[index] = value
|
31
|
-
end
|
32
|
-
|
33
|
-
# appends a row to the DataSet
|
34
|
-
# can be added as an array or a keyed hash.
|
35
|
-
# i.e if our DataSet have @fields = [:a, :b, :c]
|
36
|
-
# data << [ 1, 2, 3] and data << { :a => 1, :b => 2, :c => 3 }
|
37
|
-
# are equivalent.
|
38
|
-
def << ( stuff )
|
39
|
-
new_row = Array.new
|
40
|
-
fields.each_with_index do |key, index|
|
41
|
-
if stuff.kind_of?(Array)
|
42
|
-
new_row[index] = stuff.shift || @default
|
43
|
-
else
|
44
|
-
new_row[index] = stuff[key] || @default
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
oddness = (@data.length % 2 == 0 ? :even : :odd)
|
49
|
-
position = (@data.length == 0 ? :first : :last)
|
50
|
-
@data[@data.length - 1].position = :middle if @data.length > 1
|
51
|
-
@data << DataRow.new(new_row,@fields,oddness,position)
|
52
|
-
end
|
53
|
-
|
54
|
-
# This works in best case scenario. It should return true if both DataSets
|
55
|
-
# have the same values. Still working out the kinks here.
|
56
|
-
def eql?(data2)
|
57
|
-
return false unless (@data.length == data2.data.length)
|
58
|
-
0.upto(@data.length - 1) do |index|
|
59
|
-
(@fields + data2.fields).uniq.each do |key|
|
60
|
-
return false unless @data[index][key] == data2[index][key]
|
61
|
-
end
|
62
|
-
end
|
63
|
-
return true
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
# Allows loading of CSV files or YAML dumps. Returns a DataSet
|
68
|
-
def self.load ( source, default="")
|
69
|
-
|
70
|
-
return YAML.load(File.open(source)) if source =~ /\.(yaml|yml)/
|
71
|
-
|
72
|
-
input = CSV.read(source) if source =~ /\.csv/
|
73
|
-
loaded_data = self.new
|
74
|
-
loaded_data.fields = input[0]
|
75
|
-
loaded_data.default = default
|
76
|
-
input[1..-1].each do |row|
|
77
|
-
loaded_data << row
|
78
|
-
end
|
79
|
-
return loaded_data
|
80
|
-
end
|
81
|
-
|
82
|
-
# Converts a DataSet to CSV
|
83
|
-
def to_csv
|
84
|
-
output = CSV.generate_line(@fields) + "\n"
|
85
|
-
@data.each do |row|
|
86
|
-
output << CSV.generate_line(@fields.map { |f| row[f] }) + "\n"
|
87
|
-
end
|
88
|
-
return output
|
89
|
-
end
|
90
|
-
|
91
|
-
# Works like a standard each iterator
|
92
|
-
def each(&action)
|
93
|
-
@data[0..-1].each(&action)
|
94
|
-
end
|
95
|
-
|
96
|
-
# Works like a standard each_with_index iterator
|
97
|
-
def each_with_index(&action)
|
98
|
-
@data[0..-1].each_with_index(&action)
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|