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
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