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
@@ -0,0 +1,25 @@
1
+ require "test/unit"
2
+ require "ruportlib"
3
+
4
+ class TestSqlSplit < Test::Unit::TestCase
5
+ def teardown
6
+ FileUtils.rm '/tmp/compare.sql' if File.exist?( '/tmp/compare.sql' )
7
+ end
8
+
9
+ def test_stonecodeblog_sql
10
+ user = 'test'
11
+ password = 'password'
12
+ dbh = DBI.connect( "dbi:Mysql:test:localhost", user, password )
13
+ dbh.do 'drop database if exists stonecodeblog'
14
+ orig_sql = 'test/samples/stonecodeblog.sql'
15
+ sql = File.read orig_sql
16
+ split = Ruport::Report::SqlSplit.new sql
17
+ split.each do |sql| dbh.do( sql ); end
18
+ tmp_sql = '/tmp/compare.sql'
19
+ md_command =
20
+ "mysqldump -u#{ user } -p#{ password } --databases stonecodeblog"
21
+ `#{ md_command } > #{ tmp_sql }`
22
+ diff = `diff #{ orig_sql } #{ tmp_sql }`
23
+ assert( diff == '', diff[0..500] )
24
+ end
25
+ end
@@ -0,0 +1,42 @@
1
+ require "test/unit"
2
+ require "ruport"
3
+
4
+ class TestDocument < Test::Unit::TestCase
5
+
6
+ include Ruport
7
+
8
+ def setup
9
+ @empty_doc = Format::Document.new :test_doc1
10
+ many_pages = [:p1,:p2,:p3,:p4].map { |p| Format::Page.new(p) }
11
+ @populated_doc = Format::Document.new :test_doc2, :pages => many_pages
12
+ end
13
+
14
+ def test_basics
15
+ assert_equal(:test_doc1,@empty_doc.name)
16
+ assert_equal(:test_doc2,@populated_doc.name)
17
+ assert_equal([],@empty_doc.pages)
18
+ assert_equal([:p1,:p2,:p3,:p4],@populated_doc.pages.map { |p| p.name })
19
+ end
20
+
21
+ def test_each
22
+ page_names = [:p1,:p2,:p3,:p4]
23
+
24
+ @populated_doc.each { |p| assert_equal(page_names.shift,p.name) }
25
+ assert_equal([],page_names)
26
+
27
+ @populated_doc.pages << Format::Page.new(:p5)
28
+ page_names = [:p1,:p2,:p3,:p4,:p5]
29
+
30
+ @populated_doc.each { |p| assert_equal(page_names.shift,p.name) }
31
+ assert_equal([],page_names)
32
+ end
33
+
34
+ def test_add_page
35
+ @empty_doc.add_page :p1
36
+ @populated_doc.add_page :p5, :some_trait => "cool"
37
+ assert(@empty_doc.find { |p| p.name.eql?(:p1) })
38
+ assert(@populated_doc.find { |p| p.name.eql?(:p5) and
39
+ p.some_trait.eql?("cool") })
40
+ end
41
+
42
+ end
@@ -0,0 +1,18 @@
1
+ require "test/unit"
2
+ require "ruport"
3
+
4
+ class TestElement < Test::Unit::TestCase
5
+ include Ruport
6
+ def setup
7
+ @empty_element = Format::Element.new :test_element
8
+ @populated_element = Format::Element.new :test_element2,
9
+ :content => "Hello, Element!"
10
+ end
11
+
12
+ def test_basics
13
+ assert_equal(:test_element, @empty_element.name)
14
+ assert_equal(:test_element2, @populated_element.name)
15
+ assert_equal("Hello, Element!", @populated_element.content)
16
+ end
17
+
18
+ end
data/test/tc_page.rb ADDED
@@ -0,0 +1,42 @@
1
+ require "test/unit"
2
+ require "ruport"
3
+
4
+ class TestPage < Test::Unit::TestCase
5
+ include Ruport
6
+ def setup
7
+ @empty_page = Format::Page.new :test_page1
8
+ sections = { :s1 => Format::Section.new(:s1), :s2 => Format::Section.new(:s2) }
9
+ @populated_page = Format::Page.new :test_page2,
10
+ :sections => sections
11
+ end
12
+
13
+ def test_basics
14
+ assert_equal(:test_page1, @empty_page.name)
15
+ assert_equal(:test_page2, @populated_page.name)
16
+ assert_equal([],[:s1,:s2]-@populated_page.map { |s| s.name })
17
+ assert_equal({},@empty_page.sections)
18
+ end
19
+
20
+ def test_each
21
+ section_names = [:s1,:s2]
22
+ @populated_page.each { |s| section_names -= [s.name] }
23
+ assert_equal([],section_names)
24
+ @populated_page << Format::Section.new(:s3)
25
+ section_names = [:s1,:s2,:s3]
26
+ @populated_page.each { |s| section_names -= [s.name] }
27
+ assert_equal([],section_names)
28
+ end
29
+
30
+ def test_add_function
31
+ @populated_page.add_section :s3
32
+ @populated_page.add_section :s4, :content => "Hello from Section!"
33
+ assert(@populated_page.find { |s| s.name.eql?(:s3) })
34
+ assert(@populated_page.find { |s| s.name.eql?(:s4) and
35
+ s.content.eql?("Hello from Section!")} )
36
+
37
+ end
38
+ def test_brackets
39
+ assert_equal(:s1,@populated_page[:s1].name)
40
+ assert_equal(:s2,@populated_page[:s2].name)
41
+ end
42
+ end
data/test/tc_query.rb ADDED
@@ -0,0 +1,55 @@
1
+ require "test/unit"
2
+ require "ruport"
3
+ class TestQuery < Test::Unit::TestCase
4
+
5
+
6
+ def setup
7
+ Ruport::Config.source :default,
8
+ :dsn => "ruport:test", :user => "greg", :password => "apple"
9
+
10
+ Ruport::Config.source :alternate,
11
+ :dsn => "ruport:test2", :user => "sandal", :password => "harmonix"
12
+
13
+ @query1 = Ruport::Query.new "select * from foo", :cache_enabled => true
14
+ @query1.cached_data = [[1,2,3],[4,5,6],[7,8,9]]
15
+ end
16
+
17
+
18
+ def test_result
19
+ assert_nothing_raised { @query1.result }
20
+ assert_equal([[1,2,3],[4,5,6],[7,8,9]],@query1.result)
21
+ end
22
+
23
+ def test_each
24
+ data = [[1,2,3],[4,5,6],[7,8,9]]
25
+ @query1.each do |r|
26
+ assert_equal(data.shift,r)
27
+ end
28
+ data = [1,4,7]
29
+ @query1.each do |r|
30
+ assert_equal(data.shift,r.first)
31
+ end
32
+ assert_raise (LocalJumpError) { @query1.each }
33
+ end
34
+
35
+ def test_select_source
36
+
37
+ assert_equal( "ruport:test", @query1.instance_eval("@dsn") )
38
+ assert_equal( "greg", @query1.instance_eval("@user") )
39
+ assert_equal( "apple", @query1.instance_eval("@password") )
40
+
41
+ @query1.select_source :alternate
42
+
43
+ assert_equal( "ruport:test2", @query1.instance_eval("@dsn") )
44
+ assert_equal( "sandal", @query1.instance_eval("@user") )
45
+ assert_equal( "harmonix", @query1.instance_eval("@password") )
46
+
47
+ @query1.select_source :default
48
+
49
+ assert_equal( "ruport:test", @query1.instance_eval("@dsn") )
50
+ assert_equal( "greg", @query1.instance_eval("@user") )
51
+ assert_equal( "apple", @query1.instance_eval("@password") )
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,60 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_reading.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-08-14.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "ruport/parser"
11
+
12
+ class TestReading < Test::Unit::TestCase
13
+ def test_line_by_line_read
14
+ path = File.join(File.dirname(__FILE__), "samples/five_lines.txt")
15
+ lines = File.readlines(path)
16
+ test = self
17
+
18
+ Ruport::Parser.new(path) do
19
+ read { |line| test.assert_equal(lines.shift, line) }
20
+ end
21
+ end
22
+
23
+ def test_paragraph_read
24
+ path = File.join(File.dirname(__FILE__), "samples/five_paragraphs.txt")
25
+ paragraphs = File.readlines(path, "")
26
+ test = self
27
+
28
+ Ruport::Parser.new(path, "") do
29
+ read { |paragraph| test.assert_equal(paragraphs.shift, paragraph) }
30
+ end
31
+ end
32
+
33
+ def test_restricted_reading
34
+ path = File.join(File.dirname(__FILE__), "samples/five_lines.txt")
35
+ numbers = %w{two three}
36
+ test = self
37
+
38
+ Ruport::Parser.new(path) do
39
+ read(/ (t\w+)\./) do |number|
40
+ test.assert_equal("This is line #{numbers.first}.\n", @read)
41
+ test.assert_equal(numbers.shift, number)
42
+ end
43
+ end
44
+ end
45
+
46
+ def test_data_saving_and_retrieving
47
+ path = File.join(File.dirname(__FILE__), "samples/five_lines.txt")
48
+
49
+ data = Ruport::Parser.new( path ) do
50
+ read(/ (o\w+)\./) { |number| @number = number }
51
+ read { |line| (@lines ||= Array.new) << line }
52
+ end
53
+
54
+ assert_equal("one", data[:number])
55
+ assert_equal("one", data.number)
56
+ assert_equal(path, data.path)
57
+ assert_equal(5, data.lines.size)
58
+ assert_equal(File.readlines(path), data.lines)
59
+ end
60
+ end
data/test/tc_report.rb ADDED
@@ -0,0 +1,31 @@
1
+ #tc_report.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 "ruport"
8
+ class TestReport < Test::Unit::TestCase
9
+ include Ruport
10
+
11
+ def setup
12
+ @report = Report.new
13
+ end
14
+
15
+ def test_render
16
+ result = @report.render "<%= 2 + 3%>",
17
+ :filters => [:erb]
18
+ assert_equal("5",result)
19
+
20
+ if defined? RedCloth
21
+ result = @report.render '"foo":http://foo.com',
22
+ :filters => [:red_cloth]
23
+
24
+ assert_equal('<p><a href="http://foo.com">foo</a></p>',result)
25
+ result = @report.render %{"<%= 2 + 3%>":http://foo.com },
26
+ :filters => [:erb, :red_cloth]
27
+ assert_equal('<p><a href="http://foo.com">5</a></p>',result)
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,45 @@
1
+ require "test/unit"
2
+ require "ruport"
3
+
4
+ class TestSection < Test::Unit::TestCase
5
+ include Ruport
6
+ def setup
7
+ elements = { :e1 => Format::Element.new(:e1),
8
+ :e2 => Format::Element.new(:e2) }
9
+ @empty_section = Format::Section.new :test_section1
10
+ @populated_section = Format::Section.new :test_section2,
11
+ :elements => elements
12
+
13
+ end
14
+
15
+ def test_basics
16
+ assert_equal( :test_section1, @empty_section.name )
17
+ assert_equal( :test_section2, @populated_section.name )
18
+ assert_equal( [], [:e1,:e2]-@populated_section.map { |e| e.name } )
19
+ end
20
+
21
+ def test_each
22
+ element_names = [:e1,:e2]
23
+ @populated_section.each { |e| element_names -= [e.name] }
24
+ assert_equal([],element_names)
25
+
26
+ element_names = [:e1, :e2, :e3]
27
+ @populated_section << Format::Element.new(:e3)
28
+ @populated_section.each { |e| element_names -= [e.name] }
29
+ assert_equal([],element_names)
30
+ end
31
+
32
+ def test_add_element
33
+ @empty_section.add_element :e1
34
+ @empty_section.add_element :e2, :content => "Hello from Element!"
35
+ assert(@empty_section[:e1])
36
+ assert(@empty_section[:e2])
37
+ assert_equal("Hello from Element!",@empty_section[:e2].content)
38
+ end
39
+
40
+ def test_brackets
41
+ assert_equal(:e1,@populated_section[:e1].name)
42
+ assert_equal(:e2,@populated_section[:e2].name)
43
+ end
44
+
45
+ end
@@ -0,0 +1,18 @@
1
+ require "test/unit"
2
+ require "ruport"
3
+ class TestSqlSplit < Test::Unit::TestCase
4
+ include Ruport
5
+
6
+ def test_sql_split1
7
+ sql = File.read 'test/samples/ruport_test.sql'
8
+ split = Query::SqlSplit.new sql
9
+ assert_equal( 'SELECT * FROM ruport_test', split.last )
10
+ end
11
+
12
+ def test_sql_split2
13
+ sql = "SELECT * FROM ruport_test"
14
+ split = Query::SqlSplit.new sql
15
+ assert_equal( 1, split.size )
16
+ assert_equal( sql, split.first )
17
+ end
18
+ end
data/test/tc_state.rb ADDED
@@ -0,0 +1,142 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_state.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-08-14.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "ruport/parser"
11
+
12
+ class TestState < Test::Unit::TestCase
13
+ def test_single_skips
14
+ path = File.join(File.dirname(__FILE__), "samples/five_lines.txt")
15
+ lines = File.readlines(path).values_at(0..2, 4)
16
+ test = self
17
+
18
+ Ruport::Parser.new(path) do
19
+ skip(?u)
20
+
21
+ read { |line| test.assert_equal(lines.shift, line) }
22
+ end
23
+ end
24
+
25
+ def test_skipping_range
26
+ path = File.join(File.dirname(__FILE__), "samples/five_lines.txt")
27
+ lines = File.readlines(path).values_at(0, 3..4)
28
+ test = self
29
+
30
+ Ruport::Parser.new(path) do
31
+ start_skipping_at("two")
32
+ stop_skipping_at("three")
33
+
34
+ read { |line| test.assert_equal(lines.shift, line) }
35
+ end
36
+ end
37
+
38
+ def test_searching_skipped
39
+ path = File.join(File.dirname(__FILE__), "samples/five_lines.txt")
40
+
41
+ data = Ruport::Parser.new(path) do
42
+ @state = :skip
43
+ stop_skipping_at("four")
44
+ find_in_skipped(/ou/) { |line| @found_in_skip = line }
45
+
46
+ read { |line| (@lines ||= Array.new) << line }
47
+ end
48
+
49
+ assert_equal("This is line four.\n", data.found_in_skip)
50
+ assert_equal(["This is line five.\n"], data.lines)
51
+ end
52
+
53
+ def test_stop
54
+ path = File.join(File.dirname(__FILE__), "samples/five_lines.txt")
55
+
56
+ data = Ruport::Parser.new(path) do
57
+ stop_at("three")
58
+
59
+ read { |line| @last_line = line }
60
+ end
61
+
62
+ assert_equal("This is line two.\n", data.last_line)
63
+
64
+ data = Ruport::Parser.new(path) do
65
+ read do |line|
66
+ @last_line = line
67
+
68
+ @state = :stop if @read.index("three")
69
+ end
70
+ end
71
+
72
+ assert_equal("This is line three.\n", data.last_line)
73
+ end
74
+
75
+ def test_pre_and_post
76
+ path = File.join(File.dirname(__FILE__), "samples/five_lines.txt")
77
+
78
+ data = Ruport::Parser.new(path) do
79
+ @pre = @post = 0
80
+
81
+ pre do
82
+ @pre += 1
83
+ @post = 0
84
+ end
85
+ read { |line| (@lines ||= Array.new) << line }
86
+ read(/\w+\./) { |number| (@numbers ||= Array.new) << number }
87
+ post { @post += 1 }
88
+ end
89
+
90
+ assert_equal(5, data.pre)
91
+ assert_equal(1, data.post)
92
+ end
93
+
94
+ def test_complex
95
+ path = File.join(File.dirname(__FILE__), "samples/ross_report.txt")
96
+ test = self
97
+
98
+ Ruport::Parser.new(path) do
99
+ @state = :skip
100
+ start_skipping_at("\f")
101
+ stop_skipping_at(/\A-[- ]+-\Z/)
102
+ skip(/\A\s*\Z/)
103
+ skip(/--\Z/)
104
+
105
+ find_in_skipped(/((?:Period|Week)\s+\d.+?)\s*\Z/) do |period|
106
+ test.assert_equal("Period 02/2002", period)
107
+ end
108
+
109
+ stop_at("*** Selection Criteria ***")
110
+
111
+ read do |line|
112
+ test.assert_match(/\A\s+(?:Sales|Cust|SA)|\A[-\w]+\s+/, line)
113
+ end
114
+ end
115
+
116
+ path = File.join(File.dirname(__FILE__), "samples/car_ads.txt")
117
+
118
+ data = Ruport::Parser.new(path, "") do
119
+ @state = :skip
120
+ stop_skipping_at("Save Ad")
121
+ skip(/\A\s*\Z/)
122
+
123
+ pre { @price = @miles = nil }
124
+ read(/\$([\d,]+\d)/) { |price| @price = price.delete(",").to_i }
125
+ read(/([\d,]*\d)\s*m/) { |miles| @miles = miles.delete(",").to_i }
126
+
127
+ read do |ad|
128
+ if @price and @price < 20_000 and @miles and @miles < 40_000
129
+ (@ads ||= Array.new) << ad.strip
130
+ end
131
+ end
132
+ end
133
+
134
+ assert_equal([<<END_AD.strip], data.ads)
135
+ 2003 Chrysler Town & Country LX
136
+ $16,990, green, 21,488 mi, air, pw, power locks, ps, power mirrors,
137
+ dual air bags, keyless entry, intermittent wipers, rear defroster, alloy,
138
+ pb, abs, cruise, am/fm stereo, CD, cassette, tinted glass
139
+ VIN:2C4GP44363R153238, Stock No:C153238, CALL DAN PERKINS AT 1-800-432-6326
140
+ END_AD
141
+ end
142
+ end