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
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
|
-
|