ruport 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|