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
data/TODO CHANGED
@@ -1,135 +1,27 @@
1
- TODO:
1
+ TODO: (Wiped clean for a fresh start as of 2006.02.20)
2
2
 
3
- Bugfixes:
4
- - Fix the manual that is in the example package so it it reads FakeDB instead
5
- of MockDB. Update the manual to cover new features in 0.3.0
3
+ For Ruport 0.4.0
6
4
 
7
- - Ruport has some big trouble with running things such as table / database
8
- creations. Gotta work out the kinks here.
9
-
10
- Improvement:
5
+ - Integrate Ruport::Parser into Report#parse and Format#parser
11
6
 
12
- - Tagging... Add column and set based tagging.
7
+ - Document the inner classes of Format
13
8
 
14
- - Transposition in DataSets
9
+ - Get unit tests up to 100% coverage
15
10
 
16
- - Mail system
17
- Make attachments doable
11
+ - make the Fetchable module to abstract data acquisition
18
12
 
19
- - Template Config / Line Editing
13
+ High Priority Goals:
20
14
 
21
- Find a way to accept piped in values
22
- Make line editing work right
23
-
24
- - Queries Table System
15
+ - Implement some aspects of XST into DataSet
25
16
 
26
- Automate the generation of the table. (Optionally)
27
- Hook up unit tests.
17
+ - Offer charting support in Format
28
18
 
29
- - SQL builder
19
+ Community Requests:
30
20
 
31
- Expand so that it covers most common SQL commands.
32
- Form better more complete unit tests.
21
+ - Integration with Rails (ActiveRecord)
33
22
 
34
- - Queries from file / db need to use ERb or some other replacement ability
23
+ Other (Unordered) Goals:
35
24
 
36
- Begin implementing new features:
25
+ - Make mailer more robust via MailFactory
37
26
 
38
- - Formatter:
39
-
40
- * Implement RSS generation for Format::Builder
41
-
42
- - Charts:
43
-
44
- Build something that'll take a data set and build a chart. (SVG?),
45
- then dump it into PDF::Writer.
46
-
47
- - Multiple query reports:
48
-
49
- Allow the user to make arbitrary SQL queries,
50
- combining the rows, and then iterating through them row by row in the
51
- order specified.
52
-
53
- This could be done with select taking an array of queries and possibly
54
- some ordering instructions
55
-
56
- - Cross database import from file:
57
-
58
- Make an import(file,table,delimiter=",") command that will work
59
- regardless of database choice and import the data stored in a file into
60
- a specified table.
61
-
62
- - Parse/Input tight integration:
63
-
64
- Write wrapper functions over the Parse/Input library to give Ruport the
65
- power to feed in any data source such as a CSV, A website, or a log file
66
- and do formatting and use the other features of Ruport.
67
-
68
- - PDF::Writer and CSV convenience methods:
69
-
70
- Create functions that will allow basic and common reports to be built
71
- using PDF and CSV format without having to write the functionality over
72
- and over again. This would be especially useful for just dumping a
73
- table's values in a certain order with some fields removed.
74
-
75
- [UPDATE: to_csv is in place but can use some additional frosting]
76
-
77
- - Logger / Exception handler:
78
-
79
- Create a system to handle and log errors as well as provide log messages
80
- regarding what Ruport does when a template is run.
81
-
82
- [UPDATE: Logger is in place but is not covering many functions]
83
-
84
- - DataSets should implement tagging, allowing tag conditions to be passed and
85
- then applied to rows. Formulas should be implemented, allowing column
86
- generation by Proc. More about this later. (These are COOL and POWERFUL
87
- features... thanks to Greg Gibson for the ideas.
88
-
89
-
90
- Design considerations:
91
-
92
- Ruport will eventually need to be cleanly seperating between formatting
93
- tools and data feeders. This will likely happen in an early release, if not
94
- the next than the one after.
95
-
96
- [ UPDATE: The folders have been seperated but need reworking. db/mailer ??
97
- Ruport needs to be made into a module ]
98
-
99
- Ruport trys to use a lot of 'intelligent' defaults but it might try to be
100
- too clever in some places making it not clever at all. The community
101
- reaction will determine what places may need opening up more or need more
102
- consideration for the defaults.
103
-
104
- [ UPDATE: See changelog for a list of dropped features. Complain about any
105
- that you still think need to be dropped ]
106
-
107
- Other:
108
-
109
- A quick reference page for templates and/or tutorial would be A Good Thing
110
-
111
- The RDOC sucks!
112
-
113
- The unit tests need to be wired so that they can actually run without a ton
114
- of additional steps, they need to be expanded to cover the whole system, and
115
- they need to work in the Gem package as well as the source package.
116
-
117
- [UPDATE: Mailer is the only class that needs to be unit tested still. The
118
- units work out of the box via MockDB now. Functional tests with
119
- scaffolding are needed, though ]
120
-
121
- Ruport needs to be modified to support as many databases as possibly
122
- internally. The system was written using MySQL on Gentoo Linux
123
- and Mac OS X.3 / OS X.4, Windows 2000 / XP and Microsoft SQL Server
124
- on Windows 2000 (via ODBC),
125
-
126
- so the support for these platforms are best. An effort will be given to
127
- make Ruport less hostile in other environments.
128
-
129
-
130
- This is only the tip of the iceburg. Please feel free to continue to fill my
131
- plate by sending any suggestions to gregory.t.brown@gmail.com
132
-
133
- JEG2 Code Review 2005.11.14: (email me if you find any of this interesting)
134
- - use the many levels of logger
135
- - RQL (Ruport Query Language)
27
+ - Support KirbyBase
data/lib/ruport.rb ADDED
@@ -0,0 +1,58 @@
1
+ require "rubygems"
2
+ # ruport.rb : Ruby Reports toplevel module
3
+ #
4
+ # Author: Gregory T. Brown (gregory.t.brown at gmail dot com)
5
+ #
6
+ # Copyright (c) 2006, All Rights Reserved.
7
+ #
8
+ # This is free software. You may modify and redistribute this freely under
9
+ # your choice of the GNU General Public License or the Ruby License.
10
+ #
11
+ # See LICENSE and COPYING for details
12
+ #
13
+
14
+ module Ruport
15
+ VERSION = "Ruport Version 0.3.8 (Developmental)"
16
+
17
+ # Ruports logging and error interface.
18
+ # Can generate warnings or raise fatal errors
19
+ #
20
+ # Takes a message to display and a set of options.
21
+ # Will log to the file defined by Config::log_file
22
+ #
23
+ # Options:
24
+ # <tt>:status</tt>:: sets the severity level. defaults to <tt>:warn</tt>
25
+ # <tt>:output</tt>:: optional secondary output, defaults to <tt>$stderr</tt>
26
+ # <tt>:level</tt>:: set to <tt>:log_only</tt> to disable secondary output
27
+ # <tt>:exception</tt>:: exception to throw on fail. Defaults to RunTimeError
28
+ #
29
+ # The status <tt>:warn</tt> will invoke Logger#warn. A status of
30
+ # <tt>:fatal</tt> will invoke Logger#fatal and raise an exception
31
+ #
32
+ # By default, complain will also print warnings to $stderr
33
+ # You can redirect this to any I/O object via <tt>:output</tt>
34
+ #
35
+ # You can prevent messages from appearing on the secondary output by setting
36
+ # <tt>:level</tt> to <tt>:log_only</tt>
37
+ #
38
+ # If you want to recover these messages to secondary output for debugging, you
39
+ # can use Config::enable_paranoia
40
+ def Ruport.complain(message,options={})
41
+ options[:status] ||= :warn
42
+ options[:output] ||= $stderr
43
+ case(options[:status])
44
+ when :warn
45
+ Ruport::Config::logger.warn(message) if Ruport::Config::logger
46
+ when :fatal
47
+ Ruport::Config::logger.fatal(message) if Ruport::Config::logger
48
+ raise options[:exception] || RuntimeError, message
49
+ end
50
+ options[:output].puts "[!!] #{message}" unless
51
+ options[:level].eql?(:log_only) and not Ruport::Config.paranoid?
52
+ end
53
+
54
+ end
55
+
56
+ %w[ config report format query data_row data_set].each { |lib|
57
+ require "ruport/#{lib}"
58
+ }
@@ -0,0 +1,114 @@
1
+ # ruport/config.rb : Ruby Reports configuration system
2
+ #
3
+ # Author: Gregory T. Brown (gregory.t.brown at gmail dot com)
4
+ #
5
+ # Copyright (c) 2006, All Rights Reserved.
6
+ #
7
+ # This is free software. You may modify and redistribute this freely under
8
+ # your choice of the GNU General Public License or the Ruby License.
9
+ #
10
+ # See LICENSE and COPYING for details
11
+ #
12
+ require "singleton"
13
+ require "ostruct"
14
+ module Ruport
15
+ # This class serves as the configuration system for Ruport.
16
+ # It's functionality is implemented through Config::method_missing
17
+ #
18
+ # source :default and mailer :default will become the fallback values if one
19
+ # is not specified in Report::Mailer or Query, but you may define as many
20
+ # sources as you like and switch between them later.
21
+ #
22
+ # An example config file is shown below:
23
+ #
24
+ # # password is optional, dsn may omit hostname for localhost
25
+ # Ruport::Config.source :default,
26
+ # :dsn => "dbi:mysql:somedb:db.blixy.org", :user => "root", :password => "chunky_bacon"
27
+ #
28
+ # # :password, :port, and :auth_type are optional. :port defaults to 25 and
29
+ # # :auth_type defaults to :plain. For more information, see the source
30
+ # # of Report::Mailer#select_mailer
31
+ # Ruport::Config.mailer :default,
32
+ # :host => "mail.chunkybacon.org", :address => "chunky@bacon.net",
33
+ # :user => "cartoon", :password => "fox", :port => 25, :auth_type => :login
34
+ #
35
+ # # optional, if specifed, Ruport#complain will report to it
36
+ # Ruport::Config.log_file 'foo.log'
37
+ #
38
+ # # optional, if enabled, will force :log_only complaint calls to
39
+ # # print to secondary output ($sterr by default).
40
+ # # call Ruport::Config.disable_paranoia to disable
41
+ # Ruport::Config.enable_paranoia
42
+ #
43
+ # Alternatively, this configuration could be done by opening the class:
44
+ # class Ruport::Config
45
+ #
46
+ # source :default, :dsn => "dbi:mysql:some_db", :user => "root"
47
+ #
48
+ # mailer :default, :host => "mail.iheartwhy.com",
49
+ # :address => "sandal@ruby-harmonix.net", :user => "sandal",
50
+ # :password => "abc123"
51
+ #
52
+ # logfile 'foo.log'
53
+ #
54
+ # end
55
+ #
56
+ # Saving this config information into a file and then requiring it can allow
57
+ # you share configurations between Ruport applications.
58
+ #
59
+ class Config
60
+ include Singleton
61
+
62
+ def Config.method_missing(method_id,*args)
63
+ case(method_id)
64
+ when :source
65
+ return @@sources[args.first] if args.length == 1
66
+ @@sources[args.first] = OpenStruct.new(*args[1..-1])
67
+ unless @@sources[args.first].send(:dsn)
68
+ Ruport.complain("Bad or missing DSN for source #{args.first}!")
69
+ end
70
+ when :mailer
71
+ @@mailers[args.first] = OpenStruct.new(*args[1..-1])
72
+ when :log_file
73
+ @@logger = Logger.new(args.first)
74
+ when :default_source
75
+ @@sources[:default]
76
+ when :default_mailer
77
+ @@mailers[:default]
78
+ when :sources
79
+ @@sources
80
+ when :mailers
81
+ @@mailers
82
+ when :logger
83
+ @@logger
84
+ when :enable_paranoia
85
+ @@paranoid = true
86
+ when :disable_paranoia
87
+ @@paranoid = false
88
+ when :paranoid?
89
+ @@paranoid
90
+ else
91
+ super
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ def Config.init!
98
+ @@sources = { :default =>
99
+ OpenStruct.new( :dsn => "ruport",
100
+ :user => "",
101
+ :password => ""
102
+ )
103
+ }
104
+ @@mailers = { :default => nil }
105
+ @@logger ||= nil
106
+ @@paranoid ||= false
107
+ end
108
+
109
+
110
+
111
+ init!
112
+
113
+ end
114
+ end
@@ -0,0 +1,144 @@
1
+ # --
2
+ # data_row.rb : Ruby Reports row abstraction
3
+ #
4
+ # Author: Gregory T. Brown (gregory.t.brown at gmail dot com)
5
+ #
6
+ # Copyright (c) 2006, All Rights Reserved.
7
+ #
8
+ # This is free software. You may modify and redistribute this freely under
9
+ # your choice of the GNU General Public License or the Ruby License.
10
+ #
11
+ # See LICENSE and COPYING for details
12
+ # ++
13
+ module Ruport
14
+
15
+ # DataRows are Enumerable lists which can be accessed by field name or ordinal
16
+ # position.
17
+ #
18
+ # They feature a tagging system, allowing them to be easily
19
+ # compared or recalled.
20
+ #
21
+ # DataRows form the elements of DataSets
22
+ #
23
+ class DataRow
24
+
25
+ include Enumerable
26
+
27
+ # Takes data and field names as well as some optional parameters and
28
+ # constructs a DataRow.
29
+ #
30
+ #
31
+ # <tt>data</tt> can be specified in Hash, Array, or DataRow form
32
+ #
33
+ # Options:
34
+ # <tt>:filler</tt>:: this will be used as a default value for empty
35
+ # <tt>:tags</tt>:: an initial set of tags for the row
36
+ #
37
+ #
38
+ # Examples:
39
+ # >> Ruport::DataRow.new [1,2,3,4,5], [:a,:b,:c,:d,:e],
40
+ # :tags => %w[cat dog]
41
+ # => #<Ruport::DataRow:0xb77e4b04 @fields=[:a, :b, :c, :d, :e],
42
+ # @data=[1, 2, 3, 4, 5], @tags=["cat", "dog"]>
43
+ #
44
+ # >> Ruport::DataRow.new({ :a => 'moo', :c => 'caw'} , [:a,:b,:c,:d,:e],
45
+ # :tags => %w[cat dog])
46
+ # => #<Ruport::DataRow:0xb77c298c @fields=[:a, :b, :c, :d, :e],
47
+ # @data=["moo", nil, "caw", nil, nil], @tags=["cat", "dog"]>
48
+ #
49
+ # >> Ruport::DataRow.new [1,2,3], [:a,:b,:c,:d,:e], :tags => %w[cat dog],
50
+ # :filler => 0
51
+ # => #<Ruport::DataRow:0xb77bb4d4 @fields=[:a, :b, :c, :d, :e],
52
+ # @data=[1, 2, 3, 0, 0], @tags=["cat", "dog"]>
53
+ #
54
+ def initialize( data, fields, options={} )
55
+ @fields = fields
56
+ @tags = options[:tags] || {}
57
+ @data = []
58
+ nr_action =
59
+ if data.kind_of?(Array)
60
+ lambda { |key, index| @data[index] = data.shift || options[:filler] }
61
+ elsif data.kind_of?(DataRow)
62
+ lambda { |key, index| @data = data.to_a }
63
+ else
64
+ lambda { |key, index| @data[index] = data[key] || options[:filler] }
65
+ end
66
+ @fields.each_with_index { |key, index| nr_action.call(key,index) }
67
+ end
68
+
69
+ attr_accessor :fields, :tags
70
+
71
+ # Returns an array of values. Should probably return a DataRow.
72
+ # Loses field information.
73
+ def +(other)
74
+ self.to_a + other.to_a
75
+ end
76
+
77
+ # Lets you access individual fields
78
+ #
79
+ # i.e. row["phone"] or row[4]
80
+ def [](key)
81
+ key.kind_of?(Fixnum) ? @data[key] : @data[@fields.index(key)]
82
+ end
83
+
84
+ # Lets you set field values
85
+ #
86
+ # i.e. row["phone"] = '2038291203', row[7] = "allen"
87
+ def []=(key,value)
88
+ if key.kind_of?(Fixnum)
89
+ @data[key] = value
90
+ else
91
+ @data[@fields.index(key)] = value
92
+ end
93
+ end
94
+
95
+ # Converts the DataRow to a plain old Array
96
+ def to_a
97
+ @data
98
+ end
99
+
100
+ # Converts the DataRow to a string representation
101
+ # for outputting to screen.
102
+ def to_s
103
+ "[" + @data.join(",") + "]"
104
+ end
105
+
106
+ # Checks to see row includes the tag given.
107
+ #
108
+ # Example:
109
+ #
110
+ # >> row.has_tag? :running_balance
111
+ # => true
112
+ #
113
+ def has_tag?(tag)
114
+ @tags.include?(tag)
115
+ end
116
+
117
+ # Iterates through DataRow elements. Accepts a block.
118
+ def each(&action)
119
+ @data.each(&action)
120
+ end
121
+
122
+ # Allows you to add a tag to a row.
123
+ #
124
+ # Examples:
125
+ #
126
+ # row.tag_as(:jay_cross) if row["product"].eql?("im_courier")
127
+ # row.tag_as(:running_balance) if row.fields.include?("RB")
128
+ #
129
+ def tag_as(something)
130
+ @tags[something] = true
131
+ end
132
+
133
+ # Compares two DataRow objects. If values and fields are the same
134
+ # (and in the correct order) returns true. Otherwise returns false.
135
+ def ==(other)
136
+ self.to_a.eql?(other.to_a) && @fields.eql?(other.fields)
137
+ end
138
+
139
+ # Synonym for DataRow#==
140
+ def eql?
141
+ self == other
142
+ end
143
+ end
144
+ end