ruport 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +7 -0
- data/README +69 -0
- data/Rakefile +51 -0
- data/TODO +106 -0
- data/bin/ruport +86 -0
- data/bin/ruport.rb +4 -0
- data/lib/mailer.rb +44 -0
- data/lib/query.rb +140 -0
- data/lib/sql.rb +93 -0
- data/setup.rb +1360 -0
- data/tests/tc_ruport.rb +69 -0
- 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
|
data/Rakefile
ADDED
@@ -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
|
+
|
data/bin/ruport
ADDED
@@ -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
|
+
|
data/bin/ruport.rb
ADDED
data/lib/mailer.rb
ADDED
@@ -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
|
data/lib/query.rb
ADDED
@@ -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
|
+
|