ruport 0.2.9 → 0.3.8

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.
Files changed (60) hide show
  1. data/ACKNOWLEDGEMENTS +33 -0
  2. data/AUTHORS +13 -1
  3. data/CHANGELOG +76 -1
  4. data/README +208 -89
  5. data/Rakefile +12 -8
  6. data/TODO +14 -122
  7. data/lib/ruport.rb +58 -0
  8. data/lib/ruport/config.rb +114 -0
  9. data/lib/ruport/data_row.rb +144 -0
  10. data/lib/ruport/data_set.rb +221 -0
  11. data/lib/ruport/format.rb +116 -0
  12. data/lib/ruport/format/builder.rb +29 -5
  13. data/lib/ruport/format/document.rb +77 -0
  14. data/lib/ruport/format/open_node.rb +36 -0
  15. data/lib/ruport/parser.rb +202 -0
  16. data/lib/ruport/query.rb +208 -0
  17. data/lib/ruport/query/sql_split.rb +33 -0
  18. data/lib/ruport/report.rb +116 -0
  19. data/lib/ruport/report/mailer.rb +17 -15
  20. data/test/{addressbook.csv → samples/addressbook.csv} +0 -0
  21. data/test/samples/car_ads.txt +505 -0
  22. data/test/{data.csv → samples/data.csv} +0 -0
  23. data/test/samples/document.xml +22 -0
  24. data/test/samples/five_lines.txt +5 -0
  25. data/test/samples/five_paragraphs.txt +9 -0
  26. data/test/samples/ross_report.txt +58530 -0
  27. data/test/samples/ruport_test.sql +8 -0
  28. data/test/samples/stonecodeblog.sql +279 -0
  29. data/test/{test.sql → samples/test.sql} +2 -1
  30. data/test/{test.yaml → samples/test.yaml} +0 -0
  31. data/test/tc_builder.rb +7 -4
  32. data/test/tc_config.rb +41 -0
  33. data/test/tc_data_row.rb +16 -26
  34. data/test/tc_data_set.rb +60 -41
  35. data/test/tc_database.rb +25 -0
  36. data/test/tc_document.rb +42 -0
  37. data/test/tc_element.rb +18 -0
  38. data/test/tc_page.rb +42 -0
  39. data/test/tc_query.rb +55 -0
  40. data/test/tc_reading.rb +60 -0
  41. data/test/tc_report.rb +31 -0
  42. data/test/tc_section.rb +45 -0
  43. data/test/tc_sql_split.rb +18 -0
  44. data/test/tc_state.rb +142 -0
  45. data/test/ts_all.rb +6 -3
  46. data/test/ts_format.rb +5 -0
  47. data/test/ts_parser.rb +10 -0
  48. metadata +102 -60
  49. data/bin/ruport +0 -104
  50. data/lib/ruport/format/chart.rb +0 -1
  51. data/lib/ruport/report/data_row.rb +0 -79
  52. data/lib/ruport/report/data_set.rb +0 -153
  53. data/lib/ruport/report/engine.rb +0 -201
  54. data/lib/ruport/report/fake_db.rb +0 -54
  55. data/lib/ruport/report/fake_engine.rb +0 -26
  56. data/lib/ruport/report/fake_mailer.rb +0 -23
  57. data/lib/ruport/report/sql.rb +0 -95
  58. data/lib/ruportlib.rb +0 -11
  59. data/test/tc_engine.rb +0 -102
  60. data/test/tc_mailer.rb +0 -21
@@ -1,201 +0,0 @@
1
- #!/usr/local/bin/ruby
2
- # 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
- # 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
- module Ruport
21
- module Report
22
- class Engine
23
- def initialize( dsn, user, password, mailer=nil )
24
-
25
- File.exists?("log") or FileUtils.mkdir("log")
26
- @logger = Logger.new("log/ruport.log")
27
-
28
- @dsn = dsn
29
- @user = user
30
- @password = password
31
- @mailer = mailer
32
- @generate = true
33
- @report_name = ""
34
- @report = ""
35
- @query_table = nil
36
- @file = nil
37
- @config = nil
38
- @databases = Hash.new
39
- @databases[:default] = { :dsn => @dsn,
40
- :user => @user,
41
- :password => @password
42
- }
43
- end
44
-
45
- attr_accessor :query_table, :file
46
- attr_reader :mailer, :generate, :config, :logger
47
-
48
- # Takes a query and an optional sourcetype and then runs the query
49
- # against the database. The return from the query is then converted
50
- # into a DataSet which can then be manipulated.
51
- #
52
- # Example:
53
- # query("SELECT * FROM address_book") do |data|
54
- # @report << data.to_csv
55
- # end
56
- #
57
- # The above would select all from the _address_book_ table
58
- # and then convert the DataSet to a csv and then add it to the report
59
-
60
- def query ( statement, source = :string, &action )
61
- query_text = get_query(source,statement)
62
- data = DataSet.new
63
- DBI.connect(@dsn, @user, @password) do |dbh|
64
- dbh.execute(query_text) do |sth|
65
- if sth.rows > 0
66
- results = sth.fetch_all
67
- data.fields = sth.column_names
68
- results.each { |row| data << row }
69
- action.call(data) if block_given?
70
- else
71
- data = nil
72
- end
73
- end
74
- end
75
- return data || "command succeeded. 0 rows returned"
76
- end
77
-
78
- # Evaluates _code_ from _filename_ as pure ruby code for files ending in
79
- # .rb, and as ERb templates for anything else.
80
- def eval_report( filename, code )
81
- if filename =~ /\.rb/
82
- eval(code)
83
- else
84
- ERB.new(code, 0, "%").run(binding)
85
- end
86
- end
87
-
88
- # Loads a yaml file into the @config variable which is accessible in
89
- # templates. If _interactive_ is set to true, the user will
90
- # be prompted to enter information for each key.
91
- def load_yaml(file, interactive=false)
92
- file = "config/#{file}" unless File.exists? file
93
- @config = YAML.load(File.open(file))
94
- if (interactive)
95
- @config.keys.map { |c| c.to_s }.sort.each do |property|
96
- $stderr.print "#{property} (#{@config[property.to_sym]}): "
97
- entered = $stdin.gets.strip
98
- @config[property] = entered unless entered.eql?("")
99
- end
100
- end
101
- end
102
-
103
- # Creates an SQL Object. The block is evaluated within the SQL
104
- # instance so you may use any methods available to the SQL class.
105
- # The generated query is returned.
106
- #
107
- # Example
108
- # fetch { from :address_book order :name }
109
- # => "SELECT * FROM address_book ORDER BY name
110
-
111
- def fetch( &dsl )
112
- begin
113
- SQL.new(:SELECT, &dsl).to_s
114
- rescue Exception
115
- @logger.fatal "Error generating SQL."
116
- raise "Error generating SQL."
117
- end
118
- end
119
-
120
- # Returns the query string for queries of type string, file, or db
121
- def get_query(type,query)
122
- case (type)
123
- when :string
124
- query
125
- when :file
126
- load_file( query )
127
- when :db
128
- query ( "SELECT query FROM #{@query_table} WHERE " +
129
- "label LIKE '#{query}';" ) do |data|
130
- return data[0]["query"]
131
- end
132
- end
133
- end
134
-
135
- # Loads a query from file. Accepts absolute paths, relative paths from
136
- # the toplevel directory, and relative paths from _queries/_.
137
- # If you've been putting all your database queries in _queries_, you can
138
- # just call them by name.
139
- def load_file( query_file )
140
- begin
141
- File.read( query_file ).strip
142
- rescue
143
- @logger.fatal "Could not open #{query_file}"
144
- raise "Could not open #{query_file}"; exit
145
- end
146
- end
147
-
148
- def render ( data )
149
- builder = Format::Builder.new( data )
150
- yield(builder)
151
- builder.render
152
- end
153
-
154
- # Generates the report. If @pre or @post are defined with lambdas,
155
- # they will be called before and after the main code. generate_report
156
- # will automatically be run at the end of the execution
157
- # of a ruport template unless @generate is set to false.
158
- #
159
- # If @file != nil, ruport will print to the
160
- # file with the specified name. Otherwise, it will print to STDOUT by
161
- # default. @file can be set implictly by a file argument, i.e.
162
- # ruport templates/foo.rb reports/foo_out.html => @file =
163
- # 'reports/foo_out.html' It can also be set explicitly within a template.
164
- # A good way to define a default value is @file ||= "reports/somefile"
165
- #
166
- # Lastly, if you have your mailer configuration set up and
167
- # you've specified recipients, the contents of @mailer.body will
168
- # be automatically emailed by this fuction.
169
- #
170
- # The source for this function is probably easier to read than this
171
- # explanation, so you may want to start there.
172
- def generate_report
173
- @pre.call if @pre
174
- if (@file.nil?)
175
- puts(@report)
176
- else
177
- File.open(@file,"w") { |f| f.puts @report }
178
- end
179
- unless @mailer.nil? || @mailer.recipients.empty?
180
- @mailer.body = @report unless not @mailer.body.empty?
181
- @mailer.send_report(@report_name)
182
- end
183
- @post.call if @post
184
-
185
- end
186
-
187
- def add_dsn(label, dsn, user, password )
188
- @databases[label] = { :dsn => dsn, :user => user,
189
- :password => password }
190
- end
191
-
192
- def select_dsn(label)
193
- @dsn = @databases[label][:dsn]
194
- @user = @databases[label][:user]
195
- @password = @databases[label][:password]
196
- end
197
-
198
- end
199
- end
200
- end
201
-
@@ -1,54 +0,0 @@
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
@@ -1,26 +0,0 @@
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
-
17
- def query ( query, source = :string, &action)
18
- query = get_query(source, query)
19
- data = @fake_db.process(@dsn,@user,@password, query)
20
- action.call(data) if block_given?
21
- return data
22
- end
23
-
24
- end
25
- end
26
- end
@@ -1,23 +0,0 @@
1
- module Ruport
2
- module Report
3
- class FakeMailer < Mailer
4
-
5
- @@fake_server = Hash.new
6
- @@fake_server[:port] = 25
7
-
8
- def self.[]=(key,value)
9
- @@fake_server[key] = value
10
- end
11
-
12
- def send_report(report_name="No Subject")
13
- raise "Invalid Host" unless @@fake_server[:host].eql?(@host)
14
- raise "Invalid Account" unless @@fake_server[:account].eql?(@account)
15
- raise "Bad Email Address" unless @@fake_server[:address].eql?(@address)
16
- raise "Bad Password" unless @@fake_server[:password].eql?(@password)
17
- raise "Invalid Port" unless @@fake_server[:port].eql?(@port)
18
- raise "Bad Authorization Type" unless @@fake_server[:auth].eql?(@auth)
19
- end
20
-
21
- end
22
- end
23
- end
@@ -1,95 +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
- 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 DELETED
@@ -1,11 +0,0 @@
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
- require "ruport/report/fake_mailer"
9
- require "ruport/format/builder"
10
- require "faster_csv"
11
- include Ruport
data/test/tc_engine.rb DELETED
@@ -1,102 +0,0 @@
1
- #tc_engine.rb
2
- #
3
- # Created by Gregory Thomas Brown on 2005-08-09
4
- # Copyright 2005 (Gregory Brown) All rights reserved.
5
-
6
- require "test/unit"
7
- require "ruportlib"
8
- class TestEngine < Test::Unit::TestCase
9
- def setup
10
- @engine = Report::FakeEngine.new( "DBI:mysql:ruport:localhost",
11
- "test", "123")
12
- @engine.query_table = "ruport_queries"
13
-
14
- @engine.fake_db = Report::FakeDB.new([ "DBI:mysql","ruport",
15
- "localhost", "test", "123"])
16
-
17
- @engine.fake_db["SELECT * FROM ruport_test"] = @data =
18
- [ { "a" => "a column, row 1", "b" => "b column, row 1",
19
- "c" => "c column, row 1", "d" => "d column, row 1" },
20
- { "a" => "a column, row 2", "b" => "b column, row 2",
21
- "c" => "c column, row 2", "d" => "d column, row 2" },
22
- { "a" => "a column, row 3", "b" => "b column, row 3",
23
- "c" => "c column, row 3", "d" => "d column, row 3" } ]
24
-
25
- @engine.fake_db[ "SELECT query FROM #{@engine.query_table} " +
26
- "WHERE label LIKE 'sql_stored_test';"] =
27
- [ "query" => "SELECT * FROM ruport_test" ]
28
- end
29
-
30
- def test_load_file
31
- contents = "SELECT * FROM ruport_test"
32
-
33
- #relative to working dir
34
- assert_equal(contents, @engine.load_file("test/test.sql"));
35
-
36
- #absolute path
37
- assert_equal(contents,
38
- @engine.load_file(File.expand_path("test/test.sql")))
39
- end
40
-
41
- def test_sql_generation
42
- sql = @engine.fetch do
43
- from :ruport_test
44
- end
45
- assert_equal("SELECT * FROM ruport_test;", sql)
46
- sql = @engine.fetch do
47
- from :ruport_test
48
- condition :last_name, :"=", "Brown"
49
- order :first_name
50
- end
51
- assert_equal("SELECT * FROM ruport_test WHERE last_name = 'Brown' " +
52
- "ORDER BY first_name;",sql)
53
- end
54
-
55
- def test_load_yaml
56
- config_hash = { :name => "Greg",
57
- :friend => "Rob",
58
- :job => "Programmer" }
59
- @engine.load_yaml "test/test.yaml"
60
- config_hash.each do |key, value|
61
- assert_equal(value,@engine.config[key])
62
- end
63
- end
64
-
65
- def test_sql_file
66
- @engine.query("test/test.sql",:file) do |result|
67
- assert_equal(@data,result)
68
- end
69
- end
70
-
71
- def test_sql_stored
72
- @engine.query("sql_stored_test",:db) do |result|
73
- assert_equal(@data,result)
74
- end
75
- end
76
-
77
- def test_query
78
- @engine.query("SELECT * FROM ruport_test") do |result|
79
- assert_equal(@data,result)
80
- end
81
- end
82
-
83
- def test_render
84
- data = Report::DataSet.new
85
- data.fields = %w[ col1 col2 col3]
86
- data << %w[ a b c]
87
- data << %w[ d e f]
88
- assert_equal("col1,col2,col3\na,b,c\nd,e,f\n",
89
- @engine.render(data) do |builder|
90
- builder.format = :csv
91
- end )
92
-
93
- assert_equal("<table>\n <tr>\n <th>col1</th><th>col2</th>" +
94
- "<th>col3</th>\n </tr>\n" +
95
- " <tr>\n <td>a</td><td>b</td><td>c</td>\n </tr>\n" +
96
- " <tr>\n <td>d</td><td>e</td><td>f</td>\n </tr>\n" +
97
- "</table>", @engine.render(data) do |builder|
98
- builder.format = :html
99
- end )
100
- end
101
-
102
- end