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
data/lib/ruport/db/mailer.rb
DELETED
@@ -1,42 +0,0 @@
|
|
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
|
-
|
8
|
-
require "net/smtp"
|
9
|
-
class Mailer
|
10
|
-
|
11
|
-
# Creates a new Mailer object. User must specify their mail host, email
|
12
|
-
# address, and account. Password, port, and authentication method are all
|
13
|
-
# optional.
|
14
|
-
def initialize(host, address, account, password=nil, port=25, authentication=nil)
|
15
|
-
@host = host
|
16
|
-
@account = account
|
17
|
-
@password = password
|
18
|
-
@address = address
|
19
|
-
@port = port
|
20
|
-
@auth = authentication
|
21
|
-
@recipients = []
|
22
|
-
@body = ""
|
23
|
-
end
|
24
|
-
|
25
|
-
#A list of email addresses to send the message to.
|
26
|
-
attr_accessor :recipients
|
27
|
-
|
28
|
-
#The body of the message to be sent
|
29
|
-
attr_accessor :body
|
30
|
-
|
31
|
-
# This takes _report_name_ as argument and sends the contents of @body to
|
32
|
-
# @recipients
|
33
|
-
def send_report(report_name="No Subject")
|
34
|
-
return if @body.empty?
|
35
|
-
Net::SMTP.start(@host,@port,@host,@account,@password,@auth) do |smtp|
|
36
|
-
smtp.send_message( "Subject: #{report_name}\n\n#{@body}",
|
37
|
-
@address,
|
38
|
-
@recipients )
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
data/lib/ruport/db/mock_db.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
#!/usr/local/bin/ruby
|
2
|
-
# mock_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
|
-
class MockDB
|
11
|
-
# Creates a new MockDB e.g.
|
12
|
-
#
|
13
|
-
# MockDB.new([ "ruport", "ruport_example",
|
14
|
-
# "localhost", "test", "123"] )
|
15
|
-
#
|
16
|
-
# Which would create a fake database ruport_example at localhost with the
|
17
|
-
# username test and the password 123 using the driver 'ruport'
|
18
|
-
|
19
|
-
def initialize(args)
|
20
|
-
@db_driver, @db_name, @db_host, @username, @password = *args
|
21
|
-
@data = Hash.new
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
# Verifies account info and retrieves information
|
26
|
-
def process( dsn, user, password, query )
|
27
|
-
if ( dsn.eql?("#{@db_driver}:#{@db_name}:#{@db_host}") and
|
28
|
-
user.eql?(@username) and password.eql?(@password) )
|
29
|
-
@data[query]
|
30
|
-
else
|
31
|
-
throw "Processing Error"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
# Allows query to be looked up in the data
|
37
|
-
def [](query)
|
38
|
-
@data[query]
|
39
|
-
end
|
40
|
-
|
41
|
-
# Used to setup fake queries E.g:
|
42
|
-
#
|
43
|
-
# self.fake_db["SELECT * FROM address_book"] =
|
44
|
-
# DataSet.load("data/addressbook.csv")
|
45
|
-
def []=(query, contents)
|
46
|
-
@data[query] = contents
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
#!/usr/local/bin/ruby
|
2
|
-
# mock_report.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 MockReport < Report
|
11
|
-
|
12
|
-
attr_accessor :fake_db
|
13
|
-
|
14
|
-
def execute (query, source = :string)
|
15
|
-
query = get_query(source, query)
|
16
|
-
yield(@fake_db.process(@dsn,@user,@password, query))
|
17
|
-
end
|
18
|
-
|
19
|
-
def select( query, source = :string, &action )
|
20
|
-
source != :string || query = "SELECT " + query
|
21
|
-
execute( query, source ) do |table|
|
22
|
-
if table.kind_of?(DataSet)
|
23
|
-
@column_names = table.fields
|
24
|
-
else
|
25
|
-
@column_names = table[0].keys
|
26
|
-
end
|
27
|
-
@first_row = true
|
28
|
-
table.each do |row|
|
29
|
-
row = row.to_hash if table.kind_of?(DataSet)
|
30
|
-
action.call(row) if block_given?
|
31
|
-
@first_row = false
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def query ( query, source = :string, &action)
|
37
|
-
execute( query, source ) do |table|
|
38
|
-
action.call(table)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
|
data/lib/ruport/db/report.rb
DELETED
@@ -1,212 +0,0 @@
|
|
1
|
-
#!/usr/local/bin/ruby
|
2
|
-
# report.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
|
-
# Special thanks and acknowledgement go to James Edward Gray II
|
11
|
-
# for providing the original source code for this application
|
12
|
-
require "dbi"
|
13
|
-
require "rubygems"
|
14
|
-
require "erb"
|
15
|
-
require "csv"
|
16
|
-
require "yaml"
|
17
|
-
require "date"
|
18
|
-
require "logger"
|
19
|
-
require "fileutils"
|
20
|
-
class Report
|
21
|
-
def initialize( dsn, user, password, mailer=nil )
|
22
|
-
@dsn = dsn
|
23
|
-
@user = user
|
24
|
-
@password = password
|
25
|
-
@report_name = ""
|
26
|
-
@mailer = mailer
|
27
|
-
File.exists?("log") or FileUtils.mkdir("log")
|
28
|
-
@logger = Logger.new("log/ruport.log")
|
29
|
-
@generate = true
|
30
|
-
@report = ""
|
31
|
-
end
|
32
|
-
|
33
|
-
attr_accessor :query_table, :file
|
34
|
-
attr_reader :mailer, :generate, :config, :logger
|
35
|
-
|
36
|
-
# * DEPRECATED: Use query() *
|
37
|
-
#
|
38
|
-
# Takes a query, an optional sourcetype, and a block which is passed the
|
39
|
-
# results row by row. When passed a query in string form, it adds the
|
40
|
-
# SELECT clause to the string and executes the query. When passed a
|
41
|
-
# filename and a source :file, it looks in queries/ for the file specified.
|
42
|
-
# When given a database query label, it looks in config[query_table] for a
|
43
|
-
# query with the label specified. If no source is specified, it uses
|
44
|
-
# string by default for the source.
|
45
|
-
#
|
46
|
-
# Example:
|
47
|
-
#
|
48
|
-
# select ( "* FROM test" )
|
49
|
-
# Passes "SELECT * FROM test" to the database
|
50
|
-
#
|
51
|
-
# select ( "test.sql", :file )
|
52
|
-
# Passes the contents of queries/test.sql to the database
|
53
|
-
#
|
54
|
-
# select ( "TEST", :db )
|
55
|
-
# Calls the query TEST stored in the database and query_table specified in
|
56
|
-
# config/ruport.yaml
|
57
|
-
|
58
|
-
def select( query, source = :string, &action )
|
59
|
-
source != :string || query = "SELECT " + query
|
60
|
-
execute( query, source ) do |sth|
|
61
|
-
@column_names = sth.column_names
|
62
|
-
@first_row = true
|
63
|
-
sth.fetch do |row|
|
64
|
-
action.call(row) if block_given?
|
65
|
-
@first_row = false
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# * DEPRECATED, Use query() *
|
71
|
-
#
|
72
|
-
# Takes a query and an optional sourcetype and then runs the query
|
73
|
-
# against the database. The output is not returned. This is useful for
|
74
|
-
# doing construction and destruction actions.
|
75
|
-
def execute( query, source = :string )
|
76
|
-
query = get_query(source, query)
|
77
|
-
DBI.connect(@dsn, @user, @password) do |dbh|
|
78
|
-
dbh.prepare(query) do |sth|
|
79
|
-
sth.execute()
|
80
|
-
yield(sth)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Takes a query and an optional sourcetype and then runs the query against the
|
86
|
-
# database. The return from the query is then converted into a DataSet which
|
87
|
-
# can then be manipulated.
|
88
|
-
#
|
89
|
-
# Example:
|
90
|
-
# query("SELECT * FROM address_book") do |data|
|
91
|
-
# @report << data.to_csv
|
92
|
-
# end
|
93
|
-
#
|
94
|
-
# The above would select all from the _address_book_ table and then convert
|
95
|
-
# the DataSet to a csv and then add it to the report
|
96
|
-
|
97
|
-
def query ( statement, source = :string, &action )
|
98
|
-
query_text = get_query(source,statement)
|
99
|
-
DBI.connect(@dsn, @user, @password) do |dbh|
|
100
|
-
data = DataSet.new
|
101
|
-
sth = dbh.execute(query_text)
|
102
|
-
if block_given?
|
103
|
-
data.fields = sth.column_names
|
104
|
-
sth.each { |row| data << row }
|
105
|
-
action.call(data)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# Evaluates _code_ from _filename_ as pure ruby code for files ending in
|
111
|
-
# .rb, and as ERb templates for anything else.
|
112
|
-
def eval_report( filename, code )
|
113
|
-
if filename =~ /\.rb/
|
114
|
-
eval(code)
|
115
|
-
else
|
116
|
-
ERB.new(code, 0, "%").run(binding)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# Loads a yaml file into the @config variable which is accessible in
|
121
|
-
# templates. If _interactive_ is set to true, the user will be prompted to
|
122
|
-
# enter information for each key.
|
123
|
-
def load_yaml(file, interactive=false)
|
124
|
-
file = "config/#{file}" unless File.exists? file
|
125
|
-
@config = YAML.load(File.open(file))
|
126
|
-
if (interactive)
|
127
|
-
@config.keys.map { |c| c.to_s }.sort.each do |property|
|
128
|
-
$stderr.print "#{property} (#{@config[property.to_sym]}): "
|
129
|
-
entered = $stdin.gets.strip
|
130
|
-
@config[property] = entered unless entered.eql?("")
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
# Creates an SQL Object. The block is evaluated within the SQL instance so
|
136
|
-
# you may use any methods available to the SQL class. The generated query is
|
137
|
-
# returned.
|
138
|
-
#
|
139
|
-
# Example
|
140
|
-
# fetch { from :address_book order :name }
|
141
|
-
# => "SELECT * FROM address_book ORDER BY name
|
142
|
-
|
143
|
-
def fetch( &dsl )
|
144
|
-
begin
|
145
|
-
SQL.new(:SELECT, &dsl).to_s
|
146
|
-
rescue Exception
|
147
|
-
@logger.fatal "Error generating SQL."
|
148
|
-
raise "Error generating SQL."
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# Returns the query string for queries of type string, file, or db
|
153
|
-
def get_query(type,query)
|
154
|
-
case (type)
|
155
|
-
when :string
|
156
|
-
query
|
157
|
-
when :file
|
158
|
-
load_file( query )
|
159
|
-
when :db
|
160
|
-
select ( "query FROM #{@query_table} WHERE " +
|
161
|
-
"label LIKE '#{query}';" ) do |row| return row["query"] end
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
# Loads a query from file. Accepts absolute paths, relative paths from
|
166
|
-
# the toplevel directory, and relative paths from _queries/_.
|
167
|
-
# If you've been putting all your database queries in _queries_, you can
|
168
|
-
# just call them by name.
|
169
|
-
def load_file( query_file )
|
170
|
-
begin
|
171
|
-
File.read( query_file ).strip
|
172
|
-
rescue
|
173
|
-
@logger.fatal "Could not open #{query_file}"
|
174
|
-
raise "Could not open #{query_file}"; exit
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
# Generates the report. If @pre or @post are defined with lambdas, they will
|
179
|
-
# be called before and after the main code. generate_report will
|
180
|
-
# automatically be run at the end of the execution of a ruport template unless
|
181
|
-
# @generate is set to false.
|
182
|
-
#
|
183
|
-
#If @file != nil, ruport will print to the
|
184
|
-
# file with the specified name. Otherwise, it will print to STDOUT by
|
185
|
-
# default. @file can be set implictly by a file argument, i.e.
|
186
|
-
# ruport templates/foo.rb reports/foo_out.html => @file =
|
187
|
-
# 'reports/foo_out.html' It can also be set explicitly within a template. A
|
188
|
-
# good way to define a default value is @file ||= "reports/somefile"
|
189
|
-
#
|
190
|
-
# Lastly, if you have your mailer configuration set up and you've specified
|
191
|
-
# recipients, the contents of @mailer.body will be automatically emailed by
|
192
|
-
# this fuction.
|
193
|
-
#
|
194
|
-
# I am aware of the fact that this function is a bear. It will be cleaned up
|
195
|
-
# in future releases
|
196
|
-
|
197
|
-
def generate_report
|
198
|
-
@pre.call if @pre
|
199
|
-
if (@file.nil?)
|
200
|
-
puts(@report)
|
201
|
-
else
|
202
|
-
File.open(@file,"w") { |f| f.puts @report }
|
203
|
-
end
|
204
|
-
unless @mailer.nil? || @mailer.recipients.empty?
|
205
|
-
@mailer.body = @report unless not @mailer.body.empty?
|
206
|
-
@mailer.send_report(@report_name)
|
207
|
-
end
|
208
|
-
@post.call if @post
|
209
|
-
end
|
210
|
-
|
211
|
-
end
|
212
|
-
|
data/lib/ruport/db/sql.rb
DELETED
@@ -1,93 +0,0 @@
|
|
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
|
-
class SQL
|
15
|
-
|
16
|
-
# Generates an SQL object which can generate queries.
|
17
|
-
def initialize( statement, &init )
|
18
|
-
@statement = statement
|
19
|
-
|
20
|
-
@fields = Array.new
|
21
|
-
@tables = Array.new
|
22
|
-
@conditions = Array.new
|
23
|
-
@order_by = Array.new
|
24
|
-
|
25
|
-
instance_eval(&init) unless init.nil?
|
26
|
-
end
|
27
|
-
|
28
|
-
#Specifies the fields to select from
|
29
|
-
def columns( *fields )
|
30
|
-
fields.each { |field| @fields << "'#{field}'" }
|
31
|
-
end
|
32
|
-
|
33
|
-
#generates an FROM clause for the given tables
|
34
|
-
def from( *tables )
|
35
|
-
tables.each { |table| @tables << table }
|
36
|
-
end
|
37
|
-
|
38
|
-
# generates a conditional expression.
|
39
|
-
# condition :name, :LIKE, :jim -> "name LIKE 'jim'"
|
40
|
-
def condition( field, operator, match )
|
41
|
-
@conditions << "#{field} #{operator.to_s.upcase} '#{match}'"
|
42
|
-
end
|
43
|
-
|
44
|
-
# generates an ORDER BY clause for list +order+
|
45
|
-
def order( *order )
|
46
|
-
order.each { |table| @order_by << table }
|
47
|
-
end
|
48
|
-
|
49
|
-
# Converts SQL object into a query string
|
50
|
-
def to_s
|
51
|
-
sql = "#{@statement} "
|
52
|
-
|
53
|
-
sql << if @fields.empty?
|
54
|
-
"* "
|
55
|
-
else
|
56
|
-
@fields.join(", ") + " "
|
57
|
-
end
|
58
|
-
|
59
|
-
sql << "FROM #{@tables.join(', ')} "
|
60
|
-
|
61
|
-
unless @conditions.empty?
|
62
|
-
sql << "WHERE #{@conditions.join(' AND ')} "
|
63
|
-
end
|
64
|
-
|
65
|
-
unless @order_by.empty?
|
66
|
-
sql << "ORDER BY #{@order_by.join(', ')} "
|
67
|
-
end
|
68
|
-
|
69
|
-
sql.sub!(/ \Z/, "")
|
70
|
-
sql << ";"
|
71
|
-
|
72
|
-
sql
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
class String
|
77
|
-
def with( other_table, field = nil )
|
78
|
-
if field.nil?
|
79
|
-
"#{self} NATURAL JOIN #{other_table}"
|
80
|
-
else
|
81
|
-
"#{self} LEFT JOIN #{other_table} " +
|
82
|
-
"ON #{self}.#{field} = #{other_table}.#{field}"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
class Symbol
|
88
|
-
def with( other_table, field = nil )
|
89
|
-
to_s.with(other_table, field)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
|