ruport 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (12) hide show
  1. data/LICENSE +7 -0
  2. data/README +69 -0
  3. data/Rakefile +51 -0
  4. data/TODO +106 -0
  5. data/bin/ruport +86 -0
  6. data/bin/ruport.rb +4 -0
  7. data/lib/mailer.rb +44 -0
  8. data/lib/query.rb +140 -0
  9. data/lib/sql.rb +93 -0
  10. data/setup.rb +1360 -0
  11. data/tests/tc_ruport.rb +69 -0
  12. metadata +65 -0
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ = License Terms
2
+
3
+ Distributed under the user's choice of the GPL[http://www.gnu.org/copyleft/gpl.html] (see COPYING for details) or the
4
+ {Ruby software license}[http://www.ruby-lang.org/en/LICENSE.txt] by Gregory Brown.
5
+
6
+ Please email Greg[mailto:gregory.t.brown_AT_gmail.com] with any questions.
7
+
data/README ADDED
@@ -0,0 +1,69 @@
1
+ Thank you for taking the time to download Ruby Reports. (Ruport)
2
+
3
+ This software is a powerful report generation engine that allows users to generate custom ERb templates and easily query various forms of SQL databases via DBI.It provides helper methods and utilities to generate professional reports quickly and cleanly.
4
+
5
+ It is also alpha software, so if it offends your mother, burns out the innards
6
+ of your computer, or threatens you in any other way, you may want to wait until
7
+ further releases to play around with it.
8
+
9
+ There is a user's manual for this application available at http://ruport.rubyforge.org/ruport_manual.pdf which I strongly recommend reading.
10
+
11
+ Otherwise, here is a brief set of installation and setup instructions which will
12
+ hopefully get you going:
13
+
14
+ Ruport itself is very easy to install. However, you will need to install some
15
+ dependencies which the system relies on. The most important of these
16
+ (and unfortunately the most complex to install) is the Ruby/DBI library.
17
+ Because this library has many possible installation instructions depending on
18
+ your database and operating system setup, I will not go into the instructions
19
+ in detail here. However, it essentially boils down to finding your database
20
+ software in the list of drivers on http://ruby-dbi.sourceforge.net/ and
21
+ downloading and installing the driver. Once this is complete, you download and install DBI using the instructions at the aformentioned link. We have
22
+ successfully installed RubyDBI with a MySQL driver on Gentoo Linux and Mac OS X.
23
+ We have also successfully installed RubyDBI on Windows using ODBC.
24
+ If you are running a similar setup, feel free to email gregory.t.brown@gmail.comwith any questions. If you successfully install Ruby/DBI on another system /
25
+ database combination, we'd love to hear how you did it so that we can improve
26
+ this documentation for the next version of Ruport. Once you've got DBI
27
+ installed, the Ruport installation is a piece of cake.
28
+
29
+ Ruport is a gem. It relies on Parse/Input (which will be linked to Ruport
30
+ in future releases) but this can easily be installed using the
31
+ --include-dependencies flag. Make sure you have adequete permissions and run:
32
+
33
+ sudo gem install ruport --include-dependencies
34
+
35
+ on Linux, OS X, and other Unix like systems.
36
+
37
+ On Windows, ensure that you have adequete permission to install
38
+ software and run:
39
+
40
+ gem install ruport --include-dependencies
41
+
42
+ With any luck, Ruport is now installed and you are ready to move on to
43
+ setting up and configuring a sandbox.
44
+
45
+ To check to see if the ruport executable has been added to you path and is
46
+ working in at least minimal capacity, type ruport -v at the command prompt.
47
+
48
+ If you see something like this:
49
+
50
+ Ruport Version 0.1.0 ...
51
+
52
+ then Ruport is at least installed and running.
53
+
54
+ If you get an error instead, feel free to email me,
55
+ but please include the error message.
56
+
57
+ To generate a sandbox, type ruport generate sandbox_name.
58
+ This will dump a directory structure for you to start with.
59
+
60
+ You'll need to edit config/ruport.yaml to get things up and running, and at this
61
+ point, unless you're magic, you'll probably need to either read the
62
+ {manual}[http://ruport.rubyforge.org/ruport_manual.pdf] or the source, whichever
63
+ you're most comfortable with.
64
+
65
+ I hope you enjoy this software and that it is useful to you.
66
+
67
+ -Greg
68
+
69
+ gregory.t.brown@gmail.com
@@ -0,0 +1,51 @@
1
+ require "rake/rdoctask"
2
+ require "rake/testtask"
3
+ require "rake/gempackagetask"
4
+
5
+ require "rubygems"
6
+
7
+ task :default => [:test]
8
+
9
+ Rake::TestTask.new do |test|
10
+ test.libs << "test"
11
+ test.test_files = [ "tests/tc_ruport.rb" ]
12
+ test.verbose = true
13
+ end
14
+
15
+ spec = Gem::Specification.new do |spec|
16
+ spec.name = "ruport"
17
+ spec.version = "0.1.0"
18
+ spec.platform = Gem::Platform::RUBY
19
+ spec.summary = "A generalized Ruby report generation and templating engine."
20
+
21
+ spec.files = Dir.glob("{bin,lib,tests}/**/*.rb").
22
+ delete_if { |item| item.include?("CVS") } +
23
+ ["Rakefile", "setup.rb"]
24
+ spec.require_path = "lib"
25
+ spec.bindir = "bin"
26
+ spec.executables << "ruport" << "ruport.rb"
27
+
28
+ spec.has_rdoc = true
29
+ spec.extra_rdoc_files = %w{README LICENSE TODO}
30
+ spec.rdoc_options << '--title' << 'Ruport Documentation' <<
31
+ '--main' << 'README'
32
+
33
+ spec.add_dependency("parseinput", ">= 0.0.1")
34
+
35
+ spec.author = "Gregory Brown"
36
+ spec.email = " gregory.t.brown@gmail.com"
37
+ spec.rubyforge_project = "ruport"
38
+ spec.homepage = "http://ruport.rubyforge.org"
39
+ spec.description = <<END_DESC
40
+ Ruport is a powerful report generation engine that allows users to generate
41
+ custom ERb templates and easily query various forms of SQL databases via DBI.
42
+ It provides helper methods and utilities to generate professional reports
43
+ quickly and cleanly.
44
+ END_DESC
45
+ end
46
+
47
+ Rake::GemPackageTask.new(spec) do |pkg|
48
+ pkg.need_zip = true
49
+ pkg.need_tar = true
50
+ end
51
+
data/TODO ADDED
@@ -0,0 +1,106 @@
1
+ TODO:
2
+
3
+ Take the following features and stabilize them for Ruport 0.2.0:
4
+
5
+ - Mail system
6
+
7
+ Hook up unit tests and solidify system
8
+
9
+ - Template Config / Line Editing
10
+
11
+ Find a way to accept piped in values
12
+ Hook up unit tests.
13
+
14
+ - Queries Table System
15
+
16
+ Write a cross-database table creation script
17
+ Hook up unit tests.
18
+
19
+ - SQL builder
20
+
21
+ Expand so that it covers most common SQL commands.
22
+ Form better more complete unit tests.
23
+
24
+
25
+ Begin implementing new features:
26
+
27
+ Multiple query reports:
28
+
29
+ Allow the user to make arbitrary SQL queries,
30
+ combining the rows, and then iterating through them row by row in the
31
+ order specified.
32
+
33
+ This could be done with select taking an array of queries and possibly
34
+ some ordering instructions
35
+
36
+ Cross database import from file:
37
+
38
+ Make an import(file,table,delimiter=",") command that will work
39
+ regardless of database choice and import the data stored in a file into
40
+ a specified table.
41
+
42
+ YAML dump / restore:
43
+
44
+ Make a nice way to dump the results of a query to a yaml file,
45
+ potentially to be read back in and reconstructed by another ruport
46
+ template. This would require splitting the formatting and data feeder
47
+ functionality, but would allow a user to simply load in a YAML file and
48
+ apply arbitrary formatting.
49
+
50
+ Parse/Input tight integration:
51
+
52
+ Write wrapper functions over the Parse/Input library to give Ruport the
53
+ power to feed in any data source such as a CSV, A website, or a log file
54
+ and do formatting and use the other features of Ruport.
55
+
56
+ PDF::Writer and CSV convenience methods:
57
+
58
+ Create functions that will allow basic and common reports to be built
59
+ using PDF and CSV format without having to write the functionality over
60
+ and over again. This would be especially useful for just dumping a
61
+ table's values in a certain order with some fields removed.
62
+
63
+ Logger / Exception handler:
64
+
65
+ Create a system to handle and log errors as well as provide log messages
66
+ regarding what Ruport does when a template is run.
67
+
68
+
69
+ Design considerations:
70
+
71
+ Ruport will eventually need to be cleanly seperating between formatting
72
+ tools and data feeders. This will likely happen in an early release, if not
73
+ the next than the one after.
74
+
75
+ Ruport trys to use a lot of 'intelligent' defaults but it might try to be
76
+ too clever in some places making it not clever at all. The community
77
+ reaction will determine what places may need opening up more or need more
78
+ consideration for the defaults.
79
+
80
+ "Fix the lame hack that installs two executables" (James Edward Gray II)
81
+
82
+
83
+ Other:
84
+
85
+ A full set of examples should be made available for download.
86
+
87
+ A quick reference page for templates and/or tutorial would be A Good Thing
88
+
89
+ The RDOC sucks!
90
+
91
+ The unit tests need to be wired so that they can actually run without a ton
92
+ of additional steps, they need to be expanded to cover the whole system, and
93
+ they need to work in the Gem package as well as the source package.
94
+
95
+ Ruport needs to be modified to support as many databases as possibly
96
+ internally. The system was written with Linux/MySQL and Windows/MS SQL
97
+ (ODBC) in mind. This will change when feedback from the community is
98
+ recieved.
99
+
100
+
101
+ This is only the tip of the iceburg. Please feel free to continue to fill my
102
+ plate by sending any suggestions to gregory.t.brown@gmail.com
103
+
104
+
105
+
106
+
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env ruby
2
+ # ruport.rb : A Ruby Reporting system.
3
+ #
4
+ # Created by Gregory Thomas Brown on 2005-08-02
5
+ # Copyright (c) 2005 Gregory Brown, Stone Code Productions
6
+ # 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
+
15
+ require "rubygems"
16
+ require "query"
17
+ require "mailer"
18
+ require "ftools"
19
+
20
+ if ARGV[0].eql?("generate")
21
+ if ARGV[1].nil?
22
+ puts "You must specify a name for your ruport sandbox"
23
+ exit
24
+ end
25
+ Dir.mkdir(ARGV[1])
26
+ Dir.mkdir("#{ARGV[1]}/reports")
27
+ Dir.mkdir("#{ARGV[1]}/templates")
28
+ Dir.mkdir("#{ARGV[1]}/config")
29
+ Dir.mkdir("#{ARGV[1]}/queries")
30
+ conf = ":driver: 'DBI:mysql'\n"+
31
+ ":database: test\n"+
32
+ ":db_user:\n:db_password:\n:mail_host:\n:mail_account:\n"+
33
+ ":mail_password:\n:mail_address:\n:mail_authentication:\n"+
34
+ ":query_table: ruport_queries"
35
+
36
+ File.open("#{ARGV[1]}/config/ruport.yaml", "w") { |f| f.puts(conf) }
37
+ File.open("#{ARGV[1]}/templates/test.rb", "w") { |f|
38
+ f.puts 'select "database()" do |r| puts r end'
39
+ }
40
+ exit
41
+ elsif ARGV[0].eql?("-v")
42
+ puts "Ruport Version 0.1.0 \nA ruby report generation system by Gregory " +
43
+ "Brown.\nThis application is Free Software under the GPL/Ruby License. " +
44
+ "\nAll praise and/or criticism can be directed to "+
45
+ "gregory.t.brown@gmail.com"
46
+ exit
47
+ end
48
+ config = YAML.load(File.open("config/ruport.yaml"))
49
+ mailer = nil
50
+
51
+ if config.has_key?(:mail_host)
52
+ mailer = Mailer.new( config[:mail_host],
53
+ config[:mail_address],
54
+ config[:mail_account],
55
+ config[:mail_password],
56
+ config[:mail_port],
57
+ config[:mail_authentication] )
58
+ end
59
+
60
+
61
+ query = Query.new( "#{config[:driver]}:#{config[:database]}",
62
+ config[:db_user], config[:db_password], mailer)
63
+
64
+ query.query_table = config[:query_table]
65
+
66
+
67
+ case(ARGV[0])
68
+ when "ins_query", "insq"
69
+ query_text = query.load_file(ARGV[2])
70
+ query.execute("INSERT INTO #{query.query_table} " +
71
+ "VALUES ('#{ARGV[1]}','#{query_text}' );")
72
+ when "ls_queries", "lsq"
73
+ query.select("label FROM #{query.query_table}") do |r| puts r end
74
+ when "show_query", "sq"
75
+ query.select( "query FROM #{query.query_table} " +
76
+ "WHERE label LIKE '%#{ARGV[1]}%'" ) do |r| puts r end
77
+ when "rm_query", "rmq"
78
+ query.execute("DELETE FROM #{query.query_table} " +
79
+ "WHERE label LIKE '#{ARGV[1]}'" )
80
+ else
81
+ query.eval_report(ARGF.filename, ARGF.read)
82
+ end
83
+
84
+
85
+
86
+
@@ -0,0 +1,4 @@
1
+ # THIS IS A NASTY HACK TO GET RUPORT TO WORK IN CMD.EXE
2
+ # BETTER SOLUTION IS A MUST.
3
+
4
+ eval(File.read("C:/ruby/bin/ruport"))
@@ -0,0 +1,44 @@
1
+ # mailer.rb
2
+
3
+ # Created by Gregory Brown on 2005-08-16
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
+ require "net/smtp"
11
+ class Mailer
12
+
13
+ # Creates a new Mailer object. User must specify their mail host, email
14
+ # address, and account. Password, port, and authentication method are all
15
+ # optional.
16
+ def initialize(host, address, account, 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)
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
@@ -0,0 +1,140 @@
1
+ #!/usr/local/bin/ruby
2
+ # query.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 "parse/input"
14
+ require "erb"
15
+ require "csv"
16
+ require "yaml"
17
+ require "date"
18
+ require "sql"
19
+ class Query
20
+ def initialize( driver, user, password, mailer=nil )
21
+ @driver = driver
22
+ @user = user
23
+ @password = password
24
+ @report_name = ""
25
+ @mailer = mailer
26
+ @query_table = nil
27
+ end
28
+
29
+ attr_accessor :query_table
30
+ attr_reader :mailer
31
+
32
+ # Takes a query, an optional sourcetype, and a block which is passed the
33
+ # results row by row. When passed a query in string form, it adds the
34
+ # SELECT clause to the string and executes the query. When passed a
35
+ # filename and a source :file, it looks in queries/ for the file specified.
36
+ # When given a database query label, it looks in config[query_table] for a
37
+ # query with the label specified. If no source is specified, it uses
38
+ # string by default for the source.
39
+ #
40
+ # Example:
41
+ #
42
+ # select ( "* FROM test" )
43
+ # Passes "SELECT * FROM test" to the database
44
+ #
45
+ # select ( "test.sql", :file )
46
+ # Passes the contents of queries/test.sql to the database
47
+ #
48
+ # select ( "TEST", :db )
49
+ # Calls the query TEST stored in the database and query_table specified in
50
+ # config/ruport.yaml
51
+
52
+ def select( query, source = :string, &action )
53
+ query = get_query(source, query)
54
+ source != :string || query = "SELECT " + query
55
+ DBI.connect(@driver, @user, @password) do |dbh|
56
+ dbh.prepare(query) do |sth|
57
+ sth.execute()
58
+ @column_names = sth.column_names
59
+ @first_row = true
60
+ sth.fetch do |row|
61
+ action.call(row) if block_given?
62
+ @first_row = false
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ # Takes a query and an optional sourcetype and then runs the query
69
+ # against the database. The output is not returned. This is useful for
70
+ # doing construction and destruction actions.
71
+ def execute( query, source = :string )
72
+ query = get_query(source, query)
73
+ DBI.connect(@driver, @user, @password) do |dbh|
74
+ dbh.prepare(query) do |sth|
75
+ sth.execute()
76
+ end
77
+ end
78
+ end
79
+
80
+ # Evaluates _code_ from _filename_ as pure ruby code for files ending in
81
+ # .rb, and as ERb templates for anything else.
82
+ def eval_report( filename, code )
83
+ if filename =~ /\.rb/
84
+ eval(code)
85
+ else
86
+ ERB.new(code, 0, "%").run(binding)
87
+ end
88
+ unless @mailer.nil? || @mailer.recipients.empty?
89
+ @mailer.send_report(@report_name)
90
+ end
91
+ end
92
+
93
+ # Loads a yaml file into the @config variable which is accessible in
94
+ # templates. If _interactive_ is set to true, the user will be prompted to
95
+ # enter information for each key.
96
+ def load_yaml(file, interactive=false)
97
+ @config = YAML.load(File.open("config/#{file}"))
98
+ if (interactive)
99
+ @config.each do |property, value|
100
+ $stderr.print "#{property} (#{value}): "
101
+ entered = $stdin.gets.strip
102
+ @config[property] = entered unless entered.eql?("")
103
+ end
104
+ end
105
+ end
106
+
107
+ # Creates an SQL Object. The block is evaluated within the SQL instance so
108
+ # you may use any methods available to the SQL class. The generated query is
109
+ # returned.
110
+ def fetch( &dsl )
111
+ SQL.new(:SELECT, &dsl).to_s
112
+ end
113
+
114
+ # Returns the query string for queries of type string, file, or db
115
+ def get_query(type,query)
116
+ case (type)
117
+ when :string
118
+ query
119
+ when :file
120
+ load_file( query )
121
+ when :db
122
+ select ( "query FROM #{@query_table} WHERE " +
123
+ "label LIKE '#{query}';" ) do |row| query = row[0] end
124
+ return query
125
+
126
+ end
127
+ end
128
+
129
+ #loads in a file from queries/
130
+ def load_file( file )
131
+ query = ""
132
+ File.open("queries/#{file}", "r").each_line do |line|
133
+ query += line.chomp
134
+ end
135
+ return query
136
+ end
137
+
138
+
139
+ end
140
+