ruport 0.2.9 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
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