ruport 0.4.23 → 0.4.99

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/AUTHORS +16 -8
  2. data/CHANGELOG +30 -1
  3. data/README +144 -114
  4. data/Rakefile +12 -4
  5. data/TODO +4 -7
  6. data/bin/rope +21 -28
  7. data/examples/line_graph.rb +36 -0
  8. data/examples/sample_invoice_report.rb +1 -1
  9. data/examples/simple_graph.rb +8 -0
  10. data/lib/SVG/Graph/Bar.rb +137 -0
  11. data/lib/SVG/Graph/BarBase.rb +140 -0
  12. data/lib/SVG/Graph/BarHorizontal.rb +136 -0
  13. data/lib/SVG/Graph/Graph.rb +977 -0
  14. data/lib/SVG/Graph/Line.rb +444 -0
  15. data/lib/SVG/Graph/Pie.rb +394 -0
  16. data/lib/SVG/Graph/Plot.rb +494 -0
  17. data/lib/SVG/Graph/Schedule.rb +373 -0
  18. data/lib/SVG/Graph/TimeSeries.rb +241 -0
  19. data/lib/ruport.rb +2 -2
  20. data/lib/ruport/config.rb +47 -3
  21. data/lib/ruport/data/collection.rb +17 -1
  22. data/lib/ruport/data/record.rb +101 -8
  23. data/lib/ruport/data/set.rb +81 -2
  24. data/lib/ruport/data/set.rb.rej +147 -0
  25. data/lib/ruport/data/set.rb~ +73 -0
  26. data/lib/ruport/data/table.rb +127 -2
  27. data/lib/ruport/data/taggable.rb +21 -2
  28. data/lib/ruport/format.rb +36 -44
  29. data/lib/ruport/format/engine.rb +21 -1
  30. data/lib/ruport/format/plugin.rb +64 -1
  31. data/lib/ruport/mailer.rb +70 -36
  32. data/lib/ruport/meta_tools.rb +15 -6
  33. data/lib/ruport/query.rb +1 -1
  34. data/lib/ruport/rails/reportable.rb +23 -1
  35. data/lib/ruport/report.rb +11 -11
  36. data/lib/ruport/report/invoice.rb +16 -0
  37. data/lib/ruport/system_extensions.rb +3 -55
  38. data/test/{tc_database.rb → _test_database.rb} +0 -0
  39. data/test/{tc_config.rb → test_config.rb} +0 -0
  40. data/test/{tc_format.rb → test_format.rb} +1 -0
  41. data/test/{tc_format_engine.rb → test_format_engine.rb} +14 -2
  42. data/test/test_graph.rb +101 -0
  43. data/test/{tc_invoice.rb → test_invoice.rb} +7 -1
  44. data/test/test_mailer.rb +108 -0
  45. data/test/test_meta_tools.rb +14 -0
  46. data/test/{tc_plugin.rb → test_plugin.rb} +12 -1
  47. data/test/{tc_query.rb → test_query.rb} +0 -0
  48. data/test/{tc_record.rb → test_record.rb} +9 -0
  49. data/test/{tc_report.rb → test_report.rb} +2 -1
  50. data/test/{tc_ruport.rb → test_ruport.rb} +0 -0
  51. data/test/test_set.rb +118 -0
  52. data/test/test_set.rb.rej +16 -0
  53. data/test/{tc_set.rb → test_set.rb~} +17 -0
  54. data/test/{tc_sql_split.rb → test_sql_split.rb} +0 -0
  55. data/test/{tc_table.rb → test_table.rb} +15 -0
  56. data/test/{tc_taggable.rb → test_taggable.rb} +0 -0
  57. data/test/unit.log +361 -0
  58. metadata +52 -30
  59. data/examples/bar.pdf +0 -193
  60. data/examples/f.log +0 -5
  61. data/examples/foo.pdf +0 -193
  62. data/lib/ruport/format/document.rb +0 -78
  63. data/lib/ruport/format/open_node.rb +0 -38
  64. data/test/tc_data_row.rb +0 -132
  65. data/test/tc_data_set.rb +0 -386
  66. data/test/tc_document.rb +0 -42
  67. data/test/tc_element.rb +0 -18
  68. data/test/tc_page.rb +0 -42
  69. data/test/tc_section.rb +0 -45
  70. data/test/ts_all.rb +0 -12
  71. data/test/ts_format.rb +0 -7
@@ -0,0 +1,147 @@
1
+ ***************
2
+ *** 8,27 ****
3
+ module Ruport::Data
4
+ class Set < Collection
5
+
6
+ def initialize(options={})
7
+ @data = ::Set.new
8
+ options[:data].each {|e| self << e} if options[:data]
9
+ end
10
+
11
+ - def <<(other)
12
+ case other
13
+ when Record
14
+ @data << other
15
+ when Array
16
+ @data << Record.new(other)
17
+ end
18
+ end
19
+
20
+ def dup
21
+ a = self.class.new(:data=>@data)
22
+ a.tags = tags.dup
23
+ --- 8,42 ----
24
+ module Ruport::Data
25
+ class Set < Collection
26
+
27
+ + # Creates a new set containing the elements of options[:data].
28
+ + #
29
+ + # Set.new :data => [%w[one two three] %w[1 2 3] %w[I II III]]
30
+ def initialize(options={})
31
+ @data = ::Set.new
32
+ options[:data].each {|e| self << e} if options[:data]
33
+ end
34
+
35
+ + # Adds the given object to the set and returns self.
36
+ + # set = Set.new :data => [%w[one two three]]
37
+ + # set << [5,6,7]
38
+ + def add(other)
39
+ case other
40
+ when Record
41
+ @data << other
42
+ when Array
43
+ @data << Record.new(other)
44
+ end
45
+ + self
46
+ end
47
+ + alias_method :<<, :add
48
+
49
+ + # Produces a shallow copy of the set: the same data is referenced by both
50
+ + # the old and new sets.
51
+ + # set = Set.new :data => [%w[one two three]]
52
+ + # set2 = set.dup
53
+ + # set == set2 => true
54
+ + # set << [8,9,10]
55
+ + # set == set2 => false
56
+ def dup
57
+ a = self.class.new(:data=>@data)
58
+ a.tags = tags.dup
59
+ ***************
60
+ *** 29,53 ****
61
+ end
62
+ alias_method :clone, :dup
63
+
64
+ def ==(other)
65
+ @data == other.data
66
+ end
67
+
68
+ def |(other)
69
+ Set.new :data => (@data | other.data)
70
+ end
71
+ alias_method :union, :|
72
+
73
+ def &(other)
74
+ Set.new :data => (@data & other.data)
75
+ end
76
+ alias_method :intersection, :&
77
+
78
+ - # Set difference
79
+ def -(other)
80
+ Set.new :data => (@data - other.data)
81
+ end
82
+ alias_method :difference, :-
83
+
84
+ def_delegators :@data, :each
85
+ end
86
+ --- 44,104 ----
87
+ end
88
+ alias_method :clone, :dup
89
+
90
+ + # Equality. Two sets are equal if they contain the same set of objects.
91
+ + # s1 = Set.new :data => [[1,2,3]]
92
+ + # s2 = Set.new :data => [[1,2,3]]
93
+ + # s1 == s2 => true
94
+ def ==(other)
95
+ @data == other.data
96
+ end
97
+
98
+ + # Union. Returns a new set containing the union of the objects contained in
99
+ + # the two sets.
100
+ + # s1 = Set.new :data => [[1,2,3]]
101
+ + # s2 = Set.new :data => [[4,5,6]]
102
+ + # s3 = s1 | s2
103
+ + # s4 = Set.new :data => [[1,2,3], [4,5,6]]
104
+ + # s3 == s4 => true
105
+ def |(other)
106
+ Set.new :data => (@data | other.data)
107
+ end
108
+ alias_method :union, :|
109
+ + alias_method :+, :|
110
+
111
+ + # Intersection. Returns a new set containing the objects common to the two
112
+ + # sets.
113
+ + # s1 = Set.new :data => [%w[a b c],[1,2,3]]
114
+ + # s2 = Set.new :data => [%w[a b c],[4,5,6]]
115
+ + # s3 = s1 | s2
116
+ + # s4 = Set.new :data => [%w[a b c]]
117
+ + # s3 == s4 => true
118
+ def &(other)
119
+ Set.new :data => (@data & other.data)
120
+ end
121
+ alias_method :intersection, :&
122
+
123
+ + # Difference. Returns a new set containing those objects present in this
124
+ + # set but not the other.
125
+ + # s1 = Set.new :data => [%w[a b c],[1,2,3]]
126
+ + # s2 = Set.new :data => [%w[a b c],[4,5,6]]
127
+ + # s3 = s1 | s2
128
+ + # s4 = Set.new :data => [[1, 2, 3]]
129
+ + # s3 == s4 => true
130
+ def -(other)
131
+ Set.new :data => (@data - other.data)
132
+ end
133
+ alias_method :difference, :-
134
+ +
135
+ + # Exclusion. Returns a new set containing those objects in this set or the
136
+ + # other set but not in both.
137
+ + # s1 = Set.new :data => [%w[a b c],[1,2,3]]
138
+ + # s2 = Set.new :data => [%w[a b c],[4,5,6]]
139
+ + # s3 = s1 | s2
140
+ + # s4 = Set.new :data => [[1, 2, 3],[4,5,6]]
141
+ + # s3 == s4 => true
142
+ + def ^(other)
143
+ + Set.new :data => (@data ^ other.data)
144
+ + end
145
+
146
+ def_delegators :@data, :each
147
+ end
@@ -0,0 +1,73 @@
1
+ # The Ruport Data Collections.
2
+ # Authors: Gregory Brown / Dudley Flanders
3
+ #
4
+ # This is Free Software. For details, see LICENSE and COPYING
5
+ # Copyright 2006 by respective content owners, all rights reserved.
6
+ require 'set'
7
+
8
+ module Ruport::Data
9
+ class Set < Collection
10
+
11
+ # Creates a new set containing the elements of options[:data].
12
+ def initialize(options={})
13
+ @data = ::Set.new
14
+ options[:data].each {|e| self << e} if options[:data]
15
+ end
16
+
17
+ # Adds the given object to the set and returns self.
18
+ def add(other)
19
+ case other
20
+ when Record
21
+ @data << other
22
+ when Array
23
+ @data << Record.new(other)
24
+ end
25
+ self
26
+ end
27
+ alias_method :<<, :add
28
+
29
+ # Produces a shallow copy of the set: the same data is referenced by both
30
+ # the old and new sets.
31
+ def dup
32
+ a = self.class.new(:data=>@data)
33
+ a.tags = tags.dup
34
+ return a
35
+ end
36
+ alias_method :clone, :dup
37
+
38
+ # Equality. Two sets are equal if they contain the same set of objects.
39
+ def ==(other)
40
+ @data == other.data
41
+ end
42
+
43
+ # Union. Returns a new set containing the union of the objects contained in
44
+ # the two sets.
45
+ def |(other)
46
+ Set.new :data => (@data | other.data)
47
+ end
48
+ alias_method :union, :|
49
+ alias_method :+, :|
50
+
51
+ # Intersection. Returns a new set containing the objects common to the two
52
+ # sets.
53
+ def &(other)
54
+ Set.new :data => (@data & other.data)
55
+ end
56
+ alias_method :intersection, :&
57
+
58
+ # Difference. Returns a new set containing those objects present in this
59
+ # set but not the other.
60
+ def -(other)
61
+ Set.new :data => (@data - other.data)
62
+ end
63
+ alias_method :difference, :-
64
+
65
+ # Exclusion. Returns a new set containing those objects in this set or the
66
+ # other set but not in both.
67
+ def ^(other)
68
+ Set.new :data => (@data ^ other.data)
69
+ end
70
+
71
+ def_delegators :@data, :each
72
+ end
73
+ end
@@ -1,4 +1,14 @@
1
+ # The Ruport Data Collections.
2
+ # Authors: Gregory Brown / Dudley Flanders
3
+ #
4
+ # This is Free Software. For details, see LICENSE and COPYING
5
+ # Copyright 2006 by respective content owners, all rights reserved.
6
+
1
7
  class Array
8
+ # Converts an array to a Ruport::Data::Table object, ready to
9
+ # use in your reports.
10
+ #
11
+ # [[1,2],[3,4]].to_table(%w[a b])
2
12
  def to_table(options={})
3
13
  options = { :column_names => options } if options.kind_of? Array
4
14
  Ruport::Data::Table.new({:data => self}.merge(options))
@@ -6,7 +16,29 @@ class Array
6
16
  end
7
17
 
8
18
  module Ruport::Data
19
+
20
+ # This class is one of the core classes for building and working with data
21
+ # in Ruport. The idea is to get your data into a standard form, regardless
22
+ # of its source (a database, manual arrays, ActiveRecord, CSVs, etc.).
23
+ #
24
+ # Table is intended to be used as the data store for structured, tabular
25
+ # data - Ruport::Data::Set is an alternate intermediary data store intended
26
+ # for less structured data.
27
+ #
28
+ # Once your data is in a Ruport::Data::Table object, it can be manipulated
29
+ # to suit your needs, then used to build a report.
30
+ #
31
+ # Included in this class are methods to create Tables manually and from CSV
32
+ # files.
33
+ #
34
+ # For building a table using ActiveRecord, have a look at Ruport::Reportable.
9
35
  class Table < Collection
36
+
37
+ # Creates a new table based on the supplied options.
38
+ # Valid options are :data and :column_names.
39
+ #
40
+ # table = Table.new({:data => [1,2,3], [3,4,5],
41
+ # :column_names => %w[a b c]})
10
42
  def initialize(options={})
11
43
  @column_names = options[:column_names].dup if options[:column_names]
12
44
  @data = []
@@ -15,20 +47,42 @@ module Ruport::Data
15
47
 
16
48
  attr_reader :column_names
17
49
 
50
+ # Sets the column names for this table. The single parameter should be
51
+ # an array listing the names of the columns.
52
+ #
53
+ # tbl = Table.new({:data => [1,2,3], [3,4,5], :column_names => %w[a b c]})
54
+ # tbl.column_names = %w[e f g]
18
55
  def column_names=(other)
19
56
  @column_names = other.dup
20
57
  map { |r| r.attributes = @column_names }
21
58
  end
22
59
 
60
+ # Compares this table to another table and returns true if
61
+ # both the data and column names are equal
62
+ #
63
+ # one = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
64
+ # two = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
65
+ # one.eql?(two) #=> true
23
66
  def eql?(other)
24
67
  data.eql?(other.data) && column_names.eql?(other.column_names)
25
68
  end
26
69
  alias_method :==, :eql?
27
70
 
71
+ # Uses Ruport's built-in text plugin to render this table into a string
72
+ #
73
+ # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
74
+ # puts data.to_s
28
75
  def to_s
29
76
  as(:text)
30
77
  end
31
78
 
79
+ # Used to add extra data to the table. The single parameter can be an
80
+ # Array, Hash or Ruport::Data::Record.
81
+ #
82
+ # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
83
+ # data << [8,9]
84
+ # data << { :a => 4, :b => 5}
85
+ # data << Ruport::Data::Record.new [5,6], :attributes => %w[a b]
32
86
  def <<(other)
33
87
  case other
34
88
  when Array
@@ -39,12 +93,19 @@ module Ruport::Data
39
93
  @data << Record.new(arr, :attributes => @column_names)
40
94
  when Record
41
95
  raise ArgumentError unless column_names.eql? other.attributes
42
- @data << Record.new(other.to_a, :attributes => @column_names)
96
+ @data << Record.new(other.data, :attributes => @column_names)
97
+ @data.last.tags = other.tags.dup
43
98
  end
44
99
  self
45
100
  end
46
-
101
+
102
+ # Reorders the columns that exist in the table. Operates directly
103
+ # on this table.
104
+ #
105
+ # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
106
+ # data.reorder!([1,0])
47
107
  def reorder!(*indices)
108
+ indices = indices[0] if indices[0].kind_of? Array
48
109
  @column_names = if indices.all? { |i| i.kind_of? Integer }
49
110
  indices.map { |i| @column_names[i] }
50
111
  else
@@ -53,10 +114,21 @@ module Ruport::Data
53
114
  @data.each { |r| r.reorder! *indices }; self
54
115
  end
55
116
 
117
+ # Returns a copy of the table with its columns in the requested order.
118
+ #
119
+ # one = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
120
+ # two = one.reorder!([1,0])
56
121
  def reorder(*indices)
57
122
  dup.reorder! *indices
58
123
  end
59
124
 
125
+ # Adds an extra column to the table. Accepts an options Hash as its
126
+ # only parameter which should contain 2 keys - :name and :fill.
127
+ # :name specifies the new columns name, and :fill the default value to
128
+ # use for the column in existing rows.
129
+ #
130
+ # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
131
+ # data.append_coulmn({:name => 'new_column', :fill => 1)
60
132
  def append_column(options={})
61
133
  self.column_names += [options[:name]] if options[:name]
62
134
  if block_given?
@@ -66,10 +138,32 @@ module Ruport::Data
66
138
  end
67
139
  end
68
140
 
141
+ # Removes a column from the table. Any values in the specified column are
142
+ # lost.
143
+ # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
144
+ # data.append_column({:name => 'new_column', :fill => 1)
145
+ # data.remove_column({:name => 'new_column')
146
+ # data == Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
147
+ # => true
148
+ def remove_column(options={})
149
+ raise ArgumentError unless column_names.include? options[:name]
150
+ reorder! column_names - [options[:name]]
151
+ end
152
+
153
+ # Create a shallow copy of the table: the same data elements are referenced
154
+ # by both the old and new table.
155
+ #
156
+ # one = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
157
+ # two = one.dup
69
158
  def dup
70
159
  a = self.class.new(:data => @data, :column_names => @column_names)
160
+ a.tags = tags.dup
161
+ return a
71
162
  end
72
163
 
164
+ # Loads a CSV file directly into a table using the fasterCSV library.
165
+ #
166
+ # data = Table.load('mydata.csv')
73
167
  def self.load(csv_file, options = {})
74
168
  options = {:has_names => true}.merge(options)
75
169
  require "fastercsv"
@@ -88,6 +182,37 @@ module Ruport::Data
88
182
  end ; loaded_data
89
183
  end
90
184
 
185
+
186
+
187
+ # Allows you to split tables into multiple tables for grouping.
188
+ #
189
+ # Example:
190
+ #
191
+ # a = Table.new(:column_name => %w[name a b c])
192
+ # a << ["greg",1,2,3]
193
+ # a << ["joe", 2,3,4]
194
+ # a << ["greg",7,8,9]
195
+ # a << ["joe", 1,2,3]
196
+ #
197
+ # b = a.split :group => "name"
198
+ #
199
+ # b.greg.eql? [[1,2,3],[7,8,9]].to_table(%w[a b c]) #=> true
200
+ # b["joe"].eql? [[2,3,4],[1,2,3]].to_table(%w[a b c]) #=> true
201
+ #
202
+ # You can also pass an array to :group, and the resulting attributes in
203
+ # the group will be joined by an underscore.
204
+ #
205
+ # Example:
206
+ #
207
+ # a = Table.new(:column_names => %w[first_name last_name x]
208
+ # a << %w[greg brown foo]
209
+ # a << %w[greg gibson bar]
210
+ # a << %w[greg brown baz]
211
+ #
212
+ # b = a.split :group => %w[first_name last_name]
213
+ # a.greg_brown.length #=> 2
214
+ # a["greg_gibson"].length #=> 1
215
+ # a.greg_brown[0].x #=> "foo"
91
216
  def split(options={})
92
217
  if options[:group].kind_of? Array
93
218
  group = map { |r| options[:group].map { |e| r[e] } }.uniq
@@ -1,23 +1,42 @@
1
+ # The Ruport Data Collections.
2
+ # Authors: Gregory Brown / Dudley Flanders
3
+ #
4
+ # This is Free Software. For details, see LICENSE and COPYING
5
+ # Copyright 2006 by respective content owners, all rights reserved.
1
6
  module Ruport::Data
2
7
 
8
+ # This module provides a simple mechanism for tagging arbitrary objects. This
9
+ # provides the necessary methods to set and retrieve tags which can consist of
10
+ # any Ruby object. This is used by Data::Record and the Ruport Data
11
+ # Collections.
3
12
  module Taggable
4
13
 
14
+ # Adds a tag to the object
15
+ # taggable_obj.tag :spiffy
5
16
  def tag(tag_name)
6
17
  tags << tag_name unless has_tag? tag_name
7
18
  end
8
-
19
+
20
+ # Removes a tag
21
+ # taggable_obj.delete_tag :not_so_spiffy
9
22
  def delete_tag(tag_name)
10
23
  tags.delete tag_name
11
24
  end
12
25
 
26
+ # Checks to see if a tag is present
27
+ # taggable_obj.has_tag? :spiffy #=> true
13
28
  def has_tag?(tag_name)
14
29
  tags.include? tag_name
15
30
  end
16
31
 
32
+ # Returns an array of tags.
33
+ # taggable_obj.tags #=> [:spiffy, :kind_of_spiffy]
17
34
  def tags
18
35
  @ruport_tags ||= []
19
36
  end
20
-
37
+
38
+ # Sets the tags to some array
39
+ # taggable_obj.tags = [:really_dang_spiffy, :the_most_spiffy]
21
40
  def tags=(tags_list)
22
41
  @ruport_tags = tags_list
23
42
  end